summaryrefslogtreecommitdiffstats
path: root/dom/html/input/InputType.h
blob: a4853e09b238553c6f138f6ca0d6fbb65e130cdf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_InputType_h__
#define mozilla_dom_InputType_h__

#include <stdint.h>
#include "mozilla/Decimal.h"
#include "mozilla/Maybe.h"
#include "mozilla/TextControlState.h"
#include "mozilla/UniquePtr.h"
#include "nsIConstraintValidation.h"
#include "nsString.h"
#include "nsError.h"

// This must come outside of any namespace, or else it won't overload with the
// double based version in nsMathUtils.h
inline mozilla::Decimal NS_floorModulo(mozilla::Decimal x, mozilla::Decimal y) {
  return (x - y * (x / y).floor());
}

class nsIFrame;

namespace mozilla::dom {
class HTMLInputElement;

/**
 * A common superclass for different types of a HTMLInputElement.
 */
class InputType {
 public:
  using ValueSetterOption = TextControlState::ValueSetterOption;
  using ValueSetterOptions = TextControlState::ValueSetterOptions;

  // Custom deleter for UniquePtr<InputType> to avoid freeing memory
  // pre-allocated for InputType, but we still need to call the destructor
  // explictly.
  struct DoNotDelete {
    void operator()(InputType* p) { p->~InputType(); }
  };

  static UniquePtr<InputType, DoNotDelete> Create(
      HTMLInputElement* aInputElement, FormControlType, void* aMemory);

  virtual ~InputType() = default;

  // Float value returned by GetStep() when the step attribute is set to 'any'.
  static const Decimal kStepAny;

  /**
   * Drop the reference to the input element.
   */
  void DropReference();

  virtual bool MinAndMaxLengthApply() const { return false; }
  virtual bool IsTooLong() const;
  virtual bool IsTooShort() const;
  virtual bool IsValueMissing() const;
  virtual bool HasTypeMismatch() const;
  // May return Nothing() if the JS engine failed to evaluate the regex.
  virtual Maybe<bool> HasPatternMismatch() const;
  virtual bool IsRangeOverflow() const;
  virtual bool IsRangeUnderflow() const;
  virtual bool HasStepMismatch() const;
  virtual bool HasBadInput() const;

  nsresult GetValidationMessage(
      nsAString& aValidationMessage,
      nsIConstraintValidation::ValidityStateType aType);
  virtual nsresult GetValueMissingMessage(nsAString& aMessage);
  virtual nsresult GetTypeMismatchMessage(nsAString& aMessage);
  virtual nsresult GetRangeOverflowMessage(nsAString& aMessage);
  virtual nsresult GetRangeUnderflowMessage(nsAString& aMessage);
  virtual nsresult GetBadInputMessage(nsAString& aMessage);

  MOZ_CAN_RUN_SCRIPT virtual void MinMaxStepAttrChanged() {}

  /**
   * Convert a string to a Decimal number in a type specific way,
   * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#concept-input-value-string-number
   * ie parse a date string to a timestamp if type=date,
   * or parse a number string to its value if type=number.
   * @param aValue the string to be parsed.
   * @param aResultValue the number as a Decimal.
   * @result whether the parsing was successful.
   */
  virtual bool ConvertStringToNumber(nsAString& aValue,
                                     Decimal& aResultValue) const;

  /**
   * Convert a Decimal to a string in a type specific way, ie convert a
   * timestamp to a date string if type=date or append the number string
   * representing the value if type=number.
   *
   * @param aValue the Decimal to be converted
   * @param aResultString [out] the string representing the Decimal
   * @return whether the function succeeded, it will fail if the current input's
   *         type is not supported or the number can't be converted to a string
   *         as expected by the type.
   */
  virtual bool ConvertNumberToString(Decimal aValue,
                                     nsAString& aResultString) const;

 protected:
  explicit InputType(HTMLInputElement* aInputElement)
      : mInputElement(aInputElement) {}

