• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "frameworks/bridge/common/dom/dom_textarea.h"
17 
18 #include <iostream>
19 
20 #include "frameworks/bridge/common/dom/input/dom_textfield_util.h"
21 #include "frameworks/bridge/common/utils/utils.h"
22 
23 namespace OHOS::Ace::Framework {
24 namespace {
25 
26 constexpr uint32_t TEXTAREA_MAXLENGTH_VALUE_DEFAULT = std::numeric_limits<uint32_t>::max();
27 constexpr Dimension BOX_HOVER_RADIUS = 18.0_vp;
28 
29 } // namespace
30 
DOMTextarea(NodeId nodeId,const std::string & nodeName)31 DOMTextarea::DOMTextarea(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName)
32 {
33     textAreaChild_ = AceType::MakeRefPtr<TextFieldComponent>();
34     textAreaChild_->SetTextInputType(TextInputType::MULTILINE);
35     textAreaChild_->SetTextEditController(AceType::MakeRefPtr<TextEditController>());
36     textAreaChild_->SetTextFieldController(AceType::MakeRefPtr<TextFieldController>());
37 }
38 
ResetInitializedStyle()39 void DOMTextarea::ResetInitializedStyle()
40 {
41     InitializeStyle();
42 }
43 
InitializeStyle()44 void DOMTextarea::InitializeStyle()
45 {
46     auto boxComponent = GetBoxComponent();
47     auto component = textAreaChild_;
48     auto theme = GetTheme<TextFieldTheme>();
49     if (!boxComponent || !component || !theme) {
50         return;
51     }
52 
53     component->SetTextMaxLines(TEXTAREA_MAXLENGTH_VALUE_DEFAULT);
54     component->SetCursorColor(theme->GetCursorColor());
55     component->SetPlaceholderColor(theme->GetPlaceholderColor());
56     component->SetFocusBgColor(theme->GetFocusBgColor());
57     component->SetFocusPlaceholderColor(theme->GetFocusPlaceholderColor());
58     component->SetFocusTextColor(theme->GetFocusTextColor());
59     component->SetBgColor(theme->GetBgColor());
60     component->SetTextColor(theme->GetTextColor());
61     component->SetSelectedColor(theme->GetSelectedColor());
62     component->SetHoverColor(theme->GetHoverColor());
63     component->SetPressColor(theme->GetPressColor());
64     textStyle_.SetTextColor(theme->GetTextColor());
65     textStyle_.SetFontSize(theme->GetFontSize());
66     textStyle_.SetFontWeight(theme->GetFontWeight());
67     std::vector<std::string> textareaFontFamilyValueDefault = {
68         "sans-serif",
69     };
70     textStyle_.SetFontFamilies(textareaFontFamilyValueDefault);
71     component->SetTextStyle(textStyle_);
72     component->SetCountTextStyle(theme->GetCountTextStyle());
73     component->SetOverCountStyle(theme->GetOverCountStyle());
74     component->SetCountTextStyleOuter(theme->GetCountTextStyleOuter());
75     component->SetOverCountStyleOuter(theme->GetOverCountStyleOuter());
76 
77     component->SetErrorBorderWidth(theme->GetErrorBorderWidth());
78     component->SetErrorBorderColor(theme->GetErrorBorderColor());
79 
80     RefPtr<Decoration> backDecoration = AceType::MakeRefPtr<Decoration>();
81     backDecoration->SetPadding(theme->GetPadding());
82     backDecoration->SetBackgroundColor(theme->GetBgColor());
83     defaultRadius_ = theme->GetBorderRadius();
84     backDecoration->SetBorderRadius(defaultRadius_);
85     if (boxComponent->GetBackDecoration()) {
86         backDecoration->SetImage(boxComponent->GetBackDecoration()->GetImage());
87         backDecoration->SetGradient(boxComponent->GetBackDecoration()->GetGradient());
88     }
89     component->SetDecoration(backDecoration);
90     component->SetIconSize(theme->GetIconSize());
91     component->SetIconHotZoneSize(theme->GetIconHotZoneSize());
92 
93     boxComponent->SetBackDecoration(backDecoration);
94     boxComponent->SetPadding(theme->GetPadding());
95 }
96 
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)97 bool DOMTextarea::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
98 {
99     static const DOMTextareaMap textAreaAttrMap = {
100         { DOM_AUTO_FOCUS, [](const std::string& val,
101                               DOMTextarea& textarea) { textarea.textAreaChild_->SetAutoFocus(StringToBool(val)); } },
102         { DOM_TEXTAREA_VALUE,
103             [](const std::string& val, DOMTextarea& textarea) { textarea.textAreaChild_->SetValue(val); } },
104         { DOM_DISABLED, [](const std::string& val,
105                         DOMTextarea& textarea) { textarea.textAreaChild_->SetEnabled(!StringToBool(val)); } },
106         { DOM_INPUT_ENTERKEYTYPE,
107             [](const std::string& val, DOMTextarea& textarea) {
108                 textarea.textAreaChild_->SetAction(ConvertStrToTextInputAction(val));
109             } },
110         { DOM_TEXTAREA_PLACEHOLDER,
111             [](const std::string& val, DOMTextarea& textarea) { textarea.textAreaChild_->SetPlaceholder(val); } },
112         { DOM_TEXTAREA_MAXLENGTH,
113             [](const std::string& val, DOMTextarea& textarea) {
114                 int32_t tmp = StringUtils::StringToInt(val);
115                 textarea.textAreaChild_->SetMaxLength(
116                     tmp >= 0 ? (uint32_t)(tmp) : std::numeric_limits<uint32_t>::max());
117             } },
118         { DOM_TEXTAREA_MAXLINES,
119             [](const std::string& val, DOMTextarea& textarea) {
120                 textarea.textAreaChild_->SetTextMaxLines(std::max(StringToInt(val), 1));
121             } },
122         { DOM_TEXTAREA_OBSCURE,
123             [](const std::string& val, DOMTextarea& textarea) {
124                 textarea.textAreaChild_->SetObscure(StringToBool(val));
125             } },
126         { DOM_TEXTAREA_EXTEND, [](const std::string& val,
127                                DOMTextarea& textarea) { textarea.textAreaChild_->SetExtend(StringToBool(val)); } },
128         { DOM_TEXTAREA_SHOW_COUNTER,
129             [](const std::string& val, DOMTextarea& textarea) {
130                 textarea.textAreaChild_->SetShowCounter(StringToBool(val));
131             } },
132         { DOM_ICON_SRC,
133             [](const std::string& val, DOMTextarea& textarea) { textarea.textAreaChild_->SetIconImage(val); } },
134         { DOM_INPUT_SELECTED_START,
135             [](const std::string& val, DOMTextarea& textarea) {
136                 textarea.textAreaChild_->SetSelectedStart(StringToInt(val));
137             } },
138         { DOM_INPUT_SELECTED_END,
139             [](const std::string& val, DOMTextarea& textarea) {
140                 textarea.textAreaChild_->SetSelectedEnd(StringToInt(val)); } },
141         { DOM_INPUT_SOFT_KEYBOARD_ENABLED,
142             [](const std::string& val, DOMTextarea& textarea) {
143                 textarea.textAreaChild_->SetSoftKeyboardEnabled(StringToBool(val));
144             } },
145     };
146     auto textareaAttrIter = textAreaAttrMap.find(attr.first);
147     if (textareaAttrIter != textAreaAttrMap.end()) {
148         textareaAttrIter->second(attr.second, *this);
149         return true;
150     }
151     return false;
152 }
153 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)154 bool DOMTextarea::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
155 {
156     if (!textAreaChild_) {
157         return false;
158     }
159     static const DOMTextareaMap textAreaStyleMap = {
160         { DOM_BACKGROUND_COLOR,
161             [](const std::string& val, DOMTextarea& textarea) {
162                 textarea.textAreaChild_->SetBgColor(textarea.ParseColor(val));
163                 textarea.textAreaChild_->SetFocusBgColor(textarea.ParseColor(val));
164             } },
165         { DOM_TEXTAREA_COLOR,
166             [](const std::string& val, DOMTextarea& textarea) {
167                 textarea.textStyle_.SetTextColor(textarea.ParseColor(val));
168                 textarea.textAreaChild_->SetFocusTextColor(textarea.ParseColor(val));
169             } },
170         { DOM_TEXTAREA_FONT_SIZE,
171             [](const std::string& val, DOMTextarea& textarea) {
172                 textarea.textStyle_.SetFontSize(textarea.ParseDimension(val));
173             } },
174         { DOM_TEXTAREA_FONT_WEIGHT,
175             [](const std::string& val, DOMTextarea& textarea) {
176                 textarea.textStyle_.SetFontWeight(ConvertStrToFontWeight(val));
177             } },
178         { DOM_TEXTAREA_PLACEHOLDER_COLOR,
179             [](const std::string& val, DOMTextarea& textarea) {
180                 textarea.textAreaChild_->SetPlaceholderColor(textarea.ParseColor(val));
181                 textarea.textAreaChild_->SetFocusPlaceholderColor(textarea.ParseColor(val));
182             } },
183         { DOM_TEXTAREA_FONT_FAMILY,
184             [](const std::string& val, DOMTextarea& textarea) {
185                 textarea.textStyle_.SetFontFamilies(textarea.ParseFontFamilies(val));
186             } },
187         { DOM_TEXT_ALLOW_SCALE, [](const std::string& val,
188                                 DOMTextarea& textarea) { textarea.textStyle_.SetAllowScale(StringToBool(val)); } },
189         { DOM_TEXTAREA_CURSOR_COLOR,
190             [](const std::string& val, DOMTextarea& textarea) {
191                 textarea.textAreaChild_->SetCursorColor(textarea.ParseColor(val));
192             } },
193         { DOM_CARET_COLOR,
194             [](const std::string& val, DOMTextarea& textarea) {
195                 textarea.textAreaChild_->SetCursorColor(textarea.ParseColor(val));
196             } },
197         { DOM_PADDING,
198             [](const std::string& val, DOMTextarea& textarea) {
199                 Edge padding;
200                 if (Edge::FromString(val, padding)) {
201                     textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
202                 }
203             } },
204         { DOM_PADDING_LEFT,
205             [](const std::string& val, DOMTextarea& textarea) {
206                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
207                 padding.SetLeft(textarea.ParseDimension(val));
208                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
209             } },
210         { DOM_PADDING_RIGHT,
211             [](const std::string& val, DOMTextarea& textarea) {
212                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
213                 padding.SetRight(textarea.ParseDimension(val));
214                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
215             } },
216         { DOM_PADDING_TOP,
217             [](const std::string& val, DOMTextarea& textarea) {
218                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
219                 padding.SetTop(textarea.ParseDimension(val));
220                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
221             } },
222         { DOM_PADDING_BOTTOM,
223             [](const std::string& val, DOMTextarea& textarea) {
224                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
225                 padding.SetBottom(textarea.ParseDimension(val));
226                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
227             } },
228         { DOM_PADDING_START,
229             [](const std::string& val, DOMTextarea& textarea) {
230                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
231                 textarea.IsRightToLeft() ? padding.SetRight(textarea.ParseDimension(val))
232                                          : padding.SetLeft(textarea.ParseDimension(val));
233                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
234             } },
235         { DOM_PADDING_END,
236             [](const std::string& val, DOMTextarea& textarea) {
237                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
238                 textarea.IsRightToLeft() ? padding.SetLeft(textarea.ParseDimension(val))
239                                          : padding.SetRight(textarea.ParseDimension(val));
240                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
241             } },
242     };
243     auto textareaStyleIter = textAreaStyleMap.find(style.first);
244     if (textareaStyleIter != textAreaStyleMap.end()) {
245         textareaStyleIter->second(style.second, *this);
246         return true;
247     }
248     hasBoxRadius_ = DOMTextFieldUtil::IsRadiusStyle(style.first);
249     return false;
250 }
251 
AddSpecializedEvent(int32_t pageId,const std::string & event)252 bool DOMTextarea::AddSpecializedEvent(int32_t pageId, const std::string& event)
253 {
254     static const LinearMapNode<void (*)(const RefPtr<TextFieldComponent>&, const EventMarker&)> eventOperators[] = {
255         { DOM_CATCH_BUBBLE_CLICK,
256             [](const RefPtr<TextFieldComponent>& component, const EventMarker& event) {
257                 EventMarker eventMarker(event);
258                 eventMarker.SetCatchMode(true);
259                 component->SetOnTap(eventMarker);
260             } },
261         { DOM_CHANGE, [](const RefPtr<TextFieldComponent>& component,
262                       const EventMarker& event) { component->SetOnTextChange(event); } },
263         { DOM_CLICK,
264             [](const RefPtr<TextFieldComponent>& component, const EventMarker& event) {
265                 EventMarker eventMarker(event);
266                 eventMarker.SetCatchMode(false);
267                 component->SetOnTap(eventMarker);
268             } },
269         { DOM_LONG_PRESS, [](const RefPtr<TextFieldComponent>& component,
270                           const EventMarker& event) { component->SetOnLongPress(event); } },
271         { DOM_INPUT_EVENT_OPTION_SELECT, [](const RefPtr<TextFieldComponent>& component,
272                                          const EventMarker& event) { component->SetOnOptionsClick(event); } },
273         { DOM_INPUT_EVENT_SEARCH, [](const RefPtr<TextFieldComponent>& component,
274                                   const EventMarker& event) { component->SetOnSearch(event); } },
275         { DOM_INPUT_EVENT_SELECT_CHANGE, [](const RefPtr<TextFieldComponent>& component,
276                                              const EventMarker& event) { component->SetOnSelectChange(event); } },
277         { DOM_INPUT_EVENT_SHARE, [](const RefPtr<TextFieldComponent>& component,
278                                  const EventMarker& event) { component->SetOnShare(event); } },
279         { DOM_INPUT_EVENT_TRANSLATE, [](const RefPtr<TextFieldComponent>& component,
280                                      const EventMarker& event) { component->SetOnTranslate(event); } },
281     };
282     auto operatorIter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
283     if (operatorIter != -1) {
284         eventOperators[operatorIter].value(textAreaChild_, EventMarker(GetNodeIdForEvent(), event, pageId));
285         return true;
286     }
287     return false;
288 }
289 
CallSpecializedMethod(const std::string & method,const std::string & args)290 void DOMTextarea::CallSpecializedMethod(const std::string& method, const std::string& args)
291 {
292     if (method == DOM_INPUT_METHOD_DELETE) {
293         auto textField = AceType::DynamicCast<TextFieldComponent>(textAreaChild_);
294         if (!textField) {
295             return;
296         }
297         auto controller = textField->GetTextFieldController();
298         if (!controller) {
299             return;
300         }
301         controller->Delete();
302     }
303 }
304 
OnRequestFocus(bool shouldFocus)305 void DOMTextarea::OnRequestFocus(bool shouldFocus)
306 {
307     if (!textAreaChild_) {
308         return;
309     }
310     auto textFieldController = textAreaChild_->GetTextFieldController();
311     if (!textFieldController) {
312         return;
313     }
314     textFieldController->Focus(shouldFocus);
315 }
316 
PrepareSpecializedComponent()317 void DOMTextarea::PrepareSpecializedComponent()
318 {
319     RefPtr<BoxComponent> boxComponent = GetBoxComponent();
320     if (!boxComponent || !textAreaChild_) {
321         return;
322     }
323     boxComponent_->SetMouseAnimationType(HoverAnimationType::OPACITY);
324     textAreaChild_->SetTextDirection(IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR);
325     textAreaChild_->SetTextStyle(textStyle_);
326     textAreaChild_->SetInputOptions(inputOptions_);
327     textAreaChild_->SetImageFill(GetImageFill());
328     UpdateDecoration();
329     boxComponent->SetPadding(Edge());
330     boxComponent->SetDeliverMinToChild(true);
331     auto theme = GetTheme<TextFieldTheme>();
332     if (boxComponent_->GetHeightDimension().Value() < 0.0 && theme) {
333         boxComponent->SetHeight(theme->GetHeight().Value(), theme->GetHeight().Unit());
334     }
335     textAreaChild_->SetHeight(boxComponent_->GetHeightDimension());
336     if (textAreaChild_->IsExtend()) {
337         boxComponent_->SetHeight(-1.0, DimensionUnit::PX);
338     }
339 }
340 
UpdateDecoration()341 void DOMTextarea::UpdateDecoration()
342 {
343     RefPtr<BoxComponent> boxComponent = GetBoxComponent();
344     if (!boxComponent || !textAreaChild_) {
345         return;
346     }
347     RefPtr<Decoration> backDecoration = boxComponent->GetBackDecoration();
348 
349     // set box border properties to child component
350     RefPtr<Decoration> decoration = textAreaChild_->GetDecoration();
351     if (backDecoration) {
352         Border boxBorder = backDecoration->GetBorder();
353         if (decoration) {
354             if (hasBoxRadius_) {
355                 decoration->SetBorder(boxBorder);
356             } else {
357                 Border border = decoration->GetBorder();
358                 border.SetLeftEdge(boxBorder.Left());
359                 border.SetRightEdge(boxBorder.Right());
360                 border.SetTopEdge(boxBorder.Top());
361                 border.SetBottomEdge(boxBorder.Bottom());
362                 decoration->SetBorder(border);
363             }
364             textAreaChild_->SetOriginBorder(decoration->GetBorder());
365         }
366         // clear box properties
367         if (backDecoration->GetImage() || backDecoration->GetGradient().IsValid()) {
368             // clear box properties except background image
369             backDecoration->SetBackgroundColor(Color::TRANSPARENT);
370             Border border;
371             if (!hasBoxRadius_) {
372                 border.SetBorderRadius(defaultRadius_);
373             } else {
374                 border.SetTopLeftRadius(boxBorder.TopLeftRadius());
375                 border.SetTopRightRadius(boxBorder.TopRightRadius());
376                 border.SetBottomLeftRadius(boxBorder.BottomLeftRadius());
377                 border.SetBottomRightRadius(boxBorder.BottomRightRadius());
378             }
379             backDecoration->SetBorder(border);
380         } else {
381             backDecoration = AceType::MakeRefPtr<Decoration>();
382             backDecoration->SetBorderRadius(Radius(BOX_HOVER_RADIUS));
383             boxComponent->SetBackDecoration(backDecoration);
384         }
385     }
386 }
387 
388 } // namespace OHOS::Ace::Framework
389