[REF] web_editor,mass_mailing,website: make closestElement support predicate
To improve the api, make closestElement take a predicate as an argument. task-2984709 Part-of: odoo/odoo#105179
This commit is contained in:
@@ -2988,8 +2988,8 @@ export class OdooEditor extends EventTarget {
|
||||
}
|
||||
}
|
||||
if (sel.rangeCount) {
|
||||
const closestStartContainer = closestElement(sel.getRangeAt(0).startContainer, '*');
|
||||
const selectionStartStyle = getComputedStyle(closestStartContainer);
|
||||
const closestStartContainer = closestElement(sel.getRangeAt(0).startContainer);
|
||||
const selectionStartStyle = closestStartContainer && getComputedStyle(closestStartContainer);
|
||||
|
||||
// queryCommandState does not take stylesheets into account
|
||||
for (const format of ['bold', 'italic', 'underline', 'strikeThrough', 'switchDirection']) {
|
||||
|
||||
@@ -285,22 +285,27 @@ export function getFurthestUneditableParent(node, parentLimit) {
|
||||
return nonEditableElement;
|
||||
}
|
||||
/**
|
||||
* Returns the closest HTMLElement of the provided Node
|
||||
* if a 'selector' is provided, Returns the closest HTMLElement that match the selector
|
||||
* Returns the closest HTMLElement of the provided Node. If the predicate is a
|
||||
* string, returns the closest HTMLElement that match the predicate selector. If
|
||||
* the predicate is a function, returns the closest element that matches the
|
||||
* predicate. Any returned element will be contained within the editable.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @param {string} [selector=undefined]
|
||||
* @returns {HTMLElement}
|
||||
* @param {string | Function} [predicate='*']
|
||||
* @returns {HTMLElement|null}
|
||||
*/
|
||||
export function closestElement(node, selector) {
|
||||
let element = node;
|
||||
while (element && element.nodeType !== Node.ELEMENT_NODE) {
|
||||
element = element.parentNode;
|
||||
export function closestElement(node, predicate = "*") {
|
||||
if (!node) return null;
|
||||
let element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
||||
if (typeof predicate === 'function') {
|
||||
while (element && !predicate(element)) {
|
||||
element = element.parentElement;
|
||||
}
|
||||
} else {
|
||||
element = element?.closest(predicate);
|
||||
}
|
||||
if (element && selector) {
|
||||
element = element.closest(selector);
|
||||
}
|
||||
return element && element.querySelector('.odoo-editor-editable') ? null : element;
|
||||
|
||||
return element?.closest('.odoo-editor-editable') && element;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,6 +64,7 @@ describe('Powerbox', () => {
|
||||
describe('class', () => {
|
||||
it('should properly order default commands and categories', async () => {
|
||||
const editable = document.createElement('div');
|
||||
editable.classList.add('odoo-editor-editable');
|
||||
document.body.append(editable);
|
||||
const powerbox = new Powerbox({
|
||||
categories: [
|
||||
@@ -97,6 +98,7 @@ describe('Powerbox', () => {
|
||||
});
|
||||
it('should navigate through commands with arrow keys', async () => {
|
||||
const editable = document.createElement('div');
|
||||
editable.classList.add('odoo-editor-editable');
|
||||
document.body.append(editable);
|
||||
const powerbox = new Powerbox({
|
||||
categories: [],
|
||||
@@ -122,6 +124,7 @@ describe('Powerbox', () => {
|
||||
});
|
||||
it('should execute command on press Enter', async () => {
|
||||
const editable = document.createElement('div');
|
||||
editable.classList.add('odoo-editor-editable');
|
||||
document.body.append(editable);
|
||||
const powerbox = new Powerbox({
|
||||
categories: [],
|
||||
@@ -144,6 +147,7 @@ describe('Powerbox', () => {
|
||||
});
|
||||
it('should filter commands with `commandFilters`', async () => {
|
||||
const editable = document.createElement('div');
|
||||
editable.classList.add('odoo-editor-editable');
|
||||
document.body.append(editable);
|
||||
const powerbox = new Powerbox({
|
||||
categories: [],
|
||||
@@ -169,6 +173,7 @@ describe('Powerbox', () => {
|
||||
});
|
||||
it('should filter commands with `isDisabled`', async () => {
|
||||
const editable = document.createElement('div');
|
||||
editable.classList.add('odoo-editor-editable');
|
||||
document.body.append(editable);
|
||||
let disableCommands = false;
|
||||
const powerbox = new Powerbox({
|
||||
@@ -198,6 +203,7 @@ describe('Powerbox', () => {
|
||||
});
|
||||
it('should filter commands with filter text', async () => {
|
||||
const editable = document.createElement('div');
|
||||
editable.classList.add('odoo-editor-editable');
|
||||
document.body.append(editable);
|
||||
editable.append(document.createTextNode('original text'));
|
||||
setSelection(editable.firstChild, 13);
|
||||
@@ -236,6 +242,7 @@ describe('Powerbox', () => {
|
||||
});
|
||||
it('should close the Powerbox on remove last filter text with Backspace', async () => {
|
||||
const editable = document.createElement('div');
|
||||
editable.classList.add('odoo-editor-editable');
|
||||
document.body.append(editable);
|
||||
editable.append(document.createTextNode('1'));
|
||||
setSelection(editable.firstChild, 13);
|
||||
@@ -277,6 +284,7 @@ describe('Powerbox', () => {
|
||||
});
|
||||
it('should close the Powerbox on press Escape', async () => {
|
||||
const editable = document.createElement('div');
|
||||
editable.classList.add('odoo-editor-editable');
|
||||
document.body.append(editable);
|
||||
const powerbox = new Powerbox({
|
||||
categories: [],
|
||||
|
||||
@@ -55,6 +55,7 @@ const cleanTestHtml = () => {
|
||||
const insertTestHtml = innerHtml => {
|
||||
cleanTestHtml();
|
||||
const container = document.createElement('DIV');
|
||||
container.classList.add('odoo-editor-editable');
|
||||
container.setAttribute('contenteditable', true);
|
||||
container.innerHTML = innerHtml;
|
||||
document.body.appendChild(container);
|
||||
|
||||
Reference in New Issue
Block a user