| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>EditContext: The HTMLElement.editContext property</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src='../../html/resources/common.js'></script> |
| </head> |
| <body> |
| <div id="test"></div> |
| <div id="contenteditableDiv" contenteditable></div> |
| <script> |
| test(function() { |
| const editContextDict = { |
| text: "Hello world", |
| selectionStart: 11, |
| selectionEnd: 11 |
| }; |
| const editContext = new EditContext(editContextDict); |
| assert_not_equals(editContext, null); |
| // Verify all the members of the EditContext |
| assert_equals(editContext.text, "Hello world"); |
| assert_equals(editContext.selectionStart, 11); |
| assert_equals(editContext.selectionEnd, 11); |
| }, 'Testing EditContext Dictionary Init'); |
| |
| test(function() { |
| contenteditableDiv.editContext = new EditContext(); |
| contenteditableDiv.editContext = null; |
| contenteditableDiv.focus(); |
| assert_equals(document.activeElement, contenteditableDiv); |
| }, 'A contenteditable element should remain editable after attaching and detaching EditContext.'); |
| |
| test(function() { |
| const editContext = new EditContext(); |
| assert_not_equals(editContext, null); |
| |
| const disconnected_div = document.createElement("DIV"); |
| assert_equals(disconnected_div.editContext, null); |
| |
| disconnected_div.editContext = editContext; |
| assert_equals(disconnected_div.editContext, editContext); |
| assert_equals(editContext.attachedElements().length, 1); |
| assert_equals(editContext.attachedElements()[0], disconnected_div); |
| }, 'EditContext can be associated with an element that is not in the tree.'); |
| |
| test(function() { |
| const editContext = new EditContext(); |
| assert_not_equals(editContext, null); |
| |
| const div = document.createElement("DIV"); |
| assert_equals(div.editContext, null); |
| |
| document.body.appendChild(div); |
| div.editContext = editContext; |
| assert_equals(div.editContext, editContext); |
| assert_equals(editContext.attachedElements().length, 1); |
| assert_equals(editContext.attachedElements()[0], div); |
| |
| document.body.removeChild(div); |
| assert_equals(div.editContext, editContext); |
| assert_equals(editContext.attachedElements().length, 1); |
| assert_equals(editContext.attachedElements()[0], div); |
| }, 'If an element is removed from the tree, the associated EditContext remains connected to the element.'); |
| |
| test(function() { |
| const editContext = new EditContext(); |
| |
| const div_parent = document.createElement("DIV"); |
| const div_child = document.createElement("DIV"); |
| document.body.appendChild(div_parent); |
| div_parent.appendChild(div_child); |
| |
| div_child.editContext = editContext; |
| assert_equals(div_child.editContext, editContext); |
| assert_equals(div_parent.editContext, null); |
| assert_equals(editContext.attachedElements().length, 1); |
| assert_equals(editContext.attachedElements()[0], div_child); |
| |
| document.body.removeChild(div_parent); |
| assert_equals(div_child.editContext, editContext); |
| assert_equals(editContext.attachedElements().length, 1); |
| assert_equals(editContext.attachedElements()[0], div_child); |
| }, 'If an element\'s ancestor is removed from tree, the associated EditContext remains connected to the element.'); |
| |
| test(function() { |
| const editContext = new EditContext(); |
| const test = document.getElementById("test"); |
| |
| test.editContext = editContext; |
| |
| assert_equals(test.editContext, editContext); |
| assert_equals(editContext.attachedElements().length, 1); |
| assert_equals(editContext.attachedElements()[0], test); |
| |
| test.editContext = null; |
| |
| assert_equals(editContext.attachedElements().length, 0); |
| }, '.attachedElements() should return associated element'); |
| |
| test(function() { |
| const editContext = new EditContext(); |
| assert_not_equals(editContext, null); |
| editContext.updateText(0, 3, "foo"); |
| assert_equals(editContext.text, "foo"); |
| const test = document.getElementById('test'); |
| // Update the layout of the |EditContext| |
| var viewRect = test.getBoundingClientRect(); |
| viewRect.x = viewRect.left; |
| viewRect.y = viewRect.top; |
| var caretRect = test.getBoundingClientRect(); |
| caretRect.x = caretRect.left; |
| caretRect.y = 2.2 * caretRect.top; |
| caretRect.width = 1; |
| editContext.updateSelection(0, 0); |
| assert_equals(editContext.selectionStart, 0); |
| assert_equals(editContext.selectionEnd, 0); |
| editContext.updateSelection(1, 0); |
| assert_equals(editContext.selectionStart, 1); |
| assert_equals(editContext.selectionEnd, 0); |
| editContext.updateSelection(0, 1); |
| assert_equals(editContext.selectionStart, 0); |
| assert_equals(editContext.selectionEnd, 1); |
| editContext.updateSelection(1, 1); |
| assert_equals(editContext.selectionStart, 1); |
| assert_equals(editContext.selectionEnd, 1); |
| editContext.updateControlBounds(viewRect); |
| editContext.updateSelectionBounds(caretRect); |
| editContext.updateCharacterBounds(0, [caretRect]); |
| |
| assert_throws_js(TypeError, function() { editContext.updateControlBounds(42); }); |
| assert_throws_js(TypeError, function() { editContext.updateSelectionBounds(42); }); |
| assert_throws_js(TypeError, function() { editContext.updateControlBounds(undefined); }); |
| assert_throws_js(TypeError, function() { editContext.updateSelectionBounds(undefined); }); |
| assert_throws_js(TypeError, function() { editContext.updateCharacterBounds(0); }); |
| assert_throws_js(TypeError, function() { editContext.updateCharacterBounds([caretRect]); }); |
| assert_throws_js(TypeError, function() { editContext.updateCharacterBounds(0, caretRect); }); |
| assert_throws_js(TypeError, function() { editContext.updateCharacterBounds(0, 42); }); |
| assert_throws_js(TypeError, function() { editContext.updateCharacterBounds(0, undefined); }); |
| assert_throws_js(TypeError, function() { editContext.updateCharacterBounds(0, [undefined]); }); |
| |
| viewRect.x = viewRect.y = viewRect.width = viewRect.height = undefined; |
| editContext.updateControlBounds(viewRect); |
| editContext.updateSelectionBounds(viewRect); |
| editContext.updateCharacterBounds(0, [viewRect]); |
| }, 'Testing EditContext update text, selection and layout'); |
| |
| test(function() { |
| const editContext = new EditContext(); |
| const test = document.getElementById('test'); |
| var rect1 = DOMRect.fromRect({x:0, y:1, width:100, height:200}); |
| var rect2 = DOMRect.fromRect({x:2, y:3, width:300, height:400}); |
| var rectArray = [rect1, rect2]; |
| var rangeStart = 2; |
| editContext.updateCharacterBounds(rangeStart, rectArray); |
| assert_equals(editContext.characterBoundsRangeStart, 2); |
| |
| var actualRectArray = editContext.characterBounds(); |
| assert_equals(actualRectArray.length, 2); |
| assert_equals(actualRectArray[0].x, 0); |
| assert_equals(actualRectArray[0].y, 1); |
| assert_equals(actualRectArray[0].width, 100); |
| assert_equals(actualRectArray[0].height, 200); |
| rect2.x=100; |
| assert_equals(actualRectArray[1].x, 2); // the cached value shouldn't change. |
| assert_equals(actualRectArray[1].y, 3); |
| assert_equals(actualRectArray[1].width, 300); |
| assert_equals(actualRectArray[1].height, 400); |
| }, 'updateCharacterBounds(), characterBounds(), and characterBoundsRangeStart should work properly'); |
| |
| // The behavior in this test case is not well-defined in the spec. |
| // See https://github.com/w3c/edit-context/issues/88 |
| // test(function() { |
| // const editContext = new EditContext(); |
| // assert_not_equals(editContext, null); |
| // editContext.updateText(0, 3, "foo"); |
| // assert_equals(editContext.text, "foo"); |
| // assert_throws_dom("IndexSizeError", function() { editContext.updateSelection(10, 0); }); |
| // assert_equals(editContext.selectionStart, 0); |
| // assert_equals(editContext.selectionEnd, 0); |
| // assert_throws_dom("IndexSizeError", function() { editContext.updateText(10, 1, "h"); }); |
| // assert_equals(editContext.text, "foo"); |
| // }, 'Testing EditContext update text and selection with invalid values'); |
| |
| test(function() { |
| const editContext = new EditContext(); |
| assert_not_equals(editContext, null); |
| editContext.updateText(0, 3, "foo"); |
| assert_equals(editContext.text, "foo"); |
| editContext.updateSelection(3, 0); |
| assert_equals(editContext.selectionStart, 3); |
| assert_equals(editContext.selectionEnd, 0); |
| }, 'EditContext should allow a backwards selection'); |
| |
| test(function() { |
| const editContext = new EditContext(); |
| assert_not_equals(editContext, null); |
| editContext.updateText(6, 0, "abcdef"); |
| assert_equals(editContext.text, "abcdef"); |
| |
| editContext.updateText(2, 5, "ghi"); |
| assert_equals(editContext.text, "abghif"); |
| |
| editContext.updateText(5, 2, "jkl"); |
| assert_equals(editContext.text, "abjklf"); |
| }, 'updateText can replace substrings including with backwards parameters'); |
| </script> |
| </body> |
| </html> |