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 #ifndef mozilla_dom_InputType_h__
8 #define mozilla_dom_InputType_h__
9
10 #include <stdint.h>
11 #include "mozilla/Decimal.h"
12 #include "mozilla/Maybe.h"
13 #include "mozilla/TextControlState.h"
14 #include "mozilla/UniquePtr.h"
15 #include "nsIConstraintValidation.h"
16 #include "nsString.h"
17 #include "nsError.h"
18
19 // This must come outside of any namespace, or else it won't overload with the
20 // double based version in nsMathUtils.h
NS_floorModulo(mozilla::Decimal x,mozilla::Decimal y)21 inline mozilla::Decimal NS_floorModulo(mozilla::Decimal x, mozilla::Decimal y) {
22 return (x - y * (x / y).floor());
23 }
24
25 class nsIFrame;
26
27 namespace mozilla {
28 namespace dom {
29 class HTMLInputElement;
30
31 /**
32 * A common superclass for different types of a HTMLInputElement.
33 */
34 class InputType {
35 public:
36 using ValueSetterOption = TextControlState::ValueSetterOption;
37 using ValueSetterOptions = TextControlState::ValueSetterOptions;
38
39 // Custom deleter for UniquePtr<InputType> to avoid freeing memory
40 // pre-allocated for InputType, but we still need to call the destructor
41 // explictly.
42 struct DoNotDelete {
operatorDoNotDelete43 void operator()(InputType* p) { p->~InputType(); }
44 };
45
46 static UniquePtr<InputType, DoNotDelete> Create(
47 HTMLInputElement* aInputElement, FormControlType, void* aMemory);
48
49 virtual ~InputType() = default;
50
51 // Float value returned by GetStep() when the step attribute is set to 'any'.
52 static const Decimal kStepAny;
53
54 /**
55 * Drop the reference to the input element.
56 */
57 void DropReference();
58
MinAndMaxLengthApply()59 virtual bool MinAndMaxLengthApply() const { return false; }
60 virtual bool IsTooLong() const;
61 virtual bool IsTooShort() const;
62 virtual bool IsValueMissing() const;
63 virtual bool HasTypeMismatch() const;
64 // May return Nothing() if the JS engine failed to evaluate the regex.
65 virtual Maybe<bool> HasPatternMismatch() const;
66 virtual bool IsRangeOverflow() const;
67 virtual bool IsRangeUnderflow() const;
68 virtual bool HasStepMismatch(bool aUseZeroIfValueNaN) const;
69 virtual bool HasBadInput() const;
70
71 nsresult GetValidationMessage(
72 nsAString& aValidationMessage,
73 nsIConstraintValidation::ValidityStateType aType);
74 virtual nsresult GetValueMissingMessage(nsAString& aMessage);
75 virtual nsresult GetTypeMismatchMessage(nsAString& aMessage);
76 virtual nsresult GetRangeOverflowMessage(nsAString& aMessage);
77 virtual nsresult GetRangeUnderflowMessage(nsAString& aMessage);
78 virtual nsresult GetBadInputMessage(nsAString& aMessage);
79
80 MOZ_CAN_RUN_SCRIPT virtual nsresult MinMaxStepAttrChanged();
81
82 /**
83 * Convert a string to a Decimal number in a type specific way,
84 * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#concept-input-value-string-number
85 * ie parse a date string to a timestamp if type=date,
86 * or parse a number string to its value if type=number.
87 * @param aValue the string to be parsed.
88 * @param aResultValue the number as a Decimal.
89 * @result whether the parsing was successful.
90 */
91 virtual bool ConvertStringToNumber(nsAString& aValue,
92 Decimal& aResultValue) const;
93
94 /**
95 * Convert a Decimal to a string in a type specific way, ie convert a
96 * timestamp to a date string if type=date or append the number string
97 * representing the value if type=number.
98 *
99 * @param aValue the Decimal to be converted
100 * @param aResultString [out] the string representing the Decimal
101 * @return whether the function succeeded, it will fail if the current input's
102 * type is not supported or the number can't be converted to a string
103 * as expected by the type.
104 */
105 virtual bool ConvertNumberToString(Decimal aValue,
106 nsAString& aResultString) const;
107
108 protected:
InputType(HTMLInputElement * aInputElement)109 explicit InputType(HTMLInputElement* aInputElement)
110 : mInputElement(aInputElement) {}
111
112 /**
113 * Get the mutable state of the element.
114 * When the element isn't mutable (immutable), the value or checkedness
115 * should not be changed by the user.
116 *
117 * See:
118 * https://html.spec.whatwg.org/multipage/forms.html#the-input-element:concept-fe-mutable
119 */
120 virtual bool IsMutable() const;
121
122 /**
123 * Returns whether the input element's current value is the empty string.
124 * This only makes sense for some input types; does NOT make sense for file
125 * inputs.
126 *
127 * @return whether the input element's current value is the empty string.
128 */
129 bool IsValueEmpty() const;
130
131 // A getter for callers that know we're not dealing with a file input, so they
132 // don't have to think about the caller type.
133 void GetNonFileValueInternal(nsAString& aValue) const;
134
135 /**
136 * Setting the input element's value.
137 *
138 * @param aValue String to set.
139 * @param aOptions See TextControlState::ValueSetterOption.
140 */
141 MOZ_CAN_RUN_SCRIPT nsresult
142 SetValueInternal(const nsAString& aValue, const ValueSetterOptions& aOptions);
143
144 /**
145 * Return the base used to compute if a value matches step.
146 * Basically, it's the min attribute if present and a default value otherwise.
147 *
148 * @return The step base.
149 */
150 Decimal GetStepBase() const;
151
152 /**
153 * Get the primary frame for the input element.
154 */
155 nsIFrame* GetPrimaryFrame() const;
156
157 /**
158 * Parse a date string of the form yyyy-mm-dd
159 *
160 * @param aValue the string to be parsed.
161 * @return the date in aYear, aMonth, aDay.
162 * @return whether the parsing was successful.
163 */
164 bool ParseDate(const nsAString& aValue, uint32_t* aYear, uint32_t* aMonth,
165 uint32_t* aDay) const;
166
167 /**
168 * Returns the time expressed in milliseconds of |aValue| being parsed as a
169 * time following the HTML specifications:
170 * https://html.spec.whatwg.org/multipage/infrastructure.html#parse-a-time-string
171 *
172 * Note: |aResult| can be null.
173 *
174 * @param aValue the string to be parsed.
175 * @param aResult the time expressed in milliseconds representing the time
176 * [out]
177 * @return whether the parsing was successful.
178 */
179 bool ParseTime(const nsAString& aValue, uint32_t* aResult) const;
180
181 /**
182 * Parse a month string of the form yyyy-mm
183 *
184 * @param the string to be parsed.
185 * @return the year and month in aYear and aMonth.
186 * @return whether the parsing was successful.
187 */
188 bool ParseMonth(const nsAString& aValue, uint32_t* aYear,
189 uint32_t* aMonth) const;
190
191 /**
192 * Parse a week string of the form yyyy-Www
193 *
194 * @param the string to be parsed.
195 * @return the year and week in aYear and aWeek.
196 * @return whether the parsing was successful.
197 */
198 bool ParseWeek(const nsAString& aValue, uint32_t* aYear,
199 uint32_t* aWeek) const;
200
201 /**
202 * Parse a datetime-local string of the form yyyy-mm-ddThh:mm[:ss.s] or
203 * yyyy-mm-dd hh:mm[:ss.s], where fractions of seconds can be 1 to 3 digits.
204 *
205 * @param the string to be parsed.
206 * @return the date in aYear, aMonth, aDay and time expressed in milliseconds
207 * in aTime.
208 * @return whether the parsing was successful.
209 */
210 bool ParseDateTimeLocal(const nsAString& aValue, uint32_t* aYear,
211 uint32_t* aMonth, uint32_t* aDay,
212 uint32_t* aTime) const;
213
214 /**
215 * This methods returns the number of months between January 1970 and the
216 * given year and month.
217 */
218 int32_t MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) const;
219
220 /**
221 * This methods returns the number of days since epoch for a given year and
222 * week.
223 */
224 double DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const;
225
226 /**
227 * This methods returns the day of the week given a date. If @isoWeek is true,
228 * 7=Sunday, otherwise, 0=Sunday.
229 */
230 uint32_t DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
231 bool isoWeek) const;
232
233 /**
234 * This methods returns the maximum number of week in a given year, the
235 * result is either 52 or 53.
236 */
237 uint32_t MaximumWeekInYear(uint32_t aYear) const;
238
239 HTMLInputElement* mInputElement;
240 };
241
242 } // namespace dom
243 } // namespace mozilla
244
245 #endif /* mozilla_dom_InputType_h__ */
246