From 5d0294f5f5196070479e64bacdbf2d7ea9abf852 Mon Sep 17 00:00:00 2001 From: Zignature Date: Sat, 15 Jan 2022 13:20:28 +0100 Subject: [PATCH 1/8] Fix issue #373 problems in urls with special characters Added function to escape URLs entered via JS prompt. It's a partial fix because people cannot be stopped entering URLs manually and forgetting to escape them. --- src/js/easymde.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/js/easymde.js b/src/js/easymde.js index cece3b0..72f7254 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -848,6 +848,8 @@ function drawLink(editor) { if (!url) { return false; } + + if (/[()<>]/.test(url)) url = escapeUrl(url); } _replaceSelection(cm, stat.link, options.insertTexts.link, url); } @@ -865,10 +867,26 @@ function drawImage(editor) { if (!url) { return false; } + + if (/[()<>]/.test(url)) url = escapeUrl(url); } _replaceSelection(cm, stat.image, options.insertTexts.image, url); } +/** + * Escape URLs to prevent breaking up rendered Markdown links + * @param url {string} The url of the link or image + */ +function escapeUrl(url) { + + url = url.replace(/\(/g,'\\(') + .replace(/\)/g,'\\)') + .replace(//g,'\\>'); + + return url; +} + /** * Action for opening the browse-file window to upload an image to a server. * @param editor {EasyMDE} The EasyMDE object From 33489ab616bc2282d29287c1eb55f16948197f48 Mon Sep 17 00:00:00 2001 From: Zignature Date: Sat, 15 Jan 2022 23:26:10 +0100 Subject: [PATCH 2/8] URL encoding and escaping for JS prompt URLs - URL encoding and escaping added for JS prompt entered URLs - added option escapeURLs (boolean) --- src/js/easymde.js | 18 ++++++++++-------- types/easymde.d.ts | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 72f7254..b419d5d 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -849,7 +849,10 @@ function drawLink(editor) { return false; } - if (/[()<>]/.test(url)) url = escapeUrl(url); + if (options.escapeURLs) { + url = encodeURI(url); + if (/[()]/.test(url)) url = escapeURI(url); + } } _replaceSelection(cm, stat.link, options.insertTexts.link, url); } @@ -868,7 +871,10 @@ function drawImage(editor) { return false; } - if (/[()<>]/.test(url)) url = escapeUrl(url); + if (options.escapeURLs) { + url = encodeURI(url); + if (/[()]/.test(url)) url = escapeURI(url); + } } _replaceSelection(cm, stat.image, options.insertTexts.image, url); } @@ -877,12 +883,8 @@ function drawImage(editor) { * Escape URLs to prevent breaking up rendered Markdown links * @param url {string} The url of the link or image */ -function escapeUrl(url) { - - url = url.replace(/\(/g,'\\(') - .replace(/\)/g,'\\)') - .replace(//g,'\\>'); +function escapeURI(url) { + url = url.replace(/\(/g,'\\(').replace(/\)/g,'\\)'); return url; } diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 2aa161b..b082324 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -197,6 +197,7 @@ declare namespace EasyMDE { previewImagesInEditor?: boolean; previewRender?: (markdownPlaintext: string, previewElement: HTMLElement) => string; promptURLs?: boolean; + escapeURLs?: boolean; renderingConfig?: RenderingOptions; shortcuts?: Shortcuts; showIcons?: ReadonlyArray; From c174b6f149ce9dd6d540beda91331ba7a936e593 Mon Sep 17 00:00:00 2001 From: Zignature Date: Sat, 15 Jan 2022 23:34:05 +0100 Subject: [PATCH 3/8] Changed function name escapeURI to escapedPromptURL and option escapeURLs to option escapePromptURLs --- src/js/easymde.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index b419d5d..8aedf80 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -849,9 +849,9 @@ function drawLink(editor) { return false; } - if (options.escapeURLs) { + if (options.escapePromptURLs) { url = encodeURI(url); - if (/[()]/.test(url)) url = escapeURI(url); + if (/[()]/.test(url)) url = escapePromptURL(url); } } _replaceSelection(cm, stat.link, options.insertTexts.link, url); @@ -871,9 +871,9 @@ function drawImage(editor) { return false; } - if (options.escapeURLs) { + if (options.escapePromptURLs) { url = encodeURI(url); - if (/[()]/.test(url)) url = escapeURI(url); + if (/[()]/.test(url)) url = escapePromptURL(url); } } _replaceSelection(cm, stat.image, options.insertTexts.image, url); @@ -883,7 +883,7 @@ function drawImage(editor) { * Escape URLs to prevent breaking up rendered Markdown links * @param url {string} The url of the link or image */ -function escapeURI(url) { +function escapePromptURL(url) { url = url.replace(/\(/g,'\\(').replace(/\)/g,'\\)'); return url; From 47f1e4f892b36b8171f043a9dc5d73a0efe9fef2 Mon Sep 17 00:00:00 2001 From: Zignature Date: Sat, 15 Jan 2022 23:56:27 +0100 Subject: [PATCH 4/8] Updated readme and easymde.d.ts to reflect escapePrompURLs option --- README.md | 2 ++ types/easymde.d.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f47da4c..fa0b07a 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ easyMDE.value('New input for **EasyMDE**'); - **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`. +- **escapePromptURLs**: If set to `true`, urlencodes and escapes links entered via the JS prompt to prevent malformed Markdown rendered links. Only works when `promptURLs` is set to `true`. Defaults to `false`. - **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:`. @@ -276,6 +277,7 @@ const editor = new EasyMDE({ return "Loading..."; }, promptURLs: true, + escapePromptURLs: true, promptTexts: { image: "Custom prompt for URL:", link: "Custom prompt for URL:", diff --git a/types/easymde.d.ts b/types/easymde.d.ts index b082324..12ba258 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -197,7 +197,7 @@ declare namespace EasyMDE { previewImagesInEditor?: boolean; previewRender?: (markdownPlaintext: string, previewElement: HTMLElement) => string; promptURLs?: boolean; - escapeURLs?: boolean; + escapePromptURLs?: boolean; renderingConfig?: RenderingOptions; shortcuts?: Shortcuts; showIcons?: ReadonlyArray; From 16545eb0e1b0224e4e1402523aa85e1d0038d5a8 Mon Sep 17 00:00:00 2001 From: Zignature Date: Sun, 16 Jan 2022 00:14:00 +0100 Subject: [PATCH 5/8] Made escaping prompt URLs automatic instead of optional again --- README.md | 2 -- src/js/easymde.js | 12 ++++-------- types/easymde.d.ts | 1 - 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index fa0b07a..f47da4c 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,6 @@ easyMDE.value('New input for **EasyMDE**'); - **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`. -- **escapePromptURLs**: If set to `true`, urlencodes and escapes links entered via the JS prompt to prevent malformed Markdown rendered links. Only works when `promptURLs` is set to `true`. Defaults to `false`. - **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:`. @@ -277,7 +276,6 @@ const editor = new EasyMDE({ return "Loading..."; }, promptURLs: true, - escapePromptURLs: true, promptTexts: { image: "Custom prompt for URL:", link: "Custom prompt for URL:", diff --git a/src/js/easymde.js b/src/js/easymde.js index 8aedf80..db068ef 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -849,10 +849,8 @@ function drawLink(editor) { return false; } - if (options.escapePromptURLs) { - url = encodeURI(url); - if (/[()]/.test(url)) url = escapePromptURL(url); - } + url = encodeURI(url); + if (/[()]/.test(url)) url = escapePromptURL(url); } _replaceSelection(cm, stat.link, options.insertTexts.link, url); } @@ -871,10 +869,8 @@ function drawImage(editor) { return false; } - if (options.escapePromptURLs) { - url = encodeURI(url); - if (/[()]/.test(url)) url = escapePromptURL(url); - } + url = encodeURI(url); + if (/[()]/.test(url)) url = escapePromptURL(url); } _replaceSelection(cm, stat.image, options.insertTexts.image, url); } diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 12ba258..2aa161b 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -197,7 +197,6 @@ declare namespace EasyMDE { previewImagesInEditor?: boolean; previewRender?: (markdownPlaintext: string, previewElement: HTMLElement) => string; promptURLs?: boolean; - escapePromptURLs?: boolean; renderingConfig?: RenderingOptions; shortcuts?: Shortcuts; showIcons?: ReadonlyArray; From 0c2cf4cd51a0f1fe721e7dc70adfdc768449a20c Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Mon, 17 Jan 2022 00:04:18 +0100 Subject: [PATCH 6/8] Add tests for url prompts --- .../{default.html => index.html} | 0 .../1-default-editor/preview.spec.js | 6 +- .../1-default-editor/statusbar.spec.js | 2 +- .../1-default-editor/visual.spec.js | 4 +- cypress/integration/2-url-prompt/index.html | 20 ++ .../2-url-prompt/url-prompt.spec.js | 228 ++++++++++++++++++ cypress/support/commands.js | 16 ++ 7 files changed, 269 insertions(+), 7 deletions(-) rename cypress/integration/1-default-editor/{default.html => index.html} (100%) create mode 100644 cypress/integration/2-url-prompt/index.html create mode 100644 cypress/integration/2-url-prompt/url-prompt.spec.js diff --git a/cypress/integration/1-default-editor/default.html b/cypress/integration/1-default-editor/index.html similarity index 100% rename from cypress/integration/1-default-editor/default.html rename to cypress/integration/1-default-editor/index.html diff --git a/cypress/integration/1-default-editor/preview.spec.js b/cypress/integration/1-default-editor/preview.spec.js index ced582c..e437bbe 100644 --- a/cypress/integration/1-default-editor/preview.spec.js +++ b/cypress/integration/1-default-editor/preview.spec.js @@ -2,7 +2,7 @@ describe('Preview', () => { beforeEach(() => { - cy.visit(__dirname + '/default.html'); + cy.visit(__dirname + '/index.html'); }); it('can show a preview of markdown text', () => { @@ -22,9 +22,7 @@ describe('Preview', () => { cy.get('.EasyMDEContainer .cm-strong').should('contain', '**'); cy.get('.EasyMDEContainer .cm-strong').should('contain', 'important'); - // Toggle preview. - cy.get('.EasyMDEContainer .editor-toolbar button.preview').click(); - cy.get('.EasyMDEContainer .editor-preview').should('be.visible'); + cy.previewOn(); // Check preview window for rendered markdown. cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

