• 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_checkbox.h"
17 
18 #include <optional>
19 #include <string>
20 
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
23 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
24 #include "bridge/declarative_frontend/jsview/models/checkbox_model_impl.h"
25 #include "bridge/declarative_frontend/view_stack_processor.h"
26 #include "core/common/container.h"
27 #include "core/components/checkable/checkable_component.h"
28 #include "core/components_ng/base/view_abstract.h"
29 #include "core/components_ng/base/view_abstract_model.h"
30 #include "core/components_ng/base/view_stack_model.h"
31 #include "core/components_ng/base/view_stack_processor.h"
32 #include "core/components_ng/pattern/checkbox/checkbox_model_ng.h"
33 #include "core/components_v2/inspector/inspector_constants.h"
34 
35 namespace OHOS::Ace {
36 namespace {
37 constexpr float CHECK_BOX_MARK_SIZE_INVALID_VALUE = -1.0f;
38 }
39 
GetInstance()40 CheckBoxModel* CheckBoxModel::GetInstance()
41 {
42 #ifdef NG_BUILD
43     static NG::CheckBoxModelNG instance;
44     return &instance;
45 #else
46     if (Container::IsCurrentUseNewPipeline()) {
47         static NG::CheckBoxModelNG instance;
48         return &instance;
49     } else {
50         static Framework::CheckBoxModelImpl instance;
51         return &instance;
52     }
53 #endif
54 }
55 } // namespace OHOS::Ace
56 
57 namespace OHOS::Ace::Framework {
Create(const JSCallbackInfo & info)58 void JSCheckbox::Create(const JSCallbackInfo& info)
59 {
60     auto checkboxName = std::optional<std::string>("");
61     auto checkboxGroup = std::optional<std::string>("");
62     std::optional<std::function<void()>> customBuilderFunc;
63     if ((info.Length() >= 1) && info[0]->IsObject()) {
64         auto paramObject = JSRef<JSObject>::Cast(info[0]);
65         auto name = paramObject->GetProperty("name");
66         auto group = paramObject->GetProperty("group");
67         if (name->IsString()) {
68             checkboxName = name->ToString();
69         }
70         if (group->IsString()) {
71             checkboxGroup = group->ToString();
72         }
73         auto builderObject = paramObject->GetProperty("indicatorBuilder");
74         if (builderObject->IsFunction()) {
75             auto builderFunc = AceType::MakeRefPtr<JsFunction>(info.This(), JSRef<JSFunc>::Cast(builderObject));
76             CHECK_NULL_VOID(builderFunc);
77             auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
78             auto callbackFunc = [execCtx = info.GetExecutionContext(),
79                 func = std::move(builderFunc), node = targetNode]() {
80                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
81                 ACE_SCORING_EVENT("CheckBox.builder");
82                 PipelineContext::SetCallBackNode(node);
83                 func->Execute();
84             };
85             customBuilderFunc = std::move(callbackFunc);
86         }
87     }
88     CheckBoxModel::GetInstance()->Create(checkboxName, checkboxGroup, V2::CHECK_BOX_ETS_TAG);
89     CheckBoxModel::GetInstance()->SetBuilder(customBuilderFunc);
90 }
91 
JSBind(BindingTarget globalObj)92 void JSCheckbox::JSBind(BindingTarget globalObj)
93 {
94     JSClass<JSCheckbox>::Declare("Checkbox");
95 
96     JSClass<JSCheckbox>::StaticMethod("create", &JSCheckbox::Create);
97     JSClass<JSCheckbox>::StaticMethod("select", &JSCheckbox::SetSelect);
98     JSClass<JSCheckbox>::StaticMethod("shape", &JSCheckbox::SetCheckboxStyle);
99     JSClass<JSCheckbox>::StaticMethod("onChange", &JSCheckbox::SetOnChange);
100     JSClass<JSCheckbox>::StaticMethod("selectedColor", &JSCheckbox::SelectedColor);
101     JSClass<JSCheckbox>::StaticMethod("unselectedColor", &JSCheckbox::UnSelectedColor);
102     JSClass<JSCheckbox>::StaticMethod("mark", &JSCheckbox::Mark);
103     JSClass<JSCheckbox>::StaticMethod("responseRegion", &JSCheckbox::JsResponseRegion);
104     JSClass<JSCheckbox>::StaticMethod("padding", &JSCheckbox::JsPadding);
105     JSClass<JSCheckbox>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
106     JSClass<JSCheckbox>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
107     JSClass<JSCheckbox>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
108     JSClass<JSCheckbox>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
109     JSClass<JSCheckbox>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
110     JSClass<JSCheckbox>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
111     JSClass<JSCheckbox>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
112     JSClass<JSCheckbox>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
113     JSClass<JSCheckbox>::InheritAndBind<JSViewAbstract>(globalObj);
114 }
115 
ParseSelectObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)116 void ParseSelectObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
117 {
118     CHECK_NULL_VOID(changeEventVal->IsFunction());
119 
120     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
121     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
122     auto changeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](bool param) {
123         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
124         ACE_SCORING_EVENT("CheckBox.ChangeEvent");
125         PipelineContext::SetCallBackNode(node);
126         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(param));
127         func->ExecuteJS(1, &newJSVal);
128     };
129     CheckBoxModel::GetInstance()->SetChangeEvent(std::move(changeEvent));
130 }
131 
SetSelect(const JSCallbackInfo & info)132 void JSCheckbox::SetSelect(const JSCallbackInfo& info)
133 {
134     auto length = info.Length();
135     if (length < 1 || length > 2) {
136         return;
137     }
138     bool select = 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         select = selectedVal->ToBoolean();
151     }
152     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "checkbox set select %{public}d", select);
153     CheckBoxModel::GetInstance()->SetSelect(select);
154     if (changeEventVal->IsFunction()) {
155         ParseSelectObject(info, changeEventVal);
156     }
157 }
158 
SetOnChange(const JSCallbackInfo & args)159 void JSCheckbox::SetOnChange(const JSCallbackInfo& args)
160 {
161     if (!args[0]->IsFunction()) {
162         return;
163     }
164     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
165     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
166     auto onChange = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](bool select) {
167         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
168         ACE_SCORING_EVENT("CheckBox.onChange");
169         PipelineContext::SetCallBackNode(node);
170         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(select));
171         func->ExecuteJS(1, &newJSVal);
172     };
173     CheckBoxModel::GetInstance()->SetOnChange(onChange);
174     args.ReturnSelf();
175 }
176 
JsResponseRegion(const JSCallbackInfo & info)177 void JSCheckbox::JsResponseRegion(const JSCallbackInfo& info)
178 {
179     if (!Container::IsCurrentUseNewPipeline()) {
180         JSViewAbstract::JsResponseRegion(info);
181         return;
182     }
183     if (info.Length() < 1) {
184         return;
185     }
186     std::vector<DimensionRect> result;
187     if (!JSViewAbstract::ParseJsResponseRegionArray(info[0], result)) {
188         return;
189     }
190     CheckBoxModel::GetInstance()->SetResponseRegion(result);
191 }
192 
JsWidth(const JSCallbackInfo & info)193 void JSCheckbox::JsWidth(const JSCallbackInfo& info)
194 {
195     if (info.Length() < 1) {
196         return;
197     }
198 
199     JsWidth(info[0]);
200 }
201 
JsWidth(const JSRef<JSVal> & jsValue)202 void JSCheckbox::JsWidth(const JSRef<JSVal>& jsValue)
203 {
204     CalcDimension value;
205     ParseJsDimensionVp(jsValue, value);
206     if (value.IsNegative()) {
207         ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true);
208         return;
209     }
210     CheckBoxModel::GetInstance()->SetWidth(value);
211 }
212 
JsHeight(const JSCallbackInfo & info)213 void JSCheckbox::JsHeight(const JSCallbackInfo& info)
214 {
215     if (info.Length() < 1) {
216         return;
217     }
218 
219     JsHeight(info[0]);
220 }
221 
JsHeight(const JSRef<JSVal> & jsValue)222 void JSCheckbox::JsHeight(const JSRef<JSVal>& jsValue)
223 {
224     CalcDimension value;
225     ParseJsDimensionVp(jsValue, value);
226     if (value.IsNegative()) {
227         ViewAbstractModel::GetInstance()->ClearWidthOrHeight(false);
228         return;
229     }
230     CheckBoxModel::GetInstance()->SetHeight(value);
231 }
232 
JsSize(const JSCallbackInfo & info)233 void JSCheckbox::JsSize(const JSCallbackInfo& info)
234 {
235     if (info.Length() < 1) {
236         return;
237     }
238 
239     if (!info[0]->IsObject()) {
240         return;
241     }
242 
243     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
244     JsWidth(sizeObj->GetProperty("width"));
245     JsHeight(sizeObj->GetProperty("height"));
246 }
247 
SelectedColor(const JSCallbackInfo & info)248 void JSCheckbox::SelectedColor(const JSCallbackInfo& info)
249 {
250     if (info.Length() < 1) {
251         return;
252     }
253     Color selectedColor;
254     if (!ParseJsColor(info[0], selectedColor)) {
255         CheckBoxModel::GetInstance()->ResetSelectedColor();
256         return;
257     }
258     CheckBoxModel::GetInstance()->SetSelectedColor(selectedColor);
259 }
260 
UnSelectedColor(const JSCallbackInfo & info)261 void JSCheckbox::UnSelectedColor(const JSCallbackInfo& info)
262 {
263     if (info.Length() < 1) {
264         return;
265     }
266     Color unSelectedColor;
267     if (!ParseJsColor(info[0], unSelectedColor)) {
268         CheckBoxModel::GetInstance()->ResetUnSelectedColor();
269         return;
270     }
271 
272     CheckBoxModel::GetInstance()->SetUnSelectedColor(unSelectedColor);
273 }
274 
SetCheckboxStyle(int32_t checkBoxStyle)275 void JSCheckbox::SetCheckboxStyle(int32_t checkBoxStyle)
276 {
277     CheckBoxStyle curCheckBoxStyle = static_cast<CheckBoxStyle>(checkBoxStyle);
278     CheckBoxModel::GetInstance()->SetCheckboxStyle(curCheckBoxStyle);
279 }
Mark(const JSCallbackInfo & info)280 void JSCheckbox::Mark(const JSCallbackInfo& info)
281 {
282     auto theme = GetTheme<CheckboxTheme>();
283     if (!info[0]->IsObject()) {
284         CheckBoxModel::GetInstance()->ResetCheckMarkColor();
285         CheckBoxModel::GetInstance()->SetCheckMarkSize(Dimension(CHECK_BOX_MARK_SIZE_INVALID_VALUE));
286         CheckBoxModel::GetInstance()->SetCheckMarkWidth(theme->GetCheckStroke());
287         return;
288     }
289 
290     auto markObj = JSRef<JSObject>::Cast(info[0]);
291     auto strokeColorValue = markObj->GetProperty("strokeColor");
292     Color strokeColor;
293     if (!ParseJsColor(strokeColorValue, strokeColor)) {
294         CheckBoxModel::GetInstance()->ResetCheckMarkColor();
295     } else {
296         CheckBoxModel::GetInstance()->SetCheckMarkColor(strokeColor);
297     }
298     auto sizeValue = markObj->GetProperty("size");
299     CalcDimension size;
300     if ((ParseJsDimensionVp(sizeValue, size)) && (size.Unit() != DimensionUnit::PERCENT) && (size.ConvertToVp() >= 0)) {
301         CheckBoxModel::GetInstance()->SetCheckMarkSize(size);
302     } else {
303         CheckBoxModel::GetInstance()->SetCheckMarkSize(Dimension(CHECK_BOX_MARK_SIZE_INVALID_VALUE));
304     }
305 
306     auto strokeWidthValue = markObj->GetProperty("strokeWidth");
307     CalcDimension strokeWidth;
308     if ((ParseJsDimensionVp(strokeWidthValue, strokeWidth)) && (strokeWidth.Unit() != DimensionUnit::PERCENT) &&
309         (strokeWidth.ConvertToVp() >= 0)) {
310         CheckBoxModel::GetInstance()->SetCheckMarkWidth(strokeWidth);
311     } else {
312         CheckBoxModel::GetInstance()->SetCheckMarkWidth(theme->GetCheckStroke());
313     }
314 }
315 
JsPadding(const JSCallbackInfo & info)316 void JSCheckbox::JsPadding(const JSCallbackInfo& info)
317 {
318     if (info.Length() < 1) {
319         return;
320     }
321     NG::PaddingPropertyF oldPadding({ 0.0f, 0.0f, 0.0f, 0.0f });
322     bool flag = GetOldPadding(info, oldPadding);
323     NG::PaddingProperty newPadding = GetNewPadding(info);
324     CheckBoxModel::GetInstance()->SetPadding(oldPadding, newPadding, flag);
325 }
326 
GetOldPadding(const JSCallbackInfo & info,NG::PaddingPropertyF & padding)327 bool JSCheckbox::GetOldPadding(const JSCallbackInfo& info, NG::PaddingPropertyF& padding)
328 {
329     if (info[0]->IsObject()) {
330         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
331         if (jsObj->HasProperty("top") || jsObj->HasProperty("bottom")
332             || jsObj->HasProperty("left") || jsObj->HasProperty("right")) {
333             CalcDimension topDimen = CalcDimension(0.0, DimensionUnit::VP);
334             CalcDimension leftDimen = CalcDimension(0.0, DimensionUnit::VP);
335             CalcDimension rightDimen = CalcDimension(0.0, DimensionUnit::VP);
336             CalcDimension bottomDimen = CalcDimension(0.0, DimensionUnit::VP);
337             ParseJsDimensionVp(jsObj->GetProperty("top"), topDimen);
338             ParseJsDimensionVp(jsObj->GetProperty("left"), leftDimen);
339             ParseJsDimensionVp(jsObj->GetProperty("right"), rightDimen);
340             ParseJsDimensionVp(jsObj->GetProperty("bottom"), bottomDimen);
341             if (leftDimen == 0.0_vp) {
342                 leftDimen = rightDimen;
343             }
344             if (topDimen == 0.0_vp) {
345                 topDimen = bottomDimen;
346             }
347             if (leftDimen == 0.0_vp) {
348                 leftDimen = topDimen;
349             }
350 
351             padding.left = leftDimen.ConvertToPx();
352             padding.right = rightDimen.ConvertToPx();
353             padding.top = topDimen.ConvertToPx();
354             padding.bottom = bottomDimen.ConvertToPx();
355             return true;
356         }
357     }
358 
359     CalcDimension length;
360     if (!ParseJsDimensionVp(info[0], length)) {
361         return false;
362     }
363 
364     padding.left = length.ConvertToPx();
365     padding.right = length.ConvertToPx();
366     padding.top = length.ConvertToPx();
367     padding.bottom = length.ConvertToPx();
368     return true;
369 }
370 
GetNewPadding(const JSCallbackInfo & info)371 NG::PaddingProperty JSCheckbox::GetNewPadding(const JSCallbackInfo& info)
372 {
373     NG::PaddingProperty padding({ NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp),
374         NG::CalcLength(0.0_vp), std::nullopt, std::nullopt });
375     if (info[0]->IsObject()) {
376         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
377         CommonCalcDimension commonCalcDimension;
378         ParseCommonMarginOrPaddingCorner(paddingObj, commonCalcDimension);
379         if (commonCalcDimension.left.has_value() || commonCalcDimension.right.has_value() ||
380             commonCalcDimension.top.has_value() || commonCalcDimension.bottom.has_value()) {
381             padding = GetPadding(commonCalcDimension.top, commonCalcDimension.bottom, commonCalcDimension.left,
382                 commonCalcDimension.right);
383             return padding;
384         }
385     }
386     CalcDimension length;
387     if (!ParseJsDimensionVp(info[0], length)) {
388         length.Reset();
389     }
390 
391     padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
392     return padding;
393 }
394 
GetPadding(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)395 NG::PaddingProperty JSCheckbox::GetPadding(const std::optional<CalcDimension>& top,
396     const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
397     const std::optional<CalcDimension>& right)
398 {
399     NG::PaddingProperty padding({ NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp),
400         NG::CalcLength(0.0_vp), std::nullopt, std::nullopt });
401     if (left.has_value()) {
402         if (left.value().Unit() == DimensionUnit::CALC) {
403             padding.left =
404                 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
405         } else {
406             padding.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
407         }
408     }
409     if (right.has_value()) {
410         if (right.value().Unit() == DimensionUnit::CALC) {
411             padding.right =
412                 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
413         } else {
414             padding.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
415         }
416     }
417     if (top.has_value()) {
418         if (top.value().Unit() == DimensionUnit::CALC) {
419             padding.top =
420                 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
421         } else {
422             padding.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
423         }
424     }
425     if (bottom.has_value()) {
426         if (bottom.value().Unit() == DimensionUnit::CALC) {
427             padding.bottom = NG::CalcLength(
428                 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
429         } else {
430             padding.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
431         }
432     }
433     return padding;
434 }
435 } // namespace OHOS::Ace::Framework
436