  /**
   * Get the mutable state of the element.
   * When the element isn't mutable (immutable), the value or checkedness
   * should not be changed by the user.
   *
   * See:
   * https://html.spec.whatwg.org/multipage/forms.html#the-input-element:concept-fe-mutable
   */
  virtual bool IsMutable() const;

  /**
   * Returns whether the input element's current value is the empty string.
   * This only makes sense for some input types; does NOT make sense for file
   * inputs.
   *
   * @return whether the input element's current value is the empty string.
   */
  bool IsValueEmpty() const;

  // A getter for callers that know we're not dealing with a file input, so they
  // don't have to think about the caller type.
  void GetNonFileValueInternal(nsAString& aValue) const;

  /**
   * Setting the input element's value.
   *
   * @param aValue      String to set.
   * @param aOptions    See TextControlState::ValueSetterOption.
   */
  MOZ_CAN_RUN_SCRIPT nsresult
  SetValueInternal(const nsAString& aValue, const ValueSetterOptions& aOptions);

  /**
   * Get the primary frame for the input element.
   */
  nsIFrame* GetPrimaryFrame() const;

  /**
   * Parse a date string of the form yyyy-mm-dd
   *
   * @param aValue the string to be parsed.
   * @return the date in aYear, aMonth, aDay.
   * @return whether the parsing was successful.
   */
  bool ParseDate(const nsAString& aValue, uint32_t* aYear, uint32_t* aMonth,
                 uint32_t* aDay) const;

  /**
   * Returns the time expressed in milliseconds of |aValue| being parsed as a
   * time following the HTML specifications:
   * https://html.spec.whatwg.org/multipage/infrastructure.html#parse-a-time-string
   *
   * Note: |aResult| can be null.
   *
   * @param aValue the string to be parsed.
   * @param aResult the time expressed in milliseconds representing the time
   * [out]
   * @return whether the parsing was successful.
   */
  bool ParseTime(const nsAString& aValue, uint32_t* aResult) const;

  /**
   * Parse a month string of the form yyyy-mm
   *
   * @param the string to be parsed.
   * @return the year and month in aYear and aMonth.
   * @return whether the parsing was successful.
   */
  bool ParseMonth(const nsAString& aValue, uint32_t* aYear,
                  uint32_t* aMonth) const;

  /**
   * Parse a week string of the form yyyy-Www
   *
   * @param the string to be parsed.
   * @return the year and week in aYear and aWeek.
   * @return whether the parsing was successful.
   */
  bool ParseWeek(const nsAString& aValue, uint32_t* aYear,
                 uint32_t* aWeek) const;

  /**
   * Parse a datetime-local string of the form yyyy-mm-ddThh:mm[:ss.s] or
   * yyyy-mm-dd hh:mm[:ss.s], where fractions of seconds can be 1 to 3 digits.
   *
   * @param the string to be parsed.
   * @return the date in aYear, aMonth, aDay and time expressed in milliseconds
   *         in aTime.
   * @return whether the parsing was successful.
   */
  bool ParseDateTimeLocal(const nsAString& aValue, uint32_t* aYear,
                          uint32_t* aMonth, uint32_t* aDay,
                          uint32_t* aTime) const;

  /**
   * This methods returns the number of months between January 1970 and the
   * given year and month.
   */
  int32_t MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) const;

  /**
   * This methods returns the number of days since epoch for a given year and
   * week.
   */
  double DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const;

  /**
   * This methods returns the day of the week given a date. If @isoWeek is true,
   * 7=Sunday, otherwise, 0=Sunday.
   */
  uint32_t DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
                     bool isoWeek) const;

  /**
   * This methods returns the maximum number of week in a given year, the
   * result is either 52 or 53.
   */
  uint32_t MaximumWeekInYear(uint32_t aYear) const;

  HTMLInputElement* mInputElement;
};

}  // namespace mozilla::dom

#endif /* mozilla_dom_InputType_h__ */