diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js index f4b9626cee5..b7e6a8c7c0c 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js @@ -50,7 +50,7 @@ const tldWhitelist = [ 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', 'zr', 'zw', 'co\\.uk']; -const urlRegexBase = `|(?:www.))[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-zA-Z][a-zA-Z0-9]{1,62}|(?:[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.(?:${tldWhitelist.join('|')})\\b))(?:\\/[^\\s.,'")}\\]]*[?#.,)}\\]'"]?[^\\s.,'")}\\]]+|(?:[^!(){}.,\\[\\]'"\\s]+)|\\/[^\\s.,'")}\\]]*[^\\s?#.,'")}\\]]*)?`; +const urlRegexBase = `|(?:www.))[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-zA-Z][a-zA-Z0-9]{1,62}|(?:[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.(?:${tldWhitelist.join('|')})\\b))(?:(?:[/?#])[^\\s]*[^!.,})\\]'"\\s]|(?:[^!(){}.,[\\]'"\\s]+))?`; const httpCapturedRegex= `(https?:\\/\\/)`; export const URL_REGEX = new RegExp(`((?:(?:${httpCapturedRegex}${urlRegexBase})`, 'i'); diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/link.test.js b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/link.test.js index 257ff164f2b..cc083316086 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/link.test.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/link.test.js @@ -48,6 +48,7 @@ describe('Link', () => { testUrlRegex('google.com!', {expectedUrl: 'google.com'}); testUrlRegex('google.com)', {expectedUrl: 'google.com'}); testUrlRegex('google.com(', {expectedUrl: 'google.com'}); + testUrlRegex('google.com/ a', {expectedUrl: 'google.com/'}); testUrlRegex('google.com. a', {expectedUrl: 'google.com'}); testUrlRegex('google.com, a', {expectedUrl: 'google.com'}); @@ -59,6 +60,20 @@ describe('Link', () => { testUrlRegex('google.com/}', {expectedUrl: 'google.com/'}); testUrlRegex("google.com/'", {expectedUrl: 'google.com/'}); testUrlRegex('google.com/"', {expectedUrl: 'google.com/'}); + testUrlRegex('google.com#.', {expectedUrl: 'google.com#'}); + testUrlRegex('google.com#,', {expectedUrl: 'google.com#'}); + testUrlRegex('google.com#)', {expectedUrl: 'google.com#'}); + testUrlRegex('google.com#]', {expectedUrl: 'google.com#'}); + testUrlRegex('google.com#}', {expectedUrl: 'google.com#'}); + testUrlRegex("google.com#'", {expectedUrl: 'google.com#'}); + testUrlRegex('google.com#"', {expectedUrl: 'google.com#'}); + testUrlRegex('google.com?,', {expectedUrl: 'google.com?'}); + testUrlRegex('google.com?.', {expectedUrl: 'google.com?'}); + testUrlRegex('google.com?)', {expectedUrl: 'google.com?'}); + testUrlRegex('google.com?]', {expectedUrl: 'google.com?'}); + testUrlRegex('google.com?}', {expectedUrl: 'google.com?'}); + testUrlRegex("google.com?'", {expectedUrl: 'google.com?'}); + testUrlRegex('google.com?"', {expectedUrl: 'google.com?'}); // The previous special character should be included when they are nt at the end. testUrlRegex('google.com/.a', {expectedUrl: 'google.com/.a'}); @@ -73,20 +88,33 @@ describe('Link', () => { testUrlRegex('google.com/(', {expectedUrl: 'google.com/('}); testUrlRegex('google.com/[', {expectedUrl: 'google.com/['}); testUrlRegex('google.com/{', {expectedUrl: 'google.com/{'}); + testUrlRegex('google.com?(', {expectedUrl: 'google.com?('}); + testUrlRegex('google.com?[', {expectedUrl: 'google.com?['}); + testUrlRegex('google.com?{', {expectedUrl: 'google.com?{'}); + testUrlRegex('google.com#(', {expectedUrl: 'google.com#('}); + testUrlRegex('google.com#[', {expectedUrl: 'google.com#['}); + testUrlRegex('google.com#{', {expectedUrl: 'google.com#{'}); testUrlRegex('google.co.uk'); + testUrlRegex('google123.com'); testUrlRegex('http://google.com'); + testUrlRegex('http://google123.com'); testUrlRegex('https://google.com'); + testUrlRegex('https://google123.com'); testUrlRegex('https://www.google.com'); testUrlRegex('https://google.shop'); testNotUrlRegex('google.shop'); testUrlRegex('google.com/'); + testUrlRegex('google.com/path/123/abc/4'); testUrlRegex('http://google.com/'); + testUrlRegex('http://google.com/home'); + testUrlRegex('http://google.com/home/'); testUrlRegex('https://google.com/'); testUrlRegex('https://google.co.uk/'); testUrlRegex('https://www.google.com/'); testNotUrlRegex('google.shop/'); testUrlRegex('http://google.com/foo#test'); + testUrlRegex('http://google.com/#test'); testNotUrlRegex('a.bcd.ef'); testUrlRegex('a.bc.de'); testNotUrlRegex('a.bc.d'); @@ -98,11 +126,26 @@ describe('Link', () => { testUrlRegex('google.com?data=hello', { expectedUrl: 'google.com?data=hello' }); testUrlRegex('google.com/?data=hello', { expectedUrl: 'google.com/?data=hello' }); testUrlRegex('google.com/foo/?data=hello', { expectedUrl: 'google.com/foo/?data=hello' }); + testUrlRegex('google.com/foo/?data1=hello1&data2=hello2', { expectedUrl: 'google.com/foo/?data1=hello1&data2=hello2' }); testUrlRegex('google.com/.?data=hello', { expectedUrl: 'google.com/.?data=hello' }); testUrlRegex('google.com?data=hello#anchor', { expectedUrl: 'google.com?data=hello#anchor' }); testUrlRegex('google.com/?data=hello#anchor', { expectedUrl: 'google.com/?data=hello#anchor' }); testUrlRegex('google.com/.?data=hello#anchor', { expectedUrl: 'google.com/.?data=hello#anchor' }); testUrlRegex('google.com/foo/?data=hello&data2=foo#anchor', { expectedUrl: 'google.com/foo/?data=hello&data2=foo#anchor' }); + + // Url containing some special characters + testUrlRegex('www.google.com/path/1-2-3', { expectedUrl: 'www.google.com/path/1-2-3' }); + testUrlRegex('https://google.com/abc..def', { expectedUrl: 'https://google.com/abc..def' }); + testUrlRegex('https://google.com/a/b+c@d', { expectedUrl: 'https://google.com/a/b+c@d' }); + testUrlRegex('sub.example-website.com', { expectedUrl: 'sub.example-website.com' }); + testUrlRegex('http://sub.example-website.com', { expectedUrl: 'http://sub.example-website.com' }); + testUrlRegex('http://user:password@example.com', { expectedUrl: 'http://user:password@example.com' }); + testUrlRegex('http://google.com/a_b', { expectedUrl: 'http://google.com/a_b' }); + testUrlRegex('https://google.com?query=ab.cd', { expectedUrl: 'https://google.com?query=ab.cd' }); + testUrlRegex(`google.com/'ab'/cd`, { expectedUrl: "google.com/'ab'/cd" }); + testUrlRegex(`www.google.com/a!b/c?d,e,f#g!i`, { expectedUrl: 'www.google.com/a!b/c?d,e,f#g!i' }); + testUrlRegex(`www.google.com/a%b%c`, { expectedUrl: 'www.google.com/a%b%c' }); + testUrlRegex(`http://google.com?a.b.c&d!e#e'f`, { expectedUrl: "http://google.com?a.b.c&d!e#e'f" }); }); describe('insert Link', () => { describe('range collapsed', () => { diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/urlRegex.test.js b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/urlRegex.test.js index f812e87013c..2a6ca839179 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/urlRegex.test.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/urlRegex.test.js @@ -21,6 +21,18 @@ describe('urlRegex', () => { const match = text.match(URL_REGEX); chai.expect(match[0]).to.be.equal(url); }); + it('should match abc.abc.com', () => { + const url = 'abc.abc.com'; + const text = `abc ${url} abc`; + const match = text.match(URL_REGEX); + chai.expect(match[0]).to.be.equal(url); + }); + it('should not match abc.abc.abc', () => { + const url = 'abc.abc.abc'; + const text = `abc ${url} abc`; + const match = text.match(URL_REGEX); + chai.expect(match).to.be.equal(null); + }); it('should match http://abc.abc.abc', () => { const url = 'http://abc.abc.abc'; const text = `abc ${url} abc`;