mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
Bug 771331 - make form elements fire events when <input type=password> elements are added/removed; r=smaug
This commit is contained in:
parent
6572a66348
commit
414a18b60f
@ -152,6 +152,7 @@ _BROWSER_FILES = \
|
||||
browser_bug749738.js \
|
||||
browser_bug763468_perwindowpb.js \
|
||||
browser_bug767836_perwindowpb.js \
|
||||
browser_bug771331.js \
|
||||
browser_bug783614.js \
|
||||
browser_bug797677.js \
|
||||
browser_bug816527.js \
|
||||
|
82
browser/base/content/test/browser_bug771331.js
Normal file
82
browser/base/content/test/browser_bug771331.js
Normal file
@ -0,0 +1,82 @@
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
const INPUT_ID = "input1";
|
||||
const FORM1_ID = "form1";
|
||||
const FORM2_ID = "form2";
|
||||
const CHANGE_INPUT_ID = "input2";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
let tab = gBrowser.selectedTab =
|
||||
gBrowser.addTab("data:text/html;charset=utf-8," +
|
||||
"<html><body>" +
|
||||
"<form id='" + FORM1_ID + "'><input id='" + CHANGE_INPUT_ID + "'></form>" +
|
||||
"<form id='" + FORM2_ID + "'></form>" +
|
||||
"</body></html>");
|
||||
tab.linkedBrowser.addEventListener("load", tabLoad, true);
|
||||
}
|
||||
|
||||
function unexpectedContentEvent(evt) {
|
||||
ok(false, "Received a " + evt.type + " event on content");
|
||||
}
|
||||
|
||||
var gDoc = null;
|
||||
|
||||
function tabLoad() {
|
||||
let tab = gBrowser.selectedTab;
|
||||
tab.linkedBrowser.removeEventListener("load", tabLoad, true);
|
||||
gDoc = gBrowser.selectedBrowser.contentDocument;
|
||||
// These events shouldn't escape to content.
|
||||
gDoc.addEventListener("DOMFormHasPassword", unexpectedContentEvent, false);
|
||||
gDoc.defaultView.setTimeout(test_inputAdd, 0);
|
||||
}
|
||||
|
||||
function test_inputAdd() {
|
||||
gBrowser.addEventListener("DOMFormHasPassword", test_inputAddHandler, false);
|
||||
let input = gDoc.createElementNS(HTML_NS, "input");
|
||||
input.setAttribute("type", "password");
|
||||
input.setAttribute("id", INPUT_ID);
|
||||
input.setAttribute("data-test", "unique-attribute");
|
||||
gDoc.getElementById(FORM1_ID).appendChild(input);
|
||||
info("Done appending the input element");
|
||||
}
|
||||
|
||||
function test_inputAddHandler(evt) {
|
||||
gBrowser.removeEventListener(evt.type, test_inputAddHandler, false);
|
||||
is(evt.target.id, FORM1_ID,
|
||||
evt.type + " event targets correct form element (added password element)");
|
||||
gDoc.defaultView.setTimeout(test_inputChangeForm, 0);
|
||||
}
|
||||
|
||||
function test_inputChangeForm() {
|
||||
gBrowser.addEventListener("DOMFormHasPassword", test_inputChangeFormHandler, false);
|
||||
let input = gDoc.getElementById(INPUT_ID);
|
||||
input.setAttribute("form", FORM2_ID);
|
||||
}
|
||||
|
||||
function test_inputChangeFormHandler(evt) {
|
||||
gBrowser.removeEventListener(evt.type, test_inputChangeFormHandler, false);
|
||||
is(evt.target.id, FORM2_ID,
|
||||
evt.type + " event targets correct form element (changed form)");
|
||||
gDoc.defaultView.setTimeout(test_inputChangesType, 0);
|
||||
}
|
||||
|
||||
function test_inputChangesType() {
|
||||
gBrowser.addEventListener("DOMFormHasPassword", test_inputChangesTypeHandler, false);
|
||||
let input = gDoc.getElementById(CHANGE_INPUT_ID);
|
||||
input.setAttribute("type", "password");
|
||||
}
|
||||
|
||||
function test_inputChangesTypeHandler(evt) {
|
||||
gBrowser.removeEventListener(evt.type, test_inputChangesTypeHandler, false);
|
||||
is(evt.target.id, FORM1_ID,
|
||||
evt.type + " event targets correct form element (changed type)");
|
||||
gDoc.defaultView.setTimeout(completeTest, 0);
|
||||
}
|
||||
|
||||
function completeTest() {
|
||||
ok(true, "Test completed");
|
||||
gDoc.removeEventListener("DOMFormHasPassword", unexpectedContentEvent, false);
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
@ -1090,6 +1090,20 @@ AssertDocumentOrder(const nsTArray<nsGenericHTMLFormElement*>& aControls,
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsHTMLFormElement::PostPasswordEvent()
|
||||
{
|
||||
// Don't fire another add event if we have a pending add event.
|
||||
if (mFormPasswordEvent.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<FormPasswordEvent> event =
|
||||
new FormPasswordEvent(this, NS_LITERAL_STRING("DOMFormHasPassword"));
|
||||
mFormPasswordEvent = event;
|
||||
event->PostDOMEvent();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
|
||||
bool aUpdateValidity, bool aNotify)
|
||||
@ -1157,12 +1171,14 @@ nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
|
||||
// If it is a password control, and the password manager has not yet been
|
||||
// initialized, initialize the password manager
|
||||
//
|
||||
if (!gPasswordManagerInitialized && type == NS_FORM_INPUT_PASSWORD) {
|
||||
// Initialize the password manager category
|
||||
gPasswordManagerInitialized = true;
|
||||
NS_CreateServicesFromCategory(NS_PASSWORDMANAGER_CATEGORY,
|
||||
nullptr,
|
||||
NS_PASSWORDMANAGER_CATEGORY);
|
||||
if (type == NS_FORM_INPUT_PASSWORD) {
|
||||
if (!gPasswordManagerInitialized) {
|
||||
gPasswordManagerInitialized = true;
|
||||
NS_CreateServicesFromCategory(NS_PASSWORDMANAGER_CATEGORY,
|
||||
nullptr,
|
||||
NS_PASSWORDMANAGER_CATEGORY);
|
||||
}
|
||||
PostPasswordEvent();
|
||||
}
|
||||
|
||||
// Default submit element handling
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsAsyncDOMEvent.h"
|
||||
|
||||
class nsFormControlList;
|
||||
class nsIMutableArray;
|
||||
@ -240,6 +241,26 @@ public:
|
||||
bool HasEverTriedInvalidSubmit() const { return mEverTriedInvalidSubmit; }
|
||||
|
||||
protected:
|
||||
void PostPasswordEvent();
|
||||
void EventHandled() { mFormPasswordEvent = nullptr; }
|
||||
|
||||
class FormPasswordEvent : public nsAsyncDOMEvent
|
||||
{
|
||||
public:
|
||||
FormPasswordEvent(nsHTMLFormElement* aEventNode,
|
||||
const nsAString& aEventType)
|
||||
: nsAsyncDOMEvent(aEventNode, aEventType, true, true)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
static_cast<nsHTMLFormElement*>(mEventNode.get())->EventHandled();
|
||||
return nsAsyncDOMEvent::Run();
|
||||
}
|
||||
};
|
||||
|
||||
nsRefPtr<FormPasswordEvent> mFormPasswordEvent;
|
||||
|
||||
class RemoveElementRunnable;
|
||||
friend class RemoveElementRunnable;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user