• 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_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