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