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