1 /*
2 * Copyright (c) 2021-2022 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 "bridge/declarative_frontend/jsview/js_radio.h"
17
18 #include "base/log/ace_scoring_log.h"
19 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
20 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
21 #include "bridge/declarative_frontend/jsview/models/radio_model_impl.h"
22 #include "bridge/declarative_frontend/view_stack_processor.h"
23 #include "core/components/checkable/checkable_component.h"
24 #include "core/components_ng/base/view_abstract.h"
25 #include "core/components_ng/pattern/radio/radio_model_ng.h"
26
27 namespace OHOS::Ace {
28
29 std::unique_ptr<RadioModel> RadioModel::instance_ = nullptr;
30
GetInstance()31 RadioModel* RadioModel::GetInstance()
32 {
33 if (!instance_) {
34 #ifdef NG_BUILD
35 instance_.reset(new NG::RadioModelNG());
36 #else
37 if (Container::IsCurrentUseNewPipeline()) {
38 instance_.reset(new NG::RadioModelNG());
39 } else {
40 instance_.reset(new Framework::RadioModelImpl());
41 }
42 #endif
43 }
44 return instance_.get();
45 }
46
47 } // namespace OHOS::Ace
48 namespace OHOS::Ace::Framework {
49
Create(const JSCallbackInfo & info)50 void JSRadio::Create(const JSCallbackInfo& info)
51 {
52 if (info.Length() < 1) {
53 LOGE("radio create error, info is not-valid");
54 return;
55 }
56
57 std::optional<std::string> value;
58 std::optional<std::string> group;
59 if ((info.Length() >= 1) && info[0]->IsObject()) {
60 auto paramObject = JSRef<JSObject>::Cast(info[0]);
61 auto valueTemp = paramObject->GetProperty("value");
62 auto groupTemp = paramObject->GetProperty("group");
63 if (valueTemp->IsString()) {
64 value = valueTemp->ToString();
65 }
66 if (groupTemp->IsString()) {
67 group = groupTemp->ToString();
68 }
69 }
70 RadioModel::GetInstance()->Create(value, group);
71 }
72
JSBind(BindingTarget globalObj)73 void JSRadio::JSBind(BindingTarget globalObj)
74 {
75 JSClass<JSRadio>::Declare("Radio");
76
77 JSClass<JSRadio>::StaticMethod("create", &JSRadio::Create);
78 JSClass<JSRadio>::StaticMethod("checked", &JSRadio::Checked);
79 JSClass<JSRadio>::StaticMethod("width", &JSRadio::JsWidth);
80 JSClass<JSRadio>::StaticMethod("height", &JSRadio::JsHeight);
81 JSClass<JSRadio>::StaticMethod("size", &JSRadio::JsSize);
82 JSClass<JSRadio>::StaticMethod("padding", &JSRadio::JsPadding);
83 JSClass<JSRadio>::StaticMethod("onChange", &JSRadio::OnChange);
84 JSClass<JSRadio>::StaticMethod("onClick", &JSRadio::JsOnClick);
85 JSClass<JSRadio>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
86 JSClass<JSRadio>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
87 JSClass<JSRadio>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
88 JSClass<JSRadio>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
89 JSClass<JSRadio>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
90 JSClass<JSRadio>::Inherit<JSViewAbstract>();
91 JSClass<JSRadio>::Bind<>(globalObj);
92 }
93
Checked(bool checked)94 void JSRadio::Checked(bool checked)
95 {
96 auto stack = ViewStackProcessor::GetInstance();
97 auto radioComponent = AceType::DynamicCast<RadioComponent<std::string>>(stack->GetMainComponent());
98 if (checked) {
99 radioComponent->SetGroupValue(radioComponent->GetValue());
100 radioComponent->SetOriginChecked(checked);
101 } else {
102 radioComponent->SetGroupValue("");
103 }
104 }
105
Checked(const JSCallbackInfo & info)106 void JSRadio::Checked(const JSCallbackInfo& info)
107 {
108 if (info[0]->IsBoolean()) {
109 RadioModel::GetInstance()->SetChecked(info[0]->ToBoolean());
110 }
111 }
112
JsWidth(const JSCallbackInfo & info)113 void JSRadio::JsWidth(const JSCallbackInfo& info)
114 {
115 if (info.Length() < 1) {
116 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
117 return;
118 }
119
120 JsWidth(info[0]);
121 }
122
JsWidth(const JSRef<JSVal> & jsValue)123 void JSRadio::JsWidth(const JSRef<JSVal>& jsValue)
124 {
125 Dimension value;
126 if (!ParseJsDimensionVp(jsValue, value)) {
127 return;
128 }
129
130 if (Container::IsCurrentUseNewPipeline()) {
131 NG::ViewAbstract::SetWidth(NG::CalcLength(value));
132 return;
133 }
134
135 RadioModel::GetInstance()->SetWidth(value);
136 }
137
JsHeight(const JSCallbackInfo & info)138 void JSRadio::JsHeight(const JSCallbackInfo& info)
139 {
140 if (info.Length() < 1) {
141 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
142 return;
143 }
144
145 JsHeight(info[0]);
146 }
147
JsHeight(const JSRef<JSVal> & jsValue)148 void JSRadio::JsHeight(const JSRef<JSVal>& jsValue)
149 {
150 Dimension value;
151 if (!ParseJsDimensionVp(jsValue, value)) {
152 return;
153 }
154
155 if (Container::IsCurrentUseNewPipeline()) {
156 NG::ViewAbstract::SetHeight(NG::CalcLength(value));
157 return;
158 }
159
160 RadioModel::GetInstance()->SetHeight(value);
161 }
162
JsSize(const JSCallbackInfo & info)163 void JSRadio::JsSize(const JSCallbackInfo& info)
164 {
165 if (info.Length() < 1) {
166 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
167 return;
168 }
169
170 if (!info[0]->IsObject()) {
171 LOGE("arg is not Object or String.");
172 return;
173 }
174
175 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
176 JsWidth(sizeObj->GetProperty("width"));
177 JsHeight(sizeObj->GetProperty("height"));
178 }
179
JsPadding(const JSCallbackInfo & info)180 void JSRadio::JsPadding(const JSCallbackInfo& info)
181 {
182 if (!info[0]->IsString() && !info[0]->IsNumber() && !info[0]->IsObject()) {
183 LOGE("arg is not a string, number or object.");
184 return;
185 }
186
187 Dimension value;
188 if (!ParseJsDimensionVp(info[0], value)) {
189 return;
190 }
191
192 if (Container::IsCurrentUseNewPipeline()) {
193 NG::ViewAbstract::SetPadding(NG::CalcLength(value));
194 return;
195 }
196
197 if (info[0]->IsObject()) {
198 auto argsPtrItem = JsonUtil::ParseJsonString(info[0]->ToString());
199 if (!argsPtrItem || argsPtrItem->IsNull()) {
200 LOGE("Js Parse object failed. argsPtr is null. %s", info[0]->ToString().c_str());
201 return;
202 }
203 if (argsPtrItem->Contains("top") || argsPtrItem->Contains("bottom") || argsPtrItem->Contains("left") ||
204 argsPtrItem->Contains("right")) {
205 Dimension topDimen = Dimension(0.0, DimensionUnit::VP);
206 Dimension leftDimen = Dimension(0.0, DimensionUnit::VP);
207 Dimension rightDimen = Dimension(0.0, DimensionUnit::VP);
208 Dimension bottomDimen = Dimension(0.0, DimensionUnit::VP);
209 ParseJsonDimensionVp(argsPtrItem->GetValue("top"), topDimen);
210 ParseJsonDimensionVp(argsPtrItem->GetValue("left"), leftDimen);
211 ParseJsonDimensionVp(argsPtrItem->GetValue("right"), rightDimen);
212 ParseJsonDimensionVp(argsPtrItem->GetValue("bottom"), bottomDimen);
213 if (leftDimen == 0.0_vp) {
214 leftDimen = rightDimen;
215 }
216 if (topDimen == 0.0_vp) {
217 topDimen = bottomDimen;
218 }
219 if (leftDimen == 0.0_vp) {
220 leftDimen = topDimen;
221 }
222 NG::PaddingPropertyF padding;
223 padding.left = leftDimen.ConvertToPx();
224 padding.right = rightDimen.ConvertToPx();
225 padding.top = topDimen.ConvertToPx();
226 padding.bottom = bottomDimen.ConvertToPx();
227 RadioModel::GetInstance()->SetPadding(padding);
228 return;
229 }
230 }
231 Dimension length;
232 if (!ParseJsDimensionVp(info[0], length)) {
233 return;
234 }
235 NG::PaddingPropertyF padding;
236 padding.left = length.ConvertToPx();
237 padding.right = length.ConvertToPx();
238 padding.top = length.ConvertToPx();
239 padding.bottom = length.ConvertToPx();
240 RadioModel::GetInstance()->SetPadding(padding);
241 }
242
SetPadding(const Dimension & topDimen,const Dimension & leftDimen)243 void JSRadio::SetPadding(const Dimension& topDimen, const Dimension& leftDimen)
244 {
245 auto stack = ViewStackProcessor::GetInstance();
246 auto radioComponent = AceType::DynamicCast<RadioComponent<std::string>>(stack->GetMainComponent());
247 auto box = ViewStackProcessor::GetInstance()->GetBoxComponent();
248
249 if (radioComponent) {
250 auto width = radioComponent->GetWidth();
251 auto height = radioComponent->GetHeight();
252 radioComponent->SetHeight(height);
253 radioComponent->SetWidth(width);
254 box->SetHeight(height + topDimen * 2);
255 box->SetWidth(width + leftDimen * 2);
256 radioComponent->SetHotZoneVerticalPadding(topDimen);
257 radioComponent->SetHorizontalPadding(leftDimen);
258 }
259 }
260
OnChange(const JSCallbackInfo & args)261 void JSRadio::OnChange(const JSCallbackInfo& args)
262 {
263 if (!args[0]->IsFunction()) {
264 return;
265 }
266 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
267 auto onChange = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc)](bool check) {
268 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
269 ACE_SCORING_EVENT("Radio.onChange");
270 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(check));
271 func->ExecuteJS(1, &newJSVal);
272 };
273 RadioModel::GetInstance()->SetOnChange(std::move(onChange));
274 args.ReturnSelf();
275 }
276
JsOnClick(const JSCallbackInfo & args)277 void JSRadio::JsOnClick(const JSCallbackInfo& args)
278 {
279 if (Container::IsCurrentUseNewPipeline()) {
280 JSViewAbstract::JsOnClick(args);
281 return;
282 }
283
284 if (JSViewBindEvent(&CheckableComponent::SetOnClick, args)) {
285 } else {
286 LOGW("Failed to bind event");
287 }
288
289 args.ReturnSelf();
290 }
291
292 } // namespace OHOS::Ace::Framework
293