diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6 index 8042d248da4..876851b6588 100644 --- a/app/assets/javascripts/discourse/components/composer-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6 @@ -836,7 +836,11 @@ export default Component.extend({ return; } - const replacement = match.replace(imageScaleRegex, `$1,${scale}%$3`); + const replacement = match.replace( + imageScaleRegex, + `![$1|$2, ${scale}%]($4)` + ); + this.appEvents.trigger( "composer:replace-text", matchingPlaceholder[index], @@ -851,11 +855,18 @@ export default Component.extend({ // regex matches only upload placeholders with size defined, // which is required for resizing - // original string `![28|690x226,5%](upload://ceEfx3vO7bx7Cecv2co1SrnoTpW.png)` - // match 1 `![28|690x226` - // match 2 `5` - // match 3 `](upload://ceEfx3vO7bx7Cecv2co1SrnoTpW.png)` - const imageScaleRegex = /(!\[(?:\S*?(?=\|)\|)*?(?:\d{1,6}x\d{1,6})+?)(?:,?(\d{1,3})?%?)?(\]\(upload:\/\/\S*?\))/g; + // original string `![image|690x220, 50%](upload://1TjaobgKObzpU7xRMw2HuUc87vO.png "image title")` + // group 1 `image` + // group 2 `690x220` + // group 3 `, 50%` + // group 4 'upload://1TjaobgKObzpU7xRMw2HuUc87vO.png' + // group 4 'upload://1TjaobgKObzpU7xRMw2HuUc87vO.png "image title"' + + // Notes: + // Group 3 is optional. group 4 can match images with or without a markdown title. + // All matches are whitespace tolerant as long it's still valid markdown + + const imageScaleRegex = /!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?\]\((upload:\/\/.*?)\)/g; // wraps previewed upload markdown in a codeblock in its own class to keep a track // of indexes later on to replace the correct upload placeholder in the composer diff --git a/test/javascripts/acceptance/composer-test.js.es6 b/test/javascripts/acceptance/composer-test.js.es6 index 39573aa31be..655df953570 100644 --- a/test/javascripts/acceptance/composer-test.js.es6 +++ b/test/javascripts/acceptance/composer-test.js.es6 @@ -721,49 +721,68 @@ QUnit.test("Image resizing buttons", async assert => { await click("#create-topic"); let uploads = [ + // 0 Default markdown with dimensions- should work "![test|690x313](upload://test.png)", - "[img]http://example.com/image.jpg[/img]", - "![anotherOne|690x463](upload://anotherOne.jpeg)", - "![](upload://withoutAltAndSize.jpeg)", + // 1 Image with scaling percentage, should work + "![test|690x313,50%](upload://test.png)", + // 2 image with scaling percentage and a proceeding whitespace, should work + "![test|690x313, 50%](upload://test.png)", + // 3 No dimensions, should not work + "![test](upload://test.jpeg)", + // 4 Wrapped in backquetes should not work "`![test|690x313](upload://test.png)`", - "![withoutSize](upload://withoutSize.png)", + // 5 html image - should not work "", + // 6 two images one the same line, but both are syntactically correct - both should work "![onTheSameLine1|200x200](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250](upload://onTheSameLine2.jpeg)", + // 7 & 8 Identical images - both should work "![identicalImage|300x300](upload://identicalImage.png)", - "![identicalImage|300x300](upload://identicalImage.png)" + "![identicalImage|300x300](upload://identicalImage.png)", + // 9 Image with whitespaces in alt - should work + "![image with spaces in alt|690x220](upload://test.png)", + // 10 Image with markdown title - should work + `![image|690x220](upload://test.png "image title")`, + // 11 bbcode - should not work + "[img]http://example.com/image.jpg[/img]" ]; await fillIn(".d-editor-input", uploads.join("\n")); assert.ok( - find(".button-wrapper").length === 6, + find(".button-wrapper").length === 9, "it adds correct amount of scaling button groups" ); - uploads[0] = "![test|690x313,50%](upload://test.png)"; + // Default + uploads[0] = "![test|690x313, 50%](upload://test.png)"; await click(find(".button-wrapper .scale-btn[data-scale='50']")[0]); assertImageResized(assert, uploads); - uploads[2] = "![anotherOne|690x463,75%](upload://anotherOne.jpeg)"; - await click(find(".button-wrapper .scale-btn[data-scale='75']")[1]); + // Targets the correct image if two on the same line + uploads[6] = + "![onTheSameLine1|200x200, 50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250](upload://onTheSameLine2.jpeg)"; + await click(find(".button-wrapper .scale-btn[data-scale='50']")[3]); assertImageResized(assert, uploads); - uploads[7] = - "![onTheSameLine1|200x200,50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250](upload://onTheSameLine2.jpeg)"; - await click(find(".button-wrapper .scale-btn[data-scale='50']")[2]); + // Try the other image on the same line + uploads[6] = + "![onTheSameLine1|200x200, 50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250, 75%](upload://onTheSameLine2.jpeg)"; + await click(find(".button-wrapper .scale-btn[data-scale='75']")[4]); assertImageResized(assert, uploads); - uploads[7] = - "![onTheSameLine1|200x200,50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250,75%](upload://onTheSameLine2.jpeg)"; - await click(find(".button-wrapper .scale-btn[data-scale='75']")[3]); + // Make sure we target the correct image if there are duplicates + uploads[7] = "![identicalImage|300x300, 50%](upload://identicalImage.png)"; + await click(find(".button-wrapper .scale-btn[data-scale='50']")[5]); assertImageResized(assert, uploads); - uploads[8] = "![identicalImage|300x300,50%](upload://identicalImage.png)"; - await click(find(".button-wrapper .scale-btn[data-scale='50']")[4]); + // Try the other dupe + uploads[8] = "![identicalImage|300x300, 75%](upload://identicalImage.png)"; + await click(find(".button-wrapper .scale-btn[data-scale='75']")[6]); assertImageResized(assert, uploads); - uploads[9] = "![identicalImage|300x300,75%](upload://identicalImage.png)"; - await click(find(".button-wrapper .scale-btn[data-scale='75']")[5]); + // Don't mess with image titles + uploads[10] = `![image|690x220, 75%](upload://test.png "image title")`; + await click(find(".button-wrapper .scale-btn[data-scale='75']")[8]); assertImageResized(assert, uploads); await fillIn(