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 "NumericInputTypes.h"
8 :
9 : #include "mozilla/dom/HTMLInputElement.h"
10 : #include "nsNumberControlFrame.h"
11 : #include "nsTextEditorState.h"
12 :
13 : bool
14 0 : NumericInputTypeBase::IsRangeOverflow() const
15 : {
16 0 : mozilla::Decimal maximum = mInputElement->GetMaximum();
17 0 : if (maximum.isNaN()) {
18 0 : return false;
19 : }
20 :
21 0 : mozilla::Decimal value = mInputElement->GetValueAsDecimal();
22 0 : if (value.isNaN()) {
23 0 : return false;
24 : }
25 :
26 0 : return value > maximum;
27 : }
28 :
29 : bool
30 0 : NumericInputTypeBase::IsRangeUnderflow() const
31 : {
32 0 : mozilla::Decimal minimum = mInputElement->GetMinimum();
33 0 : if (minimum.isNaN()) {
34 0 : return false;
35 : }
36 :
37 0 : mozilla::Decimal value = mInputElement->GetValueAsDecimal();
38 0 : if (value.isNaN()) {
39 0 : return false;
40 : }
41 :
42 0 : return value < minimum;
43 : }
44 :
45 : bool
46 0 : NumericInputTypeBase::HasStepMismatch(bool aUseZeroIfValueNaN) const
47 : {
48 0 : mozilla::Decimal value = mInputElement->GetValueAsDecimal();
49 0 : if (value.isNaN()) {
50 0 : if (aUseZeroIfValueNaN) {
51 0 : value = mozilla::Decimal(0);
52 : } else {
53 : // The element can't suffer from step mismatch if it's value isn't a number.
54 0 : return false;
55 : }
56 : }
57 :
58 0 : mozilla::Decimal step = mInputElement->GetStep();
59 0 : if (step == kStepAny) {
60 0 : return false;
61 : }
62 :
63 : // Value has to be an integral multiple of step.
64 0 : return NS_floorModulo(value - GetStepBase(), step) != mozilla::Decimal(0);
65 : }
66 :
67 : nsresult
68 0 : NumericInputTypeBase::GetRangeOverflowMessage(nsXPIDLString& aMessage)
69 : {
70 : // We want to show the value as parsed when it's a number
71 0 : mozilla::Decimal maximum = mInputElement->GetMaximum();
72 0 : MOZ_ASSERT(!maximum.isNaN());
73 :
74 0 : nsAutoString maxStr;
75 : char buf[32];
76 0 : mozilla::DebugOnly<bool> ok = maximum.toString(buf,
77 0 : mozilla::ArrayLength(buf));
78 0 : maxStr.AssignASCII(buf);
79 0 : MOZ_ASSERT(ok, "buf not big enough");
80 :
81 0 : const char16_t* params[] = { maxStr.get() };
82 : return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
83 0 : "FormValidationNumberRangeOverflow", params, aMessage);
84 : }
85 :
86 : nsresult
87 0 : NumericInputTypeBase::GetRangeUnderflowMessage(nsXPIDLString& aMessage)
88 : {
89 0 : mozilla::Decimal minimum = mInputElement->GetMinimum();
90 0 : MOZ_ASSERT(!minimum.isNaN());
91 :
92 0 : nsAutoString minStr;
93 : char buf[32];
94 0 : mozilla::DebugOnly<bool> ok = minimum.toString(buf,
95 0 : mozilla::ArrayLength(buf));
96 0 : minStr.AssignASCII(buf);
97 0 : MOZ_ASSERT(ok, "buf not big enough");
98 :
99 0 : const char16_t* params[] = { minStr.get() };
100 : return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
101 0 : "FormValidationNumberRangeUnderflow", params, aMessage);
102 : }
103 :
104 : bool
105 0 : NumericInputTypeBase::ConvertStringToNumber(nsAString& aValue,
106 : mozilla::Decimal& aResultValue) const
107 : {
108 0 : aResultValue = mozilla::dom::HTMLInputElement::StringToDecimal(aValue);
109 0 : if (!aResultValue.isFinite()) {
110 0 : return false;
111 : }
112 0 : return true;
113 : }
114 :
115 : bool
116 0 : NumericInputTypeBase::ConvertNumberToString(mozilla::Decimal aValue,
117 : nsAString& aResultString) const
118 : {
119 0 : MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
120 :
121 0 : aResultString.Truncate();
122 :
123 : char buf[32];
124 0 : bool ok = aValue.toString(buf, mozilla::ArrayLength(buf));
125 0 : aResultString.AssignASCII(buf);
126 0 : MOZ_ASSERT(ok, "buf not big enough");
127 :
128 0 : return ok;
129 : }
130 :
131 : /* input type=numer */
132 :
133 : bool
134 0 : NumberInputType::IsValueMissing() const
135 : {
136 0 : if (!mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
137 0 : return false;
138 : }
139 :
140 0 : if (!IsMutable()) {
141 0 : return false;
142 : }
143 :
144 0 : return IsValueEmpty();
145 : }
146 :
147 : bool
148 0 : NumberInputType::HasBadInput() const
149 : {
150 0 : nsAutoString value;
151 0 : GetNonFileValueInternal(value);
152 0 : if (!value.IsEmpty()) {
153 : // The input can't be bad, otherwise it would have been sanitized to the
154 : // empty string.
155 0 : NS_ASSERTION(!mInputElement->GetValueAsDecimal().isNaN(),
156 : "Should have sanitized");
157 0 : return false;
158 : }
159 : nsNumberControlFrame* numberControlFrame =
160 0 : do_QueryFrame(GetPrimaryFrame());
161 0 : if (numberControlFrame &&
162 0 : !numberControlFrame->AnonTextControlIsEmpty()) {
163 : // The input the user entered failed to parse as a number.
164 0 : return true;
165 : }
166 0 : return false;
167 : }
168 :
169 : nsresult
170 0 : NumberInputType::GetValueMissingMessage(nsXPIDLString& aMessage)
171 : {
172 : return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
173 0 : "FormValidationBadInputNumber", aMessage);
174 : }
175 :
176 : nsresult
177 0 : NumberInputType::GetBadInputMessage(nsXPIDLString& aMessage)
178 : {
179 : return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
180 0 : "FormValidationBadInputNumber", aMessage);
181 : }
182 :
183 : bool
184 0 : NumberInputType::IsMutable() const
185 : {
186 0 : return !mInputElement->IsDisabled() &&
187 0 : !mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
188 : }
189 :
190 : /* input type=range */
191 : nsresult
192 0 : RangeInputType::MinMaxStepAttrChanged()
193 : {
194 : // The value may need to change when @min/max/step changes since the value may
195 : // have been invalid and can now change to a valid value, or vice versa. For
196 : // example, consider: <input type=range value=-1 max=1 step=3>. The valid
197 : // range is 0 to 1 while the nearest valid steps are -1 and 2 (the max value
198 : // having prevented there being a valid step in range). Changing @max to/from
199 : // 1 and a number greater than on equal to 3 should change whether we have a
200 : // step mismatch or not.
201 : // The value may also need to change between a value that results in a step
202 : // mismatch and a value that results in overflow. For example, if @max in the
203 : // example above were to change from 1 to -1.
204 0 : nsAutoString value;
205 0 : GetNonFileValueInternal(value);
206 0 : return SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
207 : }
|