Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsIConstraintValidation.h"
8 :
9 : #include "nsAString.h"
10 : #include "nsGenericHTMLElement.h"
11 : #include "mozilla/dom/HTMLFormElement.h"
12 : #include "mozilla/dom/HTMLFieldSetElement.h"
13 : #include "mozilla/dom/HTMLInputElement.h"
14 : #include "mozilla/dom/ValidityState.h"
15 : #include "nsIFormControl.h"
16 : #include "nsContentUtils.h"
17 :
18 : #include "nsIFormSubmitObserver.h"
19 : #include "nsIObserverService.h"
20 :
21 : const uint16_t nsIConstraintValidation::sContentSpecifiedMaxLengthMessage = 256;
22 :
23 : using namespace mozilla;
24 : using namespace mozilla::dom;
25 :
26 9 : nsIConstraintValidation::nsIConstraintValidation()
27 : : mValidityBitField(0)
28 : // By default, all elements are subjects to constraint validation.
29 9 : , mBarredFromConstraintValidation(false)
30 : {
31 9 : }
32 :
33 0 : nsIConstraintValidation::~nsIConstraintValidation()
34 : {
35 0 : }
36 :
37 : mozilla::dom::ValidityState*
38 0 : nsIConstraintValidation::Validity()
39 : {
40 0 : if (!mValidity) {
41 0 : mValidity = new mozilla::dom::ValidityState(this);
42 : }
43 :
44 0 : return mValidity;
45 : }
46 :
47 : nsresult
48 0 : nsIConstraintValidation::GetValidity(nsIDOMValidityState** aValidity)
49 : {
50 0 : NS_ENSURE_ARG_POINTER(aValidity);
51 :
52 0 : NS_ADDREF(*aValidity = Validity());
53 :
54 0 : return NS_OK;
55 : }
56 :
57 : NS_IMETHODIMP
58 0 : nsIConstraintValidation::GetValidationMessage(nsAString& aValidationMessage)
59 : {
60 0 : aValidationMessage.Truncate();
61 :
62 0 : if (IsCandidateForConstraintValidation() && !IsValid()) {
63 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(this);
64 0 : NS_ASSERTION(content, "This class should be inherited by HTML elements only!");
65 :
66 0 : nsAutoString authorMessage;
67 0 : content->GetAttr(kNameSpaceID_None, nsGkAtoms::x_moz_errormessage,
68 0 : authorMessage);
69 :
70 0 : if (!authorMessage.IsEmpty()) {
71 0 : aValidationMessage.Assign(authorMessage);
72 0 : if (aValidationMessage.Length() > sContentSpecifiedMaxLengthMessage) {
73 0 : aValidationMessage.Truncate(sContentSpecifiedMaxLengthMessage);
74 : }
75 0 : } else if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR)) {
76 0 : aValidationMessage.Assign(mCustomValidity);
77 0 : if (aValidationMessage.Length() > sContentSpecifiedMaxLengthMessage) {
78 0 : aValidationMessage.Truncate(sContentSpecifiedMaxLengthMessage);
79 : }
80 0 : } else if (GetValidityState(VALIDITY_STATE_TOO_LONG)) {
81 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_TOO_LONG);
82 0 : } else if (GetValidityState(VALIDITY_STATE_TOO_SHORT)) {
83 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_TOO_SHORT);
84 0 : } else if (GetValidityState(VALIDITY_STATE_VALUE_MISSING)) {
85 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_VALUE_MISSING);
86 0 : } else if (GetValidityState(VALIDITY_STATE_TYPE_MISMATCH)) {
87 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_TYPE_MISMATCH);
88 0 : } else if (GetValidityState(VALIDITY_STATE_PATTERN_MISMATCH)) {
89 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_PATTERN_MISMATCH);
90 0 : } else if (GetValidityState(VALIDITY_STATE_RANGE_OVERFLOW)) {
91 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_RANGE_OVERFLOW);
92 0 : } else if (GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW)) {
93 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_RANGE_UNDERFLOW);
94 0 : } else if (GetValidityState(VALIDITY_STATE_STEP_MISMATCH)) {
95 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_STEP_MISMATCH);
96 0 : } else if (GetValidityState(VALIDITY_STATE_BAD_INPUT)) {
97 0 : GetValidationMessage(aValidationMessage, VALIDITY_STATE_BAD_INPUT);
98 : } else {
99 : // There should not be other validity states.
100 0 : return NS_ERROR_UNEXPECTED;
101 : }
102 : } else {
103 0 : aValidationMessage.Truncate();
104 : }
105 :
106 0 : return NS_OK;
107 : }
108 :
109 : bool
110 0 : nsIConstraintValidation::CheckValidity()
111 : {
112 0 : if (!IsCandidateForConstraintValidation() || IsValid()) {
113 0 : return true;
114 : }
115 :
116 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(this);
117 0 : NS_ASSERTION(content, "This class should be inherited by HTML elements only!");
118 :
119 0 : nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content,
120 0 : NS_LITERAL_STRING("invalid"),
121 0 : false, true);
122 0 : return false;
123 : }
124 :
125 : nsresult
126 0 : nsIConstraintValidation::CheckValidity(bool* aValidity)
127 : {
128 0 : NS_ENSURE_ARG_POINTER(aValidity);
129 :
130 0 : *aValidity = CheckValidity();
131 :
132 0 : return NS_OK;
133 : }
134 :
135 : bool
136 0 : nsIConstraintValidation::ReportValidity()
137 : {
138 0 : if (!IsCandidateForConstraintValidation() || IsValid()) {
139 0 : return true;
140 : }
141 :
142 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(this);
143 0 : MOZ_ASSERT(content, "This class should be inherited by HTML elements only!");
144 :
145 0 : bool defaultAction = true;
146 0 : nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content,
147 0 : NS_LITERAL_STRING("invalid"),
148 0 : false, true, &defaultAction);
149 0 : if (!defaultAction) {
150 0 : return false;
151 : }
152 :
153 : nsCOMPtr<nsIObserverService> service =
154 0 : mozilla::services::GetObserverService();
155 0 : if (!service) {
156 0 : NS_WARNING("No observer service available!");
157 0 : return true;
158 : }
159 :
160 0 : nsCOMPtr<nsISimpleEnumerator> theEnum;
161 0 : nsresult rv = service->EnumerateObservers(NS_INVALIDFORMSUBMIT_SUBJECT,
162 0 : getter_AddRefs(theEnum));
163 :
164 : // Return true on error here because that's what we always did
165 0 : NS_ENSURE_SUCCESS(rv, true);
166 :
167 0 : bool hasObserver = false;
168 0 : rv = theEnum->HasMoreElements(&hasObserver);
169 :
170 : nsCOMPtr<nsIMutableArray> invalidElements =
171 0 : do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
172 0 : invalidElements->AppendElement(content, false);
173 :
174 0 : NS_ENSURE_SUCCESS(rv, true);
175 0 : nsCOMPtr<nsISupports> inst;
176 0 : nsCOMPtr<nsIFormSubmitObserver> observer;
177 0 : bool more = true;
178 0 : while (NS_SUCCEEDED(theEnum->HasMoreElements(&more)) && more) {
179 0 : theEnum->GetNext(getter_AddRefs(inst));
180 0 : observer = do_QueryInterface(inst);
181 :
182 0 : if (observer) {
183 0 : observer->NotifyInvalidSubmit(nullptr, invalidElements);
184 : }
185 : }
186 :
187 0 : if (content->IsHTMLElement(nsGkAtoms::input) &&
188 0 : nsContentUtils::IsFocusedContent(content)) {
189 : HTMLInputElement* inputElement =
190 0 : HTMLInputElement::FromContentOrNull(content);
191 :
192 0 : inputElement->UpdateValidityUIBits(true);
193 : }
194 :
195 0 : dom::Element* element = content->AsElement();
196 0 : element->UpdateState(true);
197 0 : return false;
198 : }
199 :
200 : void
201 89 : nsIConstraintValidation::SetValidityState(ValidityStateType aState,
202 : bool aValue)
203 : {
204 89 : bool previousValidity = IsValid();
205 :
206 89 : if (aValue) {
207 0 : mValidityBitField |= aState;
208 : } else {
209 89 : mValidityBitField &= ~aState;
210 : }
211 :
212 : // Inform the form and fieldset elements if our validity has changed.
213 89 : if (previousValidity != IsValid() && IsCandidateForConstraintValidation()) {
214 0 : nsCOMPtr<nsIFormControl> formCtrl = do_QueryInterface(this);
215 0 : NS_ASSERTION(formCtrl, "This interface should be used by form elements!");
216 :
217 : HTMLFormElement* form =
218 0 : static_cast<HTMLFormElement*>(formCtrl->GetFormElement());
219 0 : if (form) {
220 0 : form->UpdateValidity(IsValid());
221 : }
222 0 : HTMLFieldSetElement* fieldSet = formCtrl->GetFieldSet();
223 0 : if (fieldSet) {
224 0 : fieldSet->UpdateValidity(IsValid());
225 : }
226 : }
227 89 : }
228 :
229 : void
230 0 : nsIConstraintValidation::SetCustomValidity(const nsAString& aError)
231 : {
232 0 : mCustomValidity.Assign(aError);
233 0 : SetValidityState(VALIDITY_STATE_CUSTOM_ERROR, !mCustomValidity.IsEmpty());
234 0 : }
235 :
236 : void
237 27 : nsIConstraintValidation::SetBarredFromConstraintValidation(bool aBarred)
238 : {
239 27 : bool previousBarred = mBarredFromConstraintValidation;
240 :
241 27 : mBarredFromConstraintValidation = aBarred;
242 :
243 : // Inform the form and fieldset elements if our status regarding constraint
244 : // validation is going to change.
245 27 : if (!IsValid() && previousBarred != mBarredFromConstraintValidation) {
246 0 : nsCOMPtr<nsIFormControl> formCtrl = do_QueryInterface(this);
247 0 : NS_ASSERTION(formCtrl, "This interface should be used by form elements!");
248 :
249 : // If the element is going to be barred from constraint validation, we can
250 : // inform the form and fieldset that we are now valid. Otherwise, we are now
251 : // invalid.
252 : HTMLFormElement* form =
253 0 : static_cast<HTMLFormElement*>(formCtrl->GetFormElement());
254 0 : if (form) {
255 0 : form->UpdateValidity(aBarred);
256 : }
257 0 : HTMLFieldSetElement* fieldSet = formCtrl->GetFieldSet();
258 0 : if (fieldSet) {
259 0 : fieldSet->UpdateValidity(aBarred);
260 : }
261 : }
262 27 : }
263 :
|