forked from mirrors/gecko-dev
Bug 1898343 - Don't fire selectionchange if there is one pending, r=masayuki
Differential Revision: https://phabricator.services.mozilla.com/D211263
This commit is contained in:
parent
977c6db99e
commit
c9f32debe1
10 changed files with 50 additions and 59 deletions
|
|
@ -23,9 +23,7 @@ async function testFontHighlighting(view) {
|
|||
// The number of window selection change events we expect to get as we hover over each
|
||||
// font in the list. Waiting for those events is how we know that text-runs were
|
||||
// highlighted in the page.
|
||||
// The reason why these numbers vary is because the highlighter may create more than
|
||||
// 1 selection range object, depending on the number of text-runs found.
|
||||
const expectedSelectionChangeEvents = [2, 2, 2, 1, 1];
|
||||
const expectedSelectionChangeEvents = [1, 1, 1, 1, 1];
|
||||
|
||||
const viewDoc = view.document;
|
||||
|
||||
|
|
|
|||
|
|
@ -164,12 +164,21 @@ void SelectionChangeEventDispatcher::OnSelectionChange(Document* aDoc,
|
|||
|
||||
nsINode* target =
|
||||
textControl ? static_cast<nsINode*>(textControl.get()) : aDoc;
|
||||
if (target) {
|
||||
CanBubble canBubble = textControl ? CanBubble::eYes : CanBubble::eNo;
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(target, eSelectionChange, canBubble);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target->HasScheduledSelectionChangeEvent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
target->SetHasScheduledSelectionChangeEvent();
|
||||
|
||||
CanBubble canBubble = textControl ? CanBubble::eYes : CanBubble::eNo;
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncSelectionChangeEventDispatcher(target, eSelectionChange,
|
||||
canBubble);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -164,8 +164,10 @@ enum : uint32_t {
|
|||
|
||||
NODE_MAY_HAVE_ELEMENT_CHILDREN = NODE_FLAG_BIT(12),
|
||||
|
||||
NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT = NODE_FLAG_BIT(13),
|
||||
|
||||
// Remaining bits are node type specific.
|
||||
NODE_TYPE_SPECIFIC_BITS_OFFSET = 13
|
||||
NODE_TYPE_SPECIFIC_BITS_OFFSET = 14
|
||||
};
|
||||
|
||||
// Flags for selectors that persist to the DOM node.
|
||||
|
|
@ -1642,6 +1644,18 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||
MOZ_CAN_RUN_SCRIPT nsIContent* GetSelectionRootContent(
|
||||
mozilla::PresShell* aPresShell, bool aAllowCrossShadowBoundary = false);
|
||||
|
||||
bool HasScheduledSelectionChangeEvent() {
|
||||
return HasFlag(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT);
|
||||
}
|
||||
|
||||
void SetHasScheduledSelectionChangeEvent() {
|
||||
SetFlags(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT);
|
||||
}
|
||||
|
||||
void ClearHasScheduledSelectionChangeEvent() {
|
||||
UnsetFlags(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT);
|
||||
}
|
||||
|
||||
nsINodeList* ChildNodes();
|
||||
|
||||
nsIContent* GetFirstChild() const { return mFirstChild; }
|
||||
|
|
|
|||
|
|
@ -205,6 +205,19 @@ class LoadBlockingAsyncEventDispatcher final : public AsyncEventDispatcher {
|
|||
RefPtr<dom::Document> mBlockedDoc;
|
||||
};
|
||||
|
||||
class AsyncSelectionChangeEventDispatcher : public AsyncEventDispatcher {
|
||||
public:
|
||||
AsyncSelectionChangeEventDispatcher(dom::EventTarget* aTarget,
|
||||
EventMessage aEventMessage,
|
||||
CanBubble aCanBubble)
|
||||
: AsyncEventDispatcher(aTarget, aEventMessage, aCanBubble) {}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
|
||||
mTarget->GetAsNode()->ClearHasScheduledSelectionChangeEvent();
|
||||
return AsyncEventDispatcher::Run();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_AsyncEventDispatcher_h_
|
||||
|
|
|
|||
|
|
@ -2116,8 +2116,10 @@ void TextControlState::SetSelectionRange(uint32_t aStart, uint32_t aEnd,
|
|||
// XXX(krosylight): Shouldn't it fire before select event?
|
||||
// Currently Gecko and Blink both fire selectionchange after select.
|
||||
if (IsSelectionCached() &&
|
||||
StaticPrefs::dom_select_events_textcontrols_selectionchange_enabled()) {
|
||||
asyncDispatcher = new AsyncEventDispatcher(
|
||||
StaticPrefs::dom_select_events_textcontrols_selectionchange_enabled() &&
|
||||
!mTextCtrlElement->HasScheduledSelectionChangeEvent()) {
|
||||
mTextCtrlElement->SetHasScheduledSelectionChangeEvent();
|
||||
asyncDispatcher = new AsyncSelectionChangeEventDispatcher(
|
||||
mTextCtrlElement, eSelectionChange, CanBubble::eYes);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -645,14 +645,7 @@
|
|||
{ x: 50 },
|
||||
"mousedown",
|
||||
{
|
||||
// XXX Bug 1721287: For some reason we fire 2 selectchange events
|
||||
// on the body when switching from the <input> to the <textarea>.
|
||||
selectionchangeOnDocument:
|
||||
document.activeElement != textControl &&
|
||||
(document.activeElement.tagName.toLocaleLowerCase() == "input" ||
|
||||
document.activeElement.tagName.toLocaleLowerCase() == "textarea")
|
||||
? 2
|
||||
: 1,
|
||||
selectionchangeOnDocument: 1,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div id="editor" contenteditable></div>
|
||||
<div id="clickaway" style="width: 3px; height: 3px;"></div>
|
||||
<div id="editor" contenteditable></div><br>
|
||||
<div id="clickaway" style="width: 30px; height: 30px; border: 3px solid red;"></div>
|
||||
<img src="green.png"><!-- for ensuring to load the image at first test of <img> case -->
|
||||
<pre id="test">
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
[onselectionchange-on-distinct-text-controls.html]
|
||||
[selectionchange event on each input element fires independently]
|
||||
expected: FAIL
|
||||
|
||||
[selectionchange event on each textarea element fires independently]
|
||||
expected: FAIL
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[onselectionchange-on-document.html]
|
||||
[task to fire selectionchange event gets queued each time selection is mutated]
|
||||
expected: FAIL
|
||||
|
||||
[has scheduled selectionchange event is set to false at the beginning of a task to fire selectionchange event]
|
||||
expected: FAIL
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
[selectionchange.html]
|
||||
[Calling setRangeText() after select() on the input element]
|
||||
expected:
|
||||
if (os == "android") and not debug: [PASS, FAIL]
|
||||
FAIL
|
||||
|
||||
[Calling setRangeText() repeatedly on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() after select() on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() repeatedly on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() after select() on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() repeatedly on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() after select() on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() repeatedly on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
Loading…
Reference in a new issue