[FIX] web_editor: link update on label change
OdooEditor has a mechanism to update a link's href on label change, if the new label is a valid URL. Before this commit, there were two issues: 1. it did not work for email links. In fact, because this mechanism was incorrectly prepending email URLS with 'https://', [1] disabled it for 'mailto:' links. 2. when a link had a 'http' href but its label did not contain the protocol, upon label change (into a valid URL) the link had its href changed to 'https'. This commit: 1. re-enables the auto update mechanism for email links and fixes it, so that it can correctly update both http and mailto links. 2. fixes the 'http' to 'https' coercion issue, making sure the current protocol is kept when updating http(s) links. task-3284649 [1]: https://github.com/odoo/odoo/commit/ea00a628969a0eeda66e06776af721a99a32cc57 X-original-commit: 6740e2821c51897baa110e9e4129b40c403e000c Part-of: odoo/odoo#136278
This commit is contained in:
@@ -16,9 +16,10 @@ import {
|
||||
isEditorTab,
|
||||
isProtected,
|
||||
isZWS,
|
||||
getUrlsInfosInString,
|
||||
isArtificialVoidElement,
|
||||
ancestors,
|
||||
EMAIL_REGEX,
|
||||
URL_REGEX_WITH_INFOS,
|
||||
} from './utils.js';
|
||||
|
||||
const NOT_A_NUMBER = /[^\d]/g;
|
||||
@@ -74,6 +75,39 @@ export function areSimilarElements(node, node2) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a URL if link's label is a valid email of http URL, null otherwise.
|
||||
*
|
||||
* @param {HTMLAnchorElement} link
|
||||
* @returns {String|null}
|
||||
*/
|
||||
function deduceURLfromLabel(link) {
|
||||
const label = link.innerText.trim();
|
||||
// Check first for e-mail.
|
||||
let match = label.match(EMAIL_REGEX);
|
||||
if (match) {
|
||||
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;
|
||||
if (match && match[0] === label) {
|
||||
const currentHttpProtocol = (link.href.match(/^http(s)?:\/\//gi) || [])[0];
|
||||
if (match[2]) {
|
||||
return match[0];
|
||||
} else if (currentHttpProtocol) {
|
||||
// Avoid converting a http link to https.
|
||||
return currentHttpProtocol + match[0];
|
||||
} else {
|
||||
return 'https://' + match[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the given node and return it.
|
||||
*
|
||||
@@ -208,10 +242,9 @@ export function sanitize(nodeToSanitize, root = nodeToSanitize) {
|
||||
// Update link URL if label is a new valid link.
|
||||
const startEl = start && closestElement(start, 'a');
|
||||
if (startEl && root.contains(startEl)) {
|
||||
const linkLabel = startEl.innerText;
|
||||
const urlInfo = getUrlsInfosInString(linkLabel);
|
||||
if (urlInfo.length && urlInfo[0].label === linkLabel && !startEl.href.startsWith('mailto:')) {
|
||||
startEl.setAttribute('href', urlInfo[0].url);
|
||||
const url = deduceURLfromLabel(startEl);
|
||||
if (url) {
|
||||
startEl.setAttribute('href', url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1417,7 +1417,7 @@ describe('Paste', () => {
|
||||
stepFunction: async editor => {
|
||||
await pasteText(editor, 'oom');
|
||||
},
|
||||
contentAfter: '<p>a<a href="https://boom.com">boom[].com</a>d</p>',
|
||||
contentAfter: '<p>a<a href="http://boom.com">boom[].com</a>d</p>',
|
||||
});
|
||||
});
|
||||
it('should replace link for new content when pasting in an empty link', async () => {
|
||||
|
||||
@@ -275,6 +275,45 @@ describe('Link', () => {
|
||||
},
|
||||
contentAfter: '<p>a<a href="http://google.com">http://goo[]gle.com</a>b</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>a<a href="mailto:hello@moto.com">hello@moto[].com</a></p>',
|
||||
stepFunction: async editor => {
|
||||
await insertText(editor, 'r');
|
||||
},
|
||||
contentAfter: '<p>a<a href="mailto:hello@motor.com">hello@motor[].com</a></p>',
|
||||
});
|
||||
});
|
||||
it('should change the url when the label change, without changing the protocol', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>a<a href="http://google.co">google.co[]</a>b</p>',
|
||||
stepFunction: async editor => {
|
||||
await insertText(editor, 'm');
|
||||
},
|
||||
contentAfter: '<p>a<a href="http://google.com">google.com[]</a>b</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>a<a href="https://google.co">google.co[]</a>b</p>',
|
||||
stepFunction: async editor => {
|
||||
await insertText(editor, 'm');
|
||||
},
|
||||
contentAfter: '<p>a<a href="https://google.com">google.com[]</a>b</p>',
|
||||
});
|
||||
});
|
||||
it('should change the url when the label change, changing to the suitable protocol', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>a<a href="http://hellomoto.com">hello[]moto.com</a></p>',
|
||||
stepFunction: async editor => {
|
||||
await insertText(editor, '@');
|
||||
},
|
||||
contentAfter: '<p>a<a href="mailto:hello@moto.com">hello@[]moto.com</a></p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>a<a href="mailto:hello@moto.com">hello@[]moto.com</a></p>',
|
||||
stepFunction: async editor => {
|
||||
await deleteBackward(editor);
|
||||
},
|
||||
contentAfter: '<p>a<a href="https://hellomoto.com">hello[]moto.com</a></p>',
|
||||
});
|
||||
});
|
||||
it('should change the url in one step', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
|
||||
Reference in New Issue
Block a user