1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #include "nsIDOMHTMLButtonElement.h"
38 : #include "nsIDOMHTMLFormElement.h"
39 : #include "nsIDOMEventTarget.h"
40 : #include "nsGenericHTMLElement.h"
41 : #include "nsGkAtoms.h"
42 : #include "nsIPresShell.h"
43 : #include "nsStyleConsts.h"
44 : #include "nsPresContext.h"
45 : #include "nsIFormControl.h"
46 : #include "nsIForm.h"
47 : #include "nsFormSubmission.h"
48 : #include "nsFormSubmissionConstants.h"
49 : #include "nsIURL.h"
50 : #include "nsEventStateManager.h"
51 : #include "nsIFrame.h"
52 : #include "nsIFormControlFrame.h"
53 : #include "nsIDOMEvent.h"
54 : #include "nsIDOMNSEvent.h"
55 : #include "nsIDocument.h"
56 : #include "nsGUIEvent.h"
57 : #include "nsUnicharUtils.h"
58 : #include "nsLayoutUtils.h"
59 : #include "nsEventDispatcher.h"
60 : #include "nsPresState.h"
61 : #include "nsLayoutErrors.h"
62 : #include "nsFocusManager.h"
63 : #include "nsHTMLFormElement.h"
64 : #include "nsIConstraintValidation.h"
65 : #include "mozAutoDocUpdate.h"
66 :
67 : using namespace mozilla::dom;
68 :
69 : #define NS_IN_SUBMIT_CLICK (1 << 0)
70 : #define NS_OUTER_ACTIVATE_EVENT (1 << 1)
71 :
72 : static const nsAttrValue::EnumTable kButtonTypeTable[] = {
73 : { "button", NS_FORM_BUTTON_BUTTON },
74 : { "reset", NS_FORM_BUTTON_RESET },
75 : { "submit", NS_FORM_BUTTON_SUBMIT },
76 : { 0 }
77 : };
78 :
79 : // Default type is 'submit'.
80 : static const nsAttrValue::EnumTable* kButtonDefaultType = &kButtonTypeTable[2];
81 :
82 : class nsHTMLButtonElement : public nsGenericHTMLFormElement,
83 : public nsIDOMHTMLButtonElement,
84 : public nsIConstraintValidation
85 : {
86 : public:
87 : using nsIConstraintValidation::GetValidationMessage;
88 :
89 : nsHTMLButtonElement(already_AddRefed<nsINodeInfo> aNodeInfo,
90 : FromParser aFromParser = NOT_FROM_PARSER);
91 : virtual ~nsHTMLButtonElement();
92 :
93 : // nsISupports
94 : NS_DECL_ISUPPORTS_INHERITED
95 :
96 : // nsIDOMNode
97 0 : NS_FORWARD_NSIDOMNODE(nsGenericHTMLFormElement::)
98 :
99 : // nsIDOMElement
100 0 : NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLFormElement::)
101 :
102 : // nsIDOMHTMLElement
103 0 : NS_FORWARD_NSIDOMHTMLELEMENT_BASIC(nsGenericHTMLFormElement::)
104 0 : NS_SCRIPTABLE NS_IMETHOD Click() {
105 0 : return nsGenericHTMLFormElement::Click();
106 : }
107 : NS_SCRIPTABLE NS_IMETHOD GetTabIndex(PRInt32* aTabIndex);
108 : NS_SCRIPTABLE NS_IMETHOD SetTabIndex(PRInt32 aTabIndex);
109 0 : NS_SCRIPTABLE NS_IMETHOD Focus() {
110 0 : return nsGenericHTMLFormElement::Focus();
111 : }
112 0 : NS_SCRIPTABLE NS_IMETHOD GetDraggable(bool* aDraggable) {
113 0 : return nsGenericHTMLFormElement::GetDraggable(aDraggable);
114 : }
115 0 : NS_SCRIPTABLE NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) {
116 0 : return nsGenericHTMLFormElement::GetInnerHTML(aInnerHTML);
117 : }
118 0 : NS_SCRIPTABLE NS_IMETHOD SetInnerHTML(const nsAString& aInnerHTML) {
119 0 : return nsGenericHTMLFormElement::SetInnerHTML(aInnerHTML);
120 : }
121 :
122 : // nsIDOMHTMLButtonElement
123 : NS_DECL_NSIDOMHTMLBUTTONELEMENT
124 :
125 : // overriden nsIFormControl methods
126 0 : NS_IMETHOD_(PRUint32) GetType() const { return mType; }
127 : NS_IMETHOD Reset();
128 : NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
129 : NS_IMETHOD SaveState();
130 : bool RestoreState(nsPresState* aState);
131 :
132 : nsEventStates IntrinsicState() const;
133 :
134 : /**
135 : * Called when an attribute is about to be changed
136 : */
137 : virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
138 : const nsAttrValueOrString* aValue,
139 : bool aNotify);
140 : /**
141 : * Called when an attribute has just been changed
142 : */
143 : nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
144 : const nsAttrValue* aValue, bool aNotify);
145 :
146 : // nsIContent overrides...
147 : virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex);
148 : virtual bool ParseAttribute(PRInt32 aNamespaceID,
149 : nsIAtom* aAttribute,
150 : const nsAString& aValue,
151 : nsAttrValue& aResult);
152 : virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
153 : virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
154 :
155 : virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
156 : nsIContent* aBindingParent,
157 : bool aCompileEventHandlers);
158 : virtual void UnbindFromTree(bool aDeep = true,
159 : bool aNullParent = true);
160 :
161 : virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
162 : virtual void DoneCreatingElement();
163 : virtual nsXPCClassInfo* GetClassInfo();
164 :
165 : protected:
166 : PRUint8 mType;
167 : bool mDisabledChanged;
168 : bool mInInternalActivate;
169 : bool mInhibitStateRestoration;
170 :
171 : private:
172 : // The analogue of defaultValue in the DOM for input and textarea
173 : nsresult SetDefaultValue(const nsAString& aDefaultValue);
174 : nsresult GetDefaultValue(nsAString& aDefaultValue);
175 : };
176 :
177 :
178 : // Construction, destruction
179 :
180 :
181 0 : NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Button)
182 :
183 :
184 0 : nsHTMLButtonElement::nsHTMLButtonElement(already_AddRefed<nsINodeInfo> aNodeInfo,
185 : FromParser aFromParser)
186 : : nsGenericHTMLFormElement(aNodeInfo),
187 : mType(kButtonDefaultType->value),
188 : mDisabledChanged(false),
189 : mInInternalActivate(false),
190 0 : mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT))
191 : {
192 : // <button> is always barred from constraint validation.
193 0 : SetBarredFromConstraintValidation(true);
194 :
195 : // Set up our default state: enabled
196 0 : AddStatesSilently(NS_EVENT_STATE_ENABLED);
197 0 : }
198 :
199 0 : nsHTMLButtonElement::~nsHTMLButtonElement()
200 : {
201 0 : }
202 :
203 : // nsISupports
204 :
205 0 : NS_IMPL_ADDREF_INHERITED(nsHTMLButtonElement, nsGenericElement)
206 0 : NS_IMPL_RELEASE_INHERITED(nsHTMLButtonElement, nsGenericElement)
207 :
208 :
209 0 : DOMCI_NODE_DATA(HTMLButtonElement, nsHTMLButtonElement)
210 :
211 : // QueryInterface implementation for nsHTMLButtonElement
212 0 : NS_INTERFACE_TABLE_HEAD(nsHTMLButtonElement)
213 0 : NS_HTML_CONTENT_INTERFACE_TABLE2(nsHTMLButtonElement,
214 : nsIDOMHTMLButtonElement,
215 : nsIConstraintValidation)
216 0 : NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLButtonElement,
217 : nsGenericHTMLFormElement)
218 0 : NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLButtonElement)
219 :
220 : // nsIConstraintValidation
221 0 : NS_IMPL_NSICONSTRAINTVALIDATION(nsHTMLButtonElement)
222 :
223 : // nsIDOMHTMLButtonElement
224 :
225 :
226 0 : NS_IMPL_ELEMENT_CLONE(nsHTMLButtonElement)
227 :
228 :
229 : // nsIDOMHTMLButtonElement
230 :
231 : NS_IMETHODIMP
232 0 : nsHTMLButtonElement::GetForm(nsIDOMHTMLFormElement** aForm)
233 : {
234 0 : return nsGenericHTMLFormElement::GetForm(aForm);
235 : }
236 :
237 0 : NS_IMPL_BOOL_ATTR(nsHTMLButtonElement, Autofocus, autofocus)
238 0 : NS_IMPL_BOOL_ATTR(nsHTMLButtonElement, Disabled, disabled)
239 0 : NS_IMPL_ACTION_ATTR(nsHTMLButtonElement, FormAction, formaction)
240 0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLButtonElement, FormEnctype, formenctype,
241 : kFormDefaultEnctype->tag)
242 0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLButtonElement, FormMethod, formmethod,
243 : kFormDefaultMethod->tag)
244 0 : NS_IMPL_BOOL_ATTR(nsHTMLButtonElement, FormNoValidate, formnovalidate)
245 0 : NS_IMPL_STRING_ATTR(nsHTMLButtonElement, FormTarget, formtarget)
246 0 : NS_IMPL_STRING_ATTR(nsHTMLButtonElement, Name, name)
247 0 : NS_IMPL_INT_ATTR(nsHTMLButtonElement, TabIndex, tabindex)
248 0 : NS_IMPL_STRING_ATTR(nsHTMLButtonElement, Value, value)
249 0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLButtonElement, Type, type,
250 : kButtonDefaultType->tag)
251 :
252 : bool
253 0 : nsHTMLButtonElement::IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex)
254 : {
255 0 : if (nsGenericHTMLFormElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
256 0 : return true;
257 : }
258 :
259 : *aIsFocusable =
260 : #ifdef XP_MACOSX
261 : (!aWithMouse || nsFocusManager::sMouseFocusesFormControl) &&
262 : #endif
263 0 : !IsDisabled();
264 :
265 0 : return false;
266 : }
267 :
268 : bool
269 0 : nsHTMLButtonElement::ParseAttribute(PRInt32 aNamespaceID,
270 : nsIAtom* aAttribute,
271 : const nsAString& aValue,
272 : nsAttrValue& aResult)
273 : {
274 0 : if (aNamespaceID == kNameSpaceID_None) {
275 0 : if (aAttribute == nsGkAtoms::type) {
276 : // XXX ARG!! This is major evilness. ParseAttribute
277 : // shouldn't set members. Override SetAttr instead
278 0 : bool success = aResult.ParseEnumValue(aValue, kButtonTypeTable, false);
279 0 : if (success) {
280 0 : mType = aResult.GetEnumValue();
281 : } else {
282 0 : mType = kButtonDefaultType->value;
283 : }
284 :
285 0 : return success;
286 : }
287 :
288 0 : if (aAttribute == nsGkAtoms::formmethod) {
289 0 : return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
290 : }
291 0 : if (aAttribute == nsGkAtoms::formenctype) {
292 0 : return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
293 : }
294 : }
295 :
296 : return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
297 0 : aResult);
298 : }
299 :
300 : nsresult
301 0 : nsHTMLButtonElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
302 : {
303 0 : nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
304 0 : nsIFrame* formFrame = NULL;
305 0 : if (formControlFrame) {
306 0 : formFrame = do_QueryFrame(formControlFrame);
307 : }
308 :
309 0 : aVisitor.mCanHandle = false;
310 0 : if (IsElementDisabledForEvents(aVisitor.mEvent->message, formFrame)) {
311 0 : return NS_OK;
312 : }
313 :
314 : // Track whether we're in the outermost Dispatch invocation that will
315 : // cause activation of the input. That is, if we're a click event, or a
316 : // DOMActivate that was dispatched directly, this will be set, but if we're
317 : // a DOMActivate dispatched from click handling, it will not be set.
318 : bool outerActivateEvent =
319 : (NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent) ||
320 : (aVisitor.mEvent->message == NS_UI_ACTIVATE &&
321 0 : !mInInternalActivate));
322 :
323 0 : if (outerActivateEvent) {
324 0 : aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
325 0 : if (mType == NS_FORM_BUTTON_SUBMIT && mForm) {
326 0 : aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK;
327 : // tell the form that we are about to enter a click handler.
328 : // that means that if there are scripted submissions, the
329 : // latest one will be deferred until after the exit point of the handler.
330 0 : mForm->OnSubmitClickBegin(this);
331 : }
332 : }
333 :
334 0 : return nsGenericHTMLElement::PreHandleEvent(aVisitor);
335 : }
336 :
337 : nsresult
338 0 : nsHTMLButtonElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
339 : {
340 0 : nsresult rv = NS_OK;
341 0 : if (!aVisitor.mPresContext) {
342 0 : return rv;
343 : }
344 :
345 0 : if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault &&
346 : NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) {
347 0 : nsUIEvent actEvent(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_UI_ACTIVATE, 1);
348 :
349 0 : nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
350 0 : if (shell) {
351 0 : nsEventStatus status = nsEventStatus_eIgnore;
352 0 : mInInternalActivate = true;
353 0 : shell->HandleDOMEventWithTarget(this, &actEvent, &status);
354 0 : mInInternalActivate = false;
355 :
356 : // If activate is cancelled, we must do the same as when click is
357 : // cancelled (revert the checkbox to its original value).
358 0 : if (status == nsEventStatus_eConsumeNoDefault)
359 0 : aVisitor.mEventStatus = status;
360 : }
361 : }
362 :
363 : // mForm is null if the event handler removed us from the document (bug 194582).
364 0 : if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) {
365 : // tell the form that we are about to exit a click handler
366 : // so the form knows not to defer subsequent submissions
367 : // the pending ones that were created during the handler
368 : // will be flushed or forgoten.
369 0 : mForm->OnSubmitClickEnd();
370 : }
371 :
372 0 : if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
373 0 : switch (aVisitor.mEvent->message) {
374 : case NS_KEY_PRESS:
375 : case NS_KEY_UP:
376 : {
377 : // For backwards compat, trigger buttons with space or enter
378 : // (bug 25300)
379 0 : nsKeyEvent * keyEvent = (nsKeyEvent *)aVisitor.mEvent;
380 0 : if ((keyEvent->keyCode == NS_VK_RETURN &&
381 : NS_KEY_PRESS == aVisitor.mEvent->message) ||
382 : (keyEvent->keyCode == NS_VK_SPACE &&
383 : NS_KEY_UP == aVisitor.mEvent->message)) {
384 0 : nsEventStatus status = nsEventStatus_eIgnore;
385 :
386 : nsMouseEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent),
387 : NS_MOUSE_CLICK, nsnull,
388 0 : nsMouseEvent::eReal);
389 0 : event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
390 : nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
391 : aVisitor.mPresContext, &event, nsnull,
392 0 : &status);
393 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
394 : }
395 : }
396 0 : break;// NS_KEY_PRESS
397 :
398 : case NS_MOUSE_BUTTON_DOWN:
399 : {
400 0 : if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT) {
401 0 : if (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
402 : nsMouseEvent::eLeftButton) {
403 0 : if (NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
404 : nsEventStateManager* esm =
405 0 : aVisitor.mPresContext->EventStateManager();
406 : nsEventStateManager::SetActiveManager(
407 0 : static_cast<nsEventStateManager*>(esm), this);
408 : }
409 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
410 0 : if (fm)
411 : fm->SetFocus(this, nsIFocusManager::FLAG_BYMOUSE |
412 0 : nsIFocusManager::FLAG_NOSCROLL);
413 0 : aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
414 0 : } else if (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
415 : nsMouseEvent::eMiddleButton ||
416 : static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
417 : nsMouseEvent::eRightButton) {
418 : // cancel all of these events for buttons
419 : //XXXsmaug What to do with these events? Why these should be cancelled?
420 0 : if (aVisitor.mDOMEvent) {
421 0 : aVisitor.mDOMEvent->StopPropagation();
422 : }
423 : }
424 : }
425 : }
426 0 : break;
427 :
428 : // cancel all of these events for buttons
429 : //XXXsmaug What to do with these events? Why these should be cancelled?
430 : case NS_MOUSE_BUTTON_UP:
431 : case NS_MOUSE_DOUBLECLICK:
432 : {
433 0 : if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT &&
434 : aVisitor.mDOMEvent &&
435 : (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
436 : nsMouseEvent::eMiddleButton ||
437 : static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
438 : nsMouseEvent::eRightButton)) {
439 0 : aVisitor.mDOMEvent->StopPropagation();
440 : }
441 : }
442 0 : break;
443 :
444 : case NS_MOUSE_ENTER_SYNTH:
445 : {
446 : aVisitor.mPresContext->EventStateManager()->
447 0 : SetContentState(this, NS_EVENT_STATE_HOVER);
448 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
449 : }
450 0 : break;
451 :
452 : // XXX this doesn't seem to do anything yet
453 : case NS_MOUSE_EXIT_SYNTH:
454 : {
455 : aVisitor.mPresContext->EventStateManager()->
456 0 : SetContentState(nsnull, NS_EVENT_STATE_HOVER);
457 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
458 : }
459 0 : break;
460 :
461 : default:
462 0 : break;
463 : }
464 0 : if (aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) {
465 0 : if (mForm && (mType == NS_FORM_BUTTON_SUBMIT ||
466 : mType == NS_FORM_BUTTON_RESET)) {
467 : nsFormEvent event(true,
468 : (mType == NS_FORM_BUTTON_RESET)
469 0 : ? NS_FORM_RESET : NS_FORM_SUBMIT);
470 0 : event.originator = this;
471 0 : nsEventStatus status = nsEventStatus_eIgnore;
472 :
473 : nsCOMPtr<nsIPresShell> presShell =
474 0 : aVisitor.mPresContext->GetPresShell();
475 : // If |nsIPresShell::Destroy| has been called due to
476 : // handling the event, the pres context will return
477 : // a null pres shell. See bug 125624.
478 : //
479 : // Using presShell to dispatch the event. It makes sure that
480 : // event is not handled if the window is being destroyed.
481 0 : if (presShell && (event.message != NS_FORM_SUBMIT ||
482 0 : mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
483 : // We know the element is a submit control, if this check is moved,
484 : // make sure formnovalidate is used only if it's a submit control.
485 0 : HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) ||
486 0 : mForm->CheckValidFormSubmission())) {
487 : // TODO: removing this code and have the submit event sent by the form
488 : // see bug 592124.
489 : // Hold a strong ref while dispatching
490 0 : nsRefPtr<nsHTMLFormElement> form(mForm);
491 0 : presShell->HandleDOMEventWithTarget(mForm, &event, &status);
492 0 : aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
493 : }
494 : }
495 : }
496 0 : } else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) {
497 : // Tell the form to flush a possible pending submission.
498 : // the reason is that the script returned false (the event was
499 : // not ignored) so if there is a stored submission, it needs to
500 : // be submitted immediatelly.
501 : // Note, NS_IN_SUBMIT_CLICK is set only when we're in outer activate event.
502 0 : mForm->FlushPendingSubmission();
503 : } //if
504 :
505 0 : return rv;
506 : }
507 :
508 : nsresult
509 0 : nsHTMLButtonElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
510 : nsIContent* aBindingParent,
511 : bool aCompileEventHandlers)
512 : {
513 : nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
514 : aBindingParent,
515 0 : aCompileEventHandlers);
516 0 : NS_ENSURE_SUCCESS(rv, rv);
517 :
518 : // Update our state; we may now be the default submit element
519 0 : UpdateState(false);
520 :
521 0 : return NS_OK;
522 : }
523 :
524 : void
525 0 : nsHTMLButtonElement::UnbindFromTree(bool aDeep, bool aNullParent)
526 : {
527 0 : nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
528 :
529 : // Update our state; we may no longer be the default submit element
530 0 : UpdateState(false);
531 0 : }
532 :
533 : nsresult
534 0 : nsHTMLButtonElement::GetDefaultValue(nsAString& aDefaultValue)
535 : {
536 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::value, aDefaultValue);
537 0 : return NS_OK;
538 : }
539 :
540 : nsresult
541 0 : nsHTMLButtonElement::SetDefaultValue(const nsAString& aDefaultValue)
542 : {
543 0 : return SetAttr(kNameSpaceID_None, nsGkAtoms::value, aDefaultValue, true);
544 : }
545 :
546 : NS_IMETHODIMP
547 0 : nsHTMLButtonElement::Reset()
548 : {
549 0 : return NS_OK;
550 : }
551 :
552 : NS_IMETHODIMP
553 0 : nsHTMLButtonElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
554 : {
555 : //
556 : // We only submit if we were the button pressed
557 : //
558 0 : if (aFormSubmission->GetOriginatingElement() != this) {
559 0 : return NS_OK;
560 : }
561 :
562 : // Disabled elements don't submit
563 0 : if (IsDisabled()) {
564 0 : return NS_OK;
565 : }
566 :
567 : //
568 : // Get the name (if no name, no submit)
569 : //
570 0 : nsAutoString name;
571 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
572 0 : if (name.IsEmpty()) {
573 0 : return NS_OK;
574 : }
575 :
576 : //
577 : // Get the value
578 : //
579 0 : nsAutoString value;
580 0 : nsresult rv = GetValue(value);
581 0 : if (NS_FAILED(rv)) {
582 0 : return rv;
583 : }
584 :
585 : //
586 : // Submit
587 : //
588 0 : return aFormSubmission->AddNameValuePair(name, value);
589 : }
590 :
591 : void
592 0 : nsHTMLButtonElement::DoneCreatingElement()
593 : {
594 0 : if (!mInhibitStateRestoration) {
595 : // Restore state as needed.
596 0 : RestoreFormControlState(this, this);
597 : }
598 0 : }
599 :
600 : nsresult
601 0 : nsHTMLButtonElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
602 : const nsAttrValueOrString* aValue,
603 : bool aNotify)
604 : {
605 0 : if (aNotify && aName == nsGkAtoms::disabled &&
606 : aNameSpaceID == kNameSpaceID_None) {
607 0 : mDisabledChanged = true;
608 : }
609 :
610 : return nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName,
611 0 : aValue, aNotify);
612 : }
613 :
614 : nsresult
615 0 : nsHTMLButtonElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
616 : const nsAttrValue* aValue, bool aNotify)
617 : {
618 0 : if (aNameSpaceID == kNameSpaceID_None) {
619 0 : if (aName == nsGkAtoms::type) {
620 0 : if (!aValue) {
621 0 : mType = kButtonDefaultType->value;
622 : }
623 :
624 0 : UpdateState(aNotify);
625 : }
626 : }
627 :
628 : return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
629 0 : aValue, aNotify);
630 : }
631 :
632 : NS_IMETHODIMP
633 0 : nsHTMLButtonElement::SaveState()
634 : {
635 0 : if (!mDisabledChanged) {
636 0 : return NS_OK;
637 : }
638 :
639 0 : nsPresState *state = nsnull;
640 0 : nsresult rv = GetPrimaryPresState(this, &state);
641 0 : if (state) {
642 : // We do not want to save the real disabled state but the disabled
643 : // attribute.
644 0 : state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
645 : }
646 :
647 0 : return rv;
648 : }
649 :
650 : bool
651 0 : nsHTMLButtonElement::RestoreState(nsPresState* aState)
652 : {
653 0 : if (aState && aState->IsDisabledSet()) {
654 0 : SetDisabled(aState->GetDisabled());
655 : }
656 :
657 0 : return false;
658 : }
659 :
660 : nsEventStates
661 0 : nsHTMLButtonElement::IntrinsicState() const
662 : {
663 0 : nsEventStates state = nsGenericHTMLFormElement::IntrinsicState();
664 :
665 0 : if (mForm && !mForm->GetValidity() && IsSubmitControl()) {
666 0 : state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
667 : }
668 :
669 : return state;
670 : }
|