My Big Title

'); diff --git a/cypress/integration/1-default-editor/statusbar.spec.js b/cypress/integration/1-default-editor/statusbar.spec.js index 12e8276..9b96735 100644 --- a/cypress/integration/1-default-editor/statusbar.spec.js +++ b/cypress/integration/1-default-editor/statusbar.spec.js @@ -2,7 +2,7 @@ describe('Default statusbar', () => { beforeEach(() => { - cy.visit(__dirname + '/default.html'); + cy.visit(__dirname + '/index.html'); }); it('loads the editor with default statusbar', () => { diff --git a/cypress/integration/1-default-editor/visual.spec.js b/cypress/integration/1-default-editor/visual.spec.js index 0ba1afc..18b7be2 100644 --- a/cypress/integration/1-default-editor/visual.spec.js +++ b/cypress/integration/1-default-editor/visual.spec.js @@ -2,10 +2,10 @@ describe('Default editor', () => { beforeEach(() => { - cy.visit(__dirname + '/default.html'); + cy.visit(__dirname + '/index.html'); }); - it('Loads the editor with default settings', () => { + it('loads the editor with default settings', () => { cy.get('.EasyMDEContainer').should('be.visible'); cy.get('#textarea').should('not.be.visible'); diff --git a/cypress/integration/2-url-prompt/index.html b/cypress/integration/2-url-prompt/index.html new file mode 100644 index 0000000..aa5f9e5 --- /dev/null +++ b/cypress/integration/2-url-prompt/index.html @@ -0,0 +1,20 @@ + + + + + + Default + + + + + + + + + + diff --git a/cypress/integration/2-url-prompt/url-prompt.spec.js b/cypress/integration/2-url-prompt/url-prompt.spec.js new file mode 100644 index 0000000..1436b12 --- /dev/null +++ b/cypress/integration/2-url-prompt/url-prompt.spec.js @@ -0,0 +1,228 @@ +/// + +describe('URL prompts', () => { + beforeEach(() => { + cy.visit(__dirname + '/index.html'); + }); + + it('must show the correct text for a link prompt', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + const stub = cy.stub($win, 'prompt'); + cy.get('button.link').click().then(() => { + expect(stub).to.be.calledWith('URL for the link:', 'https://'); + }); + }); + }); + + it('must show the correct text for an image prompt', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + const stub = cy.stub($win, 'prompt'); + cy.get('button.image').click().then(() => { + expect(stub).to.be.calledWith('URL of the image:', 'https://'); + }); + }); + }); + + it('must enter a link correctly through a prompt', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com)'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a website!

