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_INPUT_PLACEHOLDER,
136 [](TextFieldDeclaration& declaration, const std::string& value) { declaration.SetPlaceholder(value); } },
137 { DOM_INPUT_SELECTED_END, [](TextFieldDeclaration& declaration,
138 const std::string& value) { declaration.SetSelectedEnd(StringToInt(value)); } },
139 { DOM_INPUT_SELECTED_START,
140 [](TextFieldDeclaration& declaration, const std::string& value) {
141 declaration.SetSelectedStart(StringToInt(value));
142 } },
143 { DOM_INPUT_SHOW_COUNTER, [](TextFieldDeclaration& declaration,
144 const std::string& value) { declaration.SetShowCounter(StringToBool(value)); } },
145 { DOM_SHOW_ICON_SRC,
146 [](TextFieldDeclaration& declaration, const std::string& value) { declaration.SetShowIconImage(value); } },
147 { DOM_INPUT_SHOW_PASSWORD_ICON,
148 [](TextFieldDeclaration& declaration, const std::string& value) {
149 declaration.SetShowPasswordIcon(StringToBool(value));
150 } },
151 { DOM_INPUT_SOFT_KEYBOARD_ENABLED,
152 [](TextFieldDeclaration& declaration, const std::string& value) {
153 declaration.SetSoftKeyboardEnabled(StringToBool(value));
154 } },
155 { DOM_INPUT_TYPE,
156 [](TextFieldDeclaration& declaration, const std::string& value) {
157 declaration.SetTextInputType(ConvertStrToTextInputType(value));
158 declaration.SetObscure(value == DOM_INPUT_TYPE_PASSWORD);
159 } },
160 { DOM_INPUT_VALUE,
161 [](TextFieldDeclaration& declaration, const std::string& value) { declaration.SetValue(value); } },
162 };
163 auto operatorIter = BinarySearchFindIndex(attrOperators, ArraySize(attrOperators), attr.first.c_str());
164 if (operatorIter != -1) {
165 attrOperators[operatorIter].value(*this, attr.second);
166 return true;
167 }
168 return false;
169 }
170
SetSpecializedStyle(const std::pair<std::string,std::string> & style)171 bool TextFieldDeclaration::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
172 {
173 // static linear map must be sorted by key.
174 static const LinearMapNode<void (*)(TextFieldDeclaration&, const std::string&)> styleOperators[] = {
175 { DOM_TEXT_ALLOW_SCALE,
176 [](TextFieldDeclaration& declaration, const std::string& value) {
177 declaration.GetTextStyle().SetAllowScale(StringToBool(value));
178 } },
179 { DOM_BACKGROUND_COLOR,
180 [](TextFieldDeclaration& declaration, const std::string& value) {
181 declaration.SetBgColor(declaration.ParseColor(value));
182 declaration.SetFocusBgColor(declaration.ParseColor(value));
183 } },
184 { DOM_CARET_COLOR,
185 [](TextFieldDeclaration& declaration, const std::string& value) {
186 declaration.SetCursorColor(declaration.ParseColor(value));
187 } },
188 { DOM_INPUT_COLOR,
189 [](TextFieldDeclaration& declaration, const std::string& value) {
190 declaration.GetTextStyle().SetTextColor(declaration.ParseColor(value));
191 declaration.SetFocusTextColor(declaration.ParseColor(value));
192 } },
193 { DOM_INPUT_CURSOR_COLOR,
194 [](TextFieldDeclaration& declaration, const std::string& value) {
195 declaration.SetCursorColor(declaration.ParseColor(value));
196 } },
197 { DOM_INPUT_FONT_FAMILY,
198 [](TextFieldDeclaration& declaration, const std::string& value) {
199 std::vector<std::string> fontFamilies;
200 std::stringstream sstr(value);
201 std::string fontFamily;
202 while (getline(sstr, fontFamily, ',')) {
203 fontFamilies.emplace_back(fontFamily);
204 }
205 declaration.GetTextStyle().SetFontFamilies(fontFamilies);
206 } },
207 { DOM_INPUT_FONT_SIZE,
208 [](TextFieldDeclaration& declaration, const std::string& value) {
209 declaration.GetTextStyle().SetFontSize(declaration.ParseDimension(value));
210 } },
211 { DOM_INPUT_FONT_WEIGHT,
212 [](TextFieldDeclaration& declaration, const std::string& value) {
213 declaration.GetTextStyle().SetFontWeight(ConvertStrToFontWeight(value));
214 } },
215 { DOM_PADDING,
216 [](TextFieldDeclaration& declaration, const std::string& value) {
217 Edge padding;
218 if (Edge::FromString(value, padding)) {
219 declaration.GetDecoration()->SetPadding(padding);
220 }
221 } },
222 { DOM_PADDING_BOTTOM,
223 [](TextFieldDeclaration& declaration, const std::string& value) {
224 auto padding = declaration.GetDecoration()->GetPadding();
225 padding.SetBottom(declaration.ParseDimension(value));
226 declaration.GetDecoration()->SetPadding(padding);
227 } },
228 { DOM_PADDING_END,
229 [](TextFieldDeclaration& declaration, const std::string& value) {
230 auto padding = declaration.GetDecoration()->GetPadding();
231 declaration.IsRightToLeft() ? padding.SetLeft(declaration.ParseDimension(value))
232 : padding.SetRight(declaration.ParseDimension(value));
233 declaration.GetDecoration()->SetPadding(padding);
234 } },
235 { DOM_PADDING_LEFT,
236 [](TextFieldDeclaration& declaration, const std::string& value) {
237 auto padding = declaration.GetDecoration()->GetPadding();
238 padding.SetLeft(declaration.ParseDimension(value));
239 declaration.GetDecoration()->SetPadding(padding);
240 } },
241 { DOM_PADDING_RIGHT,
242 [](TextFieldDeclaration& declaration, const std::string& value) {
243 auto padding = declaration.GetDecoration()->GetPadding();
244 padding.SetRight(declaration.ParseDimension(value));
245 declaration.GetDecoration()->SetPadding(padding);
246 } },
247 { DOM_PADDING_START,
248 [](TextFieldDeclaration& declaration, const std::string& value) {
249 auto padding = declaration.GetDecoration()->GetPadding();
250 declaration.IsRightToLeft() ? padding.SetRight(declaration.ParseDimension(value))
251 : padding.SetLeft(declaration.ParseDimension(value));
252 declaration.GetDecoration()->SetPadding(padding);
253 } },
254 { DOM_PADDING_TOP,
255 [](TextFieldDeclaration& declaration, const std::string& value) {
256 auto padding = declaration.GetDecoration()->GetPadding();
257 padding.SetTop(declaration.ParseDimension(value));
258 declaration.GetDecoration()->SetPadding(padding);
259 } },
260 { DOM_INPUT_PLACEHOLDER_COLOR,
261 [](TextFieldDeclaration& declaration, const std::string& value) {
262 declaration.SetPlaceholderColor(declaration.ParseColor(value));
263 declaration.SetFocusPlaceholderColor(declaration.ParseColor(value));
264 } },
265 };
266 if (IsRadiusStyle(style.first)) {
267 hasBoxRadius_ = true;
268 }
269 auto operatorIter = BinarySearchFindIndex(styleOperators, ArraySize(styleOperators), style.first.c_str());
270 if (operatorIter != -1) {
271 styleOperators[operatorIter].value(*this, style.second);
272 return true;
273 }
274 return false;
275 }
276
SetSpecializedEvent(int32_t pageId,const std::string & eventId,const std::string & event)277 bool TextFieldDeclaration::SetSpecializedEvent(int32_t pageId, const std::string& eventId, const std::string& event)
278 {
279 static const LinearMapNode<void (*)(TextFieldDeclaration&, const EventMarker&)> eventOperators[] = {
280 { DOM_CATCH_BUBBLE_CLICK,
281 [](TextFieldDeclaration& declaration, const EventMarker& event) {
282 EventMarker eventMarker(event);
283 eventMarker.SetCatchMode(true);
284 declaration.SetOnTap(eventMarker);
285 } },
286 { DOM_CHANGE,
287 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnTextChange(event); } },
288 { DOM_CLICK, [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnTap(event); } },
289 { DOM_INPUT_EVENT_ENTERKEYCLICK,
290 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnFinishInput(event); } },
291 { DOM_LONG_PRESS,
292 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnLongPress(event); } },
293 { DOM_INPUT_EVENT_OPTION_SELECT,
294 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnOptionsClick(event); } },
295 { DOM_INPUT_EVENT_SEARCH,
296 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnSearch(event); } },
297 { DOM_INPUT_EVENT_SELECT_CHANGE,
298 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnSelectChange(event); } },
299 { DOM_INPUT_EVENT_SHARE,
300 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnShare(event); } },
301 { DOM_INPUT_EVENT_TRANSLATE,
302 [](TextFieldDeclaration& declaration, const EventMarker& event) { declaration.SetOnTranslate(event); } },
303 };
304 auto operatorIter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
305 if (operatorIter != -1) {
306 eventOperators[operatorIter].value(*this, EventMarker(eventId, event, pageId));
307 return true;
308 }
309 return false;
310 }
311
CallSpecializedMethod(const std::string & method,const std::string & args)312 void TextFieldDeclaration::CallSpecializedMethod(const std::string& method, const std::string& args)
313 {
314 if (!textFieldController_) {
315 return;
316 }
317 if (method == DOM_INPUT_METHOD_SHOW_ERROR) {
318 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
319 if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != METHOD_SHOW_ERROR_ARGS_SIZE) {
320 LOGE("parse args error");
321 return;
322 }
323
324 std::unique_ptr<JsonValue> error = argsValue->GetArrayItem(0)->GetValue("error");
325 if (!error || !error->IsString()) {
326 LOGE("get error text failed");
327 return;
328 }
329 std::string errorText = error->GetString();
330 textFieldController_->ShowError(errorText);
331 } else if (method == DOM_INPUT_METHOD_DELETE) {
332 textFieldController_->Delete();
333 }
334 }
335
OnRequestFocus(bool shouldFocus)336 void TextFieldDeclaration::OnRequestFocus(bool shouldFocus)
337 {
338 if (textFieldController_) {
339 textFieldController_->Focus(shouldFocus);
340 }
341 }
342
343 } // namespace OHOS::Ace
344