Commit fbe37c72 authored by tkent's avatar tkent Committed by Commit bot

INPUT element: Do not dispatch events in detachLayoutTree().

When a color chooser is closed, we dispatches a 'change' event asynchronously.
Some tests need to be updated due to this behavior change.

BUG=658535

Review-Url: https://codereview.chromium.org/2447653002
Cr-Commit-Position: refs/heads/master@{#427286}
parent 32a7028b
<!DOCTYPE html>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../resources/common.js"></script>
<input type="color" list>
<script>
test(() => {
var color = document.querySelector('input');
color.setAttribute('value', '#010101');
document.body.offsetLeft;
clickElement(color);
color.remove();
}, 'Detaching a layout object from a color input should not cause a DCHECK failure.');
</script>
......@@ -10,11 +10,13 @@
<input type="color" id="input" value="#ffffff">
<script>
description('Test if change event fires when the user selects the default value after the value was changed by JS.');
jsTestIsAsync = true;
var input = document.getElementById('input');
input.onchange = function() {
debug("onchange fired: " + input.value);
finishJSTest();
};
clickElement(input);
......
......@@ -7,13 +7,12 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS internals.selectColorInColorChooser({}, '#ff0000'); threw exception TypeError: Failed to execute 'selectColorInColorChooser' on 'Internals': parameter 1 is not of type 'Element'..
PASS internals.selectColorInColorChooser(document, '#ff0000'); threw exception TypeError: Failed to execute 'selectColorInColorChooser' on 'Internals': parameter 1 is not of type 'Element'..
input event dispatched - value is: #ff0000
PASS input.value is "#ff0000"
change event dispatched - value changed to #ff0000
PASS input.value is "#ff0000"
Change event is only dispatched, when color chooser is closed
input event dispatched - value is: #ff0002
PASS onChange is 0
change event dispatched - value changed to #ff0002
PASS onChange is 1
PASS Change event was dispatched.
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -8,6 +8,7 @@
<div id="console"></div>
<script>
description('Test if change event fires properly when color chooser changes. Bug 66848 <br> To manually test this, click on the input color element in the top left corner and change the value from the color chooser. See if the number of "value changed" messages matches the number of times you changed the color.');
jsTestIsAsync = true;
var input = document.createElement('input');
input.type = 'color';
......@@ -22,11 +23,6 @@ input.style.height = '20px';
var onChange = 0;
input.onchange = function() {
debug("change event dispatched - value changed to " + input.value);
onChange++;
};
input.oninput = function() {
debug("input event dispatched - value is: " + input.value);
};
......@@ -39,21 +35,39 @@ eventSender.mouseUp();
shouldThrow("internals.selectColorInColorChooser({}, '#ff0000');");
shouldThrow("internals.selectColorInColorChooser(document, '#ff0000');");
// input.onchange should be called
internals.selectColorInColorChooser(input, '#ff0000');
internals.endColorChooser(input);
// input.onchange should not be called
internals.selectColorInColorChooser(input, '#ff0000');
internals.endColorChooser(input);
shouldBe('input.value', '"#ff0000"');
debug('Change event is only dispatched, when color chooser is closed');
onChange = 0;
internals.selectColorInColorChooser(input, '#ff0002');
shouldBe('onChange', '0');
internals.endColorChooser(input);
shouldBe('onChange', '1');
function step1() {
// input.onchange should be called
input.onchange = step2;
internals.selectColorInColorChooser(input, '#ff0000');
internals.endColorChooser(input);
shouldBe('input.value', '"#ff0000"');
}
function step2() {
debug("change event dispatched - value changed to " + input.value);
// input.onchange should not be called
input.onchange = () => {
testFailed("Change event should not be dispatched.");
};
internals.selectColorInColorChooser(input, '#ff0000');
internals.endColorChooser(input);
shouldBe('input.value', '"#ff0000"');
step3();
}
function step3() {
debug('Change event is only dispatched, when color chooser is closed');
input.onchange = step4;
internals.selectColorInColorChooser(input, '#ff0002');
internals.endColorChooser(input);
}
function step4() {
testPassed('Change event was dispatched.');
finishJSTest();
}
step1();
</script>
</body>
</html>
......@@ -11,9 +11,8 @@ change event dispatched - value changed to #ff0000
PASS input.value is "#ff0000"
Change event is only dispatched, when color chooser is closed
input event dispatched - value is: #ff0002
change event dispatched - value changed to #ff0002
FAIL onChange should be 0. Was 1.
PASS onChange is 1
PASS Change event was dispatched.
FAIL input.value should be #ff0000. Was #ff0002.
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -224,6 +224,18 @@ void HTMLTextFormControlElement::dispatchFormControlChangeEvent() {
setChangedSinceLastFormControlChangeEvent(false);
}
void HTMLTextFormControlElement::enqueueChangeEvent() {
String newValue = value();
if (shouldDispatchFormControlChangeEvent(m_textAsOfLastFormControlChangeEvent,
newValue)) {
setTextAsOfLastFormControlChangeEvent(newValue);
Event* event = Event::createBubble(EventTypeNames::change);
event->setTarget(this);
document().enqueueAnimationFrameEvent(event);
}
setChangedSinceLastFormControlChangeEvent(false);
}
void HTMLTextFormControlElement::setRangeText(const String& replacement,
ExceptionState& exceptionState) {
setRangeText(replacement, selectionStart(), selectionEnd(), "preserve",
......
......@@ -103,6 +103,7 @@ class CORE_EXPORT HTMLTextFormControlElement
void setAutocapitalize(const AtomicString&);
void dispatchFormControlChangeEvent() final;
void enqueueChangeEvent();
virtual String value() const = 0;
virtual void setValue(const String&,
......
......@@ -202,9 +202,8 @@ void ColorInputType::didChooseColor(const Color& color) {
}
void ColorInputType::didEndChooser() {
EventQueueScope scope;
if (LayoutTheme::theme().isModalColorChooser())
element().dispatchFormControlChangeEvent();
element().enqueueChangeEvent();
m_chooser.clear();
}
......
......@@ -518,26 +518,27 @@ void WebPagePopupImpl::close() {
}
void WebPagePopupImpl::closePopup() {
// This function can be called in EventDispatchForbiddenScope for the main
// document, and the following operations dispatch some events. It's safe
// because web authors can't listen the events.
EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents;
if (m_page) {
toLocalFrame(m_page->mainFrame())->loader().stopAllLoaders();
PagePopupSupplement::uninstall(*toLocalFrame(m_page->mainFrame()));
}
bool closeAlreadyCalled = m_closing;
m_closing = true;
{
// This function can be called in EventDispatchForbiddenScope for the main
// document, and the following operations dispatch some events. It's safe
// because web authors can't listen the events.
EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents;
if (m_page) {
toLocalFrame(m_page->mainFrame())->loader().stopAllLoaders();
PagePopupSupplement::uninstall(*toLocalFrame(m_page->mainFrame()));
}
bool closeAlreadyCalled = m_closing;
m_closing = true;
destroyPage();
destroyPage();
// m_widgetClient might be 0 because this widget might be already closed.
if (m_widgetClient && !closeAlreadyCalled) {
// closeWidgetSoon() will call this->close() later.
m_widgetClient->closeWidgetSoon();
// m_widgetClient might be 0 because this widget might be already closed.
if (m_widgetClient && !closeAlreadyCalled) {
// closeWidgetSoon() will call this->close() later.
m_widgetClient->closeWidgetSoon();
}
}
m_popupClient->didClosePopup();
m_webView->cleanupPagePopup();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment