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