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