175 lines
6.0 KiB
TypeScript
175 lines
6.0 KiB
TypeScript
import { expect, tap, webhelpers } from '@push.rocks/tapbundle';
|
|
import { DeesWysiwygBlock } from '../ts_web/elements/wysiwyg/dees-wysiwyg-block.js';
|
|
import { WysiwygSelection } from '../ts_web/elements/wysiwyg/wysiwyg.selection.js';
|
|
|
|
tap.test('Shadow DOM containment should work correctly', async () => {
|
|
console.log('=== Testing Shadow DOM Containment ===');
|
|
|
|
// Create a WYSIWYG block component
|
|
const block = await webhelpers.fixture<DeesWysiwygBlock>(
|
|
'<dees-wysiwyg-block></dees-wysiwyg-block>'
|
|
);
|
|
|
|
// Set the block data
|
|
block.block = {
|
|
id: 'test-1',
|
|
type: 'paragraph',
|
|
content: 'Hello world test content'
|
|
};
|
|
|
|
block.handlers = {
|
|
onInput: () => {},
|
|
onKeyDown: () => {},
|
|
onFocus: () => {},
|
|
onBlur: () => {},
|
|
onCompositionStart: () => {},
|
|
onCompositionEnd: () => {}
|
|
};
|
|
|
|
await block.updateComplete;
|
|
|
|
// Get the paragraph element inside Shadow DOM
|
|
const container = block.shadowRoot?.querySelector('.wysiwyg-block-container') as HTMLElement;
|
|
const paragraphBlock = container?.querySelector('.block.paragraph') as HTMLElement;
|
|
|
|
expect(paragraphBlock).toBeTruthy();
|
|
console.log('Found paragraph block:', paragraphBlock);
|
|
console.log('Paragraph text content:', paragraphBlock.textContent);
|
|
|
|
// Focus the paragraph
|
|
paragraphBlock.focus();
|
|
|
|
// Manually set cursor position
|
|
const textNode = paragraphBlock.firstChild;
|
|
if (textNode && textNode.nodeType === Node.TEXT_NODE) {
|
|
const range = document.createRange();
|
|
const selection = window.getSelection();
|
|
|
|
// Set cursor at position 11 (after "Hello world")
|
|
range.setStart(textNode, 11);
|
|
range.setEnd(textNode, 11);
|
|
|
|
selection?.removeAllRanges();
|
|
selection?.addRange(range);
|
|
|
|
console.log('Set cursor at position 11');
|
|
|
|
// Test the containment check
|
|
console.log('\n--- Testing containment ---');
|
|
const currentSelection = window.getSelection();
|
|
if (currentSelection && currentSelection.rangeCount > 0) {
|
|
const selRange = currentSelection.getRangeAt(0);
|
|
console.log('Selection range:', {
|
|
startContainer: selRange.startContainer,
|
|
startOffset: selRange.startOffset,
|
|
containerText: selRange.startContainer.textContent
|
|
});
|
|
|
|
// Test regular contains (should fail across Shadow DOM)
|
|
const regularContains = paragraphBlock.contains(selRange.startContainer);
|
|
console.log('Regular contains:', regularContains);
|
|
|
|
// Test Shadow DOM-aware contains
|
|
const shadowDOMContains = WysiwygSelection.containsAcrossShadowDOM(paragraphBlock, selRange.startContainer);
|
|
console.log('Shadow DOM contains:', shadowDOMContains);
|
|
|
|
// Since we're setting selection within the same shadow DOM, both should be true
|
|
expect(regularContains).toBeTrue();
|
|
expect(shadowDOMContains).toBeTrue();
|
|
}
|
|
|
|
// Test getSplitContent
|
|
console.log('\n--- Testing getSplitContent ---');
|
|
const splitResult = block.getSplitContent();
|
|
console.log('Split result:', splitResult);
|
|
|
|
expect(splitResult).toBeTruthy();
|
|
if (splitResult) {
|
|
console.log('Before:', JSON.stringify(splitResult.before));
|
|
console.log('After:', JSON.stringify(splitResult.after));
|
|
|
|
// Expected split at position 11
|
|
expect(splitResult.before).toEqual('Hello world');
|
|
expect(splitResult.after).toEqual(' test content');
|
|
}
|
|
}
|
|
});
|
|
|
|
tap.test('Shadow DOM containment across different shadow roots', async () => {
|
|
console.log('=== Testing Cross Shadow Root Containment ===');
|
|
|
|
// Create parent component with WYSIWYG editor
|
|
const parentDiv = document.createElement('div');
|
|
parentDiv.innerHTML = `
|
|
<dees-input-wysiwyg>
|
|
<dees-wysiwyg-block></dees-wysiwyg-block>
|
|
</dees-input-wysiwyg>
|
|
`;
|
|
document.body.appendChild(parentDiv);
|
|
|
|
// Wait for components to be ready
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
|
const wysiwygInput = parentDiv.querySelector('dees-input-wysiwyg') as any;
|
|
const blockElement = wysiwygInput?.shadowRoot?.querySelector('dees-wysiwyg-block') as DeesWysiwygBlock;
|
|
|
|
if (blockElement) {
|
|
// Set block data
|
|
blockElement.block = {
|
|
id: 'test-2',
|
|
type: 'paragraph',
|
|
content: 'Cross shadow DOM test'
|
|
};
|
|
|
|
blockElement.handlers = {
|
|
onInput: () => {},
|
|
onKeyDown: () => {},
|
|
onFocus: () => {},
|
|
onBlur: () => {},
|
|
onCompositionStart: () => {},
|
|
onCompositionEnd: () => {}
|
|
};
|
|
|
|
await blockElement.updateComplete;
|
|
|
|
// Get the paragraph inside the nested shadow DOM
|
|
const container = blockElement.shadowRoot?.querySelector('.wysiwyg-block-container') as HTMLElement;
|
|
const paragraphBlock = container?.querySelector('.block.paragraph') as HTMLElement;
|
|
|
|
if (paragraphBlock) {
|
|
console.log('Found nested paragraph block');
|
|
|
|
// Focus and set selection
|
|
paragraphBlock.focus();
|
|
const textNode = paragraphBlock.firstChild;
|
|
if (textNode && textNode.nodeType === Node.TEXT_NODE) {
|
|
const range = document.createRange();
|
|
range.setStart(textNode, 5);
|
|
range.setEnd(textNode, 5);
|
|
|
|
const selection = window.getSelection();
|
|
selection?.removeAllRanges();
|
|
selection?.addRange(range);
|
|
|
|
// Test containment from parent's perspective
|
|
const selRange = selection?.getRangeAt(0);
|
|
if (selRange) {
|
|
// This should fail because it crosses shadow DOM boundary
|
|
const regularContains = wysiwygInput.contains(selRange.startContainer);
|
|
console.log('Parent regular contains:', regularContains);
|
|
expect(regularContains).toBeFalse();
|
|
|
|
// This should work with our Shadow DOM-aware method
|
|
const shadowDOMContains = WysiwygSelection.containsAcrossShadowDOM(wysiwygInput, selRange.startContainer);
|
|
console.log('Parent shadow DOM contains:', shadowDOMContains);
|
|
expect(shadowDOMContains).toBeTrue();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up
|
|
document.body.removeChild(parentDiv);
|
|
});
|
|
|
|
export default tap.start(); |