• 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("margin", &JSCheckbox::JsMargin);
106     JSClass<JSCheckbox>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
107     JSClass<JSCheckbox>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
108     JSClass<JSCheckbox>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
109     JSClass<JSCheckbox>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
110     JSClass<JSCheckbox>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
111     JSClass<JSCheckbox>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
112     JSClass<JSCheckbox>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
113     JSClass<JSCheckbox>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
114     JSClass<JSCheckbox>::InheritAndBind<JSViewAbstract>(globalObj);
115 }
116 
ParseSelectObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)117 void ParseSelectObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
118 {
119     CHECK_NULL_VOID(changeEventVal->IsFunction());
120 
121     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
122     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
123     auto changeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](bool param) {
124         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
125         ACE_SCORING_EVENT("CheckBox.ChangeEvent");
126         PipelineContext::SetCallBackNode(node);
127         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(param));
128         func->ExecuteJS(1, &newJSVal);
129     };
130     CheckBoxModel::GetInstance()->SetChangeEvent(std::move(changeEvent));
131 }
132 
SetSelect(const JSCallbackInfo & info)133 void JSCheckbox::SetSelect(const JSCallbackInfo& info)
134 {
135     auto length = info.Length();
136     if (length < 1 || length > 2) {
137         return;
138     }
139     bool select = 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         select = selectedVal->ToBoolean();
152     }
153     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "checkbox set select %{public}d", select);
154     CheckBoxModel::GetInstance()->SetSelect(select);
155     if (changeEventVal->IsFunction()) {
156         ParseSelectObject(info, changeEventVal);
157     }
158 }
159 
SetOnChange(const JSCallbackInfo & args)160 void JSCheckbox::SetOnChange(const JSCallbackInfo& args)
161 {
162     if (!args[0]->IsFunction()) {
163         return;
164     }
165     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
166     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
167     auto onChange = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](bool select) {
168         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
169         ACE_SCORING_EVENT("CheckBox.onChange");
170         PipelineContext::SetCallBackNode(node);
171         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(select));
172         func->ExecuteJS(1, &newJSVal);
173     };
174     CheckBoxModel::GetInstance()->SetOnChange(onChange);
175     args.ReturnSelf();
176 }
177 
JsResponseRegion(const JSCallbackInfo & info)178 void JSCheckbox::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     CheckBoxModel::GetInstance()->SetResponseRegion(result);
192 }
193 
JsWidth(const JSCallbackInfo & info)194 void JSCheckbox::JsWidth(const JSCallbackInfo& info)
195 {
196     if (info.Length() < 1) {
197         return;
198     }
199 
200     JsWidth(info[0]);
201 }
202 
JsWidth(const JSRef<JSVal> & jsValue)203 void JSCheckbox::JsWidth(const JSRef<JSVal>& jsValue)
204 {
205     CalcDimension value;
206     ParseJsDimensionVp(jsValue, value);
207     if (value.IsNegative()) {
208         ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true);
209         return;
210     }
211     CheckBoxModel::GetInstance()->SetWidth(value);
212 }
213 
JsHeight(const JSCallbackInfo & info)214 void JSCheckbox::JsHeight(const JSCallbackInfo& info)
215 {
216     if (info.Length() < 1) {
217         return;
218     }
219 
220     JsHeight(info[0]);
221 }
222 
JsHeight(const JSRef<JSVal> & jsValue)223 void JSCheckbox::JsHeight(const JSRef<JSVal>& jsValue)
224 {
225     CalcDimension value;
226     ParseJsDimensionVp(jsValue, value);
227     if (value.IsNegative()) {
228         ViewAbstractModel::GetInstance()->ClearWidthOrHeight(false);
229         return;
230     }
231     CheckBoxModel::GetInstance()->SetHeight(value);
232 }
233 
JsSize(const JSCallbackInfo & info)234 void JSCheckbox::JsSize(const JSCallbackInfo& info)
235 {
236     if (info.Length() < 1) {
237         return;
238     }
239 
240     if (!info[0]->IsObject()) {
241         return;
242     }
243 
244     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
245     JsWidth(sizeObj->GetProperty("width"));
246     JsHeight(sizeObj->GetProperty("height"));
247 }
248 
SelectedColor(const JSCallbackInfo & info)249 void JSCheckbox::SelectedColor(const JSCallbackInfo& info)
250 {
251     if (info.Length() < 1) {
252         return;
253     }
254     Color selectedColor;
255     RefPtr<ResourceObject> resObj;
256     if (!ParseJsColor(info[0], selectedColor, resObj)) {
257         CheckBoxModel::GetInstance()->ResetSelectedColor();
258     } else {
259         CheckBoxModel::GetInstance()->SetSelectedColor(selectedColor);
260     }
261     if (SystemProperties::ConfigChangePerform()) {
262         CheckBoxModel::GetInstance()->CreateWithColorResourceObj(resObj, CheckBoxColorType::SELECTED_COLOR);
263     }
264 }
265 
UnSelectedColor(const JSCallbackInfo & info)266 void JSCheckbox::UnSelectedColor(const JSCallbackInfo& info)
267 {
268     if (info.Length() < 1) {
269         return;
270     }
271     Color unSelectedColor;
272     RefPtr<ResourceObject> resObj;
273     if (!ParseJsColor(info[0], unSelectedColor, resObj)) {
274         CheckBoxModel::GetInstance()->ResetUnSelectedColor();
275     } else {
276         CheckBoxModel::GetInstance()->SetUnSelectedColor(unSelectedColor);
277     }
278     if (SystemProperties::ConfigChangePerform()) {
279         CheckBoxModel::GetInstance()->CreateWithColorResourceObj(resObj, CheckBoxColorType::UN_SELECTED_COLOR);
280     }
281 }
282 
SetCheckboxStyle(int32_t checkBoxStyle)283 void JSCheckbox::SetCheckboxStyle(int32_t checkBoxStyle)
284 {
285     CheckBoxStyle curCheckBoxStyle = static_cast<CheckBoxStyle>(checkBoxStyle);
286     CheckBoxModel::GetInstance()->SetCheckboxStyle(curCheckBoxStyle);
287 }
Mark(const JSCallbackInfo & info)288 void JSCheckbox::Mark(const JSCallbackInfo& info)
289 {
290     auto theme = GetTheme<CheckboxTheme>();
291     auto defaultStroke = theme ? theme->GetCheckStroke() : Dimension();
292     if (!info[0]->IsObject()) {
293         CheckBoxModel::GetInstance()->ResetCheckMarkColor();
294         CheckBoxModel::GetInstance()->SetCheckMarkSize(Dimension(CHECK_BOX_MARK_SIZE_INVALID_VALUE));
295         CheckBoxModel::GetInstance()->SetCheckMarkWidth(defaultStroke);
296         return;
297     }
298 
299     auto markObj = JSRef<JSObject>::Cast(info[0]);
300     auto strokeColorValue = markObj->GetProperty("strokeColor");
301     Color strokeColor;
302     if (!ParseJsColor(strokeColorValue, strokeColor)) {
303         CheckBoxModel::GetInstance()->ResetCheckMarkColor();
304     } else {
305         CheckBoxModel::GetInstance()->SetCheckMarkColor(strokeColor);
306     }
307     auto sizeValue = markObj->GetProperty("size");
308     CalcDimension size;
309     if ((ParseJsDimensionVp(sizeValue, size)) && (size.Unit() != DimensionUnit::PERCENT) && (size.ConvertToVp() >= 0)) {
310         CheckBoxModel::GetInstance()->SetCheckMarkSize(size);
311     } else {
312         CheckBoxModel::GetInstance()->SetCheckMarkSize(Dimension(CHECK_BOX_MARK_SIZE_INVALID_VALUE));
313     }
314 
315     auto strokeWidthValue = markObj->GetProperty("strokeWidth");
316     CalcDimension strokeWidth;
317     if ((ParseJsDimensionVp(strokeWidthValue, strokeWidth)) && (strokeWidth.Unit() != DimensionUnit::PERCENT) &&
318         (strokeWidth.ConvertToVp() >= 0)) {
319         CheckBoxModel::GetInstance()->SetCheckMarkWidth(strokeWidth);
320     } else {
321         CheckBoxModel::GetInstance()->SetCheckMarkWidth(defaultStroke);
322     }
323 }
324 
JsPadding(const JSCallbackInfo & info)325 void JSCheckbox::JsPadding(const JSCallbackInfo& info)
326 {
327     if (info.Length() < 1) {
328         return;
329     }
330     NG::PaddingPropertyF oldPadding({ 0.0f, 0.0f, 0.0f, 0.0f });
331     bool flag = GetOldPadding(info, oldPadding);
332     NG::PaddingProperty newPadding = GetNewPadding(info);
333     CheckBoxModel::GetInstance()->SetPadding(oldPadding, newPadding, flag);
334 }
335 
JsMargin(const JSCallbackInfo & info)336 void JSCheckbox::JsMargin(const JSCallbackInfo& info)
337 {
338     CheckBoxModel::GetInstance()->SetIsUserSetMargin(true);
339     JSViewAbstract::JsMargin(info);
340 }
341 
GetOldPadding(const JSCallbackInfo & info,NG::PaddingPropertyF & padding)342 bool JSCheckbox::GetOldPadding(const JSCallbackInfo& info, NG::PaddingPropertyF& padding)
343 {
344     if (info[0]->IsObject()) {
345         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
346         if (jsObj->HasProperty("top") || jsObj->HasProperty("bottom")
347             || jsObj->HasProperty("left") || jsObj->HasProperty("right")) {
348             CalcDimension topDimen = CalcDimension(0.0, DimensionUnit::VP);
349             CalcDimension leftDimen = CalcDimension(0.0, DimensionUnit::VP);
350             CalcDimension rightDimen = CalcDimension(0.0, DimensionUnit::VP);
351             CalcDimension bottomDimen = CalcDimension(0.0, DimensionUnit::VP);
352             ParseJsDimensionVp(jsObj->GetProperty("top"), topDimen);
353             ParseJsDimensionVp(jsObj->GetProperty("left"), leftDimen);
354             ParseJsDimensionVp(jsObj->GetProperty("right"), rightDimen);
355             ParseJsDimensionVp(jsObj->GetProperty("bottom"), bottomDimen);
356             if (leftDimen == 0.0_vp) {
357                 leftDimen = rightDimen;
358             }
359             if (topDimen == 0.0_vp) {
360                 topDimen = bottomDimen;
361             }
362             if (leftDimen == 0.0_vp) {
363                 leftDimen = topDimen;
364             }
365 
366             padding.left = leftDimen.ConvertToPx();
367             padding.right = rightDimen.ConvertToPx();
368             padding.top = topDimen.ConvertToPx();
369             padding.bottom = bottomDimen.ConvertToPx();
370             return true;
371         }
372     }
373 
374     CalcDimension length;
375     if (!ParseJsDimensionVp(info[0], length)) {
376         return false;
377     }
378 
379     padding.left = length.ConvertToPx();
380     padding.right = length.ConvertToPx();
381     padding.top = length.ConvertToPx();
382     padding.bottom = length.ConvertToPx();
383     return true;
384 }
385 
GetNewPadding(const JSCallbackInfo & info)386 NG::PaddingProperty JSCheckbox::GetNewPadding(const JSCallbackInfo& info)
387 {
388     NG::PaddingProperty padding({ NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp),
389         NG::CalcLength(0.0_vp), std::nullopt, std::nullopt });
390     if (info[0]->IsObject()) {
391         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
392         CommonCalcDimension commonCalcDimension;
393         ParseCommonMarginOrPaddingCorner(paddingObj, commonCalcDimension);
394         if (commonCalcDimension.left.has_value() || commonCalcDimension.right.has_value() ||
395             commonCalcDimension.top.has_value() || commonCalcDimension.bottom.has_value()) {
396             padding = GetPadding(commonCalcDimension.top, commonCalcDimension.bottom, commonCalcDimension.left,
397                 commonCalcDimension.right);
398             return padding;
399         }
400     }
401     CalcDimension length;
402     if (!ParseJsDimensionVp(info[0], length)) {
403         length.Reset();
404     }
405 
406     padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
407     return padding;
408 }
409 
GetPadding(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)410 NG::PaddingProperty JSCheckbox::GetPadding(const std::optional<CalcDimension>& top,
411     const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
412     const std::optional<CalcDimension>& right)
413 {
414     NG::PaddingProperty padding({ NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp),
415         NG::CalcLength(0.0_vp), std::nullopt, std::nullopt });
416     if (left.has_value()) {
417         if (left.value().Unit() == DimensionUnit::CALC) {
418             padding.left =
419                 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
420         } else {
421             padding.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
422         }
423     }
424     if (right.has_value()) {
425         if (right.value().Unit() == DimensionUnit::CALC) {
426             padding.right =
427                 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
428         } else {
429             padding.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
430         }
431     }
432     if (top.has_value()) {
433         if (top.value().Unit() == DimensionUnit::CALC) {
434             padding.top =
435                 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
436         } else {
437             padding.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
438         }
439     }
440     if (bottom.has_value()) {
441         if (bottom.value().Unit() == DimensionUnit::CALC) {
442             padding.bottom = NG::CalcLength(
443                 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
444         } else {
445             padding.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
446         }
447     }
448     return padding;
449 }
450 } // namespace OHOS::Ace::Framework
451