[IMP] web_editor: unify http regexes

Before this commit there were two regexes for matching http(s) URLs,
being the only difference between them the presence of a capturing group
for the protocol/scheme. The need for a nearly duplicated version of the
same regex was its use in `_onPaste` as delimiter for String.split(), in
which capturing groups are returned in the resulting array, and the
protocol/scheme was not desired.

This commmit removes the need for two different regexes to match http(s)
URLs, adapting `_onPaste`'s code to work with the presence of the
referred capturing group.

task-3520513

closes odoo/odoo#136497

Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
This commit is contained in:
Rodolpho Lima
2023-10-03 19:20:09 +00:00
parent 4da0608f7c
commit 49277b5950
5 changed files with 9 additions and 56 deletions
@@ -47,7 +47,6 @@ import {
fillEmpty,
isEmptyBlock,
URL_REGEX,
URL_REGEX_WITH_INFOS,
isSelectionFormat,
YOUTUBE_URL_GET_VIDEO_ID,
unwrapContents,
@@ -4594,7 +4593,7 @@ export class OdooEditor extends EventTarget {
const textSliced = selection.anchorNode.textContent.slice(0, selection.anchorOffset);
const textNodeSplitted = textSliced.split(/\s/);
const potentialUrl = textNodeSplitted.pop();
const match = potentialUrl.match(URL_REGEX_WITH_INFOS);
const match = potentialUrl.match(URL_REGEX);
if (match && match[0] === potentialUrl && !EMAIL_REGEX.test(potentialUrl)) {
const url = match[2] ? match[0] : 'http://' + match[0];
@@ -4703,6 +4702,9 @@ export class OdooEditor extends EventTarget {
// Avoid transforming dynamic placeholder pattern to url.
if(!text.match(/\${.*}/gi)) {
splitAroundUrl = text.split(URL_REGEX);
// Remove 'http(s)://' capturing group from the result (indexes
// 2, 5, 8, ...).
splitAroundUrl = splitAroundUrl.filter((_, index) => ((index + 1) % 3));
}
if (splitAroundUrl.length === 3 && !splitAroundUrl[0] && !splitAroundUrl[2]) {
// Pasted content is a single URL.
@@ -19,8 +19,8 @@ import {
isArtificialVoidElement,
ancestors,
EMAIL_REGEX,
URL_REGEX_WITH_INFOS,
PHONE_REGEX,
URL_REGEX,
} from './utils.js';
const NOT_A_NUMBER = /[^\d]/g;
@@ -94,7 +94,7 @@ export function deduceURLfromText(text, link) {
return match[1] ? match[0] : 'mailto:' + match[0];
}
// Check for http link.
match = label.match(URL_REGEX_WITH_INFOS);
match = label.match(URL_REGEX);
if (match && match[0] === label) {
const currentHttpProtocol = (link?.href.match(/^http(s)?:\/\//gi) || [])[0];
if (match[2]) {
@@ -48,11 +48,9 @@ const tldWhitelist = [
'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', 'zr', 'zw', 'co\\.uk'];
const urlRegexBase = `|(?:[-a-zA-Z0-9@:%._\\+~#=]{1,64}\\.))[-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 httpRegex = `(?:https?:\\/\\/)`;
const httpCapturedRegex= `(https?:\\/\\/)`;
export const URL_REGEX = new RegExp(`((?:(?:${httpRegex}${urlRegexBase})`, 'i');
export const URL_REGEX_WITH_INFOS = new RegExp(`((?:(?:${httpCapturedRegex}${urlRegexBase})`, 'i');
export const URL_REGEX = new RegExp(`((?:(?:${httpCapturedRegex}${urlRegexBase})`, 'i');
export const YOUTUBE_URL_GET_VIDEO_ID =
/^(?:(?:https?:)?\/\/)?(?:(?:www|m)\.)?(?:youtube\.com|youtu\.be)(?:\/(?:[\w-]+\?v=|embed\/|v\/)?)([^\s?&#]+)(?:\S+)?$/i;
export const EMAIL_REGEX = /^(mailto:)?[\w-.]+@(?:[\w-]+\.)+[\w-]{2,4}$/i;
@@ -1,6 +1,6 @@
/** @odoo-module */
import { URL_REGEX, URL_REGEX_WITH_INFOS } from '../../src/OdooEditor.js';
import { URL_REGEX } from '../../src/OdooEditor.js';
import {
BasicEditor,
click,
@@ -27,13 +27,11 @@ const testUrlRegex = (content, {expectedUrl} = {}) => {
window.chai.assert.equal(expectedUrl, match && match[0]);
}
window.chai.assert.exists(content.match(URL_REGEX));
window.chai.assert.exists(content.match(URL_REGEX_WITH_INFOS));
});
}
const testNotUrlRegex = (url) => {
it(`should NOT be a link: ${url}`, () => {
window.chai.assert.notExists(url.match(URL_REGEX));
window.chai.assert.notExists(url.match(URL_REGEX_WITH_INFOS));
});
}
@@ -1,6 +1,6 @@
/** @odoo-module */
import { URL_REGEX, URL_REGEX_WITH_INFOS } from '../../src/OdooEditor.js';
import { URL_REGEX } from '../../src/OdooEditor.js';
describe('urlRegex', () => {
it('should match foo.com', () => {
@@ -46,48 +46,3 @@ describe('urlRegex', () => {
chai.expect(match[0]).to.be.equal(url);
});
});
describe('urlRegex with infos', () => {
it('should match foo.com', () => {
const url = 'foo.com';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX_WITH_INFOS);
chai.expect(match[0]).to.be.equal(url);
});
it('should not match foo.else', () => {
const url = 'foo.else';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX_WITH_INFOS);
chai.expect(match).to.be.equal(null);
});
it('should match abc.abc.abc', () => {
const url = 'abc.abc.abc';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX_WITH_INFOS);
chai.expect(match[0]).to.be.equal(url);
});
it('should match http://abc.abc.abc', () => {
const url = 'http://abc.abc.abc';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX_WITH_INFOS);
chai.expect(match[0]).to.be.equal(url);
});
it('should match https://abc.abc.abc', () => {
const url = 'https://abc.abc.abc';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX_WITH_INFOS);
chai.expect(match[0]).to.be.equal(url);
});
it('should match 1234-abc.runbot007.odoo.com/web#id=3&menu_id=221', () => {
const url = '1234-abc.runbot007.odoo.com/web#id=3&menu_id=221';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX_WITH_INFOS);
chai.expect(match[0]).to.be.equal(url);
});
it('should match https://1234-abc.runbot007.odoo.com/web#id=3&menu_id=221', () => {
const url = 'https://1234-abc.runbot007.odoo.com/web#id=3&menu_id=221';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX_WITH_INFOS);
chai.expect(match[0]).to.be.equal(url);
});
});