From 4da0608f7c7cd7a6550ec40535b9562fb35c5417 Mon Sep 17 00:00:00 2001 From: Rodolpho Lima Date: Thu, 21 Sep 2023 17:51:34 +0200 Subject: [PATCH] [IMP] web_editor: remove global flag from URL regex A Regex object with the 'g' flag is stateful [1]. As the URL_REGEX and URL_REGEX_WITH_INFOS objects are exported, code that calls their `exec` method would be changing their `lastIndex` property, affecting future `exec` calls in different code sections. This commit removes the 'g' flag from the URL regexes, in order to allow us to: - avoid side effects of one call to `exec` to subsequent calls, - remove the `getUrlsInfosInString` utility function, - use `match` instead of `exec` for having results containing the capturing groups (see [2]). [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex#avoiding_side_effects [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@match#return_value task-3520513 Part-of: odoo/odoo#136497 --- .../js/editor/odoo-editor/src/OdooEditor.js | 16 ++++++------- .../editor/odoo-editor/src/utils/sanitize.js | 6 +---- .../js/editor/odoo-editor/src/utils/utils.js | 24 ++----------------- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js index 0b351d70e88..d24377a81ff 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js @@ -46,7 +46,6 @@ import { isUnremovable, fillEmpty, isEmptyBlock, - getUrlsInfosInString, URL_REGEX, URL_REGEX_WITH_INFOS, isSelectionFormat, @@ -4594,16 +4593,15 @@ export class OdooEditor extends EventTarget { ) { const textSliced = selection.anchorNode.textContent.slice(0, selection.anchorOffset); const textNodeSplitted = textSliced.split(/\s/); - let potentialUrl = textNodeSplitted.pop(); - const lastWordMatch = potentialUrl.match(URL_REGEX_WITH_INFOS) && !potentialUrl.match(EMAIL_REGEX); + const potentialUrl = textNodeSplitted.pop(); + const match = potentialUrl.match(URL_REGEX_WITH_INFOS); - if (lastWordMatch) { - const matches = getUrlsInfosInString(textSliced); - const match = matches[matches.length - 1]; + if (match && match[0] === potentialUrl && !EMAIL_REGEX.test(potentialUrl)) { + const url = match[2] ? match[0] : 'http://' + match[0]; const range = this.document.createRange(); - range.setStart(selection.anchorNode, match.index); - range.setEnd(selection.anchorNode, match.index + match.length); - const link = this._createLink(range.extractContents().textContent, match.url); + range.setStart(selection.anchorNode, selection.anchorOffset - match[0].length); + range.setEnd(selection.anchorNode, selection.anchorOffset); + const link = this._createLink(range.extractContents().textContent, url); range.insertNode(link); const container = link.parentElement; const offset = childNodeIndex(link) + 1; diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/sanitize.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/sanitize.js index d5a7320c892..a455374e73b 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/sanitize.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/sanitize.js @@ -94,11 +94,7 @@ export function deduceURLfromText(text, link) { return match[1] ? match[0] : 'mailto:' + match[0]; } // Check for http link. - // Regex with 'g' flag is stateful, reset lastIndex before and after using - // exec. - URL_REGEX_WITH_INFOS.lastIndex = 0; - match = URL_REGEX_WITH_INFOS.exec(label); - URL_REGEX_WITH_INFOS.lastIndex = 0; + match = label.match(URL_REGEX_WITH_INFOS); if (match && match[0] === label) { const currentHttpProtocol = (link?.href.match(/^http(s)?:\/\//gi) || [])[0]; if (match[2]) { 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 2c1ad4d273a..8ce3f40f358 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 @@ -51,8 +51,8 @@ const urlRegexBase = `|(?:[-a-zA-Z0-9@:%._\\+~#=]{1,64}\\.))[-a-zA-Z0-9@:%._\\+~ const httpRegex = `(?:https?:\\/\\/)`; const httpCapturedRegex= `(https?:\\/\\/)`; -export const URL_REGEX = new RegExp(`((?:(?:${httpRegex}${urlRegexBase})`, 'gi'); -export const URL_REGEX_WITH_INFOS = new RegExp(`((?:(?:${httpCapturedRegex}${urlRegexBase})`, 'gi'); +export const URL_REGEX = new RegExp(`((?:(?:${httpRegex}${urlRegexBase})`, 'i'); +export const URL_REGEX_WITH_INFOS = 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; @@ -1520,26 +1520,6 @@ export function makeContentsInline(node) { } } -/** - * Returns an array of url infos for url matched in the given string. - * - * @param {String} string - * @returns {Array} - */ -export function getUrlsInfosInString(string) { - let infos = [], - match; - while ((match = URL_REGEX_WITH_INFOS.exec(string))) { - infos.push({ - url: match[2] ? match[0] : 'http://' + match[0], - label: match[0], - index: match.index, - length: match[0].length, - }); - } - return infos; -} - // optimize: use the parent Oid to speed up detection export function getOuid(node, optimize = false) { while (node && !isUnbreakable(node)) {