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