1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components/declaration/textfield/textfield_declaration.h"
17
18 #include "base/utils/string_utils.h"
19 #include "core/components/declaration/common/declaration_constants.h"
20 #include "frameworks/bridge/common/utils/utils.h"
21 #include "frameworks/core/components/text_field/textfield_theme.h"
22
23 namespace OHOS::Ace {
24 namespace {
25
26 constexpr uint32_t METHOD_SHOW_ERROR_ARGS_SIZE = 1;
27 const TextInputAction INPUT_TEXTINPUTACTION_VALUE_DEFAULT = TextInputAction::UNSPECIFIED;
28 const std::vector<std::string> INPUT_FONT_FAMILY_VALUE = {
29 "sans-serif",
30 };
31
IsRadiusStyle(const std::string & style)32 bool IsRadiusStyle(const std::string& style)
33 {
34 return (style == DOM_BORDER_TOP_LEFT_RADIUS || style == DOM_BORDER_TOP_RIGHT_RADIUS ||
35 style == DOM_BORDER_BOTTOM_LEFT_RADIUS || style == DOM_BORDER_BOTTOM_RIGHT_RADIUS ||
36 style == DOM_BORDER_RADIUS);
37 }
38
39 } // namespace
40
41 using namespace Framework;
42
InitSpecialized()43 void TextFieldDeclaration::InitSpecialized()
44 {
45 AddCommonStyle(StyleTag::COMMON_IMAGE_STYLE);
46 AddSpecializedAttribute(DeclarationConstants::DEFAULT_TEXTFIELD_ATTR);
47 AddSpecializedStyle(DeclarationConstants::DEFAULT_TEXTFIELD_STYLE);
48 AddSpecializedEvent(DeclarationConstants::DEFAULT_TEXTFIELD_EVENT);
49 AddSpecializedMethod(DeclarationConstants::DEFAULT_TEXTFIELD_METHOD);
50 }
51
InitializeStyle()52 void TextFieldDeclaration::InitializeStyle()
53 {
54 auto theme = GetTheme<TextFieldTheme>();
55 if (!theme) {
56 return;
57 }
58
59 auto& attribute = static_cast<TextFieldAttribute&>(GetAttribute(AttributeTag::SPECIALIZED_ATTR));
60 attribute.action = INPUT_TEXTINPUTACTION_VALUE_DEFAULT;
61 attribute.showEllipsis = theme->ShowEllipsis();
62 attribute.needFade = theme->NeedFade();
63 attribute.iconSize = theme->GetIconSize();
64 attribute.iconHotZoneSize = theme->GetIconHotZoneSize();
65
66 auto& style = static_cast<TextFieldStyle&>(GetStyle(StyleTag::SPECIALIZED_STYLE));
67 style.height = theme->GetHeight();
68 style.cursorColor = theme->GetCursorColor();
69 style.cursorColorIsSet = true;
70 style.cursorRadius = theme->GetCursorRadius();
71 style.textColor = theme->GetTextColor();
72 style.focusTextColor = theme->GetFocusTextColor();
73 style.placeholderColor = theme->GetPlaceholderColor();
74 style.focusPlaceholderColor = theme->GetFocusPlaceholderColor();
75 style.bgColor = theme->GetBgColor();
76 style.focusBgColor = theme->GetFocusBgColor();
77 style.selectedColor = theme->GetSelectedColor();
78 style.hoverColor = theme->GetHoverColor();
79 style.pressColor = theme->GetPressColor();
80
81 style.textStyle.SetTextColor(theme->GetTextColor());
82 style.textStyle.SetFontSize(theme->GetFontSize());
83 style.textStyle.SetFontWeight(theme->GetFontWeight());
84 style.textStyle.SetFontFamilies(INPUT_FONT_FAMILY_VALUE);
85
86 style.countTextStyle = theme->GetCountTextStyle();
87 style.overCountStyle = theme->GetOverCountStyle();
88 style.countTextStyleOuter = theme->GetCountTextStyleOuter();
89 style.overCountStyleOuter = theme->GetOverCountStyleOuter();
90
91 style.errorTextStyle = theme->GetErrorTextStyle();
92 style.errorSpacing = theme->GetErrorSpacing();
93 style.errorIsInner = theme->GetErrorIsInner();
94 style.errorBorderWidth = theme->GetErrorBorderWidth();
95 style.errorBorderColor = theme->GetErrorBorderColor();
96
97 RefPtr<Decoration> decoration = AceType::MakeRefPtr<Decoration>();
98 decoration->SetPadding(theme->GetPadding());
99 decoration->SetBackgroundColor(theme->GetBgColor());
100 decoration->SetBorderRadius(theme->GetBorderRadius());
101 auto boxDecoration = GetDecoration();
102 if (boxDecoration) {
103 decoration->SetImage(boxDecoration->GetImage());
104 decoration->SetGradient(boxDecoration->GetGradient());
105 }
106 style.decoration = decoration;
107
108 textEditController_ = AceType::MakeRefPtr<TextEditController>();
109 textFieldController_ = AceType::MakeRefPtr<TextFieldController>();
110 }
111
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)112 bool TextFieldDeclaration::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
113 {
114 // this static map should be sorted by key.
115 static const LinearMapNode<void (*)(TextFieldDeclaration&, const std::string&)> attrOperators[] = {
116 { DOM_AUTO_FOCUS, [](TextFieldDeclaration& declaration,
117 const std::string& value) { declaration.SetAutoFocus(StringToBool(value)); } },
118 { DOM_DISABLED, [](TextFieldDeclaration& declaration,
119 const std::string& value) { declaration.SetEnabled(!StringToBool(value)); } },
120 { DOM_INPUT_ENTERKEYTYPE,
121 [](TextFieldDeclaration& declaration, const std::string& value) {
122 declaration.SetAction(ConvertStrToTextInputAction(value));
123 } },
124 { DOM_ICON_SRC,
125 [](TextFieldDeclaration& declaration, const std::string& value) { declaration.SetIconImage(value); } },
126 { DOM_HIDE_ICON_SRC,
127 [](TextFieldDeclaration& declaration, const std::string& value) { declaration.SetHideIconImage(value); } },
128 { DOM_INPUT_MAXLENGTH,
129 [](TextFieldDeclaration& declaration, const std::string& value) {
130 int32_t tmp = StringUtils::StringToInt(value);
131 declaration.SetMaxLength(tmp >= 0 ? (uint32_t)(tmp) : std::numeric_limits<uint32_t>::max());
132 } },
133 { DOM_INPUT_OBSCURE, [](TextFieldDeclaration& declaration,
134 const std::string& value) { declaration.SetObscure(StringToBool(value)); } },
135 { DOM_TEXTAREA_OVERFLOWX,
136 [](TextFieldDeclaration& declaration, const std::string& value) {
137 declaration.SetOverflowX(ConvertStrToTextFieldOverflowX(value));
138 } },
139 { DOM_INPUT_PLACEHOLDER,
140 [](TextFieldDeclaration& declaration, const std::string& value) {
141 declaration.SetPlaceholder(value);
142 } },
143 { DOM_INPUT_SELECTED_END, [](TextFieldDeclaration& declaration,
144 const std::string& value) { declaration.SetSelectedEnd(StringToInt(value)); } },
145 { DOM_INPUT_SELECTED_START,
146 [](TextFieldDeclaration& declaration, const std::string& value) {
147 declaration.SetSelectedStart(StringToInt(value));
148 } },
149 { DOM_INPUT_SHOW_COUNTER, [](TextFieldDeclaration& declaration,
150 const std::string& value) { declaration.SetShowCounter(StringToBool(value)); } },
151 { DOM_SHOW_ICON_SRC,
152 [](TextFieldDeclaration& declaration, const std::string& value) { declaration.SetShowIconImage(value); } },
153 { DOM_INPUT_SHOW_PASSWORD_ICON,
154 [](TextFieldDeclaration& declaration, const std::string& value) {
155 declaration.SetShowPasswordIcon(StringToBool(value));
156 } },
157 { DOM_INPUT_SOFT_KEYBOARD_ENABLED,
158 [](TextFieldDeclaration& declaration, const std::string& value) {
159 declaration.SetSoftKeyboardEnabled(StringToBool(value));
160 } },
161 { DOM_INPUT_TYPE,
162 [](TextFieldDeclaration& declaration, const std::string& value) {
163 declaration.SetTextInputType(ConvertStrToTextInputType(value));
164 declaration.SetObscure(value == DOM_INPUT_TYPE_PASSWORD);
165 } },
166 { DOM_INPUT_VALUE,
167 [](TextFieldDeclaration& declaration, const std::string& value) { declaration.SetValue(value); } },
168 };
169 auto operatorIter = BinarySearchFindIndex(attrOperators, ArraySize(attrOperators), attr.first.c_str());
170 if (operatorIter != -1) {
171 attrOperators[operatorIter].value(*this, attr.second);
172 return true;
173 }
174 return false;
175 }
176
SetSpecializedStyle(const std::pair<std::string,std::string> & style)177 bool TextFieldDeclaration::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
178 {
179 // static linear map must be sorted by key.
180 static const LinearMapNode<void (*)(TextFieldDeclaration&, const std::string&)> styleOperators[] = {
181 { DOM_TEXT_ALLOW_SCALE,
182 [](TextFieldDeclaration& declaration, const std::string& value) {
183 declaration.GetTextStyle().SetAllowScale(StringToBool(value));
184 } },
185 { DOM_BACKGROUND_COLOR,
186 [](TextFieldDeclaration& declaration, const std::string& value) {
187 declaration.SetBgColor(declaration.ParseColor(value));
188 declaration.SetFocusBgColor(declaration.ParseColor(value));
189 } },
190 { DOM_CARET_COLOR,
191 [](TextFieldDeclaration& declaration, const std::string& value) {
192 declaration.SetCursorColor(declaration.ParseColor(value));
193 } },
194 { DOM_INPUT_COLOR,
195 [](TextFieldDeclaration& declaration, const std::string& value) {
196 declaration.GetTextStyle().SetTextColor(declaration.ParseColor(value));
197 declaration.SetFocusTextColor(declaration.ParseColor(value));
198 } },
199 { DOM_INPUT_CURSOR_COLOR,
200 [](TextFieldDeclaration& declaration, const std::string& value) {
201 declaration.SetCursorColor(declaration.ParseColor(value));
202 } },
203 { DOM_INPUT_FONT_FAMILY,
204 [](TextFieldDeclaration& declaration, const std::string& value) {
205 std::vector<std::string> fontFamilies;
206 std::stringstream sstr(value);
207 std::string fontFamily;
208 while (getline(sstr, fontFamily, ',')) {
209 fontFamilies.emplace_back(fontFamily);
210 }
211 declaration.GetTextStyle().SetFontFamilies(fontFamilies);
212 } },
213 { DOM_INPUT_FONT_SIZE,
214 [](TextFieldDeclaration& declaration, const std::string& value) {
215 declaration.GetTextStyle().SetFontSize(declaration.ParseDimension(value));
216 } },
217 { DOM_INPUT_FONT_WEIGHT,
218 [](TextFieldDeclaration& declaration, const std::string& value) {
219 declaration.GetTextStyle().SetFontWeight(ConvertStrToFontWeight(value));
220 } },
221 { DOM_PADDING,
222 [](TextFieldDeclaration& declaration, const std::string& value) {
223 Edge padding;
224 if (Edge::FromString(value, padding)) {
225 declaration.GetDecoration()->SetPadding(padding);
226 }
227 } },
228 { DOM_PADDING_BOTTOM,
229 [](TextFieldDeclaration& declaration, const std::string& value) {
230 auto padding = declaration.GetDecoration()->GetPadding();
231 padding.SetBottom(declaration.ParseDimension(value));
232 declaration.GetDecoration()->SetPadding(padding);
233 } },
234 { DOM_PADDING_END,
235 [](TextFieldDeclaration& declaration, const std::string& value) {
236 auto padding = declaration.GetDecoration()->GetPadding();
237 declaration.IsRightToLeft() ? padding.SetLeft(declaration.ParseDimension(value))
238 : padding.SetRight(declaration.ParseDimension(value));
239 declaration.GetDecoration()->SetPadding(padding);
240 } },
241 { DOM_PADDING_LEFT,
242 [](TextFieldDeclaration& declaration, const std::string& value) {
243 auto padding = declaration.GetDecoration()->GetPadding();
244 padding.SetLeft(declaration.ParseDimension(value));
245 declaration.GetDecoration()->SetPadding(padding);
246 } },
247 { DOM_PADDING_RIGHT,
248 [](TextFieldDeclaration& declaration, const std::string& value) {
249 auto padding = declaration.GetDecoration()->GetPadding();
250 padding.SetRight(declaration.ParseDimension(value));
251 declaration.GetDecoration()->SetPadding(padding);
252 } },
253 { DOM_PADDING_START,
254 [](TextFieldDeclaration& declaration, const std::string& value) {
255 auto padding = declaration.GetDecoration()->GetPadding();
256 declaration.IsRightToLeft() ? padding.SetRight(declaration.ParseDimension(value))
257 : padding.SetLeft(declaration.ParseDimension(value));
258 declaration.GetDecoration()->SetPadding(padding);
259 } },
260 { DOM_PADDING_TOP,
261 [](TextFieldDeclaration& declaration, const std::string& value) {
262 auto padding = declaration.GetDecoration()->GetPadding();
263 padding.SetTop(declaration.ParseDimension(value));
264 declaration.GetDecoration()->SetPadding(padding);
265 } },
266 { DOM_INPUT_PLACEHOLDER_COLOR,
267 [](TextFieldDeclaration& declaration, const std::string& value) {
268 declaration.SetPlaceholderColor(declaration.ParseColor(value));
269 declaration.SetFocusPlaceholderColor(declaration.ParseColor(value));
270 } },
271 };
272 if (IsRadiusStyle(style.first)) {
273 hasBoxRadius_ = true;
274 }
275 auto operatorIter = BinarySearchFindIndex(styleOperators, ArraySize(styleOperators), style.first.c_str());
276 if (operatorIter != -1) {
277 styleOperators[operatorIter].value(*this, style.second);
278 return true;
279 }
280 return false;
281 }
282
SetSpecializedEvent(int32_t pageId,const std::string & eventId,const std::string & event)283 bool TextFieldDeclaration::SetSpecializedEvent(int32_t pageId, const std::string& eventId, const std::string& event)
284 {
285 static const LinearMapNode<void (*)(TextFieldDeclaration&, const EventMarker&)> eventOperators[] = {
286 { DOM_CATCH_BUBBLE_CLICK,
287 [](TextFieldDeclaration& declaration, const EventMarker& event) {
288 EventMarker eventMarker(event);
289 eventMarker.SetCatchMode(true);
290 declaration.SetOnTap(eventMarker);
291 } },
292 { DOM_CHANGE,
293 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnTextChange(event); } },
294 { DOM_CLICK, [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnTap(event); } },
295 { DOM_INPUT_EVENT_ENTERKEYCLICK,
296 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnFinishInput(event); } },
297 { DOM_LONG_PRESS,
298 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnLongPress(event); } },
299 { DOM_INPUT_EVENT_OPTION_SELECT,
300 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnOptionsClick(event); } },
301 { DOM_INPUT_EVENT_SEARCH,
302 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnSearch(event); } },
303 { DOM_INPUT_EVENT_SELECT_CHANGE,
304 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnSelectChange(event); } },
305 { DOM_INPUT_EVENT_SHARE,
306 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnShare(event); } },
307 { DOM_INPUT_EVENT_TRANSLATE,
308 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnTranslate(event); } },
309 };
310 auto operatorIter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
311 if (operatorIter != -1) {
312 eventOperators[operatorIter].value(*this, EventMarker(eventId, event, pageId));
313 return true;
314 }
315 return false;
316 }
317
CallSpecializedMethod(const std::string & method,const std::string & args)318 void TextFieldDeclaration::CallSpecializedMethod(const std::string& method, const std::string& args)
319 {
320 if (!textFieldController_) {
321 return;
322 }
323 if (method == DOM_INPUT_METHOD_SHOW_ERROR) {
324 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
325 if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != METHOD_SHOW_ERROR_ARGS_SIZE) {
326 LOGE("parse args error");
327 return;
328 }
329
330 std::unique_ptr<JsonValue> error = argsValue->GetArrayItem(0)->GetValue("error");
331 if (!error || !error->IsString()) {
332 LOGE("get error text failed");
333 return;
334 }
335 std::string errorText = error->GetString();
336 textFieldController_->ShowError(errorText);
337 } else if (method == DOM_INPUT_METHOD_DELETE) {
338 textFieldController_->Delete();
339 }
340 }
341
OnRequestFocus(bool shouldFocus)342 void TextFieldDeclaration::OnRequestFocus(bool shouldFocus)
343 {
344 if (textFieldController_) {
345 textFieldController_->Focus(shouldFocus);
346 }
347 }
348
349 } // namespace OHOS::Ace
350