922 lines
31 KiB
HTML
922 lines
31 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>Testing Selection Events</title>
|
|
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
|
</head>
|
|
|
|
<body>
|
|
<div id="normal">
|
|
<span id="inner">A bunch of text in a span inside of a div which should be selected</span>
|
|
</div>
|
|
|
|
<div id="ce">
|
|
This is a random block of text
|
|
</div>
|
|
|
|
<input type="text" id="input" value="XXXXXXXXXXXXXXXXXXX" width="200"> <br>
|
|
|
|
<textarea id="textarea" width="200">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</textarea>
|
|
|
|
<script>
|
|
// Call the testing methods from the parent window
|
|
var is = parent.is;
|
|
var ok = parent.ok;
|
|
|
|
// spin() spins the event loop for two cycles, giving time for
|
|
// selectionchange events to be fired, and handled by our listeners.
|
|
function spin() {
|
|
return new Promise(function(a) {
|
|
parent.SimpleTest.executeSoon(function() {
|
|
parent.SimpleTest.executeSoon(a)
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param {Node} node
|
|
*/
|
|
function isProperSelectionChangeTarget(node) {
|
|
return node === document || node === input || node === textarea;
|
|
}
|
|
|
|
// The main test
|
|
parent.add_task(async function() {
|
|
await spin();
|
|
|
|
var selectstart = 0;
|
|
var selectionchange = 0;
|
|
var inputSelectionchange = 0;
|
|
var textareaSelectionchange = 0;
|
|
|
|
var cancel = false;
|
|
var selectstartTarget = null;
|
|
|
|
async function UpdateSelectEventsOnTextControlsPref({ selectstart, selectionchange }) {
|
|
await SpecialPowers.pushPrefEnv({
|
|
'set': [
|
|
['dom.select_events.textcontrols.selectstart.enabled', !!selectstart],
|
|
['dom.select_events.textcontrols.selectionchange.enabled', !!selectionchange],
|
|
]
|
|
});
|
|
}
|
|
await UpdateSelectEventsOnTextControlsPref({
|
|
selectstart: false,
|
|
selectionchange: false,
|
|
});
|
|
|
|
document.addEventListener('selectstart', function(aEvent) {
|
|
console.log("originaltarget", aEvent.originalTarget, "new", selectstartTarget);
|
|
is(aEvent.originalTarget, selectstartTarget,
|
|
"The original target of selectstart");
|
|
selectstartTarget = null;
|
|
|
|
console.log(selectstart);
|
|
selectstart++;
|
|
|
|
if (cancel) {
|
|
aEvent.preventDefault();
|
|
}
|
|
});
|
|
document.addEventListener('selectionchange', function(aEvent) {
|
|
ok(isProperSelectionChangeTarget(aEvent.target),
|
|
"The target of selectionchange should be one of document, input, or textarea");
|
|
console.log(selectionchange);
|
|
selectionchange++;
|
|
});
|
|
|
|
function elt(aId) { return document.getElementById(aId); }
|
|
function reset() {
|
|
selectstart = 0;
|
|
selectionchange = 0;
|
|
inputSelectionchange = 0;
|
|
textareaSelectionchange = 0;
|
|
cancel = false;
|
|
}
|
|
|
|
elt("input").addEventListener('selectionchange', function(aEvent) {
|
|
is (aEvent.originalTarget, elt("input"),
|
|
"The original target of selectionchange should be the input");
|
|
console.log(inputSelectionchange);
|
|
inputSelectionchange++;
|
|
});
|
|
elt("textarea").addEventListener('selectionchange', function(aEvent) {
|
|
is (aEvent.originalTarget, elt("textarea"),
|
|
"The original target of selectionchange should be the textarea");
|
|
console.log(textareaSelectionchange);
|
|
textareaSelectionchange++;
|
|
});
|
|
|
|
function checkEventCounts(
|
|
aTestDescription,
|
|
aSituationDescription,
|
|
aExpectedEventCounts
|
|
) {
|
|
let {
|
|
selectstartOnDocument = 0,
|
|
selectionchangeOnDocument = 0,
|
|
selectionchangeOnInput = 0,
|
|
selectionchangeOnTextarea = 0,
|
|
} = aExpectedEventCounts;
|
|
|
|
is(
|
|
selectstart,
|
|
selectstartOnDocument,
|
|
`${
|
|
aTestDescription
|
|
}: "selectstart" event on the document node should be fired ${
|
|
selectstartOnDocument
|
|
} times ${aSituationDescription}`
|
|
);
|
|
is(
|
|
selectionchange,
|
|
selectionchangeOnDocument,
|
|
`${
|
|
aTestDescription
|
|
}: "selectionchange" event on the document node should be fired ${
|
|
selectionchangeOnDocument
|
|
} times ${aSituationDescription}`
|
|
);
|
|
is(
|
|
inputSelectionchange,
|
|
selectionchangeOnInput,
|
|
`${
|
|
aTestDescription
|
|
}: "selectionchange" event on the <input> should be fired ${
|
|
selectionchangeOnInput
|
|
} times ${aSituationDescription}`
|
|
);
|
|
is(
|
|
textareaSelectionchange,
|
|
selectionchangeOnTextarea,
|
|
`${
|
|
aTestDescription
|
|
}: "selectionchange" event on the <textarea> should be fired ${
|
|
selectionchangeOnTextarea
|
|
} times ${aSituationDescription}`
|
|
);
|
|
}
|
|
|
|
async function testWithSynthesizingMouse(
|
|
aDescription,
|
|
aElement,
|
|
aOffset,
|
|
aType,
|
|
aExpectedEventCounts
|
|
) {
|
|
const eventObject = aType == "click" ? {} : { type: aType };
|
|
if (aOffset.y === undefined || aOffset.y === null) {
|
|
aOffset.y = 10;
|
|
}
|
|
synthesizeMouse(aElement, aOffset.x, aOffset.y, eventObject);
|
|
await spin();
|
|
|
|
checkEventCounts(
|
|
aDescription,
|
|
`after synthesizing ${aType} at ${aOffset.x}, ${aOffset.y}`,
|
|
aExpectedEventCounts
|
|
);
|
|
reset();
|
|
}
|
|
|
|
async function testWithSynthesizingKey(
|
|
aDescription,
|
|
aKey,
|
|
aEventObject,
|
|
aExpectedEventCounts
|
|
) {
|
|
synthesizeKey(aKey, aEventObject);
|
|
await spin();
|
|
|
|
checkEventCounts(
|
|
aDescription,
|
|
`after synthesizing a key press of "${aKey}"`,
|
|
aExpectedEventCounts
|
|
);
|
|
reset();
|
|
}
|
|
|
|
async function testWithSettingContentEditableAttribute(
|
|
aDescription,
|
|
aElement,
|
|
aContentEditableValue,
|
|
aExpectedEventCounts
|
|
) {
|
|
aElement.setAttribute("contenteditable",
|
|
aContentEditableValue ? "true" : "false");
|
|
await spin();
|
|
|
|
checkEventCounts(
|
|
aDescription,
|
|
`after setting contenteditable attribute to ${
|
|
aElement.getAttribute("contenteditable")
|
|
}`,
|
|
aExpectedEventCounts
|
|
);
|
|
reset();
|
|
}
|
|
|
|
var selection = document.getSelection();
|
|
function isCollapsed() {
|
|
is(selection.isCollapsed, true, "Selection is collapsed");
|
|
}
|
|
function isNotCollapsed() {
|
|
is(selection.isCollapsed, false, "Selection is not collapsed");
|
|
}
|
|
|
|
// Make sure setting the element to contentEditable doesn't cause any selectionchange events
|
|
await testWithSettingContentEditableAttribute(
|
|
"Setting contenteditable attribute to true of <div> should not change selection",
|
|
elt("ce"),
|
|
true,
|
|
{}
|
|
);
|
|
|
|
// Make sure setting the element to not be contentEditable doesn't cause any selectionchange events
|
|
await testWithSettingContentEditableAttribute(
|
|
'Setting contenteditable attribute to false of <div contenteditable="true"> should not change selection',
|
|
elt("ce"),
|
|
false,
|
|
{}
|
|
);
|
|
|
|
// Now make the div contentEditable and proceed with the test
|
|
await testWithSettingContentEditableAttribute(
|
|
'Setting contenteditable attribute to true of <div contenteditable="false"> should not change selection',
|
|
elt("ce"),
|
|
true,
|
|
{}
|
|
);
|
|
|
|
// Focus the contenteditable text
|
|
await testWithSynthesizingMouse(
|
|
'Clicking in <div contenteditable="true"> should change selection',
|
|
elt("ce"),
|
|
{ x: 100 },
|
|
"click",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
|
|
// Move the selection to the right, this should only fire selectstart once
|
|
selectstartTarget = elt("ce").firstChild;
|
|
await testWithSynthesizingKey(
|
|
'Synthesizing Shift-ArrowRight to select a character in the text node of <div contenteditable="true"> should start to select again and change selection',
|
|
"KEY_ArrowRight",
|
|
{ shiftKey: true },
|
|
{ selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
await testWithSynthesizingKey(
|
|
'Synthesizing Shift-ArrowRight again to select 2 characters in the text node of <div contenteditable="true"> should change selection',
|
|
"KEY_ArrowRight",
|
|
{ shiftKey: true },
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
|
|
// Move it back so that the selection is empty again
|
|
await testWithSynthesizingKey(
|
|
'Synthesizing Shift-ArrowLeft to shrink selection in the text node of <div contenteditable="true"> should change selection',
|
|
"KEY_ArrowLeft",
|
|
{ shiftKey: true },
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
await testWithSynthesizingKey(
|
|
'Synthesizing Shift-ArrowLeft again to collapse selection in the text node of <div contenteditable="true"> should change selection',
|
|
"KEY_ArrowLeft",
|
|
{ shiftKey: true },
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
|
|
// Going from empty to non-empty should fire selectstart again
|
|
selectstartTarget = elt("ce").firstChild;
|
|
await testWithSynthesizingKey(
|
|
'Synthesizing Shift-ArrowLeft again to select a character on the other side in the text node of <div contenteditable="true"> should start to select and change selection',
|
|
"KEY_ArrowLeft",
|
|
{ shiftKey: true },
|
|
{ selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
|
|
async function testWithSynthesizingMouseDrag(
|
|
aDescription,
|
|
aElement,
|
|
aSelectstartTarget
|
|
) {
|
|
// Select a region
|
|
await testWithSynthesizingMouse(
|
|
`Pressing left mouse button ${
|
|
aDescription
|
|
} should not start to select but should change selection`,
|
|
aElement,
|
|
{ x: 50 },
|
|
"mousedown",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
|
|
selectstartTarget = aSelectstartTarget;
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to right to extend selection ${
|
|
aDescription
|
|
} should start to select and change selection`,
|
|
aElement,
|
|
{ x: 100 },
|
|
"mousemove",
|
|
{ selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
|
|
// Moving it more shouldn't trigger a start (move back to empty)
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to left to shrink selection ${
|
|
aDescription
|
|
} should change selection`,
|
|
aElement,
|
|
{ x: 75 },
|
|
"mousemove",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to left to collapse selection ${
|
|
aDescription
|
|
} should change selection`,
|
|
aElement,
|
|
{ x: 50 },
|
|
"mousemove",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
|
|
// Wiggling the mouse a little such that it doesn't select any
|
|
// characters shouldn't trigger a selection
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to bottom a bit ${
|
|
aDescription
|
|
} should not cause selection change`,
|
|
aElement,
|
|
{ x: 50, y: 11 },
|
|
"mousemove",
|
|
{}
|
|
);
|
|
isCollapsed();
|
|
|
|
// Moving the mouse again from an empty selection should trigger a
|
|
// selectstart
|
|
selectstartTarget = aSelectstartTarget;
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to left to extend selection ${
|
|
aDescription
|
|
} should start to select and change selection`,
|
|
aElement,
|
|
{ x: 25 },
|
|
"mousemove",
|
|
{ selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
|
|
// Releasing the mouse shouldn't do anything
|
|
await testWithSynthesizingMouse(
|
|
`Releasing left mouse button to stop dragging ${
|
|
aDescription
|
|
} should not change selection`,
|
|
aElement,
|
|
{ x: 25 },
|
|
"mouseup",
|
|
{}
|
|
);
|
|
isNotCollapsed();
|
|
|
|
// And neither should moving your mouse around when the mouse
|
|
// button isn't pressed
|
|
await testWithSynthesizingMouse(
|
|
`Just moving mouse to right ${
|
|
aDescription
|
|
} should not start to select nor change selection`,
|
|
aElement,
|
|
{ x: 50 },
|
|
"mousemove",
|
|
{}
|
|
);
|
|
isNotCollapsed();
|
|
|
|
// Clicking in an random location should move the selection, but not perform a
|
|
// selectstart
|
|
await testWithSynthesizingMouse(
|
|
`Clicking to collapse selection ${
|
|
aDescription
|
|
} should cause only selection change`,
|
|
aElement,
|
|
{ x: 50 },
|
|
"click",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
|
|
// Clicking there again should do nothing
|
|
await testWithSynthesizingMouse(
|
|
`Clicking same position again ${
|
|
aDescription
|
|
} should not change selection`,
|
|
aElement,
|
|
{ x: 50 },
|
|
"click",
|
|
{}
|
|
);
|
|
isCollapsed();
|
|
|
|
// Selecting a region, and canceling the selectstart should mean that the
|
|
// selection remains collapsed
|
|
await testWithSynthesizingMouse(
|
|
`Pressing left mouse button on different character to move caret ${
|
|
aDescription
|
|
} should cause only selection change`,
|
|
aElement,
|
|
{ x: 75 },
|
|
"mousedown",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
cancel = true;
|
|
selectstartTarget = aSelectstartTarget;
|
|
await testWithSynthesizingMouse(
|
|
`Moving mouse to right to extend selection but selectstart event will be prevented default ${
|
|
aDescription
|
|
} should start to select and change selection`,
|
|
aElement,
|
|
{ x: 100 },
|
|
"mousemove",
|
|
{ selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
await testWithSynthesizingMouse(
|
|
`Releasing the left mouse button after dragging but selectstart was prevented the default ${
|
|
aDescription
|
|
} should not change selection`,
|
|
aElement,
|
|
{ x: 100 },
|
|
"mouseup",
|
|
{}
|
|
);
|
|
isCollapsed();
|
|
}
|
|
|
|
// Should work both on normal
|
|
await testWithSynthesizingMouseDrag(
|
|
"on the text node in the non-editable <div>",
|
|
elt("inner"),
|
|
elt("inner").firstChild
|
|
);
|
|
// and contenteditable fields
|
|
await testWithSynthesizingMouseDrag(
|
|
'on the text node in the editable <div contenteditable="true">',
|
|
elt("ce"),
|
|
elt("ce").firstChild
|
|
);
|
|
// and fields with elements in them
|
|
await testWithSynthesizingMouseDrag(
|
|
"on the text node in the non-editable <div>'s child",
|
|
elt("normal"),
|
|
elt("inner").firstChild
|
|
);
|
|
|
|
await testWithSynthesizingMouse(
|
|
"Clicking in the text node in the `<div>` should change selection",
|
|
elt("inner"),
|
|
{ x: 50 },
|
|
"click",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
|
|
reset();
|
|
// Select all should fire both selectstart and change
|
|
selectstartTarget = document.body;
|
|
await testWithSynthesizingKey(
|
|
"Select All when no editor has focus should start to select and select all content",
|
|
"a", { accelKey: true },
|
|
{ selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
|
|
// Clear the selection
|
|
await testWithSynthesizingMouse(
|
|
"Clicking in the non-editable <div> should clear selection",
|
|
elt("inner"),
|
|
{ x: 50 },
|
|
"click",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
|
|
// Even if we already have a selection
|
|
await testWithSynthesizingMouse(
|
|
"Pressing the left mouse button in non-editable <div> should change selection",
|
|
elt("inner"),
|
|
{ x: 75 },
|
|
"mousedown",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
selectstartTarget = elt("inner").firstChild;
|
|
await testWithSynthesizingMouse(
|
|
"Dragging mouse to right to extend selection should start and change selection",
|
|
elt("inner"),
|
|
{ x: 100 },
|
|
"mousemove",
|
|
{ selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
await testWithSynthesizingMouse(
|
|
"Releasing the left mouse button should not change selection",
|
|
elt("inner"),
|
|
{ x: 100 },
|
|
"mouseup",
|
|
{}
|
|
);
|
|
isNotCollapsed();
|
|
|
|
selectstartTarget = document.body;
|
|
await testWithSynthesizingKey(
|
|
"Select All when no editor has focus should start to select and select all content (again)",
|
|
"a",
|
|
{ accelKey: true },
|
|
{ selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
|
|
);
|
|
isNotCollapsed();
|
|
|
|
// Clear the selection
|
|
await testWithSynthesizingMouse(
|
|
"Clicking in the non-editable <div> should clear selection (again)",
|
|
elt("inner"),
|
|
{ x: 50 },
|
|
"click",
|
|
{selectionchangeOnDocument: 1 }
|
|
);
|
|
isCollapsed();
|
|
|
|
// Make sure that a synthesized selection change doesn't fire selectstart
|
|
getSelection().removeAllRanges();
|
|
await spin();
|
|
is(
|
|
selectstart,
|
|
0,
|
|
"Selection.removeAllRanges() should not cause selectstart event"
|
|
);
|
|
is(
|
|
selectionchange,
|
|
1,
|
|
"Selection.removeAllRanges() should cause selectionchange event"
|
|
);
|
|
reset();
|
|
isCollapsed();
|
|
|
|
await (async function test_Selection_selectNode() {
|
|
const range = document.createRange();
|
|
range.selectNode(elt("inner"));
|
|
getSelection().addRange(range);
|
|
await spin();
|
|
is(
|
|
selectstart,
|
|
0,
|
|
"Selection.addRange() should not cause selectstart event"
|
|
);
|
|
is(
|
|
selectionchange,
|
|
1,
|
|
"Selection.addRange() should cause selectionchange event"
|
|
);
|
|
reset();
|
|
isNotCollapsed();
|
|
})();
|
|
|
|
// Change the range, without replacing
|
|
await (async function test_Selection_getRangeAt_selectNode() {
|
|
getSelection().getRangeAt(0).selectNode(elt("ce"));
|
|
await spin();
|
|
is(
|
|
selectstart,
|
|
0,
|
|
"Selection.getRangeAt(0).selectNode() should not cause selectstart event"
|
|
);
|
|
is(
|
|
selectionchange,
|
|
1,
|
|
"Selection.getRangeAt(0).selectNode() should cause selectionchange event"
|
|
);
|
|
reset();
|
|
isNotCollapsed();
|
|
})();
|
|
|
|
// Remove the range
|
|
getSelection().removeAllRanges();
|
|
await spin();
|
|
is(
|
|
selectstart,
|
|
0,
|
|
"Selection.removeAllRanges() should not cause selectstart event (again)"
|
|
);
|
|
is(
|
|
selectionchange,
|
|
1,
|
|
"Selection.removeAllRanges() should cause selectionchange event (again)"
|
|
);
|
|
reset();
|
|
isCollapsed();
|
|
|
|
for (const textControl of [elt("input"), elt("textarea")]) {
|
|
await UpdateSelectEventsOnTextControlsPref({
|
|
selectstart: false,
|
|
selectionchange: false,
|
|
});
|
|
|
|
// Without the dom.select_events.textcontrols.enabled pref,
|
|
// pressing the mouse shouldn't do anything.
|
|
await testWithSynthesizingMouse(
|
|
`Pressing the left mouse button in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should change selection of the document`,
|
|
textControl,
|
|
{ x: 50 },
|
|
"mousedown",
|
|
{
|
|
selectionchangeOnDocument: 1,
|
|
}
|
|
);
|
|
|
|
// Releasing the mouse shouldn't do anything
|
|
await testWithSynthesizingMouse(
|
|
`Releasing the left mouse button in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should not change any selection`,
|
|
textControl,
|
|
{ x: 50 },
|
|
"mouseup",
|
|
{}
|
|
);
|
|
|
|
for (const selectstart of [1, 0]) {
|
|
await UpdateSelectEventsOnTextControlsPref({
|
|
selectstart,
|
|
selectionchange: true,
|
|
});
|
|
|
|
const selectstartEventSetting = `selectstart in text controls is ${
|
|
selectstart ? "enabled" : "disabled"
|
|
}`;
|
|
|
|
const isInput = textControl.tagName.toLocaleLowerCase() == "input";
|
|
|
|
await testWithSynthesizingMouse(
|
|
`Pressing the left mouse button in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should change selection (${selectstartEventSetting})`,
|
|
textControl,
|
|
{ x: 40 },
|
|
"mousedown",
|
|
{
|
|
selectionchangeOnDocument: 1,
|
|
selectionchangeOnInput: isInput ? 1 : 0,
|
|
selectionchangeOnTextarea: isInput ? 0 : 1,
|
|
}
|
|
);
|
|
|
|
selectstartTarget = textControl;
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to right to extend selection in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should start to select and change selection (${
|
|
selectstartEventSetting
|
|
})`,
|
|
textControl,
|
|
{ x: 100 },
|
|
"mousemove",
|
|
{
|
|
selectstartOnDocument: selectstart,
|
|
selectionchangeOnDocument: 1,
|
|
selectionchangeOnInput: isInput ? 1 : 0,
|
|
selectionchangeOnTextarea: isInput ? 0 : 1,
|
|
}
|
|
);
|
|
|
|
// Moving it more shouldn't trigger a start (move back to empty)
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to left to shrink selection in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should change selection (${selectstartEventSetting})`,
|
|
textControl,
|
|
{ x: 75 },
|
|
"mousemove",
|
|
{
|
|
selectionchangeOnDocument: 1,
|
|
selectionchangeOnInput: isInput ? 1 : 0,
|
|
selectionchangeOnTextarea: isInput ? 0 : 1,
|
|
}
|
|
);
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to left to collapse selection in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should change selection (${selectstartEventSetting})`,
|
|
textControl,
|
|
{ x: 40 },
|
|
"mousemove",
|
|
{
|
|
selectionchangeOnDocument: 1,
|
|
selectionchangeOnInput: isInput ? 1 : 0,
|
|
selectionchangeOnTextarea: isInput ? 0 : 1,
|
|
}
|
|
);
|
|
|
|
// Wiggling the mouse a little such that it doesn't select any
|
|
// characters shouldn't trigger a selection
|
|
await testWithSynthesizingMouse(
|
|
`Pressing the left mouse button at caret in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should not change selection (${selectstartEventSetting})`,
|
|
textControl,
|
|
{
|
|
x: 40,
|
|
y: 11,
|
|
},
|
|
"mousemove",
|
|
{}
|
|
);
|
|
|
|
// Moving the mouse again from an empty selection should trigger a
|
|
// selectstart
|
|
selectstartTarget = textControl;
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to left to extend selection in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should start to select and change selection (${
|
|
selectstartEventSetting
|
|
})`,
|
|
textControl,
|
|
{ x: 25 },
|
|
"mousemove",
|
|
{
|
|
selectstartOnDocument: selectstart,
|
|
selectionchangeOnDocument: 1,
|
|
selectionchangeOnInput: isInput ? 1 : 0,
|
|
selectionchangeOnTextarea: isInput ? 0 : 1,
|
|
}
|
|
);
|
|
|
|
// Releasing the mouse shouldn't do anything
|
|
await testWithSynthesizingMouse(
|
|
`Releasing the left mouse button in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should not change selection (${selectstartEventSetting})`,
|
|
textControl,
|
|
{ x: 25 },
|
|
"mouseup",
|
|
{}
|
|
);
|
|
|
|
// And neither should moving your mouse around when the mouse
|
|
// button isn't pressed
|
|
await testWithSynthesizingMouse(
|
|
`Just moving mouse to right in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should not start to select nor change selection (${
|
|
selectstartEventSetting
|
|
})`,
|
|
textControl,
|
|
{ x: 50 },
|
|
"mousemove",
|
|
{}
|
|
);
|
|
|
|
// Clicking in an random location should move the selection, but
|
|
// not perform a selectstart
|
|
await testWithSynthesizingMouse(
|
|
`Clicking in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should change selection, but should not start selection (${
|
|
selectstartEventSetting
|
|
})`,
|
|
textControl,
|
|
{ x: 50 },
|
|
"click",
|
|
{
|
|
selectionchangeOnDocument: 1,
|
|
selectionchangeOnInput: isInput ? 1 : 0,
|
|
selectionchangeOnTextarea: isInput ? 0 : 1,
|
|
}
|
|
);
|
|
|
|
// Clicking there again should do nothing
|
|
await testWithSynthesizingMouse(
|
|
`Clicking at caret in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should not change selection (${selectstartEventSetting})`,
|
|
textControl,
|
|
{ x: 50 },
|
|
"click",
|
|
{}
|
|
);
|
|
|
|
// Selecting a region, and canceling the selectstart should mean that the
|
|
// selection remains collapsed
|
|
await testWithSynthesizingMouse(
|
|
`Pressing the left mouse button at different character in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should change selection (${selectstartEventSetting})`,
|
|
textControl,
|
|
{ x: 75 },
|
|
"mousedown",
|
|
{
|
|
selectionchangeOnDocument: 1,
|
|
selectionchangeOnInput: isInput ? 1 : 0,
|
|
selectionchangeOnTextarea: isInput ? 0 : 1,
|
|
}
|
|
);
|
|
cancel = true;
|
|
selectstartTarget = textControl;
|
|
await testWithSynthesizingMouse(
|
|
`Dragging mouse to right to extend selection in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> but the default of selectstart is prevented should cause selectstart and selectionchange events (${
|
|
selectstartEventSetting
|
|
})`,
|
|
textControl,
|
|
{ x: 100 },
|
|
"mousemove",
|
|
{
|
|
selectstartOnDocument: selectstart,
|
|
selectionchangeOnDocument: 1,
|
|
selectionchangeOnInput: isInput ? 1 : 0,
|
|
selectionchangeOnTextarea: isInput ? 0 : 1,
|
|
}
|
|
);
|
|
await testWithSynthesizingMouse(
|
|
`Releasing the left mouse button in <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> should not cause changing selection (${selectstartEventSetting})`,
|
|
textControl,
|
|
{ x: 100 },
|
|
"mouseup",
|
|
{}
|
|
);
|
|
}
|
|
}
|
|
|
|
// Marking the input and textarea as display: none and then as visible again
|
|
// shouldn't trigger any changes, although the nodes will be re-framed
|
|
for (const textControl of [elt("input"), elt("textarea")]) {
|
|
await (async function test_set_display_of_text_control_to_none() {
|
|
textControl.setAttribute("style", "display: none;");
|
|
await spin();
|
|
checkEventCounts(
|
|
`Setting display of <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}> to none`,
|
|
"",
|
|
{}
|
|
);
|
|
reset();
|
|
})();
|
|
|
|
await (async function test_remove_display_none_of_text_control() {
|
|
textControl.setAttribute("style", "");
|
|
await spin();
|
|
checkEventCounts(
|
|
`Removing display:none of <${
|
|
textControl.tagName.toLocaleLowerCase()
|
|
}>`,
|
|
"",
|
|
{}
|
|
);
|
|
reset();
|
|
})();
|
|
}
|
|
|
|
// When selection is at the end of contentEditable's content,
|
|
// clearing the content should trigger selection events.
|
|
await (async function test_removing_contenteditable() {
|
|
const savedContent = elt("ce").innerHTML;
|
|
document.getSelection().setBaseAndExtent(elt("ce"), 1, elt("ce"), 1);
|
|
await spin();
|
|
reset();
|
|
|
|
elt("ce").firstChild.remove();
|
|
await spin();
|
|
checkEventCounts(
|
|
'Removing <div contenteditable="true"> from the DOM tree',
|
|
"",
|
|
{ selectionchangeOnDocument: 1 }
|
|
);
|
|
|
|
elt("ce").innerHTML = savedContent;
|
|
await spin();
|
|
reset();
|
|
})();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|