зеркало из https://github.com/mozilla/pjs.git
Bug 566160 - Implement formaction for <input> and <button> which ovverid <form> action attribute. r=sicking sr=smaug a2.0=blocking
This commit is contained in:
Родитель
2928a08300
Коммит
95c821061b
|
@ -387,6 +387,7 @@ GK_ATOM(footer, "footer")
|
|||
GK_ATOM(_for, "for")
|
||||
GK_ATOM(forEach, "for-each")
|
||||
GK_ATOM(form, "form")
|
||||
GK_ATOM(formaction, "formaction")
|
||||
GK_ATOM(format, "format")
|
||||
GK_ATOM(formatNumber, "format-number")
|
||||
GK_ATOM(formtarget, "formtarget")
|
||||
|
|
|
@ -494,6 +494,19 @@ public:
|
|||
NS_HIDDEN_(nsresult) GetEditor(nsIEditor** aEditor);
|
||||
NS_HIDDEN_(nsresult) GetEditorInternal(nsIEditor** aEditor);
|
||||
|
||||
/**
|
||||
* Helper method for NS_IMPL_URI_ATTR macro.
|
||||
* Gets the absolute URI value of an attribute, by resolving any relative
|
||||
* URIs in the attribute against the baseuri of the element. If the attribute
|
||||
* isn't a relative URI the value of the attribute is returned as is. Only
|
||||
* works for attributes in null namespace.
|
||||
*
|
||||
* @param aAttr name of attribute.
|
||||
* @param aBaseAttr name of base attribute.
|
||||
* @param aResult result value [out]
|
||||
*/
|
||||
NS_HIDDEN_(nsresult) GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsAString& aResult);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Add/remove this element to the documents name cache
|
||||
|
@ -654,19 +667,6 @@ protected:
|
|||
*/
|
||||
NS_HIDDEN_(nsresult) SetFloatAttr(nsIAtom* aAttr, float aValue);
|
||||
|
||||
/**
|
||||
* Helper method for NS_IMPL_URI_ATTR macro.
|
||||
* Gets the absolute URI value of an attribute, by resolving any relative
|
||||
* URIs in the attribute against the baseuri of the element. If the attribute
|
||||
* isn't a relative URI the value of the attribute is returned as is. Only
|
||||
* works for attributes in null namespace.
|
||||
*
|
||||
* @param aAttr name of attribute.
|
||||
* @param aBaseAttr name of base attribute.
|
||||
* @param aResult result value [out]
|
||||
*/
|
||||
NS_HIDDEN_(nsresult) GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsAString& aResult);
|
||||
|
||||
/**
|
||||
* Helper for GetURIAttr and GetHrefURIForAnchors which returns an
|
||||
* nsIURI in the out param.
|
||||
|
|
|
@ -208,6 +208,7 @@ nsHTMLButtonElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
|||
NS_IMPL_STRING_ATTR(nsHTMLButtonElement, AccessKey, accesskey)
|
||||
NS_IMPL_BOOL_ATTR(nsHTMLButtonElement, Autofocus, autofocus)
|
||||
NS_IMPL_BOOL_ATTR(nsHTMLButtonElement, Disabled, disabled)
|
||||
NS_IMPL_STRING_ATTR(nsHTMLButtonElement, FormAction, formaction)
|
||||
NS_IMPL_STRING_ATTR(nsHTMLButtonElement, FormTarget, formtarget)
|
||||
NS_IMPL_STRING_ATTR(nsHTMLButtonElement, Name, name)
|
||||
NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLButtonElement, TabIndex, tabindex, 0)
|
||||
|
@ -341,7 +342,7 @@ nsHTMLButtonElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
|||
// tell the form that we are about to enter a click handler.
|
||||
// that means that if there are scripted submissions, the
|
||||
// latest one will be deferred until after the exit point of the handler.
|
||||
mForm->OnSubmitClickBegin();
|
||||
mForm->OnSubmitClickBegin(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -775,7 +775,7 @@ nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
|
|||
// Get the action and target
|
||||
//
|
||||
nsCOMPtr<nsIURI> actionURI;
|
||||
rv = GetActionURL(getter_AddRefs(actionURI));
|
||||
rv = GetActionURL(getter_AddRefs(actionURI), originatingElement);
|
||||
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
||||
|
||||
if (!actionURI) {
|
||||
|
@ -1299,7 +1299,7 @@ nsHTMLFormElement::DoResolveName(const nsAString& aName,
|
|||
}
|
||||
|
||||
void
|
||||
nsHTMLFormElement::OnSubmitClickBegin()
|
||||
nsHTMLFormElement::OnSubmitClickBegin(nsIContent* aOriginatingElement)
|
||||
{
|
||||
mDeferSubmission = PR_TRUE;
|
||||
|
||||
|
@ -1309,7 +1309,7 @@ nsHTMLFormElement::OnSubmitClickBegin()
|
|||
nsCOMPtr<nsIURI> actionURI;
|
||||
nsresult rv;
|
||||
|
||||
rv = GetActionURL(getter_AddRefs(actionURI));
|
||||
rv = GetActionURL(getter_AddRefs(actionURI), aOriginatingElement);
|
||||
if (NS_FAILED(rv) || !actionURI)
|
||||
return;
|
||||
|
||||
|
@ -1343,7 +1343,8 @@ nsHTMLFormElement::FlushPendingSubmission()
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLFormElement::GetActionURL(nsIURI** aActionURL)
|
||||
nsHTMLFormElement::GetActionURL(nsIURI** aActionURL,
|
||||
nsIContent* aOriginatingElement)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -1352,8 +1353,23 @@ nsHTMLFormElement::GetActionURL(nsIURI** aActionURL)
|
|||
//
|
||||
// Grab the URL string
|
||||
//
|
||||
// If the originating element is a submit control and has the formaction
|
||||
// attribute specified, it should be used. Otherwise, the action attribute
|
||||
// from the form element should be used.
|
||||
//
|
||||
nsAutoString action;
|
||||
GetMozActionUri(action);
|
||||
nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aOriginatingElement);
|
||||
if (formControl && formControl->IsSubmitControl() &&
|
||||
aOriginatingElement->GetAttr(kNameSpaceID_None, nsGkAtoms::formaction,
|
||||
action)) {
|
||||
// Avoid resolving action="" to the base uri, bug 297761.
|
||||
if (!action.IsEmpty()) {
|
||||
static_cast<nsGenericHTMLElement*>(aOriginatingElement)->
|
||||
GetURIAttr(nsGkAtoms::formaction, nsnull, action);
|
||||
}
|
||||
} else {
|
||||
GetMozActionUri(action);
|
||||
}
|
||||
|
||||
//
|
||||
// Form the full action URL
|
||||
|
|
|
@ -241,7 +241,7 @@ public:
|
|||
* submission. In that case the form will defer the submission until the
|
||||
* script handler returns and the return value is known.
|
||||
*/
|
||||
void OnSubmitClickBegin();
|
||||
void OnSubmitClickBegin(nsIContent* aOriginatingElement);
|
||||
void OnSubmitClickEnd();
|
||||
|
||||
virtual nsXPCClassInfo* GetClassInfo();
|
||||
|
@ -326,8 +326,9 @@ protected:
|
|||
* Get the full URL to submit to. Do not submit if the returned URL is null.
|
||||
*
|
||||
* @param aActionURL the full, unadulterated URL you'll be submitting to [OUT]
|
||||
* @param aOriginatingElement the originating element of the form submission [IN]
|
||||
*/
|
||||
nsresult GetActionURL(nsIURI** aActionURL);
|
||||
nsresult GetActionURL(nsIURI** aActionURL, nsIContent* aOriginatingElement);
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -551,6 +551,7 @@ NS_IMPL_STRING_ATTR(nsHTMLInputElement, Alt, alt)
|
|||
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Autofocus, autofocus)
|
||||
//NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Checked, checked)
|
||||
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Disabled, disabled)
|
||||
NS_IMPL_STRING_ATTR(nsHTMLInputElement, FormAction, formaction)
|
||||
NS_IMPL_STRING_ATTR(nsHTMLInputElement, FormTarget, formtarget)
|
||||
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Multiple, multiple)
|
||||
NS_IMPL_NON_NEGATIVE_INT_ATTR(nsHTMLInputElement, MaxLength, maxlength)
|
||||
|
@ -1550,7 +1551,7 @@ nsHTMLInputElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
|||
// tell the form that we are about to enter a click handler.
|
||||
// that means that if there are scripted submissions, the
|
||||
// latest one will be deferred until after the exit point of the handler.
|
||||
mForm->OnSubmitClickBegin();
|
||||
mForm->OnSubmitClickBegin(this);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -199,6 +199,7 @@ _TEST_FILES = \
|
|||
test_bug344615.html \
|
||||
test_bug345512.html \
|
||||
test_bug566064.html \
|
||||
test_bug566160.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=566160
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 566160</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="setTimeout(runTests);">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566160">Mozilla Bug 566160</a>
|
||||
<p id="display"></p>
|
||||
<style>
|
||||
iframe { width: 130px; height: 100px;}
|
||||
</style>
|
||||
<iframe name='frame1' id='frame1'></iframe>
|
||||
<iframe name='frame2' id='frame2'></iframe>
|
||||
<iframe name='frame3' id='frame3'></iframe>
|
||||
<iframe name='frame3bis' id='frame3bis'></iframe>
|
||||
<iframe name='frame4' id='frame4'></iframe>
|
||||
<iframe name='frame5' id='frame5'></iframe>
|
||||
<iframe name='frame6' id='frame6'></iframe>
|
||||
<iframe name='frame7' id='frame7'></iframe>
|
||||
<div id="content">
|
||||
<!-- submit controls with formaction that are validated with a CLICK -->
|
||||
<form target="frame1" action="data:text/html,FAIL" method="GET">
|
||||
<input name='foo' value='foo'>
|
||||
<input type='submit' id='is' formaction="data:text/html,">
|
||||
</form>
|
||||
<form target="frame2" action="data:text/html,FAIL" method="GET">
|
||||
<input name='bar' value='bar'>
|
||||
<input type='image' id='ii' formaction="data:text/html,">
|
||||
</form>
|
||||
<form target="frame3" action="data:text/html,FAIL" method="GET">
|
||||
<input name='tulip' value='tulip'>
|
||||
<button type='submit' id='bs' formaction="data:text/html,">submit</button>
|
||||
</form>
|
||||
<form target="frame3bis" action="data:text/html,FAIL" method="GET">
|
||||
<input name='tulipbis' value='tulipbis'>
|
||||
<button type='submit' id='bsbis' formaction="data:text/html,">submit</button>
|
||||
</form>
|
||||
|
||||
<!-- submit controls with formaction that are validated with ENTER -->
|
||||
<form target="frame4" action="data:text/html,FAIL" method="GET">
|
||||
<input name='footulip' value='footulip'>
|
||||
<input type='submit' id='is2' formaction="data:text/html,">
|
||||
</form>
|
||||
<form target="frame5" action="data:text/html,FAIL" method="GET">
|
||||
<input name='foobar' value='foobar'>
|
||||
<input type='image' id='ii2' formaction="data:text/html,">
|
||||
</form>
|
||||
<form target="frame6" action="data:text/html,FAIL" method="GET">
|
||||
<input name='tulip2' value='tulip2'>
|
||||
<button type='submit' id='bs2' formaction="data:text/html,">submit</button>
|
||||
</form>
|
||||
|
||||
<!-- check that when submitting a from from an element
|
||||
which is not a submit control, @formaction isn't used -->
|
||||
<form target='frame7' action="data:text/html," method="GET">
|
||||
<input id='enter' name='input' value='enter' formaction="data:text/html,FAIL">
|
||||
</form>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 566160 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gTestResults = {
|
||||
frame1: "data:text/html,?foo=foo",
|
||||
frame2: "data:text/html,?bar=bar&x=0&y=0",
|
||||
frame3: "data:text/html,?tulip=tulip",
|
||||
frame3bis: "data:text/html,?tulipbis=tulipbis",
|
||||
frame4: "data:text/html,?footulip=footulip",
|
||||
frame5: "data:text/html,?foobar=foobar&x=0&y=0",
|
||||
frame6: "data:text/html,?tulip2=tulip2",
|
||||
frame7: "data:text/html,?input=enter",
|
||||
};
|
||||
|
||||
var gPendingLoad = 0; // Has to be set after depending on the frames number.
|
||||
|
||||
function checkFormActionAttribute(aElement)
|
||||
{
|
||||
ok("formAction" in aElement, "formAction IDL attribute should be available in "
|
||||
+ aElement);
|
||||
|
||||
is(aElement.formAction, "", "formAction IDL attribute should be " +
|
||||
"undefined by default");
|
||||
is(aElement.getAttribute('formaction'), null, "formaction content attribute " +
|
||||
"should be the empty string by default");
|
||||
|
||||
aElement.formAction = "foo";
|
||||
is(aElement.getAttribute('formaction'), "foo", "formaction content attribute " +
|
||||
"should be 'foo'.");
|
||||
is(aElement.formAction, "foo", "formAction IDL attribute should reflect " +
|
||||
"the content attribute");
|
||||
|
||||
aElement.setAttribute('formaction', 'bar');
|
||||
is(aElement.getAttribute('formaction'), "bar", "formaction content attribute " +
|
||||
"should be 'foo'.");
|
||||
is(aElement.formAction, "bar", "formAction IDL attribute should reflect " +
|
||||
"the content attribute");
|
||||
|
||||
aElement.removeAttribute('formaction');
|
||||
is(aElement.formAction, "", "formAction IDL attribute should be " +
|
||||
"undefined by default");
|
||||
is(aElement.getAttribute('formaction'), null, "formaction content attribute " +
|
||||
"should be the empty string by default");
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
// First of all, let's check if .formAction and @formaction work correctly.
|
||||
checkFormActionAttribute(document.createElement('input'));
|
||||
checkFormActionAttribute(document.createElement('button'));
|
||||
|
||||
// We add a load event for the frames which will be called when the forms
|
||||
// will be submitted.
|
||||
var frames = [ document.getElementById('frame1'),
|
||||
document.getElementById('frame2'),
|
||||
document.getElementById('frame3'),
|
||||
document.getElementById('frame3bis'),
|
||||
document.getElementById('frame4'),
|
||||
document.getElementById('frame5'),
|
||||
document.getElementById('frame6'),
|
||||
document.getElementById('frame7'),
|
||||
];
|
||||
gPendingLoad = frames.length;
|
||||
|
||||
for (var i=0; i<frames.length; i++) {
|
||||
frames[i].setAttribute('onload', "frameLoaded(this);");
|
||||
}
|
||||
|
||||
/**
|
||||
* We are going to focus each element before interacting with either for
|
||||
* simulating the ENTER key (synthesizeKey) or a click (synthesizeMouse) or
|
||||
* using .click(). This because it may be needed (ENTER) and because we want
|
||||
* to have the element visible in the iframe.
|
||||
*
|
||||
* Focusing the first element (id='is') is launching the tests.
|
||||
*/
|
||||
document.getElementById('is').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeMouse(document.getElementById('is'), 5, 5, {});
|
||||
document.getElementById('ii').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('ii').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeMouse(document.getElementById('ii'), 5, 5, {});
|
||||
document.getElementById('bs').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('bs').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeMouse(document.getElementById('bs'), 5, 5, {});
|
||||
document.getElementById('bsbis').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('bsbis').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
document.getElementById('bsbis').click();
|
||||
document.getElementById('is2').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('is2').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
document.getElementById('ii2').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('ii2').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
document.getElementById('bs2').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('bs2').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
document.getElementById('enter').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('enter').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
}, false);
|
||||
|
||||
document.getElementById('is').focus();
|
||||
}
|
||||
|
||||
function frameLoaded(aFrame) {
|
||||
// Check if formaction/action has the correct behavior.
|
||||
is(aFrame.contentWindow.location.href, gTestResults[aFrame.name],
|
||||
"the action attribute doesn't have the correct behavior");
|
||||
|
||||
if (--gPendingLoad == 0) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -49,12 +49,13 @@
|
|||
|
||||
interface nsIDOMValidityState;
|
||||
|
||||
[scriptable, uuid(4a24ca8f-cc7b-43b2-aca1-4dae149c1ed3)]
|
||||
[scriptable, uuid(f80d0ab0-a9a0-11df-94e2-0800200c9a66)]
|
||||
interface nsIDOMHTMLButtonElement : nsIDOMHTMLElement
|
||||
{
|
||||
attribute boolean autofocus;
|
||||
attribute boolean disabled;
|
||||
readonly attribute nsIDOMHTMLFormElement form;
|
||||
attribute DOMString formAction;
|
||||
attribute DOMString formTarget;
|
||||
|
||||
attribute DOMString name;
|
||||
|
|
|
@ -51,7 +51,7 @@ interface nsIDOMValidityState;
|
|||
* http://www.w3.org/TR/DOM-Level-2-HTML/
|
||||
*/
|
||||
|
||||
[scriptable, uuid(de8ae81f-85fd-4e6d-a864-00b38029c727)]
|
||||
[scriptable, uuid(da7ef8a0-a9a0-11df-94e2-0800200c9a66)]
|
||||
interface nsIDOMHTMLInputElement : nsIDOMHTMLElement
|
||||
{
|
||||
attribute DOMString accept;
|
||||
|
@ -62,6 +62,7 @@ interface nsIDOMHTMLInputElement : nsIDOMHTMLElement
|
|||
attribute boolean checked;
|
||||
attribute boolean disabled;
|
||||
readonly attribute nsIDOMHTMLFormElement form;
|
||||
attribute DOMString formAction;
|
||||
attribute DOMString formTarget;
|
||||
|
||||
readonly attribute nsIDOMFileList files;
|
||||
|
|
Загрузка…
Ссылка в новой задаче