diff --git a/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js index 849498e809c74..bbeb1e8f933fa 100644 --- a/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js +++ b/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js @@ -68,6 +68,7 @@ import { setCursorStart, paragraphRelatedElements, isUnbreakable, + buildLinkUrl, } from './utils/utils.js'; import { editorCommands } from './commands/commands.js'; import { Powerbox } from './powerbox/Powerbox.js'; @@ -3310,7 +3311,7 @@ export class OdooEditor extends EventTarget { const selectionIsInsideALink = !!closestElement(sel.anchorNode, 'a'); if (splitAroundUrl.length === 3 && !splitAroundUrl[0] && !splitAroundUrl[2]) { // Pasted content is a single URL. - const url = /^https?:\/\//i.test(text) ? text : 'https://' + text; + const url = buildLinkUrl(text); const youtubeUrl = this.options.allowCommandVideo &&YOUTUBE_URL_GET_VIDEO_ID.exec(url); const urlFileExtention = url.split('.').pop(); const isImageUrl = ['jpg', 'jpeg', 'png', 'gif', 'svg'].includes(urlFileExtention.toLowerCase()); @@ -3399,9 +3400,7 @@ export class OdooEditor extends EventTarget { } else { this.historyPauseSteps(); for (let i = 0; i < splitAroundUrl.length; i++) { - const url = /^https?:\/\//gi.test(splitAroundUrl[i]) - ? splitAroundUrl[i] - : 'https://' + splitAroundUrl[i]; + const url = buildLinkUrl(splitAroundUrl[i]); // Even indexes will always be plain text, and odd indexes will always be URL. // only allow images emebed inside an existing link. No other url or video embed. if (i % 2 && !selectionIsInsideALink) { diff --git a/addons/web_editor/static/lib/odoo-editor/src/utils/utils.js b/addons/web_editor/static/lib/odoo-editor/src/utils/utils.js index 7cd13f10e1471..a0827afed209b 100644 --- a/addons/web_editor/static/lib/odoo-editor/src/utils/utils.js +++ b/addons/web_editor/static/lib/odoo-editor/src/utils/utils.js @@ -1591,6 +1591,37 @@ export function makeContentsInline(node) { } } +/** + * Prepends mailto: or https:// if the string matches + * the URL regex. Returns the original string if the + * the regex does not match or the original string + * already contains mailto: or https://. + * + * If there is already a regex match for the string, + * it should be passed here to avoid infinite looping. + * + * @param {String} string + * @param {String} match (optional) + * @returns {String} + */ +export function buildLinkUrl(string, match) { + match = match || URL_REGEX_WITH_INFOS.exec(string); + if (!match) { + return string; + } + const matchedString = match[0]; + const schema = match[2]; + const isEmail = !schema && matchedString.includes('@'); + let prefix = ''; + if (isEmail && !matchedString.startsWith('mailto:')) { + prefix = 'mailto:'; + } + if (!isEmail && !schema) { + prefix = 'https://'; + } + return prefix + matchedString; +} + /** * Returns an array of url infos for url matched in the given string. * @@ -1602,7 +1633,7 @@ export function getUrlsInfosInString(string) { match; while ((match = URL_REGEX_WITH_INFOS.exec(string))) { infos.push({ - url: match[2] ? match[0] : 'https://' + match[0], + url: buildLinkUrl(string, match), label: match[0], index: match.index, length: match[0].length,