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 "InputType.h"
8 :
9 : #include "nsIFormControl.h"
10 : #include "ButtonInputTypes.h"
11 : #include "CheckableInputTypes.h"
12 : #include "ColorInputType.h"
13 : #include "DateTimeInputTypes.h"
14 : #include "FileInputType.h"
15 : #include "HiddenInputType.h"
16 : #include "NumericInputTypes.h"
17 : #include "SingleLineTextInputTypes.h"
18 :
19 : #include "nsContentUtils.h"
20 :
21 3 : const mozilla::Decimal InputType::kStepAny = mozilla::Decimal(0);
22 :
23 : /* static */ mozilla::UniquePtr<InputType, DoNotDelete>
24 8 : InputType::Create(mozilla::dom::HTMLInputElement* aInputElement, uint8_t aType,
25 : void* aMemory)
26 : {
27 8 : mozilla::UniquePtr<InputType, DoNotDelete> inputType;
28 8 : switch(aType) {
29 : // Single line text
30 : case NS_FORM_INPUT_TEXT:
31 7 : inputType.reset(TextInputType::Create(aInputElement, aMemory));
32 7 : break;
33 : case NS_FORM_INPUT_TEL:
34 0 : inputType.reset(TelInputType::Create(aInputElement, aMemory));
35 0 : break;
36 : case NS_FORM_INPUT_EMAIL:
37 0 : inputType.reset(EmailInputType::Create(aInputElement, aMemory));
38 0 : break;
39 : case NS_FORM_INPUT_SEARCH:
40 1 : inputType.reset(SearchInputType::Create(aInputElement, aMemory));
41 1 : break;
42 : case NS_FORM_INPUT_PASSWORD:
43 0 : inputType.reset(PasswordInputType::Create(aInputElement, aMemory));
44 0 : break;
45 : case NS_FORM_INPUT_URL:
46 0 : inputType.reset(URLInputType::Create(aInputElement, aMemory));
47 0 : break;
48 : // Button
49 : case NS_FORM_INPUT_BUTTON:
50 0 : inputType.reset(ButtonInputType::Create(aInputElement, aMemory));
51 0 : break;
52 : case NS_FORM_INPUT_SUBMIT:
53 0 : inputType.reset(SubmitInputType::Create(aInputElement, aMemory));
54 0 : break;
55 : case NS_FORM_INPUT_IMAGE:
56 0 : inputType.reset(ImageInputType::Create(aInputElement, aMemory));
57 0 : break;
58 : case NS_FORM_INPUT_RESET:
59 0 : inputType.reset(ResetInputType::Create(aInputElement, aMemory));
60 0 : break;
61 : // Checkable
62 : case NS_FORM_INPUT_CHECKBOX:
63 0 : inputType.reset(CheckboxInputType::Create(aInputElement, aMemory));
64 0 : break;
65 : case NS_FORM_INPUT_RADIO:
66 0 : inputType.reset(RadioInputType::Create(aInputElement, aMemory));
67 0 : break;
68 : // Numeric
69 : case NS_FORM_INPUT_NUMBER:
70 0 : inputType.reset(NumberInputType::Create(aInputElement, aMemory));
71 0 : break;
72 : case NS_FORM_INPUT_RANGE:
73 0 : inputType.reset(RangeInputType::Create(aInputElement, aMemory));
74 0 : break;
75 : // DateTime
76 : case NS_FORM_INPUT_DATE:
77 0 : inputType.reset(DateInputType::Create(aInputElement, aMemory));
78 0 : break;
79 : case NS_FORM_INPUT_TIME:
80 0 : inputType.reset(TimeInputType::Create(aInputElement, aMemory));
81 0 : break;
82 : case NS_FORM_INPUT_MONTH:
83 0 : inputType.reset(MonthInputType::Create(aInputElement, aMemory));
84 0 : break;
85 : case NS_FORM_INPUT_WEEK:
86 0 : inputType.reset(WeekInputType::Create(aInputElement, aMemory));
87 0 : break;
88 : case NS_FORM_INPUT_DATETIME_LOCAL:
89 0 : inputType.reset(DateTimeLocalInputType::Create(aInputElement, aMemory));
90 0 : break;
91 : // Others
92 : case NS_FORM_INPUT_COLOR:
93 0 : inputType.reset(ColorInputType::Create(aInputElement, aMemory));
94 0 : break;
95 : case NS_FORM_INPUT_FILE:
96 0 : inputType.reset(FileInputType::Create(aInputElement, aMemory));
97 0 : break;
98 : case NS_FORM_INPUT_HIDDEN:
99 0 : inputType.reset(HiddenInputType::Create(aInputElement, aMemory));
100 0 : break;
101 : default:
102 0 : inputType.reset(TextInputType::Create(aInputElement, aMemory));
103 : }
104 :
105 8 : return inputType;
106 : }
107 :
108 : bool
109 0 : InputType::IsMutable() const
110 : {
111 0 : return !mInputElement->IsDisabled();
112 : }
113 :
114 : bool
115 0 : InputType::IsValueEmpty() const
116 : {
117 0 : return mInputElement->IsValueEmpty();
118 : }
119 :
120 : void
121 0 : InputType::GetNonFileValueInternal(nsAString& aValue) const
122 : {
123 0 : return mInputElement->GetNonFileValueInternal(aValue);
124 : }
125 :
126 : nsresult
127 0 : InputType::SetValueInternal(const nsAString& aValue, uint32_t aFlags)
128 : {
129 0 : return mInputElement->SetValueInternal(aValue, aFlags);
130 : }
131 :
132 : mozilla::Decimal
133 0 : InputType::GetStepBase() const
134 : {
135 0 : return mInputElement->GetStepBase();
136 : }
137 :
138 : nsIFrame*
139 0 : InputType::GetPrimaryFrame() const
140 : {
141 0 : return mInputElement->GetPrimaryFrame();
142 : }
143 :
144 : void
145 1 : InputType::DropReference()
146 : {
147 : // Drop our (non ref-counted) reference.
148 1 : mInputElement = nullptr;
149 1 : }
150 :
151 : bool
152 0 : InputType::IsTooLong() const
153 : {
154 0 : return false;
155 : }
156 :
157 : bool
158 0 : InputType::IsTooShort() const
159 : {
160 0 : return false;
161 : }
162 :
163 : bool
164 0 : InputType::IsValueMissing() const
165 : {
166 0 : return false;
167 : }
168 :
169 : bool
170 7 : InputType::HasTypeMismatch() const
171 : {
172 7 : return false;
173 : }
174 :
175 : bool
176 0 : InputType::HasPatternMismatch() const
177 : {
178 0 : return false;
179 : }
180 :
181 : bool
182 7 : InputType::IsRangeOverflow() const
183 : {
184 7 : return false;
185 : }
186 :
187 : bool
188 7 : InputType::IsRangeUnderflow() const
189 : {
190 7 : return false;
191 : }
192 :
193 : bool
194 7 : InputType::HasStepMismatch(bool aUseZeroIfValueNaN) const
195 : {
196 7 : return false;
197 : }
198 :
199 : bool
200 7 : InputType::HasBadInput() const
201 : {
202 7 : return false;
203 : }
204 :
205 : nsresult
206 0 : InputType::GetValidationMessage(nsAString& aValidationMessage,
207 : nsIConstraintValidation::ValidityStateType aType)
208 : {
209 0 : nsresult rv = NS_OK;
210 :
211 0 : switch (aType)
212 : {
213 : case nsIConstraintValidation::VALIDITY_STATE_TOO_LONG:
214 : {
215 0 : nsXPIDLString message;
216 0 : int32_t maxLength = mInputElement->MaxLength();
217 : int32_t textLength =
218 0 : mInputElement->InputTextLength(mozilla::dom::CallerType::System);
219 0 : nsAutoString strMaxLength;
220 0 : nsAutoString strTextLength;
221 :
222 0 : strMaxLength.AppendInt(maxLength);
223 0 : strTextLength.AppendInt(textLength);
224 :
225 0 : const char16_t* params[] = { strMaxLength.get(), strTextLength.get() };
226 : rv = nsContentUtils::FormatLocalizedString(
227 : nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooLong",
228 0 : params, message);
229 0 : aValidationMessage = message;
230 0 : break;
231 : }
232 : case nsIConstraintValidation::VALIDITY_STATE_TOO_SHORT:
233 : {
234 0 : nsXPIDLString message;
235 0 : int32_t minLength = mInputElement->MinLength();
236 : int32_t textLength =
237 0 : mInputElement->InputTextLength(mozilla::dom::CallerType::System);
238 0 : nsAutoString strMinLength;
239 0 : nsAutoString strTextLength;
240 :
241 0 : strMinLength.AppendInt(minLength);
242 0 : strTextLength.AppendInt(textLength);
243 :
244 0 : const char16_t* params[] = { strMinLength.get(), strTextLength.get() };
245 : rv = nsContentUtils::FormatLocalizedString(
246 : nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooShort",
247 0 : params, message);
248 :
249 0 : aValidationMessage = message;
250 0 : break;
251 : }
252 : case nsIConstraintValidation::VALIDITY_STATE_VALUE_MISSING:
253 : {
254 0 : nsXPIDLString message;
255 0 : rv = GetValueMissingMessage(message);
256 0 : if (NS_FAILED(rv)) {
257 0 : return rv;
258 : }
259 :
260 0 : aValidationMessage = message;
261 0 : break;
262 : }
263 : case nsIConstraintValidation::VALIDITY_STATE_TYPE_MISMATCH:
264 : {
265 0 : nsXPIDLString message;
266 0 : rv = GetTypeMismatchMessage(message);
267 0 : if (NS_FAILED(rv)) {
268 0 : return rv;
269 : }
270 :
271 0 : aValidationMessage = message;
272 0 : break;
273 : }
274 : case nsIConstraintValidation::VALIDITY_STATE_PATTERN_MISMATCH:
275 : {
276 0 : nsXPIDLString message;
277 0 : nsAutoString title;
278 0 : mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
279 0 : if (title.IsEmpty()) {
280 : rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
281 0 : "FormValidationPatternMismatch", message);
282 : } else {
283 0 : if (title.Length() >
284 : nsIConstraintValidation::sContentSpecifiedMaxLengthMessage) {
285 0 : title.Truncate(
286 0 : nsIConstraintValidation::sContentSpecifiedMaxLengthMessage);
287 : }
288 0 : const char16_t* params[] = { title.get() };
289 : rv = nsContentUtils::FormatLocalizedString(
290 : nsContentUtils::eDOM_PROPERTIES,
291 0 : "FormValidationPatternMismatchWithTitle", params, message);
292 : }
293 0 : aValidationMessage = message;
294 0 : break;
295 : }
296 : case nsIConstraintValidation::VALIDITY_STATE_RANGE_OVERFLOW:
297 : {
298 0 : nsXPIDLString message;
299 0 : rv = GetRangeOverflowMessage(message);
300 0 : if (NS_FAILED(rv)) {
301 0 : return rv;
302 : }
303 :
304 0 : aValidationMessage = message;
305 0 : break;
306 : }
307 : case nsIConstraintValidation::VALIDITY_STATE_RANGE_UNDERFLOW:
308 : {
309 0 : nsXPIDLString message;
310 0 : rv = GetRangeUnderflowMessage(message);
311 0 : if (NS_FAILED(rv)) {
312 0 : return rv;
313 : }
314 :
315 0 : aValidationMessage = message;
316 0 : break;
317 : }
318 : case nsIConstraintValidation::VALIDITY_STATE_STEP_MISMATCH:
319 : {
320 0 : nsXPIDLString message;
321 :
322 0 : mozilla::Decimal value = mInputElement->GetValueAsDecimal();
323 0 : MOZ_ASSERT(!value.isNaN());
324 :
325 0 : mozilla::Decimal step = mInputElement->GetStep();
326 0 : MOZ_ASSERT(step != kStepAny && step > mozilla::Decimal(0));
327 :
328 0 : mozilla::Decimal stepBase = mInputElement->GetStepBase();
329 :
330 : mozilla::Decimal valueLow =
331 0 : value - NS_floorModulo(value - stepBase, step);
332 : mozilla::Decimal valueHigh =
333 0 : value + step - NS_floorModulo(value - stepBase, step);
334 :
335 0 : mozilla::Decimal maximum = mInputElement->GetMaximum();
336 :
337 0 : if (maximum.isNaN() || valueHigh <= maximum) {
338 0 : nsAutoString valueLowStr, valueHighStr;
339 0 : ConvertNumberToString(valueLow, valueLowStr);
340 0 : ConvertNumberToString(valueHigh, valueHighStr);
341 :
342 0 : if (valueLowStr.Equals(valueHighStr)) {
343 0 : const char16_t* params[] = { valueLowStr.get() };
344 : rv = nsContentUtils::FormatLocalizedString(
345 : nsContentUtils::eDOM_PROPERTIES,
346 0 : "FormValidationStepMismatchOneValue", params, message);
347 : } else {
348 0 : const char16_t* params[] = { valueLowStr.get(), valueHighStr.get() };
349 : rv = nsContentUtils::FormatLocalizedString(
350 : nsContentUtils::eDOM_PROPERTIES,
351 0 : "FormValidationStepMismatch", params, message);
352 : }
353 : } else {
354 0 : nsAutoString valueLowStr;
355 0 : ConvertNumberToString(valueLow, valueLowStr);
356 :
357 0 : const char16_t* params[] = { valueLowStr.get() };
358 : rv = nsContentUtils::FormatLocalizedString(
359 : nsContentUtils::eDOM_PROPERTIES,
360 0 : "FormValidationStepMismatchOneValue", params, message);
361 : }
362 :
363 0 : aValidationMessage = message;
364 0 : break;
365 : }
366 : case nsIConstraintValidation::VALIDITY_STATE_BAD_INPUT:
367 : {
368 0 : nsXPIDLString message;
369 0 : rv = GetBadInputMessage(message);
370 0 : if (NS_FAILED(rv)) {
371 0 : return rv;
372 : }
373 :
374 0 : aValidationMessage = message;
375 0 : break;
376 : }
377 : default:
378 0 : return NS_ERROR_UNEXPECTED;
379 : }
380 :
381 0 : return rv;
382 : }
383 :
384 : nsresult
385 0 : InputType::GetValueMissingMessage(nsXPIDLString& aMessage)
386 : {
387 : return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
388 0 : "FormValidationValueMissing", aMessage);
389 : }
390 :
391 : nsresult
392 0 : InputType::GetTypeMismatchMessage(nsXPIDLString& aMessage)
393 : {
394 0 : return NS_ERROR_UNEXPECTED;
395 : }
396 :
397 : nsresult
398 0 : InputType::GetRangeOverflowMessage(nsXPIDLString& aMessage)
399 : {
400 0 : return NS_ERROR_UNEXPECTED;
401 : }
402 :
403 : nsresult
404 0 : InputType::GetRangeUnderflowMessage(nsXPIDLString& aMessage)
405 : {
406 0 : return NS_ERROR_UNEXPECTED;
407 : }
408 :
409 : nsresult
410 0 : InputType::GetBadInputMessage(nsXPIDLString& aMessage)
411 : {
412 0 : return NS_ERROR_UNEXPECTED;
413 : }
414 :
415 : nsresult
416 0 : InputType::MinMaxStepAttrChanged()
417 : {
418 0 : return NS_OK;
419 : }
420 :
421 : bool
422 0 : InputType::ConvertStringToNumber(nsAString& aValue,
423 : mozilla::Decimal& aResultValue) const
424 : {
425 0 : NS_WARNING("InputType::ConvertStringToNumber called");
426 :
427 0 : return false;
428 : }
429 :
430 : bool
431 0 : InputType::ConvertNumberToString(mozilla::Decimal aValue,
432 : nsAString& aResultString) const
433 : {
434 0 : NS_WARNING("InputType::ConvertNumberToString called");
435 :
436 0 : return false;
437 : }
438 :
439 : bool
440 0 : InputType::ParseDate(const nsAString& aValue, uint32_t* aYear, uint32_t* aMonth,
441 : uint32_t* aDay) const
442 : {
443 : // TODO: move this function and implementation to DateTimeInpuTypeBase when
444 : // refactoring is completed. Now we can only call HTMLInputElement::ParseDate
445 : // from here, since the method is protected and only InputType is a friend
446 : // class.
447 0 : return mInputElement->ParseDate(aValue, aYear, aMonth, aDay);
448 : }
449 :
450 : bool
451 0 : InputType::ParseTime(const nsAString& aValue, uint32_t* aResult) const
452 : {
453 : // see comment in InputType::ParseDate().
454 0 : return mInputElement->ParseTime(aValue, aResult);
455 : }
456 :
457 : bool
458 0 : InputType::ParseMonth(const nsAString& aValue, uint32_t* aYear,
459 : uint32_t* aMonth) const
460 : {
461 : // see comment in InputType::ParseDate().
462 0 : return mInputElement->ParseMonth(aValue, aYear, aMonth);
463 : }
464 :
465 : bool
466 0 : InputType::ParseWeek(const nsAString& aValue, uint32_t* aYear,
467 : uint32_t* aWeek) const
468 : {
469 : // see comment in InputType::ParseDate().
470 0 : return mInputElement->ParseWeek(aValue, aYear, aWeek);
471 : }
472 :
473 : bool
474 0 : InputType::ParseDateTimeLocal(const nsAString& aValue, uint32_t* aYear,
475 : uint32_t* aMonth, uint32_t* aDay, uint32_t* aTime)
476 : const
477 : {
478 : // see comment in InputType::ParseDate().
479 0 : return mInputElement->ParseDateTimeLocal(aValue, aYear, aMonth, aDay, aTime);
480 : }
481 :
482 : int32_t
483 0 : InputType::MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) const
484 : {
485 : // see comment in InputType::ParseDate().
486 0 : return mInputElement->MonthsSinceJan1970(aYear, aMonth);
487 : }
488 :
489 : double
490 0 : InputType::DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const
491 : {
492 : // see comment in InputType::ParseDate().
493 0 : return mInputElement->DaysSinceEpochFromWeek(aYear, aWeek);
494 : }
495 :
496 : uint32_t
497 0 : InputType::DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
498 : bool isoWeek) const
499 : {
500 : // see comment in InputType::ParseDate().
501 0 : return mInputElement->DayOfWeek(aYear, aMonth, aDay, isoWeek);
502 : }
503 :
504 : uint32_t
505 0 : InputType::MaximumWeekInYear(uint32_t aYear) const
506 : {
507 : // see comment in InputType::ParseDate().
508 0 : return mInputElement->MaximumWeekInYear(aYear);
509 : }
|