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 if (inputChild_) {
284 inputChild_->SetTextDirection(IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR);
285 }
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