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