+2011-01-19 Dai Mikurube <dmikurube@google.com>
+
+ Reviewed by Kent Tamura.
+
+ Implement onformchange and onforminput event handlers
+ https://bugs.webkit.org/show_bug.cgi?id=26141
+
+ * fast/dom/Window/window-properties-expected.txt: Added form events.
+ * fast/dom/Window/window-property-descriptors-expected.txt: Added form events.
+ * fast/forms/formchange-event-expected.txt: Added.
+ * fast/forms/formchange-event.html: Added to test formchange events.
+ * fast/forms/forminput-event-expected.txt: Added.
+ * fast/forms/forminput-event.html: Added to test forminput events.
+ * fast/forms/script-tests/formchange-event.js: Added.
+ (sendKey):
+ (sendText):
+ * fast/forms/script-tests/forminput-event.js: Added.
+ (sendKey):
+ (sendText):
+
2011-01-18 Mikhail Naganov <mnaganov@chromium.org>
Reviewed by Yury Semikhatsky.
window.onended [null]
window.onerror [null]
window.onfocus [null]
+window.onformchange [null]
+window.onforminput [null]
window.onhashchange [null]
window.oninput [null]
window.oninvalid [null]
PASS typeof Object.getOwnPropertyDescriptor(window, 'onended') is 'object'
PASS typeof Object.getOwnPropertyDescriptor(window, 'onerror') is 'object'
PASS typeof Object.getOwnPropertyDescriptor(window, 'onfocus') is 'object'
+PASS typeof Object.getOwnPropertyDescriptor(window, 'onformchange') is 'object'
+PASS typeof Object.getOwnPropertyDescriptor(window, 'onforminput') is 'object'
PASS typeof Object.getOwnPropertyDescriptor(window, 'onhashchange') is 'object'
PASS typeof Object.getOwnPropertyDescriptor(window, 'oninput') is 'object'
PASS typeof Object.getOwnPropertyDescriptor(window, 'oninvalid') is 'object'
--- /dev/null
+Test for formchange events.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Change for input (type=text)
+PASS result is "Fired"
+Change for input (type=number)
+PASS result is "Fired"
+Change for input (type=radio)
+PASS result is "Fired"
+Change for input (type=checkbox)
+PASS result is "Fired"
+Change for textarea
+PASS result is "Fired"
+Change for select
+PASS result is "Fired"
+form.dispatchFormChange()
+PASS result is "Fired"
+
+Is formchange delivered for?
+PASS resultInputText is "Delivered"
+PASS resultInputNumber is "Delivered"
+PASS resultInputRadio is "Delivered"
+PASS resultInputCheckbox is "Delivered"
+PASS resultTextarea is "Delivered"
+PASS resultKeygen is "Delivered"
+PASS resultObject is "Not delivered"
+PASS resultOutput is "Delivered"
+PASS resultSelect is "Delivered"
+PASS resultP is "Not delivered"
+PASS resultRemovingInput is "Delivered"
+PASS resultRemovingForm is "Delivered"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/formchange-event.js"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+Test for forminput events.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Change for input (type=text)
+PASS result is "Fired"
+Change for input (type=number)
+PASS result is "Fired"
+Change for input (type=radio)
+PASS result is "Not fired"
+Change for input (type=checkbox)
+PASS result is "Not fired"
+Change for textarea
+PASS result is "Fired"
+Change for select
+PASS result is "Not fired"
+form.dispatchFormInput()
+PASS result is "Fired"
+
+Is forminput delivered for?
+PASS resultInputText is "Delivered"
+PASS resultInputNumber is "Delivered"
+PASS resultInputRadio is "Delivered"
+PASS resultInputCheckbox is "Delivered"
+PASS resultTextarea is "Delivered"
+PASS resultKeygen is "Delivered"
+PASS resultObject is "Not delivered"
+PASS resultOutput is "Delivered"
+PASS resultSelect is "Delivered"
+PASS resultP is "Not delivered"
+PASS resultRemovingInput is "Delivered"
+PASS resultRemovingForm is "Delivered"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/forminput-event.js"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+description('Test for formchange events.');
+
+function sendKey(element, keyName) {
+ var event = document.createEvent('KeyboardEvent');
+ event.initKeyboardEvent('keydown', true, true, document.defaultView, keyName);
+ element.dispatchEvent(event);
+}
+
+function sendText(element, text) {
+ var event = document.createEvent('TextEvent');
+ event.initTextEvent('textInput', true, true, document.defaultView, text);
+ element.dispatchEvent(event);
+}
+
+function sendMouseClick(element) {
+ var x = element.clientLeft + 10;
+ var y = element.clientTop + 10;
+ var event = document.createEvent("MouseEvent");
+ event.initMouseEvent("mousedown", true, true, document.defaultView, 1, x, y, x, y, false, false, false, false, 0, document);
+ element.dispatchEvent(event);
+ var event = document.createEvent("MouseEvent");
+ event.initMouseEvent("mouseup", true, true, document.defaultView, 1, x, y, x, y, false, false, false, false, 0, document);
+ element.dispatchEvent(event);
+}
+
+function $(id) {
+ return document.getElementById(id);
+}
+
+
+var form = document.createElement('form');
+form.setAttribute('id', 'form');
+form.innerHTML =
+ '<input type="text" id="default-input" value="Input here." />' +
+ '<input type="text" id="input-text" value="Input here." />' +
+ '<input type="number" id="input-number" value="24" />' +
+ '<input type="radio" name="input-radio" id="input-radio1" value="1" checked/>' +
+ '<input type="radio" name="input-radio" id="input-radio2" value="2" />' +
+ '<input type="checkbox" name="input-check" id="input-check1" value="1" checked/>' +
+ '<input type="checkbox" name="input-check" id="input-check2" value="2" />' +
+ '<textarea id="input-textarea">Input here.</textarea>' +
+ '<select id="input-select" multiple>' +
+ '<option id="input-option1" value="option1">option1</option>' +
+ '<option id="input-option2" value="option2">option2</option>' +
+ '</select>' +
+
+ '<input type="text" id="default-handler" onformchange="result = \'Fired\'" />' +
+ '<input type="text" id="handler-text" onformchange="resultInputText = \'Delivered\'" />' +
+ '<input type="number" id="handler-number" onformchange="resultInputNumber = \'Delivered\'" />' +
+ '<input type="radio" name="handler-radio" id="handler-radio" onformchange="resultInputRadio = \'Delivered\'" />' +
+ '<input type="checkbox" name="handler-check" id="handler-check" onformchange="resultInputCheckbox = \'Delivered\'" />' +
+ '<textarea id="handler-textarea" onformchange="resultTextarea = \'Delivered\'"></textarea>' +
+ '<keygen id="handler-keygen" onformchange="resultKeygen = \'Delivered\'" />' +
+ '<object id="handler-object" onformchange="resultObject = \'Delivered\'" />' +
+ '<output id="handler-output" onformchange="resultOutput = \'Delivered\'" />' +
+ '<select id="handler-select" onformchange="resultSelect = \'Delivered\'" />' +
+
+ '<p id="handler-p" onformchange="resultP = \'Delivered\'">Hi!</p>';
+document.body.appendChild(form);
+
+
+function onformchangeRemovingInput() {
+ $('form-removing-input').removeChild($('handler-removing-input'));
+ resultRemovingInput = 'Delivered';
+}
+
+var form_removing_input = document.createElement('form');
+form_removing_input.setAttribute('id', 'form-removing-input');
+form_removing_input.innerHTML =
+ '<input type="text" id="input-removing-input" value="Input here." />' +
+ '<input type="text" id="handler-removing-input" onformchange="onformchangeRemovingInput()" />';
+document.body.appendChild(form_removing_input);
+
+
+function onformchangeRemovingForm() {
+ document.body.removeChild($('form-removing-form'));
+ resultRemovingForm = 'Delivered';
+}
+
+var form_removing_form = document.createElement('form');
+form_removing_form.setAttribute('id', 'form-removing-form');
+form_removing_form.innerHTML =
+ '<input type="text" id="input-removing-form" value="Input here." />' +
+ '<input type="text" id="handler-removing-form" onformchange="onformchangeRemovingForm()" />';
+document.body.appendChild(form_removing_form);
+
+
+var result;
+
+debug('Change for input (type=text)');
+result = "Not fired";
+$('input-text').focus();
+sendText($('input-text'), 'New text.');
+$('default-input').focus();
+shouldBeEqualToString("result", "Fired");
+
+debug('Change for input (type=number)');
+result = "Not fired";
+$('input-number').focus();
+sendKey($('input-number'), 'Up');
+$('default-input').focus();
+shouldBeEqualToString("result", "Fired");
+
+debug('Change for input (type=radio)');
+result = "Not fired";
+$('input-radio2').click();
+shouldBeEqualToString("result", "Fired");
+
+debug('Change for input (type=checkbox)');
+result = "Not fired";
+$('input-check2').click();
+shouldBeEqualToString("result", "Fired");
+
+debug('Change for textarea');
+result = "Not fired";
+$('input-textarea').focus();
+sendText($('input-textarea'), 'New text.');
+$('default-input').focus();
+shouldBeEqualToString("result", "Fired");
+
+debug('Change for select');
+result = "Not fired";
+sendMouseClick($('input-select'));
+shouldBeEqualToString("result", "Fired");
+
+debug('form.dispatchFormChange()');
+result = "Not fired";
+form.dispatchFormChange();
+shouldBeEqualToString("result", "Fired");
+
+
+debug('');
+
+
+debug('Is formchange delivered for?');
+var resultInputText = "Not delivered";
+var resultInputNumber = "Not delivered";
+var resultInputRadio = "Not delivered";
+var resultInputCheckbox = "Not delivered";
+var resultTextarea = "Not delivered";
+var resultKeygen = "Not delivered";
+var resultObject = "Not delivered";
+var resultOutput = "Not delivered";
+var resultSelect = "Not delivered";
+var resultP = "Not delivered";
+$('default-input').focus();
+sendText($('default-input'), 'New text.');
+$('default-handler').focus();
+shouldBeEqualToString("resultInputText", "Delivered");
+shouldBeEqualToString("resultInputNumber", "Delivered");
+shouldBeEqualToString("resultInputRadio", "Delivered");
+shouldBeEqualToString("resultInputCheckbox", "Delivered");
+shouldBeEqualToString("resultTextarea", "Delivered");
+shouldBeEqualToString("resultKeygen", "Delivered");
+shouldBeEqualToString("resultObject", "Not delivered");
+shouldBeEqualToString("resultOutput", "Delivered");
+shouldBeEqualToString("resultSelect", "Delivered");
+shouldBeEqualToString("resultP", "Not delivered");
+
+var resultRemovingInput = "Not delivered";
+$('input-removing-input').focus();
+sendText($('input-removing-input'), 'New text.');
+$('default-handler').focus();
+shouldBeEqualToString("resultRemovingInput", "Delivered");
+
+var resultRemovingForm = "Not delivered";
+$('input-removing-form').focus();
+sendText($('input-removing-form'), 'New text.');
+$('default-handler').focus();
+shouldBeEqualToString("resultRemovingForm", "Delivered");
+
+
+document.body.removeChild(form);
+debug('');
+
+
+var successfullyParsed = true;
--- /dev/null
+description('Test for forminput events.');
+
+function sendKey(element, keyName) {
+ var event = document.createEvent('KeyboardEvent');
+ event.initKeyboardEvent('keydown', true, true, document.defaultView, keyName);
+ element.dispatchEvent(event);
+}
+
+function sendText(element, text) {
+ var event = document.createEvent('TextEvent');
+ event.initTextEvent('textInput', true, true, document.defaultView, text);
+ element.dispatchEvent(event);
+}
+
+function sendMouseClick(element) {
+ var x = element.clientLeft + 10;
+ var y = element.clientTop + 10;
+ var event = document.createEvent("MouseEvent");
+ event.initMouseEvent("mousedown", true, true, document.defaultView, 1, x, y, x, y, false, false, false, false, 0, document);
+ element.dispatchEvent(event);
+ var event = document.createEvent("MouseEvent");
+ event.initMouseEvent("mouseup", true, true, document.defaultView, 1, x, y, x, y, false, false, false, false, 0, document);
+ element.dispatchEvent(event);
+}
+
+function $(id) {
+ return document.getElementById(id);
+}
+
+
+var form = document.createElement('form');
+form.setAttribute('id', 'form');
+form.innerHTML =
+ '<input type="text" id="default-input" value="Input here." />' +
+ '<input type="text" id="input-text" value="Input here." />' +
+ '<input type="number" id="input-number" value="24" />' +
+ '<input type="radio" name="input-radio" id="input-radio1" value="1" checked/>' +
+ '<input type="radio" name="input-radio" id="input-radio2" value="2" />' +
+ '<input type="checkbox" name="input-check" id="input-check1" value="1" checked/>' +
+ '<input type="checkbox" name="input-check" id="input-check2" value="2" />' +
+ '<textarea id="input-textarea">Input here.</textarea>' +
+ '<select id="input-select" multiple>' +
+ '<option id="input-option1" value="option1">option1</option>' +
+ '<option id="input-option2" value="option2">option2</option>' +
+ '</select>' +
+
+ '<input type="text" id="default-handler" onforminput="result = \'Fired\'" />' +
+ '<input type="text" id="handler-text" onforminput="resultInputText = \'Delivered\'" />' +
+ '<input type="number" id="handler-number" onforminput="resultInputNumber = \'Delivered\'" />' +
+ '<input type="radio" name="handler-radio" id="handler-radio" onforminput="resultInputRadio = \'Delivered\'" />' +
+ '<input type="checkbox" name="handler-check" id="handler-check" onforminput="resultInputCheckbox = \'Delivered\'" />' +
+ '<textarea id="handler-textarea" onforminput="resultTextarea = \'Delivered\'"></textarea>' +
+ '<keygen id="handler-keygen" onforminput="resultKeygen = \'Delivered\'" />' +
+ '<object id="handler-object" onforminput="resultObject = \'Delivered\'" />' +
+ '<output id="handler-output" onforminput="resultOutput = \'Delivered\'" />' +
+ '<select id="handler-select" onforminput="resultSelect = \'Delivered\'" />' +
+
+ '<p id="handler-p" onforminput="resultP = \'Delivered\'">Hi!</p>';
+document.body.appendChild(form);
+
+
+function onforminputRemovingInput() {
+ $('form-removing-input').removeChild($('handler-removing-input'));
+ resultRemovingInput = 'Delivered';
+}
+
+var formRemovingInput = document.createElement('form');
+formRemovingInput.setAttribute('id', 'form-removing-input');
+formRemovingInput.innerHTML =
+ '<input type="text" id="input-removing-input" value="Input here." />' +
+ '<input type="text" id="handler-removing-input" onforminput="onforminputRemovingInput()" />';
+document.body.appendChild(formRemovingInput);
+
+
+function onforminputRemovingForm() {
+ document.body.removeChild($('form-removing-form'));
+ resultRemovingForm = 'Delivered';
+}
+
+var formRemovingForm = document.createElement('form');
+formRemovingForm.setAttribute('id', 'form-removing-form');
+formRemovingForm.innerHTML =
+ '<input type="text" id="input-removing-form" value="Input here." />' +
+ '<input type="text" id="handler-removing-form" onforminput="onforminputRemovingForm()" />';
+document.body.appendChild(formRemovingForm);
+
+
+var result;
+
+debug('Change for input (type=text)');
+result = "Not fired";
+$('input-text').focus();
+sendText($('input-text'), 'New text.');
+$('default-input').focus();
+shouldBeEqualToString("result", "Fired");
+
+debug('Change for input (type=number)');
+result = "Not fired";
+$('input-number').focus();
+sendKey($('input-number'), 'Up');
+$('default-input').focus();
+shouldBeEqualToString("result", "Fired");
+
+debug('Change for input (type=radio)');
+result = "Not fired";
+$('input-radio2').click();
+shouldBeEqualToString("result", "Not fired");
+
+debug('Change for input (type=checkbox)');
+result = "Not fired";
+$('input-check2').click();
+shouldBeEqualToString("result", "Not fired");
+
+debug('Change for textarea');
+result = "Not fired";
+$('input-textarea').focus();
+sendText($('input-textarea'), 'New text.');
+$('default-input').focus();
+shouldBeEqualToString("result", "Fired");
+
+debug('Change for select');
+result = "Not fired";
+sendMouseClick($('input-select'));
+shouldBeEqualToString("result", "Not fired");
+
+debug('form.dispatchFormInput()');
+result = "Not fired";
+form.dispatchFormInput();
+shouldBeEqualToString("result", "Fired");
+
+
+debug('');
+
+
+debug('Is forminput delivered for?');
+var resultInputText = "Not delivered";
+var resultInputNumber = "Not delivered";
+var resultInputRadio = "Not delivered";
+var resultInputCheckbox = "Not delivered";
+var resultTextarea = "Not delivered";
+var resultKeygen = "Not delivered";
+var resultObject = "Not delivered";
+var resultOutput = "Not delivered";
+var resultSelect = "Not delivered";
+var resultP = "Not delivered";
+$('default-input').focus();
+sendText($('default-input'), 'New text.');
+$('default-handler').focus();
+shouldBeEqualToString("resultInputText", "Delivered");
+shouldBeEqualToString("resultInputNumber", "Delivered");
+shouldBeEqualToString("resultInputRadio", "Delivered");
+shouldBeEqualToString("resultInputCheckbox", "Delivered");
+shouldBeEqualToString("resultTextarea", "Delivered");
+shouldBeEqualToString("resultKeygen", "Delivered");
+shouldBeEqualToString("resultObject", "Not delivered");
+shouldBeEqualToString("resultOutput", "Delivered");
+shouldBeEqualToString("resultSelect", "Delivered");
+shouldBeEqualToString("resultP", "Not delivered");
+
+var resultRemovingInput = "Not delivered";
+$('input-removing-input').focus();
+sendText($('input-removing-input'), 'New text.');
+$('default-handler').focus();
+shouldBeEqualToString("resultRemovingInput", "Delivered");
+
+var resultRemovingForm = "Not delivered";
+$('input-removing-form').focus();
+sendText($('input-removing-form'), 'New text.');
+$('default-handler').focus();
+shouldBeEqualToString("resultRemovingForm", "Delivered");
+
+
+document.body.removeChild(form);
+debug('');
+
+
+var successfullyParsed = true;
+2011-01-19 Dai Mikurube <dmikurube@google.com>
+
+ Reviewed by Kent Tamura.
+
+ Implement onformchange and onforminput event handlers
+ https://bugs.webkit.org/show_bug.cgi?id=26141
+
+ Tests: fast/forms/formchange-event.html
+ fast/forms/forminput-event.html
+
+ * bindings/scripts/CodeGeneratorGObject.pm: Added event names.
+ * dom/Document.h: Added event definitions.
+ * dom/Document.idl: Added event definitions.
+ * dom/Element.h: Added event definitions.
+ * dom/Element.idl: Added event definitions.
+ * dom/Event.cpp:
+ (WebCore::Event::fromUserGesture): Added a condition for a formchange event in handling user gestures.
+ * dom/EventNames.h: Added event definitions.
+ * dom/InputElement.cpp:
+ (WebCore::InputElement::setValueFromRenderer): Replaced a direct dispatchEvent() call into dispatchInputEvents(), a virtual function which broadcasts forminput events for HTML elements.
+ * dom/Node.cpp:
+ (WebCore::Node::dispatchInputEvents): Defined basic dispatchInputEvents() described above.
+ (WebCore::Node::dispatchChangeEvents): Defined basic dispatchChangeEvents() described above.
+ (WebCore::Node::defaultEventHandler): Replaced a direct dispatchEvent() call into dispatchInputEvents().
+ * dom/Node.h:
+ * html/FormAssociatedElement.h: Added isResettable() to check the element is resettable or not.
+ * html/HTMLAttributeNames.in: Added event names.
+ * html/HTMLElement.cpp:
+ (WebCore::HTMLElement::parseMappedAttribute): Added event handling.
+ (WebCore::HTMLElement::shadowAncestorOwnerForm): Added to get an ancestor <form> element from a shadow element.
+ (WebCore::HTMLElement::dispatchChangeEvents): Defined dispatchChangeEvents() for HTML elements described above.
+ (WebCore::HTMLElement::dispatchInputEvents): Defined dispatchInputEvents() for HTML elements described above.
+ * html/HTMLElement.h:
+ * html/HTMLFormControlElement.cpp:
+ (WebCore::HTMLFormControlElement::dispatchFormControlChangeEvent): Added calling dispatchFormChange() to broadcast formchange events.
+ (WebCore::HTMLFormControlElement::dispatchFormControlInputEvent): Defined newly to dispatch an input event with broadcasting forminput events.
+ * html/HTMLFormControlElement.h: Added isResettable().
+ * html/HTMLFormElement.cpp:
+ (WebCore::HTMLFormElement::broadcastFormEvent): Added to broadcast forminput or formchange events.
+ (WebCore::HTMLFormElement::dispatchFormInput): Defined newly to broadcast forminput events.
+ (WebCore::HTMLFormElement::dispatchFormChange): Defined newly to broadcast formchange events.
+ * html/HTMLFormElement.h:
+ * html/HTMLFormElement.idl: Added dispatchFormInput() and dispatchFormChange() DOM API definitions.
+ * html/HTMLInputElement.cpp:
+ (WebCore::HTMLInputElement::stepUpFromRenderer): Replaced a direct dispatchEvent() call into dispatchInputEvents().
+ * html/HTMLInputElement.h: Added isResettable().
+ * html/HTMLKeygenElement.h: Added isResettable().
+ * html/HTMLObjectElement.h: Added isResettable().
+ * html/HTMLOutputElement.h: Added isResettable().
+ * html/HTMLSelectElement.h: Added isResettable().
+ * html/HTMLTextAreaElement.h: Added isResettable().
+ * page/DOMWindow.h: Added event definitions.
+ * page/DOMWindow.idl: Added event definitions.
+ * rendering/TextControlInnerElements.cpp:
+ (WebCore::SearchFieldCancelButtonElement::defaultEventHandler): Replaced a direct dispatchEvent() call into dispatchInputEvents().
+
2011-01-19 Andrey Kosyakov <caseq@chromium.org>
Reviewed by Pavel Feldman.
# User Interface Event types
"focus", "blur",
# Basic Event types
- "load", "unload", "abort", "error", "select", "change", "submit", "reset",
+ "load", "unload", "abort", "error", "select", "change", "formchange", "submit", "reset",
"resize", "scroll",
# Mouse Event types
"click", "dblclick", "mousedown", "mouseup",
# Animations
"webkitanimationend", "webkitanimationstart", "webkitanimationiteration",
# Other
- "contextmenu", "input", "invalid", "search", "selectstart");
+ "contextmenu", "input", "forminput", "invalid", "search", "selectstart");
sub GenerateProperties {
my ($object, $interfaceName, $dataNode) = @_;
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(formchange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(forminput);
DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
attribute [DontEnum] EventListener ondrop;
attribute [DontEnum] EventListener onerror;
attribute [DontEnum] EventListener onfocus;
+ attribute [DontEnum] EventListener onformchange;
+ attribute [DontEnum] EventListener onforminput;
attribute [DontEnum] EventListener oninput;
attribute [DontEnum] EventListener oninvalid;
attribute [DontEnum] EventListener onkeydown;
// attribute [DontEnum] EventListener ondurationchange;
// attribute [DontEnum] EventListener onemptied;
// attribute [DontEnum] EventListener onended;
- // attribute [DontEnum] EventListener onformchange;
- // attribute [DontEnum] EventListener onforminput;
// attribute [DontEnum] EventListener onloadeddata;
// attribute [DontEnum] EventListener onloadedmetadata;
// attribute [DontEnum] EventListener onloadstart;
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(formchange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(forminput);
DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
attribute [DontEnum] EventListener ondrop;
attribute [DontEnum] EventListener onerror;
attribute [DontEnum] EventListener onfocus;
+ attribute [DontEnum] EventListener onformchange;
+ attribute [DontEnum] EventListener onforminput;
attribute [DontEnum] EventListener oninput;
attribute [DontEnum] EventListener oninvalid;
attribute [DontEnum] EventListener onkeydown;
// attribute [DontEnum] EventListener ondurationchange;
// attribute [DontEnum] EventListener onemptied;
// attribute [DontEnum] EventListener onended;
- // attribute [DontEnum] EventListener onformchange;
- // attribute [DontEnum] EventListener onforminput;
// attribute [DontEnum] EventListener onloadeddata;
// attribute [DontEnum] EventListener onloadedmetadata;
// attribute [DontEnum] EventListener onloadstart;
// other accepted events
|| type == eventNames().selectEvent || type == eventNames().changeEvent
|| type == eventNames().focusEvent || type == eventNames().blurEvent
- || type == eventNames().submitEvent;
+ || type == eventNames().submitEvent || type == eventNames().formchangeEvent;
}
bool Event::storesResultAsString() const
macro(focus) \
macro(focusin) \
macro(focusout) \
+ macro(formchange) \
+ macro(forminput) \
macro(hashchange) \
macro(input) \
macro(invalid) \
// Input event is fired by the Node::defaultEventHandler for editable controls.
if (!inputElement->isTextField())
- element->dispatchEvent(Event::create(eventNames().inputEvent, true, false));
+ element->dispatchInputEvents();
notifyFormStateChanged(element);
}
dispatchEvent(Event::create(eventNames().blurEvent, false, false));
}
+void Node::dispatchChangeEvents()
+{
+ dispatchEvent(Event::create(eventNames().changeEvent, true, false));
+}
+
+void Node::dispatchInputEvents()
+{
+ dispatchEvent(Event::create(eventNames().inputEvent, true, false));
+}
+
bool Node::disabled() const
{
return false;
if (Frame* frame = document()->frame())
frame->eventHandler()->defaultWheelEventHandler(startNode, wheelEvent);
} else if (event->type() == eventNames().webkitEditableContentChangedEvent) {
- dispatchEvent(Event::create(eventNames().inputEvent, true, false));
+ dispatchInputEvents();
}
}
virtual void dispatchFocusEvent();
virtual void dispatchBlurEvent();
+ virtual void dispatchChangeEvents();
+ virtual void dispatchInputEvents();
// Perform the default action for an event.
virtual void defaultEventHandler(Event*);
virtual bool isFormControlElement() const = 0;
virtual bool isEnumeratable() const = 0;
+ virtual bool isResettable() const = 0;
const AtomicString& name() const { return formControlName(); }
onfocus
onfocusin
onfocusout
+onformchange
+onforminput
onhashchange
oninput
oninvalid
setAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(this, attr));
} else if (attr->name() == onfocusoutAttr) {
setAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(this, attr));
+ } else if (attr->name() == onformchangeAttr) {
+ setAttributeEventListener(eventNames().formchangeEvent, createAttributeEventListener(this, attr));
+ } else if (attr->name() == onforminputAttr) {
+ setAttributeEventListener(eventNames().forminputEvent, createAttributeEventListener(this, attr));
} else if (attr->name() == onblurAttr) {
setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr));
} else if (attr->name() == onkeydownAttr) {
return findFormAncestor();
}
+HTMLFormElement* HTMLElement::shadowAncestorOwnerForm()
+{
+ Node* ancestorNode = shadowAncestorNode();
+ if (!ancestorNode)
+ return form();
+
+ if (!ancestorNode->isHTMLElement())
+ return 0;
+ HTMLElement* ancestorHTML = static_cast<HTMLElement*>(ancestorNode);
+ if (!ancestorHTML)
+ return 0;
+ return ancestorHTML->form();
+}
+
+void HTMLElement::dispatchChangeEvents()
+{
+ RefPtr<HTMLElement> protector(this);
+ RefPtr<HTMLFormElement> ownerForm(shadowAncestorOwnerForm());
+
+ Node::dispatchChangeEvents();
+ if (ownerForm)
+ ownerForm->dispatchFormChange();
+}
+
+void HTMLElement::dispatchInputEvents()
+{
+ RefPtr<HTMLElement> protector(this);
+ RefPtr<HTMLFormElement> ownerForm(shadowAncestorOwnerForm());
+
+ Node::dispatchInputEvents();
+ if (ownerForm)
+ ownerForm->dispatchFormInput();
+}
+
} // namespace WebCore
#ifndef NDEBUG
HTMLFormElement* findFormAncestor() const;
+ virtual void dispatchChangeEvents();
+ virtual void dispatchInputEvents();
+
protected:
HTMLElement(const QualifiedName& tagName, Document*);
Node* insertAdjacent(const String& where, Node* newChild, ExceptionCode&);
PassRefPtr<DocumentFragment> textToFragment(const String&, ExceptionCode&);
+
+ HTMLFormElement* shadowAncestorOwnerForm();
};
inline HTMLElement::HTMLElement(const QualifiedName& tagName, Document* document)
void HTMLFormControlElement::dispatchFormControlChangeEvent()
{
- dispatchEvent(Event::create(eventNames().changeEvent, true, false));
+ HTMLElement::dispatchChangeEvents();
+}
+
+void HTMLFormControlElement::dispatchFormControlInputEvent()
+{
+ HTMLElement::dispatchInputEvents();
}
void HTMLFormControlElement::setDisabled(bool b)
virtual void setFormControlValueMatchesRenderer(bool b) { m_valueMatchesRenderer = b; }
virtual void dispatchFormControlChangeEvent();
+ virtual void dispatchFormControlInputEvent();
virtual bool disabled() const { return m_disabled; }
void setDisabled(bool);
virtual bool isFocusable() const;
virtual bool isEnumeratable() const { return false; }
+ virtual bool isResettable() const { return false; }
// Determines whether or not a control will be automatically focused.
virtual bool autofocus() const;
return controls.isEmpty();
}
+void HTMLFormElement::broadcastFormEvent(const AtomicString& eventName)
+{
+ RefPtr<HTMLFormElement> protector(this);
+ // Copy m_associatedElements because event handlers called from
+ // formElement->dispatchEvent() might change m_associatedElements.
+ Vector<RefPtr<FormAssociatedElement> > elements;
+ elements.reserveCapacity(m_associatedElements.size());
+ for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
+ if (!m_associatedElements[i]->isResettable())
+ continue;
+ elements.append(m_associatedElements[i]);
+ }
+
+ for (unsigned i = 0; i < elements.size(); ++i) {
+ // We can assume a resettable control is always a HTMLFormControlElement.
+ // FIXME: We should handle resettable non-HTMLFormControlElements maybe in the future.
+ ASSERT(elements[i]->isFormControlElement());
+ HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(elements[i].get());
+ if (!formElement->dispatchEvent(Event::create(eventName, false, false)))
+ continue;
+ }
+}
+
+void HTMLFormElement::dispatchFormInput()
+{
+ broadcastFormEvent(eventNames().forminputEvent);
+}
+
+void HTMLFormElement::dispatchFormChange()
+{
+ broadcastFormEvent(eventNames().formchangeEvent);
+}
+
void HTMLFormElement::collectUnhandledInvalidControls(Vector<RefPtr<FormAssociatedElement> >& unhandledInvalidControls)
{
RefPtr<HTMLFormElement> protector(this);
const Vector<FormAssociatedElement*>& associatedElements() const { return m_associatedElements; }
+ void dispatchFormInput();
+ void dispatchFormChange();
+
private:
HTMLFormElement(const QualifiedName&, Document*);
// event was not canceled to the specified vector.
void collectUnhandledInvalidControls(Vector<RefPtr<FormAssociatedElement> >&);
+ void broadcastFormEvent(const AtomicString&);
+
friend class HTMLFormCollection;
typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<HTMLFormControlElement> > AliasMap;
#endif
void reset();
boolean checkValidity();
+
+ void dispatchFormInput();
+ void dispatchFormChange();
};
}
if (m_inputType->isRangeControl())
dispatchFormControlChangeEvent();
else
- dispatchEvent(Event::create(eventNames().inputEvent, true, false));
+ dispatchFormControlInputEvent();
}
}
virtual bool isKeyboardFocusable(KeyboardEvent*) const;
virtual bool isMouseFocusable() const;
virtual bool isEnumeratable() const;
+ virtual bool isResettable() const { return true; }
virtual void updateFocusAppearance(bool restorePreviousSelection);
virtual void aboutToUnload();
virtual bool shouldUseInputMethod() const;
private:
HTMLKeygenElement(const QualifiedName&, Document*, HTMLFormElement*);
+ virtual bool isResettable() const { return true; }
+
virtual const AtomicString& formControlType() const;
virtual void parseMappedAttribute(Attribute*);
virtual bool appendFormData(FormDataList&, bool);
virtual bool isFormControlElement() const { return false; }
virtual bool isEnumeratable() const { return true; }
+ virtual bool isResettable() const { return false; }
virtual bool appendFormData(FormDataList&, bool);
// Implementations of constraint validation API.
virtual void parseMappedAttribute(Attribute*);
virtual const AtomicString& formControlType() const;
virtual bool isEnumeratable() const { return true; }
+ virtual bool isResettable() const { return true; }
virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
virtual void reset();
virtual bool canStartSelection() const { return false; }
virtual bool isEnumeratable() const { return true; }
+ virtual bool isResettable() const { return true; }
virtual bool saveFormControlState(String& value) const;
virtual void restoreFormControlState(const String&);
virtual void defaultEventHandler(Event*);
virtual bool isEnumeratable() const { return true; }
+ virtual bool isResettable() const { return true; }
virtual const AtomicString& formControlType() const;
DEFINE_ATTRIBUTE_EVENT_LISTENER(ended);
DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
DEFINE_ATTRIBUTE_EVENT_LISTENER(focus);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(formchange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(forminput);
DEFINE_ATTRIBUTE_EVENT_LISTENER(hashchange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
attribute EventListener onended;
attribute EventListener onerror;
attribute EventListener onfocus;
+ attribute EventListener onformchange;
+ attribute EventListener onforminput;
attribute EventListener onhashchange;
attribute EventListener oninput;
attribute EventListener oninvalid;
// Not implemented yet.
// attribute EventListener onafterprint;
// attribute EventListener onbeforeprint;
- // attribute EventListener onformchange;
- // attribute EventListener onforminput;
// attribute EventListener onreadystatechange;
// attribute EventListener onredo;
// attribute EventListener onshow;
input->setValue("");
if (!oldValue.isEmpty()) {
toRenderTextControl(input->renderer())->setChangedSinceLastChangeEvent(true);
- input->dispatchEvent(Event::create(eventNames().inputEvent, true, false));
+ input->dispatchFormControlInputEvent();
}
input->onSearch();
event->setDefaultHandled();