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/input/dom_radio_util.h"
17 
18 #include "frameworks/bridge/js_frontend/js_frontend.h"
19 
20 namespace OHOS::Ace::Framework {
21 namespace {
22 
GetRadioGroups(const DOMNode & node)23 std::shared_ptr<JsPageRadioGroups> GetRadioGroups(const DOMNode& node)
24 {
25     auto context = node.GetPipelineContext().Upgrade();
26     if (!context) {
27         return nullptr;
28     }
29     auto frontend = context->GetFrontend();
30     if (!frontend) {
31         return nullptr;
32     }
33     auto page = frontend->GetPage(node.GetPageId());
34     if (!page) {
35         auto jsFrontend = AceType::DynamicCast<JsFrontend>(frontend);
36         if (!jsFrontend) {
37             return nullptr;
38         }
39         page = jsFrontend->GetCurrentReadyPage().Upgrade();
40     }
41     auto jsPage = AceType::DynamicCast<JsAcePage>(page);
42     if (!jsPage) {
43         return nullptr;
44     }
45     return jsPage->GetRadioGroups();
46 }
47 
48 } // namespace
49 
InitDefaultValue(const RefPtr<RadioComponent<std::string>> & component)50 void DOMRadioUtil::InitDefaultValue(const RefPtr<RadioComponent<std::string>>& component) {}
51 
CreateComponentAndSetChildAttr(const std::map<std::string,std::string> & attrs,DOMInput & node)52 RefPtr<RadioComponent<std::string>> DOMRadioUtil::CreateComponentAndSetChildAttr(
53     const std::map<std::string, std::string>& attrs, DOMInput& node)
54 {
55     // get theme to create component
56     RefPtr<RadioTheme> theme = node.GetTheme<RadioTheme>();
57     RefPtr<RadioComponent<std::string>> component = AceType::MakeRefPtr<RadioComponent<std::string>>(theme);
58     // set default value
59     InitDefaultValue(component);
60     // set the default hot zone
61     auto pipelineContext = node.GetPipelineContext().Upgrade();
62     if (pipelineContext->UseLiteStyle()) {
63         component->SetHorizontalPadding(Dimension(0));
64         component->SetHotZoneVerticalPadding(Dimension(0));
65     }
66     auto boxComponent = node.GetBoxComponent();
67     if (LessOrEqual(node.GetWidth().Value(), 0.0)) {
68         if (theme == nullptr) {
69             return nullptr;
70         }
71         node.SetWidth(theme->GetWidth());
72         boxComponent->SetWidth(theme->GetWidth().Value(), theme->GetWidth().Unit());
73     }
74     if (LessOrEqual(node.GetHeight().Value(), 0.0)) {
75         if (theme == nullptr) {
76             return nullptr;
77         }
78         node.SetHeight(theme->GetHeight());
79         boxComponent->SetHeight(theme->GetHeight().Value(), theme->GetHeight().Unit());
80     }
81     auto diameter = boxComponent->GetHeightDimension() > boxComponent->GetWidthDimension()
82                         ? boxComponent->GetWidthDimension()
83                         : boxComponent->GetHeightDimension();
84     if (!boxComponent->GetBackDecoration()) {
85         RefPtr<Decoration> backDecoration = AceType::MakeRefPtr<Decoration>();
86         backDecoration->SetBorderRadius(Radius(diameter / 2.0));
87         boxComponent->SetBackDecoration(backDecoration);
88     }
89 
90     SetChildAttr(node, component, attrs);
91 
92     return component;
93 }
94 
SetChildAttr(const DOMInput & node,const RefPtr<RadioComponent<std::string>> & component,const std::map<std::string,std::string> & attrs)95 void DOMRadioUtil::SetChildAttr(const DOMInput& node, const RefPtr<RadioComponent<std::string>>& component,
96     const std::map<std::string, std::string>& attrs)
97 {
98     if (!component) {
99         return;
100     }
101     bool checked = false;
102     for (const auto& attr : attrs) {
103         if (attr.first == DOM_INPUT_CHECKED) {
104             checked = StringToBool(attr.second);
105         } else if (attr.first == DOM_INPUT_NAME) {
106             CheckRadioGroup(node, component, attr.second);
107         } else if (attr.first == DOM_DISABLED) {
108             component->SetDisabled(StringToBool(attr.second));
109         } else if (attr.first == DOM_INPUT_VALUE) {
110             component->SetValue(attr.second);
111         }
112     }
113     if (checked) {
114         component->SetGroupValue(component->GetValue());
115         component->SetOriginChecked(checked);
116     } else {
117         component->SetGroupValue("");
118     }
119 }
120 
SetChildStyle(const RefPtr<BoxComponent> & boxComponent,const RefPtr<RadioComponent<std::string>> & component,const std::map<std::string,std::string> & styles)121 void DOMRadioUtil::SetChildStyle(const RefPtr<BoxComponent>& boxComponent,
122     const RefPtr<RadioComponent<std::string>>& component, const std::map<std::string, std::string>& styles)
123 {
124     if (!component) {
125         return;
126     }
127     // Padding is set in radio specially so that it can respond click event.
128     boxComponent->SetPadding(Edge());
129     for (const auto& style : styles) {
130         if (style.first == DOM_PADDING) {
131             Edge padding;
132             if (Edge::FromString(style.second, padding)) {
133                 component->SetHorizontalPadding(padding.Left());
134                 component->SetHotZoneVerticalPadding(padding.Top());
135             }
136         }
137     }
138 }
139 
AddChildEvent(const RefPtr<RadioComponent<std::string>> & component,int32_t pageId,const std::string & nodeId,const std::vector<std::string> & events)140 void DOMRadioUtil::AddChildEvent(const RefPtr<RadioComponent<std::string>>& component, int32_t pageId,
141     const std::string& nodeId, const std::vector<std::string>& events)
142 {
143     if (!component) {
144         return;
145     }
146     for (const auto& event : events) {
147         if (event == DOM_CHANGE) {
148             component->SetChangeEvent(EventMarker(nodeId, event, pageId));
149         } else if (event == DOM_CLICK) {
150             EventMarker eventMarker(nodeId, event, pageId);
151             eventMarker.SetCatchMode(false);
152             component->SetClickEvent(eventMarker);
153         } else if (event == DOM_CATCH_BUBBLE_CLICK) {
154             EventMarker eventMarker(nodeId, event, pageId);
155             eventMarker.SetCatchMode(true);
156             component->SetClickEvent(eventMarker);
157         }
158     }
159 }
160 
RemoveRadioComponent(const DOMInput & node,const RefPtr<RadioComponent<std::string>> & component)161 void DOMRadioUtil::RemoveRadioComponent(const DOMInput& node, const RefPtr<RadioComponent<std::string>>& component)
162 {
163     if (!component) {
164         return;
165     }
166     auto radioGroups = GetRadioGroups(node);
167     if (radioGroups == nullptr) {
168         return;
169     }
170 
171     auto radioGroupIter = (*radioGroups).find(component->GetGroupName());
172     if (radioGroupIter != (*radioGroups).end()) {
173         radioGroupIter->second.RemoveRadio(component);
174         if (radioGroupIter->second.IsEmpty()) {
175             (*radioGroups).erase(radioGroupIter);
176         }
177     }
178 }
179 
CheckRadioGroup(const DOMInput & node,const RefPtr<RadioComponent<std::string>> & component,const std::string & name)180 void DOMRadioUtil::CheckRadioGroup(
181     const DOMInput& node, const RefPtr<RadioComponent<std::string>>& component, const std::string& name)
182 {
183     auto radioGroups = GetRadioGroups(node);
184     if (radioGroups == nullptr) {
185         return;
186     }
187     const auto& groupName = component->GetGroupName();
188     if (!groupName.empty()) {
189         if (groupName == name) {
190             return;
191         }
192         auto& oldRadioGroup = (*radioGroups)[groupName];
193         oldRadioGroup.RemoveRadio(component);
194         if (oldRadioGroup.IsEmpty()) {
195             (*radioGroups).erase(groupName);
196         }
197     }
198     component->SetGroupName(name);
199     auto& radioGroup = (*radioGroups)[name];
200     radioGroup.AddRadio(component);
201 }
202 
203 } // namespace OHOS::Ace::Framework
204