'); + }); + + it('can use the prompt multiple times', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + const stub = cy.stub($win, 'prompt'); + stub.returns('https://example.com'); + cy.get('button.link').click().then(() => { + expect(stub).to.be.calledWith('URL for the link:', 'https://'); + stub.restore(); + }); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com)'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!{end}{enter}'); + + cy.window().then(($win) => { + const stub = cy.stub($win, 'prompt'); + stub.returns('https://example.eu'); + cy.get('button.link').click().then(() => { + expect(stub).to.be.calledWith('URL for the link:', 'https://'); + stub.restore(); + }); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.eu)'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a second website!'); + + cy.get('.EasyMDEContainer .CodeMirror').contains('[Link to a website!](https://example.com)'); + cy.get('.EasyMDEContainer .CodeMirror').contains('[Link to a second website!](https://example.eu)'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should( + 'contain.html', + '

Link to a website!
Link to a second website!

', + ); + }); + + it('must be able to deal with parameters in links', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=param&moo=cow'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com?some=param&moo=cow)'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a website!

'); + }); + + it('must be able to deal with brackets in links', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=[]param'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com?some=%5B%5Dparam)'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a website!

'); + }); + + it('must be able to deal with parentheses in links', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=(param)'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com?some=\\(param\\))'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a website!

'); + }); + + it('must be able to deal with parentheses in links (multiple)', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=(param1,param2)&more=(param3,param4)&end=true'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com?some=\\(param1,param2\\)&more=\\(param3,param4\\)&end=true)'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a website!

