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_input.h"
17
18 #include <set>
19
20 #include "core/components/checkable/checkable_component.h"
21 #include "core/components/text_field/text_field_component.h"
22 #include "frameworks/bridge/common/dom/dom_form.h"
23 #include "frameworks/bridge/common/dom/input/dom_button_util.h"
24 #include "frameworks/bridge/common/dom/input/dom_checkbox_util.h"
25 #include "frameworks/bridge/common/dom/input/dom_radio_util.h"
26 #include "frameworks/bridge/common/dom/input/dom_textfield_util.h"
27 #include "frameworks/bridge/common/utils/utils.h"
28
29 namespace OHOS::Ace::Framework {
30 namespace {
31
32 constexpr uint32_t METHOD_SHOW_ERROR_ARGS_SIZE = 1;
33
34 // input type
35 constexpr char INPUT_TYPE_BUTTON[] = "button";
36 constexpr char INPUT_TYPE_CHECKBOX[] = "checkbox";
37 constexpr char INPUT_TYPE_RADIO[] = "radio";
38 constexpr char INPUT_TYPE_TEXT[] = "text";
39 constexpr char INPUT_TYPE_EMAIL[] = "email";
40 constexpr char INPUT_TYPE_DATE[] = "date";
41 constexpr char INPUT_TYPE_TIME[] = "time";
42 constexpr char INPUT_TYPE_NUMBER[] = "number";
43 constexpr char INPUT_TYPE_PASSWORD[] = "password";
44 constexpr char INPUT_TYPE_SUBMIT[] = "submit";
45 constexpr char INPUT_TYPE_RESET[] = "reset";
46
47 std::set<std::string> g_textCategory;
48
49 // If type is changed between g_textCategory, there is no need to recreate components.
ShouldCreateNewComponent(const std::string & oldType,const std::string & newType)50 bool ShouldCreateNewComponent(const std::string& oldType, const std::string& newType)
51 {
52 if (g_textCategory.empty()) {
53 g_textCategory = std::set<std::string>({ INPUT_TYPE_TEXT, INPUT_TYPE_EMAIL, INPUT_TYPE_DATE, INPUT_TYPE_TIME,
54 INPUT_TYPE_NUMBER, INPUT_TYPE_PASSWORD });
55 }
56 return g_textCategory.find(oldType) == g_textCategory.end() || g_textCategory.find(newType) == g_textCategory.end();
57 }
58
GetDomFormNode(RefPtr<DOMNode> node)59 RefPtr<DOMForm> GetDomFormNode(RefPtr<DOMNode> node)
60 {
61 RefPtr<DOMForm> formNode;
62 while (node) {
63 if (AceType::InstanceOf<DOMForm>(node)) {
64 formNode = AceType::DynamicCast<DOMForm>(node);
65 break;
66 }
67 node = node->GetParentNode();
68 }
69 return formNode;
70 }
71
72 } // namespace
73
DOMInput(NodeId nodeId,const std::string & nodeName)74 DOMInput::DOMInput(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName) {}
75
~DOMInput()76 DOMInput::~DOMInput()
77 {
78 if (!checkableChangeMarker_.IsEmpty()) {
79 BackEndEventManager<void(const std::string&)>::GetInstance().RemoveBackEndEvent(checkableChangeMarker_);
80 }
81 }
82
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)83 bool DOMInput::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
84 {
85 static const std::set<std::string> inputCategory { INPUT_TYPE_BUTTON, INPUT_TYPE_CHECKBOX, INPUT_TYPE_RADIO,
86 INPUT_TYPE_TEXT, INPUT_TYPE_EMAIL, INPUT_TYPE_DATE, INPUT_TYPE_TIME, INPUT_TYPE_NUMBER, INPUT_TYPE_PASSWORD,
87 INPUT_TYPE_RESET, INPUT_TYPE_SUBMIT };
88 if (attr.first == DOM_INPUT_TYPE) {
89 std::string typeName = attr.second;
90 if (typeName.empty() || inputCategory.find(typeName) == inputCategory.end()) {
91 typeName = INPUT_TYPE_TEXT;
92 }
93 type_.second = ShouldCreateNewComponent(type_.first, typeName);
94 type_.first = typeName;
95 } else if (attr.first == DOM_INPUT_NAME) {
96 SetName(attr.second);
97 } else if (attr.first == DOM_INPUT_VALUE) {
98 SetOriginValue(attr.second);
99 } else if (attr.first == DOM_INPUT_CHECKED) {
100 SetOriginChecked(StringToBool(attr.second));
101 }
102 inputAttrs_[attr.first] = attr.second;
103 return false;
104 }
105
ResetInitializedStyle()106 void DOMInput::ResetInitializedStyle()
107 {
108 if (type_.first == INPUT_TYPE_CHECKBOX) {
109 InitCheckable<CheckboxComponent, CheckboxTheme>();
110 } else if (type_.first == INPUT_TYPE_RADIO) {
111 InitCheckable<RadioComponent<std::string>, RadioTheme>();
112 } else if ((type_.first == INPUT_TYPE_BUTTON) || (type_.first == INPUT_TYPE_SUBMIT) ||
113 (type_.first == INPUT_TYPE_RESET)) {
114 InitButton();
115 } else {
116 const auto& theme = GetTheme<TextFieldTheme>();
117 DOMTextFieldUtil::InitDefaultValue(
118 GetBoxComponent(), AceType::DynamicCast<TextFieldComponent>(inputChild_), theme);
119 DOMTextFieldUtil::SetDisableStyle(AceType::DynamicCast<TextFieldComponent>(inputChild_), theme);
120 }
121 }
122
SetSpecializedStyle(const std::pair<std::string,std::string> & style)123 bool DOMInput::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
124 {
125 inputStyles_[style.first] = style.second;
126 return false;
127 }
128
AddSpecializedEvent(int32_t pageId,const std::string & event)129 bool DOMInput::AddSpecializedEvent(int32_t pageId, const std::string& event)
130 {
131 tempEvent_.emplace_back(event);
132 pageId_ = pageId;
133 if (event == DOM_CLICK || event == DOM_CATCH_BUBBLE_CLICK) {
134 return true;
135 }
136 return false;
137 }
138
CallSpecializedMethod(const std::string & method,const std::string & args)139 void DOMInput::CallSpecializedMethod(const std::string& method, const std::string& args)
140 {
141 auto textField = AceType::DynamicCast<TextFieldComponent>(inputChild_);
142 if (!textField) {
143 return;
144 }
145 auto controller = textField->GetTextFieldController();
146 if (!controller) {
147 return;
148 }
149 if (method == DOM_INPUT_METHOD_SHOW_ERROR) {
150 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
151 if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != METHOD_SHOW_ERROR_ARGS_SIZE) {
152 LOGE("parse args error");
153 return;
154 }
155
156 std::unique_ptr<JsonValue> error = argsValue->GetArrayItem(0)->GetValue("error");
157 if (!error || !error->IsString()) {
158 LOGE("get error text failed");
159 return;
160 }
161 std::string errorText = error->GetString();
162 controller->ShowError(errorText);
163 } else if (method == DOM_INPUT_METHOD_DELETE) {
164 controller->Delete();
165 } else if (method == DOM_INPUT_METHOD_INSERT) {
166 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
167 std::unique_ptr<JsonValue> text = argsValue->GetArrayItem(0);
168 std::string inputText = text->GetString();
169 if (text->IsString()) {
170 inputText = text->GetString();
171 } else if (text->IsNumber()) {
172 inputText = std::to_string(text->GetInt());
173 }
174 controller->Insert(inputText);
175 }
176 }
177
OnRequestFocus(bool shouldFocus)178 void DOMInput::OnRequestFocus(bool shouldFocus)
179 {
180 if ((type_.first == INPUT_TYPE_CHECKBOX) || (type_.first == INPUT_TYPE_RADIO) ||
181 (type_.first == INPUT_TYPE_BUTTON) || (type_.first == INPUT_TYPE_SUBMIT) || (type_.first == INPUT_TYPE_RESET)) {
182 DOMNode::OnRequestFocus(shouldFocus);
183 return;
184 }
185 auto textField = AceType::DynamicCast<TextFieldComponent>(inputChild_);
186 if (!textField) {
187 return;
188 }
189 auto textFieldController = textField->GetTextFieldController();
190 if (!textFieldController) {
191 return;
192 }
193 textFieldController->Focus(shouldFocus);
194 }
195
PrepareCheckedListener()196 void DOMInput::PrepareCheckedListener()
197 {
198 bool isCheckbox = (type_.first == INPUT_TYPE_CHECKBOX);
199 bool isRadio = (type_.first == INPUT_TYPE_RADIO);
200 if (isCheckbox || isRadio) {
201 if (!checkableChangeMarker_.IsEmpty()) {
202 BackEndEventManager<void(const std::string&)>::GetInstance().RemoveBackEndEvent(checkableChangeMarker_);
203 }
204 auto checkableChangeCallback = [weak = AceType::WeakClaim(this)](const std::string& checked) {
205 auto domNode = weak.Upgrade();
206 if (!domNode) {
207 LOGE("get dom node failed!");
208 return;
209 }
210 bool isChecked = false;
211 if (checked.find("\"checked\":true") != std::string::npos) {
212 isChecked = true;
213 }
214 domNode->OnChecked(isChecked);
215 };
216 checkableChangeMarker_ = BackEndEventManager<void(const std::string&)>::GetInstance().GetAvailableMarker();
217 BackEndEventManager<void(const std::string&)>::GetInstance().BindBackendEvent(
218 checkableChangeMarker_, checkableChangeCallback);
219 AceType::DynamicCast<CheckableComponent>(inputChild_)->SetDomChangeEvent(checkableChangeMarker_);
220 }
221 }
222
PrepareSpecializedComponent()223 void DOMInput::PrepareSpecializedComponent()
224 {
225 if (boxComponent_) {
226 boxComponent_->SetMouseAnimationType(HoverAnimationType::OPACITY);
227 }
228 if (boxComponent_ && boxComponent_->GetBackDecoration()) {
229 boxBorder_ = boxComponent_->GetBackDecoration()->GetBorder();
230 }
231 // dom is created and type is not changed
232 if (!type_.second && inputChild_) {
233 UpdateSpecializedComponent();
234 } else {
235 CreateSpecializedComponent();
236 }
237
238 auto textField = AceType::DynamicCast<TextFieldComponent>(inputChild_);
239 if (textField) {
240 textField->SetInputOptions(inputOptions_);
241 textField->SetImageFill(GetImageFill());
242 }
243
244 inputAttrs_.erase(DOM_INPUT_VALUE);
245 UpdateSpecializedComponentStyle();
246 if (HasCheckedPseudo()) {
247 PrepareCheckedListener();
248 }
249 AddSpecializedComponentEvent();
250 SetFormValueListener();
251 }
252
GetSpecializedComponent()253 RefPtr<Component> DOMInput::GetSpecializedComponent()
254 {
255 return inputChild_;
256 }
257
CreateSpecializedComponent()258 void DOMInput::CreateSpecializedComponent()
259 {
260 SetIsCheckbox(false);
261 SetIsRadio(false);
262 type_.second = false;
263 auto radioComponent = AceType::DynamicCast<RadioComponent<std::string>>(inputChild_);
264 if (radioComponent) {
265 DOMRadioUtil::RemoveRadioComponent(*this, radioComponent);
266 }
267 if ((type_.first == INPUT_TYPE_BUTTON) || (type_.first == INPUT_TYPE_SUBMIT) || (type_.first == INPUT_TYPE_RESET)) {
268 boxComponent_->SetDeliverMinToChild(true);
269 inputChild_ = DOMButtonUtil::CreateComponentAndSetChildAttr(inputAttrs_, *this);
270 } else if (type_.first == INPUT_TYPE_CHECKBOX) {
271 boxComponent_->SetDeliverMinToChild(true);
272 inputChild_ = DOMCheckboxUtil::CreateComponentAndSetChildAttr(inputAttrs_, *this);
273 SetIsCheckbox(true);
274 } else if (type_.first == INPUT_TYPE_RADIO) {
275 boxComponent_->SetDeliverMinToChild(true);
276 inputChild_ = DOMRadioUtil::CreateComponentAndSetChildAttr(inputAttrs_, *this);
277 SetIsRadio(true);
278 } else {
279 // if type is not be set, will create a textfield component
280 inputChild_ =
281 DOMTextFieldUtil::CreateComponentAndSetChildAttr(GetBoxComponent(), type_.first, inputAttrs_, *this);
282 }
283 inputChild_->SetTextDirection(IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR);
284 }
285
UpdateSpecializedComponent()286 void DOMInput::UpdateSpecializedComponent()
287 {
288 if ((type_.first == INPUT_TYPE_BUTTON) || (type_.first == INPUT_TYPE_SUBMIT) || (type_.first == INPUT_TYPE_RESET)) {
289 boxComponent_->SetDeliverMinToChild(true);
290 DOMButtonUtil::SetChildAttr(
291 AceType::DynamicCast<ButtonComponent>(inputChild_), inputAttrs_, GetTheme<ButtonTheme>());
292 } else if (type_.first == INPUT_TYPE_CHECKBOX) {
293 boxComponent_->SetDeliverMinToChild(true);
294 DOMCheckboxUtil::SetChildAttr(AceType::DynamicCast<CheckboxComponent>(inputChild_), inputAttrs_);
295 } else if (type_.first == INPUT_TYPE_RADIO) {
296 boxComponent_->SetDeliverMinToChild(true);
297 DOMRadioUtil::SetChildAttr(*this, AceType::DynamicCast<RadioComponent<std::string>>(inputChild_), inputAttrs_);
298 } else {
299 DOMTextFieldUtil::SetChildAttr(
300 AceType::DynamicCast<TextFieldComponent>(inputChild_), GetBoxComponent(), type_.first, inputAttrs_);
301 }
302 }
303
UpdateSpecializedComponentStyle()304 void DOMInput::UpdateSpecializedComponentStyle()
305 {
306 static const LinearMapNode<void (*)(const RefPtr<BoxComponent>&, const RefPtr<Component>&,
307 const std::map<std::string, std::string>&, const Border&, DOMInput&)>
308 styleOperators[] = {
309 { INPUT_TYPE_BUTTON,
310 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
311 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input) {
312 DOMButtonUtil::SetChildStyle(
313 boxComponent, AceType::DynamicCast<ButtonComponent>(component), styles, input);
314 } },
315 { INPUT_TYPE_CHECKBOX,
316 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
317 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input){
318 input.HandlePadding(component, boxComponent, styles);
319 } },
320 { INPUT_TYPE_DATE,
321 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
322 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input) {
323 DOMTextFieldUtil::SetChildStyle(
324 boxComponent, AceType::DynamicCast<TextFieldComponent>(component), styles, boxBorder, input);
325 } },
326 { INPUT_TYPE_EMAIL,
327 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
328 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input) {
329 DOMTextFieldUtil::SetChildStyle(
330 boxComponent, AceType::DynamicCast<TextFieldComponent>(component), styles, boxBorder, input);
331 } },
332 { INPUT_TYPE_NUMBER,
333 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
334 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input) {
335 DOMTextFieldUtil::SetChildStyle(
336 boxComponent, AceType::DynamicCast<TextFieldComponent>(component), styles, boxBorder, input);
337 } },
338 { INPUT_TYPE_PASSWORD,
339 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
340 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input) {
341 DOMTextFieldUtil::SetChildStyle(
342 boxComponent, AceType::DynamicCast<TextFieldComponent>(component), styles, boxBorder, input);
343 } },
344 { INPUT_TYPE_RADIO,
345 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
346 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input) {
347 DOMRadioUtil::SetChildStyle(
348 boxComponent, AceType::DynamicCast<RadioComponent<std::string>>(component), styles);
349 input.HandlePadding(component, boxComponent, styles);
350 } },
351 { INPUT_TYPE_TEXT,
352 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
353 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input) {
354 DOMTextFieldUtil::SetChildStyle(
355 boxComponent, AceType::DynamicCast<TextFieldComponent>(component), styles, boxBorder, input);
356 } },
357 { INPUT_TYPE_TIME,
358 [](const RefPtr<BoxComponent>& boxComponent, const RefPtr<Component>& component,
359 const std::map<std::string, std::string>& styles, const Border& boxBorder, DOMInput& input) {
360 DOMTextFieldUtil::SetChildStyle(
361 boxComponent, AceType::DynamicCast<TextFieldComponent>(component), styles, boxBorder, input);
362 } },
363 };
364 auto type = type_.first;
365 if ((type == INPUT_TYPE_SUBMIT) || (type == INPUT_TYPE_RESET)) {
366 type = INPUT_TYPE_BUTTON;
367 }
368 auto styleOperatorIter = BinarySearchFindIndex(styleOperators, ArraySize(styleOperators), type.c_str());
369 if (styleOperatorIter != -1) {
370 styleOperators[styleOperatorIter].value(GetBoxComponent(), inputChild_, inputStyles_, boxBorder_, *this);
371 }
372 auto textField = DynamicCast<TextFieldComponent>(inputChild_);
373 if (textField) {
374 textField->SetIsVisible(IsShow());
375 }
376 }
377
AddSpecializedComponentEvent()378 void DOMInput::AddSpecializedComponentEvent()
379 {
380 static const LinearMapNode<void (*)(
381 const RefPtr<Component>&, const int32_t, const std::string&, const std::vector<std::string>&)>
382 eventOperators[] = {
383 { INPUT_TYPE_BUTTON,
384 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
385 const std::vector<std::string>& events) {
386 DOMButtonUtil::AddChildEvent(
387 AceType::DynamicCast<ButtonComponent>(component), pageId, nodeId, events);
388 } },
389 { INPUT_TYPE_CHECKBOX,
390 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
391 const std::vector<std::string>& events) {
392 DOMCheckboxUtil::AddChildEvent(
393 AceType::DynamicCast<CheckboxComponent>(component), pageId, nodeId, events);
394 } },
395 { INPUT_TYPE_DATE,
396 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
397 const std::vector<std::string>& events) {
398 DOMTextFieldUtil::AddChildEvent(
399 AceType::DynamicCast<TextFieldComponent>(component), pageId, nodeId, events);
400 } },
401 { INPUT_TYPE_EMAIL,
402 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
403 const std::vector<std::string>& events) {
404 DOMTextFieldUtil::AddChildEvent(
405 AceType::DynamicCast<TextFieldComponent>(component), pageId, nodeId, events);
406 } },
407 { INPUT_TYPE_NUMBER,
408 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
409 const std::vector<std::string>& events) {
410 DOMTextFieldUtil::AddChildEvent(
411 AceType::DynamicCast<TextFieldComponent>(component), pageId, nodeId, events);
412 } },
413 { INPUT_TYPE_PASSWORD,
414 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
415 const std::vector<std::string>& events) {
416 DOMTextFieldUtil::AddChildEvent(
417 AceType::DynamicCast<TextFieldComponent>(component), pageId, nodeId, events);
418 } },
419 { INPUT_TYPE_RADIO,
420 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
421 const std::vector<std::string>& events) {
422 DOMRadioUtil::AddChildEvent(
423 AceType::DynamicCast<RadioComponent<std::string>>(component), pageId, nodeId, events);
424 } },
425 { INPUT_TYPE_TEXT,
426 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
427 const std::vector<std::string>& events) {
428 DOMTextFieldUtil::AddChildEvent(
429 AceType::DynamicCast<TextFieldComponent>(component), pageId, nodeId, events);
430 } },
431 { INPUT_TYPE_TIME,
432 [](const RefPtr<Component>& component, int32_t pageId, const std::string& nodeId,
433 const std::vector<std::string>& events) {
434 DOMTextFieldUtil::AddChildEvent(
435 AceType::DynamicCast<TextFieldComponent>(component), pageId, nodeId, events);
436 } },
437 };
438 auto type = type_.first;
439 if ((type == INPUT_TYPE_SUBMIT) || (type == INPUT_TYPE_RESET)) {
440 type = INPUT_TYPE_BUTTON;
441 }
442 auto eventOperatorIter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), type.c_str());
443 if (eventOperatorIter != -1) {
444 eventOperators[eventOperatorIter].value(inputChild_, pageId_, GetNodeIdForEvent(), tempEvent_);
445 }
446 }
447
OnMounted(const RefPtr<DOMNode> & parentNode)448 void DOMInput::OnMounted(const RefPtr<DOMNode>& parentNode)
449 {
450 auto formNode = GetDomFormNode(parentNode);
451 if (formNode) {
452 formNode->AddInputChild(WeakClaim(this));
453 formNode_ = formNode;
454 CheckSubmitAndResetType();
455 }
456 }
457
CheckSubmitAndResetType()458 void DOMInput::CheckSubmitAndResetType()
459 {
460 if (type_.first == INPUT_TYPE_RESET) {
461 auto button = DynamicCast<ButtonComponent>(inputChild_);
462 button->SetClickFunction([formNode = formNode_]() {
463 auto form = AceType::DynamicCast<DOMForm>(formNode.Upgrade());
464 if (form) {
465 form->Reset();
466 }
467 });
468 return;
469 }
470 if (type_.first == INPUT_TYPE_SUBMIT) {
471 auto button = DynamicCast<ButtonComponent>(inputChild_);
472 button->SetClickFunction([formNode = formNode_]() {
473 auto form = AceType::DynamicCast<DOMForm>(formNode.Upgrade());
474 if (form) {
475 form->Submit();
476 }
477 });
478 }
479 }
480
OnReset()481 void DOMInput::OnReset()
482 {
483 auto textField = DynamicCast<TextFieldComponent>(inputChild_);
484 if (textField) {
485 textField->SetValue(GetOriginValue());
486 MarkNeedUpdate();
487 return;
488 }
489 auto radio = DynamicCast<RadioComponent<std::string>>(inputChild_);
490 if (radio) {
491 if (IsOriginChecked()) {
492 radio->SetGroupValue(GetOriginValue());
493 } else {
494 radio->SetGroupValue("");
495 }
496 MarkNeedUpdate();
497 return;
498 }
499 auto checkbox = DynamicCast<CheckboxComponent>(inputChild_);
500 if (checkbox) {
501 checkbox->SetValue(IsOriginChecked());
502 MarkNeedUpdate();
503 return;
504 }
505 }
506
SetFormValueListener()507 void DOMInput::SetFormValueListener()
508 {
509 auto changeCallback = [weak = WeakClaim(this)](const std::string& value) {
510 auto formValue = weak.Upgrade();
511 if (formValue) {
512 formValue->SetValue(value);
513 }
514 };
515 auto textField = DynamicCast<TextFieldComponent>(inputChild_);
516 if (textField) {
517 textField->SetOnTextChangeFunction(changeCallback);
518 return;
519 }
520 auto radio = DynamicCast<RadioComponent<std::string>>(inputChild_);
521 if (radio) {
522 auto& changeEvent = radio->GetChangeEvent();
523 changeEvent.SetUiStrFunction(changeCallback);
524 return;
525 }
526 auto checkbox = DynamicCast<CheckboxComponent>(inputChild_);
527 if (checkbox) {
528 auto& changeEvent = checkbox->GetChangeEvent();
529 changeEvent.SetUiStrFunction([weak = WeakClaim(this)](const std::string& value) {
530 auto formValue = weak.Upgrade();
531 if (formValue) {
532 if (value == "true") {
533 formValue->SetChecked(true);
534 } else {
535 formValue->SetChecked(false);
536 }
537 }
538 });
539 }
540 }
541
CheckPseduo(RefPtr<Decoration> decoration) const542 bool DOMInput::CheckPseduo(RefPtr<Decoration> decoration) const
543 {
544 auto assetManager = GetPipelineContext().Upgrade()->GetAssetManager();
545 if (!assetManager) {
546 return false;
547 }
548 std::string backgroundImage;
549 bool exsitBackgroundImage = false;
550 std::string pseudoBackgroundImage;
551 bool isPseudoImageExsit = false;
552 auto normalStyle = pseudoClassStyleMap_.find(STATE_NORMAL);
553 if (normalStyle != pseudoClassStyleMap_.end()) {
554 auto normalImageStyle = normalStyle->second.find("backgroundImage");
555 if (normalImageStyle != normalStyle->second.end()) {
556 backgroundImage = normalImageStyle->second;
557 exsitBackgroundImage = assetManager->GetAsset(backgroundImage) != nullptr;
558 }
559 }
560 auto pseudoStyles = pseudoClassStyleMap_.find(STATE_ACTIVE);
561 if (pseudoStyles != pseudoClassStyleMap_.end()) {
562 auto pseudoImageStyle = pseudoStyles->second.find("backgroundImage");
563 if (pseudoImageStyle != pseudoStyles->second.end()) {
564 pseudoBackgroundImage = pseudoImageStyle->second;
565 isPseudoImageExsit = assetManager->GetAsset(pseudoBackgroundImage) != nullptr;
566 }
567 }
568 // the background image and the pseudo image are not esxit, set the default button style
569 if (!exsitBackgroundImage && !isPseudoImageExsit) {
570 return false;
571 }
572 if (exsitBackgroundImage && isPseudoImageExsit) {
573 return true;
574 }
575 // set the pseudo image to be the same as the background image
576 std::string targetImage = exsitBackgroundImage ? backgroundImage : pseudoBackgroundImage;
577 auto themeManager = GetThemeManager();
578 if (!themeManager) {
579 return false;
580 }
581 decoration->GetImage()->SetSrc(targetImage, themeManager->GetThemeConstants());
582 return true;
583
584 }
585
HandlePadding(RefPtr<Component> component,RefPtr<BoxComponent> boxComponent,const std::map<std::string,std::string> & styles)586 void DOMInput::HandlePadding(RefPtr<Component> component, RefPtr<BoxComponent> boxComponent,
587 const std::map<std::string, std::string>& styles)
588 {
589 auto checkable = AceType::DynamicCast<CheckableComponent>(component);
590 if (!checkable || !boxComponent) {
591 LOGE("fail to set child attr due to checkbox component is null");
592 return;
593 }
594 // Padding is set in radio specially so that it can respond click event.
595 double left = -1.0;
596 double right = -1.0;
597 double top = -1.0;
598 double bottom = -1.0;
599 for (const auto& style : styles) {
600 if (style.first == DOM_PADDING_LEFT) {
601 left = StringUtils::StringToDouble(style.second);
602 } else if (style.first == DOM_PADDING_TOP) {
603 top = StringUtils::StringToDouble(style.second);
604 } else if (style.first == DOM_PADDING_RIGHT) {
605 right = StringUtils::StringToDouble(style.second);
606 } else if (style.first == DOM_PADDING_BOTTOM) {
607 bottom = StringUtils::StringToDouble(style.second);
608 }
609 }
610 // set the horizontal hot zone value is the minmum value in left and right,
611 // the vertical hot zone is the minmum value in top and bottom
612 Edge padding;
613 if (left >= 0 || right >= 0) {
614 left = left >= 0 ? left : 0;
615 right = right >= 0 ? right : 0;
616 double horizontal = std::min(left, right);
617 checkable->SetHorizontalPadding(Dimension(horizontal));
618 padding.SetLeft(Dimension(left - horizontal));
619 padding.SetRight(Dimension(right - horizontal));
620 }
621 if (top >= 0 || bottom >= 0) {
622 top = top >= 0 ? top : 0;
623 bottom = bottom >= 0 ? bottom : 0;
624 double vertical = std::min(top, bottom);
625 checkable->SetHotZoneVerticalPadding(Dimension(vertical));
626 padding.SetTop(Dimension(top - vertical));
627 padding.SetBottom(Dimension(bottom - vertical));
628 }
629 boxComponent->SetPadding(padding);
630 }
631 } // namespace OHOS::Ace::Framework
632