• 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 "frameworks/bridge/declarative_frontend/jsview/js_tabs.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "bridge/declarative_frontend/engine/functions/js_swiper_function.h"
20 #include "bridge/declarative_frontend/engine/functions/js_tabs_function.h"
21 #include "bridge/declarative_frontend/jsview/js_tabs_controller.h"
22 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
23 #include "bridge/declarative_frontend/jsview/models/tabs_model_impl.h"
24 #include "core/components/common/layout/constants.h"
25 #include "core/components/common/properties/decoration.h"
26 #include "core/components_ng/base/view_stack_processor.h"
27 #include "core/components_ng/pattern/tabs/tabs_model_ng.h"
28 #include "core/components_ng/pattern/tabs/tab_content_transition_proxy.h"
29 
30 namespace OHOS::Ace {
31 
32 std::unique_ptr<TabsModel> TabsModel::instance_ = nullptr;
33 std::mutex TabsModel::mutex_;
34 
GetInstance()35 TabsModel* TabsModel::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::TabsModelNG());
42 #else
43             if (Container::IsCurrentUseNewPipeline()) {
44                 instance_.reset(new NG::TabsModelNG());
45             } else {
46                 instance_.reset(new Framework::TabsModelImpl());
47             }
48 #endif
49         }
50     }
51     return instance_.get();
52 }
53 
54 } // namespace OHOS::Ace
55 
56 namespace OHOS::Ace::Framework {
57 namespace {
58 constexpr int32_t SM_COLUMN_NUM = 4;
59 constexpr int32_t MD_COLUMN_NUM = 8;
60 constexpr int32_t LG_COLUMN_NUM = 12;
61 constexpr int32_t DEFAULT_CUSTOM_ANIMATION_TIMEOUT = 1000;
62 const std::vector<BarPosition> BAR_POSITIONS = { BarPosition::START, BarPosition::END };
63 
64 const std::vector<BlurStyle> BAR_BLURSTYLE = {
65     BlurStyle::NO_MATERIAL,
66     BlurStyle::THIN,
67     BlurStyle::REGULAR,
68     BlurStyle::THICK,
69     BlurStyle::BACKGROUND_THIN,
70     BlurStyle::BACKGROUND_REGULAR,
71     BlurStyle::BACKGROUND_THICK,
72     BlurStyle::BACKGROUND_ULTRA_THICK,
73     BlurStyle::COMPONENT_ULTRA_THIN,
74     BlurStyle::COMPONENT_THIN,
75     BlurStyle::COMPONENT_REGULAR,
76     BlurStyle::COMPONENT_THICK,
77     BlurStyle::COMPONENT_ULTRA_THICK,
78 };
79 
TabContentChangeEventToJSValue(const TabContentChangeEvent & eventInfo)80 JSRef<JSVal> TabContentChangeEventToJSValue(const TabContentChangeEvent& eventInfo)
81 {
82     return JSRef<JSVal>::Make(ToJSValue(eventInfo.GetIndex()));
83 }
84 
85 } // namespace
86 
SetOnChange(const JSCallbackInfo & info)87 void JSTabs::SetOnChange(const JSCallbackInfo& info)
88 {
89     if (!info[0]->IsFunction()) {
90         return;
91     }
92 
93     auto changeHandler = AceType::MakeRefPtr<JsEventFunction<TabContentChangeEvent, 1>>(
94         JSRef<JSFunc>::Cast(info[0]), TabContentChangeEventToJSValue);
95     WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
96     auto onChange = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler), node = targetNode](
97                         const BaseEventInfo* info) {
98         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
99         const auto* tabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
100         if (!tabsInfo) {
101             TAG_LOGW(AceLogTag::ACE_TABS, "Tabs onChange callback execute failed.");
102             return;
103         }
104         ACE_SCORING_EVENT("Tabs.onChange");
105         PipelineContext::SetCallBackNode(node);
106         func->Execute(*tabsInfo);
107     };
108     TabsModel::GetInstance()->SetOnChange(std::move(onChange));
109 }
110 
SetOnTabBarClick(const JSCallbackInfo & info)111 void JSTabs::SetOnTabBarClick(const JSCallbackInfo& info)
112 {
113     if (!info[0]->IsFunction()) {
114         return;
115     }
116 
117     auto changeHandler = AceType::MakeRefPtr<JsEventFunction<TabContentChangeEvent, 1>>(
118         JSRef<JSFunc>::Cast(info[0]), TabContentChangeEventToJSValue);
119     WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
120     auto onTabBarClick = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler),
121                              node = targetNode](const BaseEventInfo* info) {
122         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
123         const auto* tabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
124         if (!tabsInfo) {
125             TAG_LOGW(AceLogTag::ACE_TABS, "Tabs onTabBarClick callback execute failed.");
126             return;
127         }
128         ACE_SCORING_EVENT("Tabs.onTabBarClick");
129         PipelineContext::SetCallBackNode(node);
130         func->Execute(*tabsInfo);
131     };
132     TabsModel::GetInstance()->SetOnTabBarClick(std::move(onTabBarClick));
133 }
134 
SetOnAnimationStart(const JSCallbackInfo & info)135 void JSTabs::SetOnAnimationStart(const JSCallbackInfo& info)
136 {
137     if (!info[0]->IsFunction()) {
138         return;
139     }
140 
141     auto animationStartHandler = AceType::MakeRefPtr<JsSwiperFunction>(JSRef<JSFunc>::Cast(info[0]));
142     auto onAnimationStart = [executionContext = info.GetExecutionContext(),
143                                 func = std::move(animationStartHandler)](
144                                 int32_t index, int32_t targetIndex, const AnimationCallbackInfo& info) {
145         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
146         ACE_SCORING_EVENT("Tabs.onAnimationStart");
147         func->Execute(index, targetIndex, info);
148     };
149     TabsModel::GetInstance()->SetOnAnimationStart(std::move(onAnimationStart));
150 }
151 
SetOnAnimationEnd(const JSCallbackInfo & info)152 void JSTabs::SetOnAnimationEnd(const JSCallbackInfo& info)
153 {
154     if (!info[0]->IsFunction()) {
155         return;
156     }
157 
158     auto animationEndHandler = AceType::MakeRefPtr<JsSwiperFunction>(JSRef<JSFunc>::Cast(info[0]));
159     auto onAnimationEnd = [executionContext = info.GetExecutionContext(), func = std::move(animationEndHandler)](
160                               int32_t index, const AnimationCallbackInfo& info) {
161         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
162         ACE_SCORING_EVENT("Tabs.onAnimationEnd");
163         func->Execute(index, info);
164     };
165     TabsModel::GetInstance()->SetOnAnimationEnd(std::move(onAnimationEnd));
166 }
167 
SetOnGestureSwipe(const JSCallbackInfo & info)168 void JSTabs::SetOnGestureSwipe(const JSCallbackInfo& info)
169 {
170     if (!info[0]->IsFunction()) {
171         return;
172     }
173 
174     auto gestureSwipeHandler = AceType::MakeRefPtr<JsSwiperFunction>(JSRef<JSFunc>::Cast(info[0]));
175     auto onGestureSwipe = [executionContext = info.GetExecutionContext(), func = std::move(gestureSwipeHandler)](
176                               int32_t index, const AnimationCallbackInfo& info) {
177         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
178         ACE_SCORING_EVENT("Tabs.onGestureSwipe");
179         func->Execute(index, info);
180     };
181     TabsModel::GetInstance()->SetOnGestureSwipe(std::move(onGestureSwipe));
182 }
183 
ParseTabsIndexObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)184 void ParseTabsIndexObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
185 {
186     CHECK_NULL_VOID(changeEventVal->IsFunction());
187 
188     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
189     WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
190     auto onChangeEvent = [executionContext = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
191                              const BaseEventInfo* info) {
192         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
193         const auto* tabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
194         if (!tabsInfo) {
195             TAG_LOGW(AceLogTag::ACE_TABS, "ParseTabsIndexObject execute onChange event failed.");
196             return;
197         }
198         ACE_SCORING_EVENT("Tabs.onChangeEvent");
199         PipelineContext::SetCallBackNode(node);
200         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(tabsInfo->GetIndex()));
201         func->ExecuteJS(1, &newJSVal);
202     };
203     TabsModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
204 }
205 
Create(const JSCallbackInfo & info)206 void JSTabs::Create(const JSCallbackInfo& info)
207 {
208     BarPosition barPosition = BarPosition::START;
209     RefPtr<TabController> tabController;
210     RefPtr<SwiperController> swiperController;
211     int32_t index = -1;
212     JSRef<JSVal> changeEventVal;
213     if (info[0]->IsObject()) {
214         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
215         JSRef<JSVal> val = obj->GetProperty("barPosition");
216         if (val->IsNumber()) {
217             auto barPositionVal = val->ToNumber<int32_t>();
218             if (barPositionVal >= 0 && barPositionVal < static_cast<int32_t>(BAR_POSITIONS.size())) {
219                 barPosition = BAR_POSITIONS[barPositionVal];
220             }
221         }
222         JSRef<JSVal> controller = obj->GetProperty("controller");
223         if (controller->IsObject()) {
224             auto* jsTabsController = JSRef<JSObject>::Cast(controller)->Unwrap<JSTabsController>();
225             if (jsTabsController) {
226                 jsTabsController->SetInstanceId(Container::CurrentId());
227                 tabController = jsTabsController->GetController();
228                 swiperController = jsTabsController->GetSwiperController();
229             }
230         }
231         JSRef<JSVal> indexVal = obj->GetProperty("index");
232         if (indexVal->IsNumber()) {
233             index = indexVal->ToNumber<int32_t>();
234             index = index < 0 ? 0 : index;
235             if (!tabController) {
236                 tabController = JSTabsController::CreateController();
237             }
238 #ifndef NG_BUILD
239             tabController->SetInitialIndex(index);
240 #endif
241         } else if (indexVal->IsObject()) {
242             JSRef<JSObject> indexObj = JSRef<JSObject>::Cast(indexVal);
243             auto indexValueProperty = indexObj->GetProperty("value");
244             if (indexValueProperty->IsNumber()) {
245                 index = indexValueProperty->ToNumber<int32_t>();
246                 index = index < 0 ? 0 : index;
247             }
248             changeEventVal = indexObj->GetProperty("changeEvent");
249         }
250     }
251 
252     TabsModel::GetInstance()->Create(barPosition, index, tabController, swiperController);
253     if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
254         ParseTabsIndexObject(info, changeEventVal);
255     }
256 }
257 
Pop()258 void JSTabs::Pop()
259 {
260     TabsModel::GetInstance()->Pop();
261 }
262 
SetBarPosition(const JSCallbackInfo & info)263 void JSTabs::SetBarPosition(const JSCallbackInfo& info)
264 {
265     BarPosition barVal = BarPosition::START;
266     if (info.Length() > 0 && info[0]->IsNumber()) {
267         auto barPositionVal = info[0]->ToNumber<int32_t>();
268         if (barPositionVal >= 0 && barPositionVal < static_cast<int32_t>(BAR_POSITIONS.size())) {
269             barVal = BAR_POSITIONS[barPositionVal];
270         }
271     }
272 
273     TabsModel::GetInstance()->SetTabBarPosition(barVal);
274 }
275 
SetVertical(const std::string & value)276 void JSTabs::SetVertical(const std::string& value)
277 {
278     TabsModel::GetInstance()->SetIsVertical(StringToBool(value));
279 }
280 
SetScrollable(const std::string & value)281 void JSTabs::SetScrollable(const std::string& value)
282 {
283     if (value == "undefined") {
284         TabsModel::GetInstance()->SetScrollable(true);
285         return;
286     }
287     TabsModel::GetInstance()->SetScrollable(StringToBool(value));
288 }
289 
SetBarMode(const JSCallbackInfo & info)290 void JSTabs::SetBarMode(const JSCallbackInfo& info)
291 {
292     TabBarMode barMode = TabBarMode::FIXED;
293     if (info.Length() < 1) {
294         TabsModel::GetInstance()->SetTabBarMode(barMode);
295         return;
296     }
297     if (info[0]->IsString()) {
298         barMode = ConvertStrToTabBarMode(info[0]->ToString());
299     }
300     if (barMode == TabBarMode::SCROLLABLE) {
301         if (info.Length() > 1 && info[1]->IsObject()) {
302             SetScrollableBarModeOptions(info[1]);
303         } else {
304             ScrollableBarModeOptions option;
305             TabsModel::GetInstance()->SetScrollableBarModeOptions(option);
306         }
307     }
308     TabsModel::GetInstance()->SetTabBarMode(barMode);
309 }
310 
SetBarWidth(const JSCallbackInfo & info)311 void JSTabs::SetBarWidth(const JSCallbackInfo& info)
312 {
313     if (info.Length() < 1) {
314         return;
315     }
316 
317     CalcDimension width = Dimension(-1.0, DimensionUnit::VP);
318     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
319         if (!ParseJsDimensionVpNG(info[0], width)) {
320             width = Dimension(-1.0, DimensionUnit::VP);
321             TabsModel::GetInstance()->SetTabBarWidth(width);
322             return;
323         }
324     } else {
325         ParseJsDimensionVp(info[0], width);
326     }
327 
328     TabsModel::GetInstance()->SetTabBarWidth(width);
329 }
330 
SetBarHeight(const JSCallbackInfo & info)331 void JSTabs::SetBarHeight(const JSCallbackInfo& info)
332 {
333     if (info.Length() < 1) {
334         return;
335     }
336     CalcDimension height = Dimension(-1.0, DimensionUnit::VP);
337     bool adaptiveHeight = false;
338     if (info[0]->IsString() && info[0]->ToString() == "auto") {
339         adaptiveHeight = true;
340     } else {
341         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
342             if (!ParseJsDimensionVpNG(info[0], height)) {
343                 height = Dimension(-1.0, DimensionUnit::VP);
344             }
345         } else {
346             ParseJsDimensionVp(info[0], height);
347         }
348     }
349     TabsModel::GetInstance()->SetBarAdaptiveHeight(adaptiveHeight);
350     TabsModel::GetInstance()->SetTabBarHeight(height);
351 }
352 
SetIndex(int32_t index)353 void JSTabs::SetIndex(int32_t index)
354 {
355     TabsModel::GetInstance()->SetIndex(index);
356 }
357 
SetAnimationDuration(const JSCallbackInfo & info)358 void JSTabs::SetAnimationDuration(const JSCallbackInfo& info)
359 {
360     if (info.Length() <= 0 || (!info[0]->IsNull() && !info[0]->IsNumber()) ||
361         (info[0]->IsNull() && Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
362         TabsModel::GetInstance()->SetAnimationDuration(-1);
363         return;
364     }
365     auto value = info[0]->IsNumber() ? info[0]->ToNumber<int32_t>() : 0;
366     TabsModel::GetInstance()->SetAnimationDuration(value);
367 }
368 
SetFadingEdge(const JSCallbackInfo & info)369 void JSTabs::SetFadingEdge(const JSCallbackInfo& info)
370 {
371     bool fadingEdge = true;
372     if (info.Length() > 0) {
373         ParseJsBool(info[0], fadingEdge);
374     }
375     TabsModel::GetInstance()->SetFadingEdge(fadingEdge);
376 }
377 
SetBarOverlap(const JSCallbackInfo & info)378 void JSTabs::SetBarOverlap(const JSCallbackInfo& info)
379 {
380     bool barOverlap = false;
381     if (info.Length() > 0) {
382         ParseJsBool(info[0], barOverlap);
383     }
384     TabsModel::GetInstance()->SetBarOverlap(barOverlap);
385 }
386 
SetBarBackgroundColor(const JSCallbackInfo & info)387 void JSTabs::SetBarBackgroundColor(const JSCallbackInfo& info)
388 {
389     Color backgroundColor = Color::BLACK.BlendOpacity(0.0f);
390     if (info.Length() > 0) {
391         ConvertFromJSValue(info[0], backgroundColor);
392     }
393     TabsModel::GetInstance()->SetBarBackgroundColor(backgroundColor);
394 }
395 
SetBarBackgroundBlurStyle(const JSCallbackInfo & info)396 void JSTabs::SetBarBackgroundBlurStyle(const JSCallbackInfo& info)
397 {
398     BlurStyle blurStyle = BlurStyle::NO_MATERIAL;
399     if (info.Length() > 0 && info[0]->IsNumber()) {
400         auto barBlurStyle = info[0]->ToNumber<int32_t>();
401         if (barBlurStyle >= 0 && barBlurStyle < static_cast<int32_t>(BAR_BLURSTYLE.size())) {
402             blurStyle = BAR_BLURSTYLE[barBlurStyle];
403         }
404     }
405     TabsModel::GetInstance()->SetBarBackgroundBlurStyle(blurStyle);
406 }
407 
SetDivider(const JSCallbackInfo & info)408 void JSTabs::SetDivider(const JSCallbackInfo& info)
409 {
410     TabsItemDivider divider;
411     CalcDimension dividerStrokeWidth;
412     CalcDimension dividerStartMargin;
413     CalcDimension dividerEndMargin;
414     RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
415     CHECK_NULL_VOID(tabTheme);
416 
417     if (info.Length() > 0) {
418         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
419         if (info[0]->IsNull()) {
420             divider.isNull = true;
421         } else {
422             if (!info[0]->IsObject() || !ParseJsDimensionVp(obj->GetProperty("strokeWidth"), dividerStrokeWidth) ||
423                 dividerStrokeWidth.Value() < 0.0f || dividerStrokeWidth.Unit() == DimensionUnit::PERCENT) {
424                 divider.strokeWidth.Reset();
425             } else {
426                 divider.strokeWidth = dividerStrokeWidth;
427             }
428             if (!info[0]->IsObject() || !ConvertFromJSValue(obj->GetProperty("color"), divider.color)) {
429                 divider.color = tabTheme->GetDividerColor();
430             }
431             if (!info[0]->IsObject() || !ParseJsDimensionVp(obj->GetProperty("startMargin"), dividerStartMargin) ||
432                 dividerStartMargin.Value() < 0.0f || dividerStartMargin.Unit() == DimensionUnit::PERCENT) {
433                 divider.startMargin.Reset();
434             } else {
435                 divider.startMargin = dividerStartMargin;
436             }
437             if (!info[0]->IsObject() || !ParseJsDimensionVp(obj->GetProperty("endMargin"), dividerEndMargin) ||
438                 dividerEndMargin.Value() < 0.0f || dividerEndMargin.Unit() == DimensionUnit::PERCENT) {
439                 divider.endMargin.Reset();
440             } else {
441                 divider.endMargin = dividerEndMargin;
442             }
443         }
444     }
445     TabsModel::GetInstance()->SetDivider(divider);
446 }
447 
SetClip(const JSCallbackInfo & info)448 void JSTabs::SetClip(const JSCallbackInfo& info)
449 {
450     if (info[0]->IsObject() || !Container::IsCurrentUseNewPipeline()) {
451         JSViewAbstract::JsClip(info);
452         return;
453     }
454     if (info[0]->IsBoolean()) {
455         TabsModel::GetInstance()->SetClipEdge(info[0]->ToBoolean());
456     }
457 }
458 
SetScrollableBarModeOptions(const JSRef<JSVal> & info)459 void JSTabs::SetScrollableBarModeOptions(const JSRef<JSVal>& info)
460 {
461     ScrollableBarModeOptions option;
462     auto optionParam = JSRef<JSObject>::Cast(info);
463     CalcDimension margin = Dimension(0.0, DimensionUnit::VP);
464     if (!ParseJsDimensionVp(optionParam->GetProperty("margin"), margin) || Negative(margin.Value()) ||
465         margin.Unit() == DimensionUnit::PERCENT) {
466         option.margin = 0.0_vp;
467     } else {
468         option.margin = margin;
469     }
470 
471     auto nonScrollableLayoutStyle = optionParam->GetProperty("nonScrollableLayoutStyle");
472     int32_t layoutStyle;
473     if (!ConvertFromJSValue(nonScrollableLayoutStyle, layoutStyle)) {
474         option.nonScrollableLayoutStyle = LayoutStyle::ALWAYS_CENTER;
475     } else {
476         option.nonScrollableLayoutStyle = (static_cast<LayoutStyle>(layoutStyle));
477     }
478     TabsModel::GetInstance()->SetScrollableBarModeOptions(option);
479 }
480 
SetBarGridAlign(const JSCallbackInfo & info)481 void JSTabs::SetBarGridAlign(const JSCallbackInfo& info)
482 {
483     BarGridColumnOptions columnOption;
484     if (info.Length() > 0 && info[0]->IsObject()) {
485         auto gridParam = JSRef<JSObject>::Cast(info[0]);
486         auto sm = gridParam->GetProperty("sm");
487         if (sm->IsNumber() && sm->ToNumber<int32_t>() >= 0 && sm->ToNumber<int32_t>() <= SM_COLUMN_NUM &&
488             sm->ToNumber<int32_t>() % 2 == 0) {
489             columnOption.sm = sm->ToNumber<int32_t>();
490         }
491         auto md = gridParam->GetProperty("md");
492         if (md->IsNumber() && md->ToNumber<int32_t>() >= 0 && md->ToNumber<int32_t>() <= MD_COLUMN_NUM &&
493             md->ToNumber<int32_t>() % 2 == 0) {
494             columnOption.md = md->ToNumber<int32_t>();
495         }
496         auto lg = gridParam->GetProperty("lg");
497         if (lg->IsNumber() && lg->ToNumber<int32_t>() >= 0 && lg->ToNumber<int32_t>() <= LG_COLUMN_NUM &&
498             lg->ToNumber<int32_t>() % 2 == 0) {
499             columnOption.lg = lg->ToNumber<int32_t>();
500         }
501         CalcDimension columnGutter;
502         if (ParseJsDimensionVp(gridParam->GetProperty("gutter"), columnGutter) && NonNegative(columnGutter.Value()) &&
503             columnGutter.Unit() != DimensionUnit::PERCENT) {
504             columnOption.gutter = columnGutter;
505         }
506         CalcDimension columnMargin;
507         if (ParseJsDimensionVp(gridParam->GetProperty("margin"), columnMargin) && NonNegative(columnMargin.Value()) &&
508             columnMargin.Unit() != DimensionUnit::PERCENT) {
509             columnOption.margin = columnMargin;
510         }
511     }
512     TabsModel::GetInstance()->SetBarGridAlign(columnOption);
513 }
514 
SetCustomContentTransition(const JSCallbackInfo & info)515 void JSTabs::SetCustomContentTransition(const JSCallbackInfo& info)
516 {
517     if (info.Length() != 1) {
518         return;
519     }
520 
521     if (info[0]->IsUndefined() || !info[0]->IsFunction()) {
522         TabsModel::GetInstance()->SetIsCustomAnimation(false);
523         return;
524     }
525 
526     RefPtr<JsTabsFunction> jsCustomAnimationFunc = AceType::MakeRefPtr<JsTabsFunction>(JSRef<JSFunc>::Cast(info[0]));
527     auto onCustomAnimation = [execCtx = info.GetExecutionContext(), func = std::move(jsCustomAnimationFunc)](
528                                  int32_t from, int32_t to) -> TabContentAnimatedTransition {
529         TabContentAnimatedTransition transitionInfo;
530         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, transitionInfo);
531 
532         auto ret = func->Execute(from, to);
533         if (!ret->IsObject()) {
534             return transitionInfo;
535         }
536 
537         auto transitionObj = JSRef<JSObject>::Cast(ret);
538         JSRef<JSVal> timeoutProperty = transitionObj->GetProperty("timeout");
539         if (timeoutProperty->IsNumber()) {
540             auto timeout = timeoutProperty->ToNumber<int32_t>();
541             transitionInfo.timeout = timeout < 0 ? DEFAULT_CUSTOM_ANIMATION_TIMEOUT : timeout;
542         } else {
543             transitionInfo.timeout = DEFAULT_CUSTOM_ANIMATION_TIMEOUT;
544         }
545 
546         JSRef<JSVal> transition = transitionObj->GetProperty("transition");
547         if (transition->IsFunction()) {
548             RefPtr<JsTabsFunction> jsOnTransition =
549                 AceType::MakeRefPtr<JsTabsFunction>(JSRef<JSFunc>::Cast(transition));
550             auto onTransition = [execCtx, func = std::move(jsOnTransition)](
551                                     const RefPtr<TabContentTransitionProxy>& proxy) {
552                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
553                 ACE_SCORING_EVENT("onTransition");
554                 func->Execute(proxy);
555             };
556 
557             transitionInfo.transition = std::move(onTransition);
558         }
559 
560         return transitionInfo;
561     };
562     TabsModel::GetInstance()->SetIsCustomAnimation(true);
563     TabsModel::GetInstance()->SetOnCustomAnimation(std::move(onCustomAnimation));
564 }
565 
SetOnContentWillChange(const JSCallbackInfo & info)566 void JSTabs::SetOnContentWillChange(const JSCallbackInfo& info)
567 {
568     if (!info[0]->IsFunction()) {
569         return;
570     }
571 
572     auto handler = AceType::MakeRefPtr<JsTabsFunction>(JSRef<JSFunc>::Cast(info[0]));
573     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(handler)]
574         (int32_t currentIndex, int32_t comingIndex) -> bool {
575         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
576         ACE_SCORING_EVENT("Tabs.onContentWillChange");
577         auto ret = func->Execute(currentIndex, comingIndex);
578         if (!ret->IsBoolean()) {
579             return true;
580         }
581         return ret->ToBoolean();
582     };
583     TabsModel::GetInstance()->SetOnContentWillChange(std::move(callback));
584 }
585 
JSBind(BindingTarget globalObj)586 void JSTabs::JSBind(BindingTarget globalObj)
587 {
588     JsTabContentTransitionProxy::JSBind(globalObj);
589     JSClass<JSTabs>::Declare("Tabs");
590     JSClass<JSTabs>::StaticMethod("create", &JSTabs::Create);
591     JSClass<JSTabs>::StaticMethod("pop", &JSTabs::Pop);
592     JSClass<JSTabs>::StaticMethod("vertical", &JSTabs::SetVertical);
593     JSClass<JSTabs>::StaticMethod("barPosition", &JSTabs::SetBarPosition);
594     JSClass<JSTabs>::StaticMethod("barBackgroundBlurStyle", &JSTabs::SetBarBackgroundBlurStyle);
595     JSClass<JSTabs>::StaticMethod("scrollable", &JSTabs::SetScrollable);
596     JSClass<JSTabs>::StaticMethod("barMode", &JSTabs::SetBarMode);
597     JSClass<JSTabs>::StaticMethod("barWidth", &JSTabs::SetBarWidth);
598     JSClass<JSTabs>::StaticMethod("barHeight", &JSTabs::SetBarHeight);
599     JSClass<JSTabs>::StaticMethod("index", &JSTabs::SetIndex);
600     JSClass<JSTabs>::StaticMethod("animationDuration", &JSTabs::SetAnimationDuration);
601     JSClass<JSTabs>::StaticMethod("divider", &JSTabs::SetDivider);
602     JSClass<JSTabs>::StaticMethod("onChange", &JSTabs::SetOnChange);
603     JSClass<JSTabs>::StaticMethod("onTabBarClick", &JSTabs::SetOnTabBarClick);
604     JSClass<JSTabs>::StaticMethod("onAnimationStart", &JSTabs::SetOnAnimationStart);
605     JSClass<JSTabs>::StaticMethod("onAnimationEnd", &JSTabs::SetOnAnimationEnd);
606     JSClass<JSTabs>::StaticMethod("onGestureSwipe", &JSTabs::SetOnGestureSwipe);
607     JSClass<JSTabs>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
608     JSClass<JSTabs>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
609     JSClass<JSTabs>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
610     JSClass<JSTabs>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
611     JSClass<JSTabs>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
612     JSClass<JSTabs>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
613     JSClass<JSTabs>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
614     JSClass<JSTabs>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
615     JSClass<JSTabs>::StaticMethod("fadingEdge", &JSTabs::SetFadingEdge);
616     JSClass<JSTabs>::StaticMethod("barOverlap", &JSTabs::SetBarOverlap);
617     JSClass<JSTabs>::StaticMethod("barBackgroundColor", &JSTabs::SetBarBackgroundColor);
618     JSClass<JSTabs>::StaticMethod("clip", &JSTabs::SetClip);
619     JSClass<JSTabs>::StaticMethod("barGridAlign", &JSTabs::SetBarGridAlign);
620     JSClass<JSTabs>::StaticMethod("customContentTransition", &JSTabs::SetCustomContentTransition);
621     JSClass<JSTabs>::StaticMethod("onContentWillChange", &JSTabs::SetOnContentWillChange);
622 
623     JSClass<JSTabs>::InheritAndBind<JSContainerBase>(globalObj);
624 }
625 
626 } // namespace OHOS::Ace::Framework
627