• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "frameworks/bridge/declarative_frontend/jsview/js_toggle.h"
17 
18 #include <cstddef>
19 #include <string>
20 
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
23 #include "bridge/declarative_frontend/jsview/models/toggle_model_impl.h"
24 #include "core/common/container.h"
25 #include "core/components/common/properties/color.h"
26 #include "core/components/toggle/toggle_theme.h"
27 #include "core/components_ng/base/view_stack_processor.h"
28 #include "core/components_ng/pattern/button/toggle_button_model_ng.h"
29 #include "core/components_ng/pattern/toggle/toggle_model_ng.h"
30 
31 namespace OHOS::Ace {
32 
33 std::unique_ptr<ToggleModel> ToggleModel::instance_ = nullptr;
34 std::mutex ToggleModel::mutex_;
35 
GetInstance()36 ToggleModel* ToggleModel::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::ToggleModelNG());
43 #else
44             if (Container::IsCurrentUseNewPipeline()) {
45                 instance_.reset(new NG::ToggleModelNG());
46             } else {
47                 instance_.reset(new Framework::ToggleModelImpl());
48             }
49 #endif
50         }
51     }
52     return instance_.get();
53 }
54 
55 } // namespace OHOS::Ace
56 
57 namespace OHOS::Ace::Framework {
58 int32_t JSToggle::toggleType_ = 1;
JSBind(BindingTarget globalObj)59 void JSToggle::JSBind(BindingTarget globalObj)
60 {
61     JSClass<JSToggle>::Declare("Toggle");
62     JSClass<JSToggle>::StaticMethod("create", &JSToggle::Create);
63     JSClass<JSToggle>::StaticMethod("onChange", &JSToggle::OnChange);
64     JSClass<JSToggle>::StaticMethod("selectedColor", &JSToggle::SelectedColor);
65     JSClass<JSToggle>::StaticMethod("width", &JSToggle::JsWidth);
66     JSClass<JSToggle>::StaticMethod("height", &JSToggle::JsHeight);
67     JSClass<JSToggle>::StaticMethod("responseRegion", &JSToggle::JsResponseRegion);
68     JSClass<JSToggle>::StaticMethod("size", &JSToggle::JsSize);
69     JSClass<JSToggle>::StaticMethod("padding", &JSToggle::JsPadding);
70     JSClass<JSToggle>::StaticMethod("switchPointColor", &JSToggle::SwitchPointColor);
71     JSClass<JSToggle>::StaticMethod("backgroundColor", &JSToggle::SetBackgroundColor);
72     JSClass<JSToggle>::StaticMethod("hoverEffect", &JSToggle::JsHoverEffect);
73     JSClass<JSToggle>::StaticMethod("pop", &JSToggle::Pop);
74 
75     JSClass<JSToggle>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
76     JSClass<JSToggle>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
77     JSClass<JSToggle>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
78     JSClass<JSToggle>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
79     JSClass<JSToggle>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
80     JSClass<JSToggle>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
81     JSClass<JSToggle>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
82     JSClass<JSToggle>::InheritAndBind<JSViewAbstract>(globalObj);
83 }
84 
ParseToggleIsOnObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)85 void ParseToggleIsOnObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
86 {
87     CHECK_NULL_VOID(changeEventVal->IsFunction());
88 
89     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
90     WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
91     auto onChangeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
92                              bool isOn) {
93         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
94         ACE_SCORING_EVENT("Toggle.onChangeEvent");
95         PipelineContext::SetCallBackNode(node);
96         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isOn));
97         func->ExecuteJS(1, &newJSVal);
98     };
99     ToggleModel::GetInstance()->OnChangeEvent(std::move(onChangeEvent));
100 }
101 
Create(const JSCallbackInfo & info)102 void JSToggle::Create(const JSCallbackInfo& info)
103 {
104     if (!info[0]->IsObject()) {
105         return;
106     }
107 
108     auto paramObject = JSRef<JSObject>::Cast(info[0]);
109     auto type = paramObject->GetProperty("type");
110     int32_t toggleTypeInt = 1;
111     if (type->IsNumber()) {
112         toggleTypeInt = type->ToNumber<int32_t>();
113     }
114     if (toggleTypeInt < 0 || toggleTypeInt > 2) {
115         toggleTypeInt = 1;
116     }
117     toggleType_ = toggleTypeInt;
118     auto tempIsOn = paramObject->GetProperty("isOn");
119     bool isOn = false;
120     JSRef<JSVal> changeEventVal;
121     if (tempIsOn->IsObject()) {
122         JSRef<JSObject> isOnObj = JSRef<JSObject>::Cast(tempIsOn);
123         changeEventVal = isOnObj->GetProperty("changeEvent");
124         auto isOnProperty = isOnObj->GetProperty("value");
125         isOn = isOnProperty->IsBoolean() ? isOnProperty->ToBoolean() : false;
126     } else {
127         isOn = tempIsOn->IsBoolean() ? tempIsOn->ToBoolean() : false;
128     }
129 
130     ToggleModel::GetInstance()->Create(NG::ToggleType(toggleTypeInt), isOn);
131     if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
132         ParseToggleIsOnObject(info, changeEventVal);
133     }
134 }
135 
JsWidth(const JSCallbackInfo & info)136 void JSToggle::JsWidth(const JSCallbackInfo& info)
137 {
138     if (info.Length() < 1) {
139         return;
140     }
141 
142     JsWidth(info[0]);
143 }
144 
JsWidth(const JSRef<JSVal> & jsValue)145 void JSToggle::JsWidth(const JSRef<JSVal>& jsValue)
146 {
147     auto switchTheme = GetTheme<SwitchTheme>();
148     CHECK_NULL_VOID(switchTheme);
149     auto defaultWidth = switchTheme->GetWidth();
150     auto horizontalPadding = switchTheme->GetHotZoneHorizontalPadding();
151     auto width = defaultWidth - horizontalPadding * 2;
152     if (toggleType_ == 0) {
153         auto checkboxTheme = GetTheme<CheckboxTheme>();
154         CHECK_NULL_VOID(checkboxTheme);
155         defaultWidth = checkboxTheme->GetDefaultWidth();
156         horizontalPadding = checkboxTheme->GetHotZoneHorizontalPadding();
157         width = defaultWidth - horizontalPadding * 2;
158     }
159     CalcDimension value(width);
160     ParseJsDimensionVp(jsValue, value);
161     if (value.IsNegative()) {
162         value = width;
163     }
164     ToggleModel::GetInstance()->SetWidth(value);
165 }
166 
JsHeight(const JSCallbackInfo & info)167 void JSToggle::JsHeight(const JSCallbackInfo& info)
168 {
169     if (info.Length() < 1) {
170         return;
171     }
172 
173     JsHeight(info[0]);
174 }
175 
JsHeight(const JSRef<JSVal> & jsValue)176 void JSToggle::JsHeight(const JSRef<JSVal>& jsValue)
177 {
178     auto pipeline = PipelineBase::GetCurrentContext();
179     CHECK_NULL_VOID(pipeline);
180     auto switchTheme = pipeline->GetTheme<SwitchTheme>();
181     CHECK_NULL_VOID(switchTheme);
182     auto defaultHeight = switchTheme->GetHeight();
183     auto verticalPadding = switchTheme->GetHotZoneVerticalPadding();
184     auto height = defaultHeight - verticalPadding * 2;
185     CalcDimension value(height);
186     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
187         if (!ParseJsDimensionVpNG(jsValue, value) || value.IsNegative()) {
188             value = height;
189         }
190     } else {
191         ParseJsDimensionVp(jsValue, value);
192         if (value.IsNegative()) {
193             value = height;
194         }
195     }
196     ToggleModel::GetInstance()->SetHeight(value);
197 }
198 
JsResponseRegion(const JSCallbackInfo & info)199 void JSToggle::JsResponseRegion(const JSCallbackInfo& info)
200 {
201     if (!Container::IsCurrentUseNewPipeline()) {
202         JSViewAbstract::JsResponseRegion(info);
203         return;
204     }
205     std::vector<DimensionRect> result;
206     if (!JSViewAbstract::ParseJsResponseRegionArray(info[0], result)) {
207         return;
208     }
209     ToggleModel::GetInstance()->SetResponseRegion(result);
210 }
211 
JsSize(const JSCallbackInfo & info)212 void JSToggle::JsSize(const JSCallbackInfo& info)
213 {
214     if (!info[0]->IsObject()) {
215         return;
216     }
217 
218     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
219     JsWidth(sizeObj->GetProperty("width"));
220     JsHeight(sizeObj->GetProperty("height"));
221 }
222 
OnChange(const JSCallbackInfo & args)223 void JSToggle::OnChange(const JSCallbackInfo& args)
224 {
225     if (!args[0]->IsFunction()) {
226         return;
227     }
228     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
229     WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
230     auto onChange = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](bool isOn) {
231         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
232         ACE_SCORING_EVENT("Toggle.onChange");
233         PipelineContext::SetCallBackNode(node);
234         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isOn));
235         func->ExecuteJS(1, &newJSVal);
236     };
237     ToggleModel::GetInstance()->OnChange(std::move(onChange));
238     args.ReturnSelf();
239 }
240 
SelectedColor(const JSCallbackInfo & info)241 void JSToggle::SelectedColor(const JSCallbackInfo& info)
242 {
243     if (info.Length() < 1) {
244         return;
245     }
246     Color color;
247     std::optional<Color> selectedColor;
248     if (ParseJsColor(info[0], color)) {
249         selectedColor = color;
250     }
251 
252     ToggleModel::GetInstance()->SetSelectedColor(selectedColor);
253 }
254 
SwitchPointColor(const JSCallbackInfo & info)255 void JSToggle::SwitchPointColor(const JSCallbackInfo& info)
256 {
257     if (info.Length() < 1) {
258         return;
259     }
260     Color color;
261     if (!ParseJsColor(info[0], color)) {
262         auto theme = GetTheme<SwitchTheme>();
263         if (theme) {
264             color = theme->GetPointColor();
265         }
266     }
267 
268     ToggleModel::GetInstance()->SetSwitchPointColor(color);
269 }
270 
JsPadding(const JSCallbackInfo & info)271 void JSToggle::JsPadding(const JSCallbackInfo& info)
272 {
273     if (info.Length() < 1) {
274         return;
275     }
276     NG::PaddingPropertyF oldPadding = GetOldPadding(info);
277     NG::PaddingProperty newPadding = GetNewPadding(info);
278     ToggleModel::GetInstance()->SetPadding(oldPadding, newPadding);
279 }
280 
GetOldPadding(const JSCallbackInfo & info)281 NG::PaddingPropertyF JSToggle::GetOldPadding(const JSCallbackInfo& info)
282 {
283     NG::PaddingPropertyF padding({ 0.0f, 0.0f, 0.0f, 0.0f });
284     if (info[0]->IsObject()) {
285         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
286         if (jsObj->HasProperty("top") || jsObj->HasProperty("bottom")
287             || jsObj->HasProperty("left") || jsObj->HasProperty("right")) {
288             CalcDimension topDimen = CalcDimension(0.0, DimensionUnit::VP);
289             CalcDimension leftDimen = CalcDimension(0.0, DimensionUnit::VP);
290             CalcDimension rightDimen = CalcDimension(0.0, DimensionUnit::VP);
291             CalcDimension bottomDimen = CalcDimension(0.0, DimensionUnit::VP);
292             ParseJsDimensionVp(jsObj->GetProperty("top"), topDimen);
293             ParseJsDimensionVp(jsObj->GetProperty("left"), leftDimen);
294             ParseJsDimensionVp(jsObj->GetProperty("right"), rightDimen);
295             ParseJsDimensionVp(jsObj->GetProperty("bottom"), bottomDimen);
296             if (leftDimen == 0.0_vp) {
297                 leftDimen = rightDimen;
298             }
299             if (topDimen == 0.0_vp) {
300                 topDimen = bottomDimen;
301             }
302             if (leftDimen == 0.0_vp) {
303                 leftDimen = topDimen;
304             }
305 
306             padding.left = leftDimen.ConvertToPx();
307             padding.right = rightDimen.ConvertToPx();
308             padding.top = topDimen.ConvertToPx();
309             padding.bottom = bottomDimen.ConvertToPx();
310             return padding;
311         }
312     }
313 
314     CalcDimension length;
315     if (!ParseJsDimensionVp(info[0], length)) {
316         return padding;
317     }
318 
319     padding.left = length.ConvertToPx();
320     padding.right = length.ConvertToPx();
321     padding.top = length.ConvertToPx();
322     padding.bottom = length.ConvertToPx();
323     return padding;
324 }
325 
GetNewPadding(const JSCallbackInfo & info)326 NG::PaddingProperty JSToggle::GetNewPadding(const JSCallbackInfo& info)
327 {
328     NG::PaddingProperty padding(
329         { NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp) });
330     if (info[0]->IsObject()) {
331         std::optional<CalcDimension> left;
332         std::optional<CalcDimension> right;
333         std::optional<CalcDimension> top;
334         std::optional<CalcDimension> bottom;
335         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
336 
337         CalcDimension leftDimen;
338         if (ParseJsDimensionVp(paddingObj->GetProperty("left"), leftDimen)) {
339             left = leftDimen;
340         }
341         CalcDimension rightDimen;
342         if (ParseJsDimensionVp(paddingObj->GetProperty("right"), rightDimen)) {
343             right = rightDimen;
344         }
345         CalcDimension topDimen;
346         if (ParseJsDimensionVp(paddingObj->GetProperty("top"), topDimen)) {
347             top = topDimen;
348         }
349         CalcDimension bottomDimen;
350         if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottomDimen)) {
351             bottom = bottomDimen;
352         }
353         if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
354             padding = GetPadding(top, bottom, left, right);
355             return padding;
356         }
357     }
358     CalcDimension length;
359     if (!ParseJsDimensionVp(info[0], length)) {
360         length.Reset();
361     }
362 
363     padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
364     return padding;
365 }
366 
GetPadding(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)367 NG::PaddingProperty JSToggle::GetPadding(const std::optional<CalcDimension>& top,
368     const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
369     const std::optional<CalcDimension>& right)
370 {
371     NG::PaddingProperty padding(
372         { NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp) });
373     if (left.has_value() && left.value().IsNonNegative()) {
374         padding.left = NG::CalcLength(left.value());
375     }
376     if (right.has_value() && right.value().IsNonNegative()) {
377         padding.right = NG::CalcLength(right.value());
378     }
379     if (top.has_value() && top.value().IsNonNegative()) {
380         padding.top = NG::CalcLength(top.value());
381     }
382     if (bottom.has_value() && bottom.value().IsNonNegative()) {
383         padding.bottom = NG::CalcLength(bottom.value());
384     }
385     return padding;
386 }
387 
SetBackgroundColor(const JSCallbackInfo & info)388 void JSToggle::SetBackgroundColor(const JSCallbackInfo& info)
389 {
390     if (info.Length() < 1) {
391         return;
392     }
393     Color backgroundColor;
394     if (!ParseJsColor(info[0], backgroundColor)) {
395         return;
396     }
397 
398     if (!Container::IsCurrentUseNewPipeline()) {
399         JSViewAbstract::JsBackgroundColor(info);
400         return;
401     }
402     ToggleModel::GetInstance()->SetBackgroundColor(backgroundColor);
403 }
404 
JsHoverEffect(const JSCallbackInfo & info)405 void JSToggle::JsHoverEffect(const JSCallbackInfo& info)
406 {
407     if (info.Length() > 0 && info[0]->IsNumber()) {
408         ToggleModel::GetInstance()->SetHoverEffect(static_cast<HoverEffectType>(info[0]->ToNumber<int32_t>()));
409     }
410 }
411 
Pop()412 void JSToggle::Pop()
413 {
414     ToggleModel::GetInstance()->Pop();
415 }
416 } // namespace OHOS::Ace::Framework
417