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