• 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_OVERFLOWX,
127             [](const std::string& val, DOMTextarea& textarea) {
128                 textarea.textAreaChild_->SetOverflowX(ConvertStrToTextFieldOverflowX(val));
129             } },
130         { DOM_TEXTAREA_EXTEND,
131             [](const std::string& val, DOMTextarea& textarea) {
132                 textarea.textAreaChild_->SetExtend(StringToBool(val));
133             } },
134         { DOM_TEXTAREA_SHOW_COUNTER,
135             [](const std::string& val, DOMTextarea& textarea) {
136                 textarea.textAreaChild_->SetShowCounter(StringToBool(val));
137             } },
138         { DOM_ICON_SRC,
139             [](const std::string& val, DOMTextarea& textarea) { textarea.textAreaChild_->SetIconImage(val); } },
140         { DOM_INPUT_SELECTED_START,
141             [](const std::string& val, DOMTextarea& textarea) {
142                 textarea.textAreaChild_->SetSelectedStart(StringToInt(val));
143             } },
144         { DOM_INPUT_SELECTED_END,
145             [](const std::string& val, DOMTextarea& textarea) {
146                 textarea.textAreaChild_->SetSelectedEnd(StringToInt(val)); } },
147         { DOM_INPUT_SOFT_KEYBOARD_ENABLED,
148             [](const std::string& val, DOMTextarea& textarea) {
149                 textarea.textAreaChild_->SetSoftKeyboardEnabled(StringToBool(val));
150             } },
151     };
152     auto textareaAttrIter = textAreaAttrMap.find(attr.first);
153     if (textareaAttrIter != textAreaAttrMap.end()) {
154         textareaAttrIter->second(attr.second, *this);
155         return true;
156     }
157     return false;
158 }
159 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)160 bool DOMTextarea::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
161 {
162     if (!textAreaChild_) {
163         return false;
164     }
165     static const DOMTextareaMap textAreaStyleMap = {
166         { DOM_BACKGROUND_COLOR,
167             [](const std::string& val, DOMTextarea& textarea) {
168                 textarea.textAreaChild_->SetBgColor(textarea.ParseColor(val));
169                 textarea.textAreaChild_->SetFocusBgColor(textarea.ParseColor(val));
170             } },
171         { DOM_TEXTAREA_COLOR,
172             [](const std::string& val, DOMTextarea& textarea) {
173                 textarea.textStyle_.SetTextColor(textarea.ParseColor(val));
174                 textarea.textAreaChild_->SetFocusTextColor(textarea.ParseColor(val));
175             } },
176         { DOM_TEXTAREA_FONT_SIZE,
177             [](const std::string& val, DOMTextarea& textarea) {
178                 textarea.textStyle_.SetFontSize(textarea.ParseDimension(val));
179             } },
180         { DOM_TEXTAREA_FONT_WEIGHT,
181             [](const std::string& val, DOMTextarea& textarea) {
182                 textarea.textStyle_.SetFontWeight(ConvertStrToFontWeight(val));
183             } },
184         { DOM_TEXTAREA_PLACEHOLDER_COLOR,
185             [](const std::string& val, DOMTextarea& textarea) {
186                 textarea.textAreaChild_->SetPlaceholderColor(textarea.ParseColor(val));
187                 textarea.textAreaChild_->SetFocusPlaceholderColor(textarea.ParseColor(val));
188             } },
189         { DOM_TEXTAREA_FONT_FAMILY,
190             [](const std::string& val, DOMTextarea& textarea) {
191                 textarea.textStyle_.SetFontFamilies(textarea.ParseFontFamilies(val));
192             } },
193         { DOM_TEXT_ALLOW_SCALE, [](const std::string& val,
194                                 DOMTextarea& textarea) { textarea.textStyle_.SetAllowScale(StringToBool(val)); } },
195         { DOM_TEXTAREA_CURSOR_COLOR,
196             [](const std::string& val, DOMTextarea& textarea) {
197                 textarea.textAreaChild_->SetCursorColor(textarea.ParseColor(val));
198             } },
199         { DOM_CARET_COLOR,
200             [](const std::string& val, DOMTextarea& textarea) {
201                 textarea.textAreaChild_->SetCursorColor(textarea.ParseColor(val));
202             } },
203         { DOM_PADDING,
204             [](const std::string& val, DOMTextarea& textarea) {
205                 Edge padding;
206                 if (Edge::FromString(val, padding)) {
207                     textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
208                 }
209             } },
210         { DOM_PADDING_LEFT,
211             [](const std::string& val, DOMTextarea& textarea) {
212                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
213                 padding.SetLeft(textarea.ParseDimension(val));
214                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
215             } },
216         { DOM_PADDING_RIGHT,
217             [](const std::string& val, DOMTextarea& textarea) {
218                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
219                 padding.SetRight(textarea.ParseDimension(val));
220                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
221             } },
222         { DOM_PADDING_TOP,
223             [](const std::string& val, DOMTextarea& textarea) {
224                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
225                 padding.SetTop(textarea.ParseDimension(val));
226                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
227             } },
228         { DOM_PADDING_BOTTOM,
229             [](const std::string& val, DOMTextarea& textarea) {
230                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
231                 padding.SetBottom(textarea.ParseDimension(val));
232                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
233             } },
234         { DOM_PADDING_START,
235             [](const std::string& val, DOMTextarea& textarea) {
236                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
237                 textarea.IsRightToLeft() ? padding.SetRight(textarea.ParseDimension(val))
238                                          : padding.SetLeft(textarea.ParseDimension(val));
239                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
240             } },
241         { DOM_PADDING_END,
242             [](const std::string& val, DOMTextarea& textarea) {
243                 auto padding = textarea.textAreaChild_->GetDecoration()->GetPadding();
244                 textarea.IsRightToLeft() ? padding.SetLeft(textarea.ParseDimension(val))
245                                          : padding.SetRight(textarea.ParseDimension(val));
246                 textarea.textAreaChild_->GetDecoration()->SetPadding(padding);
247             } },
248     };
249     auto textareaStyleIter = textAreaStyleMap.find(style.first);
250     if (textareaStyleIter != textAreaStyleMap.end()) {
251         textareaStyleIter->second(style.second, *this);
252         return true;
253     }
254     hasBoxRadius_ = DOMTextFieldUtil::IsRadiusStyle(style.first);
255     return false;
256 }
257 
AddSpecializedEvent(int32_t pageId,const std::string & event)258 bool DOMTextarea::AddSpecializedEvent(int32_t pageId, const std::string& event)
259 {
260     static const LinearMapNode<void (*)(const RefPtr<TextFieldComponent>&, const EventMarker&)> eventOperators[] = {
261         { DOM_CATCH_BUBBLE_CLICK,
262             [](const RefPtr<TextFieldComponent>& component, const EventMarker& event) {
263                 EventMarker eventMarker(event);
264                 eventMarker.SetCatchMode(true);
265                 component->SetOnTap(eventMarker);
266             } },
267         { DOM_CHANGE, [](const RefPtr<TextFieldComponent>& component,
268                       const EventMarker& event) { component->SetOnTextChange(event); } },
269         { DOM_CLICK,
270             [](const RefPtr<TextFieldComponent>& component, const EventMarker& event) {
271                 EventMarker eventMarker(event);
272                 eventMarker.SetCatchMode(false);
273                 component->SetOnTap(eventMarker);
274             } },
275         { DOM_LONG_PRESS, [](const RefPtr<TextFieldComponent>& component,
276                           const EventMarker& event) { component->SetOnLongPress(event); } },
277         { DOM_INPUT_EVENT_OPTION_SELECT, [](const RefPtr<TextFieldComponent>& component,
278                                          const EventMarker& event) { component->SetOnOptionsClick(event); } },
279         { DOM_INPUT_EVENT_SEARCH, [](const RefPtr<TextFieldComponent>& component,
280                                   const EventMarker& event) { component->SetOnSearch(event); } },
281         { DOM_INPUT_EVENT_SELECT_CHANGE, [](const RefPtr<TextFieldComponent>& component,
282                                              const EventMarker& event) { component->SetOnSelectChange(event); } },
283         { DOM_INPUT_EVENT_SHARE, [](const RefPtr<TextFieldComponent>& component,
284                                  const EventMarker& event) { component->SetOnShare(event); } },
285         { DOM_INPUT_EVENT_TRANSLATE, [](const RefPtr<TextFieldComponent>& component,
286                                      const EventMarker& event) { component->SetOnTranslate(event); } },
287     };
288     auto operatorIter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
289     if (operatorIter != -1) {
290         eventOperators[operatorIter].value(textAreaChild_, EventMarker(GetNodeIdForEvent(), event, pageId));
291         return true;
292     }
293     return false;
294 }
295 
CallSpecializedMethod(const std::string & method,const std::string & args)296 void DOMTextarea::CallSpecializedMethod(const std::string& method, const std::string& args)
297 {
298     if (method == DOM_INPUT_METHOD_DELETE) {
299         auto textField = AceType::DynamicCast<TextFieldComponent>(textAreaChild_);
300         if (!textField) {
301             return;
302         }
303         auto controller = textField->GetTextFieldController();
304         if (!controller) {
305             return;
306         }
307         controller->Delete();
308     }
309 }
310 
OnRequestFocus(bool shouldFocus)311 void DOMTextarea::OnRequestFocus(bool shouldFocus)
312 {
313     if (!textAreaChild_) {
314         return;
315     }
316     auto textFieldController = textAreaChild_->GetTextFieldController();
317     if (!textFieldController) {
318         return;
319     }
320     textFieldController->Focus(shouldFocus);
321 }
322 
PrepareSpecializedComponent()323 void DOMTextarea::PrepareSpecializedComponent()
324 {
325     RefPtr<BoxComponent> boxComponent = GetBoxComponent();
326     if (!boxComponent || !textAreaChild_) {
327         return;
328     }
329     boxComponent_->SetMouseAnimationType(HoverAnimationType::OPACITY);
330     textAreaChild_->SetTextDirection(IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR);
331     textAreaChild_->SetTextStyle(textStyle_);
332     textAreaChild_->SetInputOptions(inputOptions_);
333     textAreaChild_->SetImageFill(GetImageFill());
334     UpdateDecoration();
335     boxComponent->SetPadding(Edge());
336     boxComponent->SetDeliverMinToChild(true);
337     auto theme = GetTheme<TextFieldTheme>();
338     if (boxComponent_->GetHeightDimension().Value() < 0.0 && theme) {
339         boxComponent->SetHeight(theme->GetHeight().Value(), theme->GetHeight().Unit());
340     }
341     textAreaChild_->SetHeight(boxComponent_->GetHeightDimension());
342     if (textAreaChild_->IsExtend()) {
343         boxComponent_->SetHeight(-1.0, DimensionUnit::PX);
344     }
345 }
346 
UpdateDecoration()347 void DOMTextarea::UpdateDecoration()
348 {
349     RefPtr<BoxComponent> boxComponent = GetBoxComponent();
350     if (!boxComponent || !textAreaChild_) {
351         return;
352     }
353     RefPtr<Decoration> backDecoration = boxComponent->GetBackDecoration();
354 
355     // set box border properties to child component
356     RefPtr<Decoration> decoration = textAreaChild_->GetDecoration();
357     if (backDecoration) {
358         Border boxBorder = backDecoration->GetBorder();
359         if (decoration) {
360             if (hasBoxRadius_) {
361                 decoration->SetBorder(boxBorder);
362             } else {
363                 Border border = decoration->GetBorder();
364                 border.SetLeftEdge(boxBorder.Left());
365                 border.SetRightEdge(boxBorder.Right());
366                 border.SetTopEdge(boxBorder.Top());
367                 border.SetBottomEdge(boxBorder.Bottom());
368                 decoration->SetBorder(border);
369             }
370             textAreaChild_->SetOriginBorder(decoration->GetBorder());
371         }
372         // clear box properties
373         if (backDecoration->GetImage() || backDecoration->GetGradient().IsValid()) {
374             // clear box properties except background image
375             backDecoration->SetBackgroundColor(Color::TRANSPARENT);
376             Border border;
377             if (!hasBoxRadius_) {
378                 border.SetBorderRadius(defaultRadius_);
379             } else {
380                 border.SetTopLeftRadius(boxBorder.TopLeftRadius());
381                 border.SetTopRightRadius(boxBorder.TopRightRadius());
382                 border.SetBottomLeftRadius(boxBorder.BottomLeftRadius());
383                 border.SetBottomRightRadius(boxBorder.BottomRightRadius());
384             }
385             backDecoration->SetBorder(border);
386         } else {
387             backDecoration = AceType::MakeRefPtr<Decoration>();
388             backDecoration->SetBorderRadius(Radius(BOX_HOVER_RADIUS));
389             boxComponent->SetBackDecoration(backDecoration);
390         }
391     }
392 }
393 
394 } // namespace OHOS::Ace::Framework
395