• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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_checkboxgroup.h"
17 
18 #include "bridge/declarative_frontend/engine/functions/js_event_function.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/checkboxgroup_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/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/checkboxgroup/checkboxgroup_model_ng.h"
27 #include "frameworks/bridge/declarative_frontend/jsview/js_interactable_view.h"
28 
29 namespace OHOS::Ace {
30 namespace {
31 constexpr float CHECK_BOX_GROUP_MARK_SIZE_INVALID_VALUE = -1.0f;
32 }
33 std::unique_ptr<CheckBoxGroupModel> CheckBoxGroupModel::instance_ = nullptr;
34 std::mutex CheckBoxGroupModel::mutex_;
35 
GetInstance()36 CheckBoxGroupModel* CheckBoxGroupModel::GetInstance()
37 {
38     if (!instance_) {
39         std::lock_guard<std::mutex> lock(mutex_);
40         if (!instance_) {
41 #ifdef NG_BUILD
42             instance_.reset(new NG::CheckBoxGroupModelNG());
43 #else
44             if (Container::IsCurrentUseNewPipeline()) {
45                 instance_.reset(new NG::CheckBoxGroupModelNG());
46             } else {
47                 instance_.reset(new Framework::CheckBoxGroupModelImpl());
48             }
49 #endif
50         }
51     }
52     return instance_.get();
53 }
54 } // namespace OHOS::Ace
55 
56 namespace OHOS::Ace::Framework {
CheckboxGroupResultEventToJSValue(const CheckboxGroupResult & eventInfo)57 JSRef<JSVal> CheckboxGroupResultEventToJSValue(const CheckboxGroupResult& eventInfo)
58 {
59     JSRef<JSObject> obj = JSRef<JSObject>::New();
60     JSRef<JSArray> nameArr = JSRef<JSArray>::New();
61     std::vector<std::string> nameList = eventInfo.GetNameList();
62     for (int idx = 0; idx < static_cast<int32_t>(nameList.size()); ++idx) {
63         JSRef<JSVal> name = JSRef<JSVal>::Make(ToJSValue(nameList[idx]));
64         nameArr->SetValueAt(idx, name);
65     }
66     obj->SetPropertyObject("name", nameArr);
67     obj->SetProperty("status", eventInfo.GetStatus());
68     return JSRef<JSVal>::Cast(obj);
69 }
70 
JSBind(BindingTarget globalObj)71 void JSCheckboxGroup::JSBind(BindingTarget globalObj)
72 {
73     JSClass<JSCheckboxGroup>::Declare("CheckboxGroup");
74 
75     JSClass<JSCheckboxGroup>::StaticMethod("create", &JSCheckboxGroup::Create);
76     JSClass<JSCheckboxGroup>::StaticMethod("selectAll", &JSCheckboxGroup::SetSelectAll);
77     JSClass<JSCheckboxGroup>::StaticMethod("onChange", &JSCheckboxGroup::SetOnChange);
78     JSClass<JSCheckboxGroup>::StaticMethod("selectedColor", &JSCheckboxGroup::SelectedColor);
79     JSClass<JSCheckboxGroup>::StaticMethod("unselectedColor", &JSCheckboxGroup::UnSelectedColor);
80     JSClass<JSCheckboxGroup>::StaticMethod("mark", &JSCheckboxGroup::Mark);
81     JSClass<JSCheckboxGroup>::StaticMethod("responseRegion", &JSCheckboxGroup::JsResponseRegion);
82     JSClass<JSCheckboxGroup>::StaticMethod("size", &JSCheckboxGroup::JsSize);
83     JSClass<JSCheckboxGroup>::StaticMethod("padding", &JSCheckboxGroup::JsPadding);
84     JSClass<JSCheckboxGroup>::StaticMethod("checkboxShape", &JSCheckboxGroup::SetCheckboxGroupStyle);
85     JSClass<JSCheckboxGroup>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
86     JSClass<JSCheckboxGroup>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
87     JSClass<JSCheckboxGroup>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
88     JSClass<JSCheckboxGroup>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
89     JSClass<JSCheckboxGroup>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
90     JSClass<JSCheckboxGroup>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
91     JSClass<JSCheckboxGroup>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
92     JSClass<JSCheckboxGroup>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
93     JSClass<JSCheckboxGroup>::InheritAndBind<JSViewAbstract>(globalObj);
94 }
95 
Create(const JSCallbackInfo & info)96 void JSCheckboxGroup::Create(const JSCallbackInfo& info)
97 {
98     std::optional<std::string> checkboxGroupName = std::make_optional("");
99     if ((info.Length() >= 1) && info[0]->IsObject()) {
100         auto paramObject = JSRef<JSObject>::Cast(info[0]);
101         auto groupName = paramObject->GetProperty("group");
102         if (groupName->IsString()) {
103             checkboxGroupName = groupName->ToString();
104         }
105     }
106 
107     CheckBoxGroupModel::GetInstance()->Create(checkboxGroupName);
108 }
109 
ParseSelectAllObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)110 void ParseSelectAllObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
111 {
112     CHECK_NULL_VOID(changeEventVal->IsFunction());
113 
114     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
115     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
116     auto changeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
117                            const BaseEventInfo* info) {
118         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
119         const auto* eventInfo = TypeInfoHelper::DynamicCast<CheckboxGroupResult>(info);
120         if (eventInfo) {
121             PipelineContext::SetCallBackNode(node);
122             if (eventInfo->GetStatus() == 0) {
123                 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(true));
124                 func->ExecuteJS(1, &newJSVal);
125             } else {
126                 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(false));
127                 func->ExecuteJS(1, &newJSVal);
128             }
129         }
130     };
131     CheckBoxGroupModel::GetInstance()->SetChangeEvent(std::move(changeEvent));
132 }
133 
SetSelectAll(const JSCallbackInfo & info)134 void JSCheckboxGroup::SetSelectAll(const JSCallbackInfo& info)
135 {
136     if (info.Length() < 1 || info.Length() > 2) {
137         return;
138     }
139     bool selectAll = false;
140 
141     JSRef<JSVal> changeEventVal;
142     auto selectedVal = info[0];
143     if (selectedVal->IsObject()) {
144         JSRef<JSObject> obj = JSRef<JSObject>::Cast(selectedVal);
145         selectedVal = obj->GetProperty("value");
146         changeEventVal = obj->GetProperty("$value");
147     } else if (info.Length() > 1) {
148         changeEventVal = info[1];
149     }
150     if (selectedVal->IsBoolean()) {
151         selectAll = selectedVal->ToBoolean();
152     }
153 
154     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "checkboxgroup select all %{public}d", selectAll);
155     CheckBoxGroupModel::GetInstance()->SetSelectAll(selectAll);
156     if (changeEventVal->IsFunction()) {
157         ParseSelectAllObject(info, changeEventVal);
158     }
159 }
160 
SetOnChange(const JSCallbackInfo & args)161 void JSCheckboxGroup::SetOnChange(const JSCallbackInfo& args)
162 {
163     if (args.Length() < 1 || !args[0]->IsFunction()) {
164         return;
165     }
166     auto jsFunc = AceType::MakeRefPtr<JsEventFunction<CheckboxGroupResult, 1>>(
167         JSRef<JSFunc>::Cast(args[0]), CheckboxGroupResultEventToJSValue);
168     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
169     auto onChange = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
170                         const BaseEventInfo* info) {
171         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
172         PipelineContext::SetCallBackNode(node);
173         const auto* eventInfo = TypeInfoHelper::DynamicCast<CheckboxGroupResult>(info);
174         func->Execute(*eventInfo);
175     };
176     CheckBoxGroupModel::GetInstance()->SetOnChange(onChange);
177 }
178 
JsResponseRegion(const JSCallbackInfo & info)179 void JSCheckboxGroup::JsResponseRegion(const JSCallbackInfo& info)
180 {
181     if (!Container::IsCurrentUseNewPipeline()) {
182         JSViewAbstract::JsResponseRegion(info);
183         return;
184     }
185     if (info.Length() < 1) {
186         return;
187     }
188     std::vector<DimensionRect> result;
189     if (!JSViewAbstract::ParseJsResponseRegionArray(info[0], result)) {
190         return;
191     }
192     CheckBoxGroupModel::GetInstance()->SetResponseRegion(result);
193 }
194 
JsSize(const JSCallbackInfo & info)195 void JSCheckboxGroup::JsSize(const JSCallbackInfo& info)
196 {
197     if (!info[0]->IsObject()) {
198         JSViewAbstract::JsWidth(JSVal::Undefined());
199         JSViewAbstract::JsHeight(JSVal::Undefined());
200         return;
201     }
202     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
203     JSViewAbstract::JsWidth(sizeObj->GetProperty("width"));
204     JSViewAbstract::JsHeight(sizeObj->GetProperty("height"));
205 }
206 
SelectedColor(const JSCallbackInfo & info)207 void JSCheckboxGroup::SelectedColor(const JSCallbackInfo& info)
208 {
209     if (info.Length() < 1) {
210         return;
211     }
212     Color selectedColor;
213     RefPtr<ResourceObject> resObj;
214     if (!ParseJsColor(info[0], selectedColor, resObj)) {
215         CheckBoxGroupModel::GetInstance()->ResetSelectedColor();
216     } else {
217         CheckBoxGroupModel::GetInstance()->SetSelectedColor(selectedColor);
218     }
219     if (SystemProperties::ConfigChangePerform()) {
220         CheckBoxGroupModel::GetInstance()->CreateWithColorResourceObj(resObj, CheckBoxGroupColorType::SELECTED_COLOR);
221     }
222 }
223 
UnSelectedColor(const JSCallbackInfo & info)224 void JSCheckboxGroup::UnSelectedColor(const JSCallbackInfo& info)
225 {
226     if (info.Length() < 1) {
227         return;
228     }
229     Color unSelectedColor;
230     RefPtr<ResourceObject> resObj;
231     if (!ParseJsColor(info[0], unSelectedColor, resObj)) {
232         CheckBoxGroupModel::GetInstance()->ResetUnSelectedColor();
233     } else {
234         CheckBoxGroupModel::GetInstance()->SetUnSelectedColor(unSelectedColor);
235     }
236     if (SystemProperties::ConfigChangePerform()) {
237         CheckBoxGroupModel::GetInstance()->CreateWithColorResourceObj(
238             resObj, CheckBoxGroupColorType::UN_SELECTED_COLOR);
239     }
240 }
241 
Mark(const JSCallbackInfo & info)242 void JSCheckboxGroup::Mark(const JSCallbackInfo& info)
243 {
244     if (info.Length() < 1) {
245         return;
246     }
247 
248     if (!info[0]->IsObject()) {
249         return;
250     }
251 
252     auto markObj = JSRef<JSObject>::Cast(info[0]);
253     auto strokeColorValue = markObj->GetProperty("strokeColor");
254     auto theme = GetTheme<CheckboxTheme>();
255     Color strokeColor = theme->GetPointColor();
256     if (!ParseJsColor(strokeColorValue, strokeColor)) {
257         CheckBoxGroupModel::GetInstance()->ResetCheckMarkColor();
258     } else {
259         CheckBoxGroupModel::GetInstance()->SetCheckMarkColor(strokeColor);
260     }
261     auto sizeValue = markObj->GetProperty("size");
262     CalcDimension size;
263     if ((ParseJsDimensionVp(sizeValue, size)) && (size.Unit() != DimensionUnit::PERCENT) &&
264         (size.ConvertToVp() >= 0)) {
265         CheckBoxGroupModel::GetInstance()->SetCheckMarkSize(size);
266     } else {
267         CheckBoxGroupModel::GetInstance()->SetCheckMarkSize(Dimension(CHECK_BOX_GROUP_MARK_SIZE_INVALID_VALUE));
268     }
269 
270     auto strokeWidthValue = markObj->GetProperty("strokeWidth");
271     CalcDimension strokeWidth;
272     if ((ParseJsDimensionVp(strokeWidthValue, strokeWidth)) && (strokeWidth.Unit() != DimensionUnit::PERCENT) &&
273         (strokeWidth.ConvertToVp() >= 0)) {
274         CheckBoxGroupModel::GetInstance()->SetCheckMarkWidth(strokeWidth);
275     } else {
276         CheckBoxGroupModel::GetInstance()->SetCheckMarkWidth(theme->GetCheckStroke());
277     }
278 }
279 
JsPadding(const JSCallbackInfo & info)280 void JSCheckboxGroup::JsPadding(const JSCallbackInfo& info)
281 {
282     if (info.Length() < 1) {
283         return;
284     }
285     NG::PaddingPropertyF oldPadding({ 0.0f, 0.0f, 0.0f, 0.0f });
286     bool flag = GetOldPadding(info, oldPadding);
287     NG::PaddingProperty newPadding = GetNewPadding(info);
288     CheckBoxGroupModel::GetInstance()->SetPadding(oldPadding, newPadding, flag);
289 }
290 
GetOldPadding(const JSCallbackInfo & info,NG::PaddingPropertyF & padding)291 bool JSCheckboxGroup::GetOldPadding(const JSCallbackInfo& info, NG::PaddingPropertyF& padding)
292 {
293     if (info[0]->IsObject()) {
294         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
295         if (jsObj->HasProperty("top") || jsObj->HasProperty("bottom")
296             || jsObj->HasProperty("left") || jsObj->HasProperty("right")) {
297             CalcDimension topDimen = CalcDimension(0.0, DimensionUnit::VP);
298             CalcDimension leftDimen = CalcDimension(0.0, DimensionUnit::VP);
299             CalcDimension rightDimen = CalcDimension(0.0, DimensionUnit::VP);
300             CalcDimension bottomDimen = CalcDimension(0.0, DimensionUnit::VP);
301             ParseJsDimensionVp(jsObj->GetProperty("top"), topDimen);
302             ParseJsDimensionVp(jsObj->GetProperty("left"), leftDimen);
303             ParseJsDimensionVp(jsObj->GetProperty("right"), rightDimen);
304             ParseJsDimensionVp(jsObj->GetProperty("bottom"), bottomDimen);
305             if (leftDimen == 0.0_vp) {
306                 leftDimen = rightDimen;
307             }
308             if (topDimen == 0.0_vp) {
309                 topDimen = bottomDimen;
310             }
311             if (leftDimen == 0.0_vp) {
312                 leftDimen = topDimen;
313             }
314 
315             padding.left = leftDimen.ConvertToPx();
316             padding.right = rightDimen.ConvertToPx();
317             padding.top = topDimen.ConvertToPx();
318             padding.bottom = bottomDimen.ConvertToPx();
319             return true;
320         }
321     }
322 
323     CalcDimension length;
324     if (!ParseJsDimensionVp(info[0], length)) {
325         return false;
326     }
327 
328     padding.left = length.ConvertToPx();
329     padding.right = length.ConvertToPx();
330     padding.top = length.ConvertToPx();
331     padding.bottom = length.ConvertToPx();
332     return true;
333 }
334 
GetNewPadding(const JSCallbackInfo & info)335 NG::PaddingProperty JSCheckboxGroup::GetNewPadding(const JSCallbackInfo& info)
336 {
337     NG::PaddingProperty padding({ NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp),
338         NG::CalcLength(0.0_vp), std::nullopt, std::nullopt });
339     if (info[0]->IsObject()) {
340         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
341         CommonCalcDimension commonCalcDimension;
342         ParseCommonMarginOrPaddingCorner(paddingObj, commonCalcDimension);
343         if (commonCalcDimension.left.has_value() || commonCalcDimension.right.has_value() ||
344             commonCalcDimension.top.has_value() || commonCalcDimension.bottom.has_value()) {
345             padding = GetPadding(commonCalcDimension.top, commonCalcDimension.bottom, commonCalcDimension.left,
346                 commonCalcDimension.right);
347             return padding;
348         }
349     }
350     CalcDimension length;
351     if (!ParseJsDimensionVp(info[0], length)) {
352         length.Reset();
353     }
354 
355     padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
356     return padding;
357 }
358 
GetPadding(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)359 NG::PaddingProperty JSCheckboxGroup::GetPadding(const std::optional<CalcDimension>& top,
360     const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
361     const std::optional<CalcDimension>& right)
362 {
363     NG::PaddingProperty padding({ NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp),
364         NG::CalcLength(0.0_vp), std::nullopt, std::nullopt });
365     if (left.has_value()) {
366         if (left.value().Unit() == DimensionUnit::CALC) {
367             padding.left = NG::CalcLength(
368                 left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
369         } else {
370             padding.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
371         }
372     }
373     if (right.has_value()) {
374         if (right.value().Unit() == DimensionUnit::CALC) {
375             padding.right = NG::CalcLength(
376                 right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
377         } else {
378             padding.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
379         }
380     }
381     if (top.has_value()) {
382         if (top.value().Unit() == DimensionUnit::CALC) {
383             padding.top = NG::CalcLength(
384                 top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
385         } else {
386             padding.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
387         }
388     }
389     if (bottom.has_value()) {
390         if (bottom.value().Unit() == DimensionUnit::CALC) {
391             padding.bottom = NG::CalcLength(
392                 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
393         } else {
394             padding.bottom = NG::CalcLength(
395                 bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
396         }
397     }
398     return padding;
399 }
400 
SetCheckboxGroupStyle(int32_t checkBoxGroupStyle)401 void JSCheckboxGroup::SetCheckboxGroupStyle(int32_t checkBoxGroupStyle)
402 {
403     CheckBoxStyle curCheckBoxGroupStyle = static_cast<CheckBoxStyle>(checkBoxGroupStyle);
404     CheckBoxGroupModel::GetInstance()->SetCheckboxGroupStyle(curCheckBoxGroupStyle);
405 }
406 } // namespace OHOS::Ace::Framework
407