mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
957 lines
28 KiB
HTML
957 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<script src="testing.js"></script>
|
|
<body>
|
|
<div id="test-content">
|
|
<p id="p1">First paragraph</p>
|
|
<p id="p2">Second paragraph</p>
|
|
<span id="s1">Span content</span>
|
|
</div>
|
|
|
|
<script id=basic>
|
|
{
|
|
const range = document.createRange();
|
|
testing.expectEqual('object', typeof range);
|
|
testing.expectEqual(true, range instanceof Range);
|
|
testing.expectEqual(true, range instanceof AbstractRange);
|
|
}
|
|
</script>
|
|
|
|
<script id=initial_state>
|
|
{
|
|
const range = document.createRange();
|
|
|
|
// New range should be collapsed at document position
|
|
testing.expectEqual(document, range.startContainer);
|
|
testing.expectEqual(0, range.startOffset);
|
|
testing.expectEqual(document, range.endContainer);
|
|
testing.expectEqual(0, range.endOffset);
|
|
testing.expectEqual(true, range.collapsed);
|
|
}
|
|
</script>
|
|
|
|
<script id=setStart_setEnd>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
const p2 = $('#p2');
|
|
|
|
range.setStart(p1, 0);
|
|
testing.expectEqual(p1, range.startContainer);
|
|
testing.expectEqual(0, range.startOffset);
|
|
// After setStart, if new start is after original end, range collapses
|
|
// Since original end was at (document, 0) and p1 is inside document,
|
|
// the range auto-collapses to the new start
|
|
testing.expectEqual(p1, range.endContainer);
|
|
testing.expectEqual(0, range.endOffset);
|
|
testing.expectEqual(true, range.collapsed);
|
|
|
|
range.setEnd(p2, 0);
|
|
testing.expectEqual(p2, range.endContainer);
|
|
testing.expectEqual(0, range.endOffset);
|
|
testing.expectEqual(false, range.collapsed);
|
|
}
|
|
</script>
|
|
|
|
<script id=collapse>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
const p2 = $('#p2');
|
|
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p2, 1);
|
|
testing.expectEqual(false, range.collapsed);
|
|
|
|
// Collapse to start
|
|
range.collapse(true);
|
|
testing.expectEqual(p1, range.startContainer);
|
|
testing.expectEqual(p1, range.endContainer);
|
|
testing.expectEqual(0, range.startOffset);
|
|
testing.expectEqual(0, range.endOffset);
|
|
testing.expectEqual(true, range.collapsed);
|
|
|
|
// Reset and collapse to end
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p2, 1);
|
|
range.collapse(false);
|
|
testing.expectEqual(p2, range.startContainer);
|
|
testing.expectEqual(p2, range.endContainer);
|
|
testing.expectEqual(1, range.startOffset);
|
|
testing.expectEqual(1, range.endOffset);
|
|
testing.expectEqual(true, range.collapsed);
|
|
}
|
|
</script>
|
|
|
|
<script id=selectNode>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
const parent = p1.parentNode;
|
|
|
|
range.selectNode(p1);
|
|
|
|
testing.expectEqual(parent, range.startContainer);
|
|
testing.expectEqual(parent, range.endContainer);
|
|
testing.expectEqual(false, range.collapsed);
|
|
|
|
// Start should be before p1, end should be after p1
|
|
const startOffset = range.startOffset;
|
|
const endOffset = range.endOffset;
|
|
testing.expectEqual(startOffset + 1, endOffset);
|
|
testing.expectEqual(p1, parent.childNodes[startOffset]);
|
|
}
|
|
</script>
|
|
|
|
<script id=selectNodeContents>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
|
|
range.selectNodeContents(p1);
|
|
|
|
testing.expectEqual(p1, range.startContainer);
|
|
testing.expectEqual(p1, range.endContainer);
|
|
testing.expectEqual(0, range.startOffset);
|
|
testing.expectEqual(p1.childNodes.length, range.endOffset);
|
|
testing.expectEqual(false, range.collapsed);
|
|
}
|
|
</script>
|
|
|
|
<script id=setStartBefore_setStartAfter>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
const p2 = $('#p2');
|
|
const parent = p1.parentNode;
|
|
|
|
range.setStartBefore(p1);
|
|
testing.expectEqual(parent, range.startContainer);
|
|
const beforeOffset = range.startOffset;
|
|
testing.expectEqual(p1, parent.childNodes[beforeOffset]);
|
|
|
|
range.setStartAfter(p1);
|
|
testing.expectEqual(parent, range.startContainer);
|
|
const afterOffset = range.startOffset;
|
|
testing.expectEqual(afterOffset, beforeOffset + 1);
|
|
}
|
|
</script>
|
|
|
|
<script id=setEndBefore_setEndAfter>
|
|
{
|
|
const range = document.createRange();
|
|
const p2 = $('#p2');
|
|
const parent = p2.parentNode;
|
|
|
|
range.setEndBefore(p2);
|
|
testing.expectEqual(parent, range.endContainer);
|
|
const beforeOffset = range.endOffset;
|
|
testing.expectEqual(p2, parent.childNodes[beforeOffset]);
|
|
|
|
range.setEndAfter(p2);
|
|
testing.expectEqual(parent, range.endContainer);
|
|
const afterOffset = range.endOffset;
|
|
testing.expectEqual(afterOffset, beforeOffset + 1);
|
|
}
|
|
</script>
|
|
|
|
<script id=cloneRange>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
const p2 = $('#p2');
|
|
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p2, 1);
|
|
|
|
const clone = range.cloneRange();
|
|
|
|
testing.expectTrue(clone !== range);
|
|
testing.expectEqual(range.startContainer, clone.startContainer);
|
|
testing.expectEqual(range.startOffset, clone.startOffset);
|
|
testing.expectEqual(range.endContainer, clone.endContainer);
|
|
testing.expectEqual(range.endOffset, clone.endOffset);
|
|
testing.expectEqual(range.collapsed, clone.collapsed);
|
|
|
|
// Modifying clone shouldn't affect original
|
|
clone.collapse(true);
|
|
testing.expectEqual(true, clone.collapsed);
|
|
testing.expectEqual(false, range.collapsed);
|
|
}
|
|
</script>
|
|
|
|
<script id=toString_collapsed>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p1, 0);
|
|
|
|
testing.expectEqual('', range.toString());
|
|
}
|
|
</script>
|
|
|
|
<script id=insertNode>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
const newSpan = document.createElement('span');
|
|
newSpan.textContent = 'INSERTED';
|
|
|
|
// Select p1's contents
|
|
range.selectNodeContents(p1);
|
|
|
|
// Collapse to start
|
|
range.collapse(true);
|
|
|
|
// Insert node
|
|
range.insertNode(newSpan);
|
|
|
|
// Check that span is first child of p1
|
|
testing.expectEqual(newSpan, p1.firstChild);
|
|
testing.expectEqual('INSERTED', newSpan.textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=insertNode_splitText>
|
|
{
|
|
const div = document.createElement('div');
|
|
div.textContent = 'Hello World';
|
|
|
|
const range = document.createRange();
|
|
const textNode = div.firstChild;
|
|
|
|
// Set range to middle of text (after "Hello ")
|
|
range.setStart(textNode, 6);
|
|
range.collapse(true);
|
|
|
|
// Insert a span in the middle
|
|
const span = document.createElement('span');
|
|
span.textContent = 'MIDDLE';
|
|
range.insertNode(span);
|
|
|
|
// Should have 3 children: "Hello ", span, "World"
|
|
testing.expectEqual(3, div.childNodes.length);
|
|
testing.expectEqual('Hello ', div.childNodes[0].textContent);
|
|
testing.expectEqual(span, div.childNodes[1]);
|
|
testing.expectEqual('MIDDLE', div.childNodes[1].textContent);
|
|
testing.expectEqual('World', div.childNodes[2].textContent);
|
|
|
|
// Full text should be correct
|
|
testing.expectEqual('Hello MIDDLEWorld', div.textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=deleteContents>
|
|
{
|
|
const div = document.createElement('div');
|
|
div.innerHTML = '<p>Hello</p><span>World</span>';
|
|
|
|
const range = document.createRange();
|
|
range.selectNodeContents(div);
|
|
|
|
testing.expectEqual(2, div.childNodes.length);
|
|
|
|
range.deleteContents();
|
|
|
|
testing.expectEqual(0, div.childNodes.length);
|
|
testing.expectEqual(true, range.collapsed);
|
|
}
|
|
</script>
|
|
|
|
<script id=cloneContents>
|
|
{
|
|
const div = document.createElement('div');
|
|
div.innerHTML = '<p>First</p><span>Second</span>';
|
|
|
|
const range = document.createRange();
|
|
range.selectNodeContents(div);
|
|
|
|
const fragment = range.cloneContents();
|
|
|
|
// Original should be unchanged
|
|
testing.expectEqual(2, div.childNodes.length);
|
|
|
|
// Fragment should have copies
|
|
testing.expectEqual(2, fragment.childNodes.length);
|
|
testing.expectEqual('P', fragment.childNodes[0].tagName);
|
|
testing.expectEqual('First', fragment.childNodes[0].textContent);
|
|
testing.expectEqual('SPAN', fragment.childNodes[1].tagName);
|
|
testing.expectEqual('Second', fragment.childNodes[1].textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=extractContents>
|
|
{
|
|
const div = document.createElement('div');
|
|
div.innerHTML = '<p>First</p><span>Second</span>';
|
|
|
|
const range = document.createRange();
|
|
range.selectNodeContents(div);
|
|
|
|
const fragment = range.extractContents();
|
|
|
|
// Original should be empty
|
|
testing.expectEqual(0, div.childNodes.length);
|
|
|
|
// Fragment should have extracted content
|
|
testing.expectEqual(2, fragment.childNodes.length);
|
|
testing.expectEqual('P', fragment.childNodes[0].tagName);
|
|
testing.expectEqual('SPAN', fragment.childNodes[1].tagName);
|
|
}
|
|
</script>
|
|
|
|
<script id=surroundContents>
|
|
{
|
|
const div = document.createElement('div');
|
|
div.innerHTML = '<p>Content</p>';
|
|
|
|
const range = document.createRange();
|
|
range.selectNodeContents(div);
|
|
|
|
const wrapper = document.createElement('section');
|
|
wrapper.className = 'wrapper';
|
|
|
|
range.surroundContents(wrapper);
|
|
|
|
// Div should now contain only the wrapper
|
|
testing.expectEqual(1, div.childNodes.length);
|
|
testing.expectEqual(wrapper, div.firstChild);
|
|
testing.expectEqual('wrapper', wrapper.className);
|
|
|
|
// Wrapper should contain original content
|
|
testing.expectEqual(1, wrapper.childNodes.length);
|
|
testing.expectEqual('P', wrapper.firstChild.tagName);
|
|
testing.expectEqual('Content', wrapper.firstChild.textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=createContextualFragment_basic>
|
|
{
|
|
const div = document.createElement('div');
|
|
const range = document.createRange();
|
|
range.selectNodeContents(div);
|
|
|
|
const fragment = range.createContextualFragment('<p>Hello</p><span>World</span>');
|
|
|
|
// Fragment should contain the parsed elements
|
|
testing.expectEqual(2, fragment.childNodes.length);
|
|
testing.expectEqual('P', fragment.childNodes[0].tagName);
|
|
testing.expectEqual('Hello', fragment.childNodes[0].textContent);
|
|
testing.expectEqual('SPAN', fragment.childNodes[1].tagName);
|
|
testing.expectEqual('World', fragment.childNodes[1].textContent);
|
|
|
|
// Original div should be unchanged
|
|
testing.expectEqual(0, div.childNodes.length);
|
|
}
|
|
</script>
|
|
|
|
<script id=createContextualFragment_empty>
|
|
{
|
|
const div = document.createElement('div');
|
|
const range = document.createRange();
|
|
range.selectNodeContents(div);
|
|
|
|
const fragment = range.createContextualFragment('');
|
|
|
|
testing.expectEqual(0, fragment.childNodes.length);
|
|
}
|
|
</script>
|
|
|
|
<script id=createContextualFragment_textContext>
|
|
{
|
|
const div = document.createElement('div');
|
|
div.textContent = 'Some text';
|
|
|
|
const range = document.createRange();
|
|
const textNode = div.firstChild;
|
|
range.setStart(textNode, 5);
|
|
range.collapse(true);
|
|
|
|
// Even though range is in text node, should use parent (div) as context
|
|
const fragment = range.createContextualFragment('<b>Bold</b>');
|
|
|
|
testing.expectEqual(1, fragment.childNodes.length);
|
|
testing.expectEqual('B', fragment.childNodes[0].tagName);
|
|
testing.expectEqual('Bold', fragment.childNodes[0].textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=offset_validation_setStart>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
|
|
// Test setStart with offset beyond node length
|
|
testing.expectError('IndexSizeError: Index or size is negative or greater than the allowed amount', () => {
|
|
range.setStart(p1, 999);
|
|
});
|
|
|
|
// Test with negative offset (wraps to large u32)
|
|
testing.expectError('IndexSizeError: Index or size is negative or greater than the allowed amount', () => {
|
|
range.setStart(p1.firstChild, -1);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<script id=offset_validation_setEnd>
|
|
{
|
|
const range = document.createRange();
|
|
const p1 = $('#p1');
|
|
|
|
// Test setEnd with offset beyond node length
|
|
testing.expectError('IndexSizeError: Index or size is negative or greater than the allowed amount', () => {
|
|
range.setEnd(p1, 999);
|
|
});
|
|
|
|
// Test with text node
|
|
testing.expectError('IndexSizeError: Index or size is negative or greater than the allowed amount', () => {
|
|
range.setEnd(p1.firstChild, 9999);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<script id=comparePoint_basic>
|
|
{
|
|
// Create fresh elements to avoid DOM pollution from other tests
|
|
const div = document.createElement('div');
|
|
const p1 = document.createElement('p');
|
|
const p2 = document.createElement('p');
|
|
p1.textContent = 'First paragraph text';
|
|
p2.textContent = 'Second paragraph text';
|
|
div.appendChild(p1);
|
|
div.appendChild(p2);
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1.firstChild, 0);
|
|
range.setEnd(p2.firstChild, 5);
|
|
|
|
// Point before range
|
|
testing.expectEqual(-1, range.comparePoint(div, 0));
|
|
|
|
// Point at start boundary
|
|
testing.expectEqual(0, range.comparePoint(p1.firstChild, 0));
|
|
|
|
// Point inside range (in p1)
|
|
testing.expectEqual(0, range.comparePoint(p1.firstChild, 3));
|
|
|
|
// Point inside range (in p2)
|
|
testing.expectEqual(0, range.comparePoint(p2.firstChild, 2));
|
|
|
|
// Point at end boundary
|
|
testing.expectEqual(0, range.comparePoint(p2.firstChild, 5));
|
|
|
|
// Point after range
|
|
testing.expectEqual(1, range.comparePoint(p2.firstChild, 10));
|
|
}
|
|
</script>
|
|
|
|
<script id=comparePoint_validation>
|
|
{
|
|
// Create fresh element
|
|
const p1 = document.createElement('p');
|
|
p1.textContent = 'Test content';
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p1, 1);
|
|
|
|
// Test comparePoint with invalid offset
|
|
testing.expectError('IndexSizeError: Index or size is negative or greater than the allowed amount', () => {
|
|
range.comparePoint(p1, 20);
|
|
});
|
|
|
|
testing.expectError('IndexSizeError: Index or size is negative or greater than the allowed amount', () => {
|
|
range.comparePoint(p1.firstChild, -1);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<script id=different_document_collapse>
|
|
{
|
|
// Create fresh element in current document
|
|
const p1 = document.createElement('p');
|
|
p1.textContent = 'Local content';
|
|
|
|
const range = document.createRange();
|
|
|
|
// Create a foreign document
|
|
const foreignDoc = document.implementation.createHTMLDocument('');
|
|
const foreignP = foreignDoc.createElement('p');
|
|
foreignP.textContent = 'Foreign';
|
|
foreignDoc.body.appendChild(foreignP);
|
|
|
|
// Set up range in current document
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p1, 1);
|
|
testing.expectEqual(false, range.collapsed);
|
|
|
|
// Setting start to foreign document should collapse to that point
|
|
range.setStart(foreignP, 0);
|
|
testing.expectEqual(true, range.collapsed);
|
|
testing.expectEqual(foreignP, range.startContainer);
|
|
testing.expectEqual(foreignP, range.endContainer);
|
|
}
|
|
</script>
|
|
|
|
<script id=detached_node_collapse>
|
|
{
|
|
// Create fresh element
|
|
const p1 = document.createElement('p');
|
|
p1.textContent = 'Attached content';
|
|
|
|
const range = document.createRange();
|
|
|
|
// Create a detached element
|
|
const detached = document.createElement('div');
|
|
detached.textContent = 'Detached';
|
|
|
|
// Set up range in document
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p1, 1);
|
|
testing.expectEqual(false, range.collapsed);
|
|
|
|
// Setting end to detached node should collapse
|
|
range.setEnd(detached.firstChild, 0);
|
|
testing.expectEqual(true, range.collapsed);
|
|
testing.expectEqual(detached.firstChild, range.startContainer);
|
|
testing.expectEqual(detached.firstChild, range.endContainer);
|
|
}
|
|
</script>
|
|
|
|
<script id=isPointInRange_basic>
|
|
{
|
|
// Create fresh elements
|
|
const div = document.createElement('div');
|
|
const p1 = document.createElement('p');
|
|
const p2 = document.createElement('p');
|
|
p1.textContent = 'First paragraph';
|
|
p2.textContent = 'Second paragraph';
|
|
div.appendChild(p1);
|
|
div.appendChild(p2);
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1.firstChild, 5);
|
|
range.setEnd(p2.firstChild, 6);
|
|
|
|
// Point before range
|
|
testing.expectEqual(false, range.isPointInRange(p1.firstChild, 0));
|
|
|
|
// Point at start boundary
|
|
testing.expectEqual(true, range.isPointInRange(p1.firstChild, 5));
|
|
|
|
// Point inside range
|
|
testing.expectEqual(true, range.isPointInRange(p1.firstChild, 7));
|
|
testing.expectEqual(true, range.isPointInRange(p2.firstChild, 3));
|
|
|
|
// Point at end boundary
|
|
testing.expectEqual(true, range.isPointInRange(p2.firstChild, 6));
|
|
|
|
// Point after range
|
|
testing.expectEqual(false, range.isPointInRange(p2.firstChild, 10));
|
|
}
|
|
</script>
|
|
|
|
<script id=isPointInRange_different_root>
|
|
{
|
|
// Create element in current document
|
|
const p1 = document.createElement('p');
|
|
p1.textContent = 'Local content';
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p1, 1);
|
|
|
|
// Create element in different document
|
|
const foreignDoc = document.implementation.createHTMLDocument('');
|
|
const foreignP = foreignDoc.createElement('p');
|
|
foreignP.textContent = 'Foreign';
|
|
|
|
// Point in different root should return false (not throw)
|
|
testing.expectEqual(false, range.isPointInRange(foreignP, 0));
|
|
}
|
|
</script>
|
|
|
|
<script id=isPointInRange_validation>
|
|
{
|
|
const p1 = document.createElement('p');
|
|
p1.textContent = 'Test content';
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p1, 1);
|
|
|
|
// Invalid offset should throw IndexSizeError
|
|
testing.expectError('IndexSizeError: Index or size is negative or greater than the allowed amount', () => {
|
|
range.isPointInRange(p1, 999);
|
|
});
|
|
|
|
testing.expectError('IndexSizeError: Index or size is negative or greater than the allowed amount', () => {
|
|
range.isPointInRange(p1.firstChild, 9999);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<script id=intersectsNode_basic>
|
|
{
|
|
// Create fresh elements
|
|
const div = document.createElement('div');
|
|
const p1 = document.createElement('p');
|
|
const p2 = document.createElement('p');
|
|
const p3 = document.createElement('p');
|
|
p1.textContent = 'First';
|
|
p2.textContent = 'Second';
|
|
p3.textContent = 'Third';
|
|
div.appendChild(p1);
|
|
div.appendChild(p2);
|
|
div.appendChild(p3);
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1.firstChild, 2);
|
|
range.setEnd(p2.firstChild, 3);
|
|
|
|
// Node that intersects (p1 contains the start)
|
|
testing.expectEqual(true, range.intersectsNode(p1));
|
|
|
|
// Node that intersects (p2 contains the end)
|
|
testing.expectEqual(true, range.intersectsNode(p2));
|
|
|
|
// Node that doesn't intersect (p3 is after the range)
|
|
testing.expectEqual(false, range.intersectsNode(p3));
|
|
|
|
// Container intersects
|
|
testing.expectEqual(true, range.intersectsNode(div));
|
|
}
|
|
</script>
|
|
|
|
<script id=intersectsNode_detached>
|
|
{
|
|
const div = document.createElement('div');
|
|
const p1 = document.createElement('p');
|
|
p1.textContent = 'Content';
|
|
div.appendChild(p1);
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p1, 1);
|
|
|
|
// The root node (div) should return true when it has no parent
|
|
// (Note: div is detached, so it's in the same tree as the range)
|
|
testing.expectEqual(true, range.intersectsNode(div));
|
|
}
|
|
</script>
|
|
|
|
<script id=intersectsNode_different_root>
|
|
{
|
|
const p1 = document.createElement('p');
|
|
p1.textContent = 'Local';
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1, 0);
|
|
range.setEnd(p1, 1);
|
|
|
|
// Node in different document should return false
|
|
const foreignDoc = document.implementation.createHTMLDocument('');
|
|
const foreignP = foreignDoc.createElement('p');
|
|
testing.expectEqual(false, range.intersectsNode(foreignP));
|
|
}
|
|
</script>
|
|
|
|
<script id=commonAncestorContainer_same_node>
|
|
{
|
|
const p = document.createElement('p');
|
|
p.textContent = 'Content';
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p.firstChild, 0);
|
|
range.setEnd(p.firstChild, 3);
|
|
|
|
// Both boundaries in same text node, so that's the common ancestor
|
|
testing.expectEqual(p.firstChild, range.commonAncestorContainer);
|
|
}
|
|
</script>
|
|
|
|
<script id=commonAncestorContainer_siblings>
|
|
{
|
|
const div = document.createElement('div');
|
|
const p1 = document.createElement('p');
|
|
const p2 = document.createElement('p');
|
|
p1.textContent = 'First';
|
|
p2.textContent = 'Second';
|
|
div.appendChild(p1);
|
|
div.appendChild(p2);
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p1.firstChild, 0);
|
|
range.setEnd(p2.firstChild, 3);
|
|
|
|
// Start and end in different siblings, common ancestor is the parent div
|
|
testing.expectEqual(div, range.commonAncestorContainer);
|
|
}
|
|
</script>
|
|
|
|
<script id=commonAncestorContainer_nested>
|
|
{
|
|
const div = document.createElement('div');
|
|
const section = document.createElement('section');
|
|
const p = document.createElement('p');
|
|
const span = document.createElement('span');
|
|
p.textContent = 'Text';
|
|
span.textContent = 'Span';
|
|
|
|
div.appendChild(section);
|
|
section.appendChild(p);
|
|
div.appendChild(span);
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p.firstChild, 0);
|
|
range.setEnd(span.firstChild, 2);
|
|
|
|
// Common ancestor of deeply nested p and sibling span is div
|
|
testing.expectEqual(div, range.commonAncestorContainer);
|
|
}
|
|
</script>
|
|
|
|
<script id=compareBoundaryPoints_constants>
|
|
{
|
|
// Test that the constants are defined
|
|
testing.expectEqual(0, Range.START_TO_START);
|
|
testing.expectEqual(1, Range.START_TO_END);
|
|
testing.expectEqual(2, Range.END_TO_END);
|
|
testing.expectEqual(3, Range.END_TO_START);
|
|
}
|
|
</script>
|
|
|
|
<script id=compareBoundaryPoints_basic>
|
|
{
|
|
const div = document.createElement('div');
|
|
const p1 = document.createElement('p');
|
|
const p2 = document.createElement('p');
|
|
p1.textContent = 'First paragraph';
|
|
p2.textContent = 'Second paragraph';
|
|
div.appendChild(p1);
|
|
div.appendChild(p2);
|
|
|
|
const range1 = document.createRange();
|
|
range1.setStart(p1.firstChild, 0);
|
|
range1.setEnd(p1.firstChild, 5);
|
|
|
|
const range2 = document.createRange();
|
|
range2.setStart(p1.firstChild, 3);
|
|
range2.setEnd(p2.firstChild, 5);
|
|
|
|
// range1 start is before range2 start
|
|
testing.expectEqual(-1, range1.compareBoundaryPoints(Range.START_TO_START, range2));
|
|
|
|
// range1 end is after range2 start
|
|
testing.expectEqual(1, range1.compareBoundaryPoints(Range.START_TO_END, range2));
|
|
|
|
// range1 start is before range2 end
|
|
testing.expectEqual(-1, range1.compareBoundaryPoints(Range.END_TO_START, range2));
|
|
|
|
// range1 end is before range2 end
|
|
testing.expectEqual(-1, range1.compareBoundaryPoints(Range.END_TO_END, range2));
|
|
}
|
|
</script>
|
|
|
|
<script id=compareBoundaryPoints_same_range>
|
|
{
|
|
const p = document.createElement('p');
|
|
p.textContent = 'Content';
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p.firstChild, 2);
|
|
range.setEnd(p.firstChild, 5);
|
|
|
|
// Comparing a range to itself should return 0
|
|
testing.expectEqual(0, range.compareBoundaryPoints(Range.START_TO_START, range));
|
|
testing.expectEqual(0, range.compareBoundaryPoints(Range.END_TO_END, range));
|
|
|
|
// End is after start
|
|
testing.expectEqual(1, range.compareBoundaryPoints(Range.START_TO_END, range));
|
|
|
|
// Start is before end
|
|
testing.expectEqual(-1, range.compareBoundaryPoints(Range.END_TO_START, range));
|
|
}
|
|
</script>
|
|
|
|
<script id=compareBoundaryPoints_invalid_how>
|
|
{
|
|
const p = document.createElement('p');
|
|
p.textContent = 'Test';
|
|
|
|
const range1 = document.createRange();
|
|
const range2 = document.createRange();
|
|
range1.setStart(p, 0);
|
|
range2.setStart(p, 0);
|
|
|
|
// Invalid how parameter should throw NotSupportedError
|
|
testing.expectError('NotSupportedError: Not Supported', () => {
|
|
range1.compareBoundaryPoints(4, range2);
|
|
});
|
|
|
|
testing.expectError('NotSupportedError: Not Supported', () => {
|
|
range1.compareBoundaryPoints(99, range2);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<script id=compareBoundaryPoints_different_root>
|
|
{
|
|
const p1 = document.createElement('p');
|
|
p1.textContent = 'Local';
|
|
|
|
const range1 = document.createRange();
|
|
range1.setStart(p1, 0);
|
|
range1.setEnd(p1, 1);
|
|
|
|
// Create range in different document
|
|
const foreignDoc = document.implementation.createHTMLDocument('');
|
|
const foreignP = foreignDoc.createElement('p');
|
|
foreignP.textContent = 'Foreign';
|
|
|
|
const range2 = foreignDoc.createRange();
|
|
range2.setStart(foreignP, 0);
|
|
range2.setEnd(foreignP, 1);
|
|
|
|
// Comparing ranges in different documents should throw WrongDocumentError
|
|
testing.expectError('WrongDocumentError: wrong_document_error', () => {
|
|
range1.compareBoundaryPoints(Range.START_TO_START, range2);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<script id=deleteContents_crossNode>
|
|
{
|
|
// Test deleteContents across multiple sibling text nodes
|
|
const p = document.createElement('p');
|
|
p.appendChild(document.createTextNode('AAAA'));
|
|
p.appendChild(document.createTextNode('BBBB'));
|
|
p.appendChild(document.createTextNode('CCCC'));
|
|
|
|
testing.expectEqual(3, p.childNodes.length);
|
|
testing.expectEqual('AAAABBBBCCCC', p.textContent);
|
|
|
|
const range = document.createRange();
|
|
// Start at position 2 in first text node ("AA|AA")
|
|
range.setStart(p.childNodes[0], 2);
|
|
// End at position 2 in third text node ("CC|CC")
|
|
range.setEnd(p.childNodes[2], 2);
|
|
|
|
range.deleteContents();
|
|
|
|
// Should have truncated first node to "AA" and third node to "CC"
|
|
// Middle node should be removed
|
|
testing.expectEqual(2, p.childNodes.length);
|
|
testing.expectEqual('AA', p.childNodes[0].textContent);
|
|
testing.expectEqual('CC', p.childNodes[1].textContent);
|
|
testing.expectEqual('AACC', p.textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=deleteContents_crossNode_partial>
|
|
{
|
|
// Test deleteContents where start node is completely preserved
|
|
const p = document.createElement('p');
|
|
p.appendChild(document.createTextNode('KEEP'));
|
|
p.appendChild(document.createTextNode('DELETE'));
|
|
p.appendChild(document.createTextNode('PARTIAL'));
|
|
|
|
const range = document.createRange();
|
|
// Start at end of first text node
|
|
range.setStart(p.childNodes[0], 4);
|
|
// End in middle of third text node
|
|
range.setEnd(p.childNodes[2], 4);
|
|
|
|
range.deleteContents();
|
|
|
|
testing.expectEqual(2, p.childNodes.length);
|
|
testing.expectEqual('KEEP', p.childNodes[0].textContent);
|
|
testing.expectEqual('IAL', p.childNodes[1].textContent);
|
|
testing.expectEqual('KEEPIAL', p.textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=extractContents_crossNode>
|
|
{
|
|
// Test extractContents across multiple sibling text nodes
|
|
const p = document.createElement('p');
|
|
p.appendChild(document.createTextNode('AAAA'));
|
|
p.appendChild(document.createTextNode('BBBB'));
|
|
p.appendChild(document.createTextNode('CCCC'));
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p.childNodes[0], 2);
|
|
range.setEnd(p.childNodes[2], 2);
|
|
|
|
const fragment = range.extractContents();
|
|
|
|
// Original should be truncated
|
|
testing.expectEqual(2, p.childNodes.length);
|
|
testing.expectEqual('AA', p.childNodes[0].textContent);
|
|
testing.expectEqual('CC', p.childNodes[1].textContent);
|
|
|
|
// Fragment should contain extracted content
|
|
testing.expectEqual(3, fragment.childNodes.length);
|
|
testing.expectEqual('AA', fragment.childNodes[0].textContent);
|
|
testing.expectEqual('BBBB', fragment.childNodes[1].textContent);
|
|
testing.expectEqual('CC', fragment.childNodes[2].textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=cloneContents_crossNode>
|
|
{
|
|
// Test cloneContents across multiple sibling text nodes
|
|
const p = document.createElement('p');
|
|
p.appendChild(document.createTextNode('AAAA'));
|
|
p.appendChild(document.createTextNode('BBBB'));
|
|
p.appendChild(document.createTextNode('CCCC'));
|
|
|
|
const range = document.createRange();
|
|
range.setStart(p.childNodes[0], 2);
|
|
range.setEnd(p.childNodes[2], 2);
|
|
|
|
const fragment = range.cloneContents();
|
|
|
|
// Original should be unchanged
|
|
testing.expectEqual(3, p.childNodes.length);
|
|
testing.expectEqual('AAAA', p.childNodes[0].textContent);
|
|
testing.expectEqual('BBBB', p.childNodes[1].textContent);
|
|
testing.expectEqual('CCCC', p.childNodes[2].textContent);
|
|
|
|
// Fragment should contain cloned content
|
|
testing.expectEqual(3, fragment.childNodes.length);
|
|
testing.expectEqual('AA', fragment.childNodes[0].textContent);
|
|
testing.expectEqual('BBBB', fragment.childNodes[1].textContent);
|
|
testing.expectEqual('CC', fragment.childNodes[2].textContent);
|
|
}
|
|
</script>
|
|
|
|
<script id=deleteContents_crossNode_withElements>
|
|
{
|
|
// Test deleteContents with mixed text and element nodes
|
|
const div = document.createElement('div');
|
|
div.appendChild(document.createTextNode('Start'));
|
|
const span = document.createElement('span');
|
|
span.textContent = 'Middle';
|
|
div.appendChild(span);
|
|
div.appendChild(document.createTextNode('End'));
|
|
|
|
testing.expectEqual(3, div.childNodes.length);
|
|
|
|
const range = document.createRange();
|
|
// Start in middle of first text node
|
|
range.setStart(div.childNodes[0], 2);
|
|
// End in middle of last text node
|
|
range.setEnd(div.childNodes[2], 1);
|
|
|
|
range.deleteContents();
|
|
|
|
// Should keep "St" from start, remove span, keep "nd" from end
|
|
testing.expectEqual(2, div.childNodes.length);
|
|
testing.expectEqual('St', div.childNodes[0].textContent);
|
|
testing.expectEqual('nd', div.childNodes[1].textContent);
|
|
testing.expectEqual('Stnd', div.textContent);
|
|
}
|
|
</script>
|