'); + }); + + it('must be able to deal with unbalanced parentheses in links (opening)', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=(param'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com?some=\\(param)'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a website!

'); + }); + + it('must be able to deal with unbalanced parentheses in links (closing)', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=)param'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com?some=\\)param)'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a website!

'); + }); + + it('must be able to deal with inequality symbols in links', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=Link to a website!

'); + }); + + it('must be able to deal with emoji in links', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=👷‍♂️'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com?some=%F0%9F%91%B7%E2%80%8D%E2%99%82%EF%B8%8F'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a 👌 website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a 👌 website!

'); + }); + + it('must be able to deal with spaces in links', () => { + cy.get('.EasyMDEContainer').should('be.visible'); + cy.get('#textarea').should('not.be.visible'); + + cy.window().then(($win) => { + cy.stub($win, 'prompt').returns('https://example.com?some=very special param'); + cy.get('button.link').click(); + }); + cy.get('.EasyMDEContainer .CodeMirror').contains('[](https://example.com?some=very%20special%20param'); + cy.get('.EasyMDEContainer .CodeMirror').type('{home}{rightarrow}Link to a website!'); + + cy.previewOn(); + + cy.get('.EasyMDEContainer .editor-preview').should('contain.html', '

Link to a website!

'); + }); +}); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index d7e51ad..4927ac8 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -13,3 +13,19 @@ Cypress.Commands.add( return unquote(before.getPropertyValue(property)); }, ); + +Cypress.Commands.add('previewOn' , () => { + cy.get('.EasyMDEContainer .editor-preview').should('not.be.visible'); + cy.get('.EasyMDEContainer .editor-toolbar button.preview').should('not.have.class', 'active'); + cy.get('.EasyMDEContainer .editor-toolbar button.preview').click(); + cy.get('.EasyMDEContainer .editor-toolbar button.preview').should('have.class', 'active'); + cy.get('.EasyMDEContainer .editor-preview').should('be.visible'); +}); + +Cypress.Commands.add('previewOff' , () => { + cy.get('.EasyMDEContainer .editor-preview').should('be.visible'); + cy.get('.EasyMDEContainer .editor-toolbar button.preview').should('have.class', 'active'); + cy.get('.EasyMDEContainer .editor-toolbar button.preview').click(); + cy.get('.EasyMDEContainer .editor-toolbar button.preview').should('not.have.class', 'active'); + cy.get('.EasyMDEContainer .editor-preview').should('not.be.visible'); +}); From d8eae5d74c96e5b5dfa52ac39b92e76de432233b Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Mon, 17 Jan 2022 00:06:44 +0100 Subject: [PATCH 7/8] Improve readability of encode/escape functionality --- src/js/easymde.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index db068ef..dbb0135 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -844,13 +844,11 @@ function drawLink(editor) { var options = editor.options; var url = 'https://'; if (options.promptURLs) { - url = prompt(options.promptTexts.link, 'https://'); + url = prompt(options.promptTexts.link, url); if (!url) { return false; } - - url = encodeURI(url); - if (/[()]/.test(url)) url = escapePromptURL(url); + url = escapePromptURL(url); } _replaceSelection(cm, stat.link, options.insertTexts.link, url); } @@ -864,25 +862,21 @@ function drawImage(editor) { var options = editor.options; var url = 'https://'; if (options.promptURLs) { - url = prompt(options.promptTexts.image, 'https://'); + url = prompt(options.promptTexts.image, url); if (!url) { return false; } - - url = encodeURI(url); - if (/[()]/.test(url)) url = escapePromptURL(url); + url = escapePromptURL(url); } _replaceSelection(cm, stat.image, options.insertTexts.image, url); } /** - * Escape URLs to prevent breaking up rendered Markdown links + * Encode and escape URLs to prevent breaking up rendered Markdown links. * @param url {string} The url of the link or image */ function escapePromptURL(url) { - url = url.replace(/\(/g,'\\(').replace(/\)/g,'\\)'); - - return url; + return encodeURI(url).replace(/([\\()])/g, '\\$1'); } /** From 81ec7780bc462e38755bf03ab52ed8bf797cd3f0 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Mon, 17 Jan 2022 00:09:00 +0100 Subject: [PATCH 8/8] Update changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4090519..a7b979f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,10 @@ 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 +- URLs with certain characters entered through prompts causing invalid markdown (Thanks to [@Zignature], [#393]). + ## [2.16.1] - 2022-01-14 ### Fixed - Incorrect initial line and column count in status bar. @@ -240,6 +243,7 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown [#9]: https://github.com/Ionaru/easy-markdown-editor/issues/9 +[#393]: https://github.com/Ionaru/easy-markdown-editor/pull/393 [#389]: https://github.com/Ionaru/easy-markdown-editor/pull/389 [#388]: https://github.com/Ionaru/easy-markdown-editor/pull/388 [#384]: https://github.com/Ionaru/easy-markdown-editor/pull/384