• 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 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
18 
19 #include "base/log/ace_scoring_log.h"
20 #include "bridge/declarative_frontend/engine/functions/js_swiper_function.h"
21 #include "bridge/declarative_frontend/engine/functions/js_tabs_function.h"
22 #include "bridge/declarative_frontend/jsview/js_scrollable.h"
23 #include "bridge/declarative_frontend/jsview/js_tabs_controller.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/tabs_model_impl.h"
26 #include "core/components/common/layout/constants.h"
27 #include "core/components/common/properties/decoration.h"
28 #include "core/components_ng/base/view_stack_model.h"
29 #include "core/components_ng/base/view_stack_processor.h"
30 #include "core/components_ng/pattern/tabs/tab_content_transition_proxy.h"
31 #include "core/components_ng/pattern/tabs/tabs_model_ng.h"
32 
33 namespace OHOS::Ace {
34 
35 std::unique_ptr<TabsModel> TabsModel::instance_ = nullptr;
36 std::mutex TabsModel::mutex_;
37 
GetInstance()38 TabsModel* TabsModel::GetInstance()
39 {
40     if (!instance_) {
41         std::lock_guard<std::mutex> lock(mutex_);
42         if (!instance_) {
43 #ifdef NG_BUILD
44             instance_.reset(new NG::TabsModelNG());
45 #else
46             if (Container::IsCurrentUseNewPipeline()) {
47                 instance_.reset(new NG::TabsModelNG());
48             } else {
49                 instance_.reset(new Framework::TabsModelImpl());
50             }
51 #endif
52         }
53     }
54     return instance_.get();
55 }
56 
57 } // namespace OHOS::Ace
58 
59 namespace OHOS::Ace::Framework {
60 namespace {
61 constexpr int32_t SM_COLUMN_NUM = 4;
62 constexpr int32_t MD_COLUMN_NUM = 8;
63 constexpr int32_t LG_COLUMN_NUM = 12;
64 constexpr int32_t DEFAULT_CUSTOM_ANIMATION_TIMEOUT = 1000;
65 const std::vector<BarPosition> BAR_POSITIONS = { BarPosition::START, BarPosition::END };
66 
67 const std::vector<BlurStyle> BAR_BLURSTYLE = {
68     BlurStyle::NO_MATERIAL,
69     BlurStyle::THIN,
70     BlurStyle::REGULAR,
71     BlurStyle::THICK,
72     BlurStyle::BACKGROUND_THIN,
73     BlurStyle::BACKGROUND_REGULAR,
74     BlurStyle::BACKGROUND_THICK,
75     BlurStyle::BACKGROUND_ULTRA_THICK,
76     BlurStyle::COMPONENT_ULTRA_THIN,
77     BlurStyle::COMPONENT_THIN,
78     BlurStyle::COMPONENT_REGULAR,
79     BlurStyle::COMPONENT_THICK,
80     BlurStyle::COMPONENT_ULTRA_THICK,
81 };
82 
TabContentChangeEventToJSValue(const TabContentChangeEvent & eventInfo)83 JSRef<JSVal> TabContentChangeEventToJSValue(const TabContentChangeEvent& eventInfo)
84 {
85     return JSRef<JSVal>::Make(ToJSValue(eventInfo.GetIndex()));
86 }
87 
88 } // namespace
89 
SetOnChange(const JSCallbackInfo & info)90 void JSTabs::SetOnChange(const JSCallbackInfo& info)
91 {
92     if (!info[0]->IsFunction()) {
93         return;
94     }
95 
96     auto changeHandler = AceType::MakeRefPtr<JsEventFunction<TabContentChangeEvent, 1>>(
97         JSRef<JSFunc>::Cast(info[0]), TabContentChangeEventToJSValue);
98     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
99     auto onChange = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler), node = targetNode](
100                         const BaseEventInfo* info) {
101         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
102         const auto* tabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
103         if (!tabsInfo) {
104             TAG_LOGW(AceLogTag::ACE_TABS, "Tabs onChange callback execute failed.");
105             return;
106         }
107         ACE_SCORING_EVENT("Tabs.onChange");
108         ACE_SCOPED_TRACE("Tabs.onChange index %d", tabsInfo->GetIndex());
109         PipelineContext::SetCallBackNode(node);
110         func->Execute(*tabsInfo);
111     };
112     TabsModel::GetInstance()->SetOnChange(std::move(onChange));
113 }
114 
SetOnTabBarClick(const JSCallbackInfo & info)115 void JSTabs::SetOnTabBarClick(const JSCallbackInfo& info)
116 {
117     if (!info[0]->IsFunction()) {
118         return;
119     }
120 
121     auto changeHandler = AceType::MakeRefPtr<JsEventFunction<TabContentChangeEvent, 1>>(
122         JSRef<JSFunc>::Cast(info[0]), TabContentChangeEventToJSValue);
123     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
124     auto onTabBarClick = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler),
125                              node = targetNode](const BaseEventInfo* info) {
126         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
127         const auto* tabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
128         if (!tabsInfo) {
129             TAG_LOGW(AceLogTag::ACE_TABS, "Tabs onTabBarClick callback execute failed.");
130             return;
131         }
132         ACE_SCORING_EVENT("Tabs.onTabBarClick");
133         PipelineContext::SetCallBackNode(node);
134         func->Execute(*tabsInfo);
135         UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "Tabs.onTabBarClick");
136     };
137     TabsModel::GetInstance()->SetOnTabBarClick(std::move(onTabBarClick));
138 }
139 
SetOnUnselected(const JSCallbackInfo & info)140 void JSTabs::SetOnUnselected(const JSCallbackInfo& info)
141 {
142     if (!info[0]->IsFunction()) {
143         return;
144     }
145     auto unselectedHandler = AceType::MakeRefPtr<JsEventFunction<TabContentChangeEvent, 1>>(
146         JSRef<JSFunc>::Cast(info[0]), TabContentChangeEventToJSValue);
147     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
148     auto onUnselected = [executionContext = info.GetExecutionContext(), func = std::move(unselectedHandler),
149                           node = targetNode](const BaseEventInfo* info) {
150         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
151         const auto* tabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
152         if (!tabsInfo) {
153             TAG_LOGW(AceLogTag::ACE_TABS, "Tabs onUnselected callback execute failed.");
154             return;
155         }
156         ACE_SCORING_EVENT("Tabs.onUnselected");
157         ACE_SCOPED_TRACE("Tabs.onUnselected index %d", tabsInfo->GetIndex());
158         PipelineContext::SetCallBackNode(node);
159         func->Execute(*tabsInfo);
160     };
161     TabsModel::GetInstance()->SetOnUnselected(std::move(onUnselected));
162 }
163 
SetOnAnimationStart(const JSCallbackInfo & info)164 void JSTabs::SetOnAnimationStart(const JSCallbackInfo& info)
165 {
166     if (!info[0]->IsFunction()) {
167         return;
168     }
169 
170     auto animationStartHandler = AceType::MakeRefPtr<JsSwiperFunction>(JSRef<JSFunc>::Cast(info[0]));
171     auto onAnimationStart = [executionContext = info.GetExecutionContext(),
172                                 func = std::move(animationStartHandler)](
173                                 int32_t index, int32_t targetIndex, const AnimationCallbackInfo& info) {
174         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
175         ACE_SCORING_EVENT("Tabs.onAnimationStart");
176         func->Execute(index, targetIndex, info);
177     };
178     TabsModel::GetInstance()->SetOnAnimationStart(std::move(onAnimationStart));
179 }
180 
SetOnAnimationEnd(const JSCallbackInfo & info)181 void JSTabs::SetOnAnimationEnd(const JSCallbackInfo& info)
182 {
183     if (!info[0]->IsFunction()) {
184         return;
185     }
186 
187     auto animationEndHandler = AceType::MakeRefPtr<JsSwiperFunction>(JSRef<JSFunc>::Cast(info[0]));
188     auto onAnimationEnd = [executionContext = info.GetExecutionContext(), func = std::move(animationEndHandler)](
189                               int32_t index, const AnimationCallbackInfo& info) {
190         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
191         ACE_SCORING_EVENT("Tabs.onAnimationEnd");
192         func->Execute(index, info);
193         UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "Tabs.onAnimationEnd");
194     };
195     TabsModel::GetInstance()->SetOnAnimationEnd(std::move(onAnimationEnd));
196 }
197 
SetOnGestureSwipe(const JSCallbackInfo & info)198 void JSTabs::SetOnGestureSwipe(const JSCallbackInfo& info)
199 {
200     if (!info[0]->IsFunction()) {
201         return;
202     }
203 
204     auto gestureSwipeHandler = AceType::MakeRefPtr<JsSwiperFunction>(JSRef<JSFunc>::Cast(info[0]));
205     auto onGestureSwipe = [executionContext = info.GetExecutionContext(), func = std::move(gestureSwipeHandler)](
206                               int32_t index, const AnimationCallbackInfo& info) {
207         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
208         ACE_SCORING_EVENT("Tabs.onGestureSwipe");
209         func->Execute(index, info);
210     };
211     TabsModel::GetInstance()->SetOnGestureSwipe(std::move(onGestureSwipe));
212 }
213 
SetOnSelected(const JSCallbackInfo & info)214 void JSTabs::SetOnSelected(const JSCallbackInfo& info)
215 {
216     if (!info[0]->IsFunction()) {
217         return;
218     }
219     auto selectedHandler = AceType::MakeRefPtr<JsEventFunction<TabContentChangeEvent, 1>>(
220         JSRef<JSFunc>::Cast(info[0]), TabContentChangeEventToJSValue);
221     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
222     auto onSelected = [executionContext = info.GetExecutionContext(), func = std::move(selectedHandler),
223                           node = targetNode](const BaseEventInfo* info) {
224         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
225         const auto* tabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
226         if (!tabsInfo) {
227             TAG_LOGW(AceLogTag::ACE_TABS, "Tabs onSelected callback execute failed.");
228             return;
229         }
230         ACE_SCORING_EVENT("Tabs.onSelected");
231         ACE_SCOPED_TRACE("Tabs.onSelected index %d", tabsInfo->GetIndex());
232         PipelineContext::SetCallBackNode(node);
233         func->Execute(*tabsInfo);
234     };
235     TabsModel::GetInstance()->SetOnSelected(std::move(onSelected));
236 }
237 
ParseTabsIndexObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)238 void ParseTabsIndexObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
239 {
240     CHECK_NULL_VOID(!changeEventVal->IsUndefined() && changeEventVal->IsFunction());
241 
242     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
243     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
244     auto onChangeEvent = [executionContext = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
245                              const BaseEventInfo* info) {
246         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
247         const auto* tabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
248         if (!tabsInfo) {
249             TAG_LOGW(AceLogTag::ACE_TABS, "ParseTabsIndexObject execute onChange event failed.");
250             return;
251         }
252         ACE_SCORING_EVENT("Tabs.onChangeEvent");
253         PipelineContext::SetCallBackNode(node);
254         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(tabsInfo->GetIndex()));
255         func->ExecuteJS(1, &newJSVal);
256     };
257     TabsModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
258 }
259 
Create(const JSCallbackInfo & info)260 void JSTabs::Create(const JSCallbackInfo& info)
261 {
262     BarPosition barPosition = BarPosition::START;
263     RefPtr<TabController> tabController;
264     RefPtr<NG::TabsControllerNG> tabsController = AceType::MakeRefPtr<NG::TabsControllerNG>();
265     int32_t index = -1;
266     JSRef<JSVal> changeEventVal;
267     auto jsValue = info[0];
268     if (jsValue->IsObject()) {
269         JSRef<JSObject> obj = JSRef<JSObject>::Cast(jsValue);
270         JSRef<JSVal> val = obj->GetProperty("barPosition");
271         if (val->IsNumber()) {
272             auto barPositionVal = val->ToNumber<int32_t>();
273             if (barPositionVal >= 0 && barPositionVal < static_cast<int32_t>(BAR_POSITIONS.size())) {
274                 barPosition = BAR_POSITIONS[barPositionVal];
275             }
276         }
277         JSRef<JSVal> controller = obj->GetProperty("controller");
278         if (controller->IsObject()) {
279             auto* jsTabsController = JSRef<JSObject>::Cast(controller)->Unwrap<JSTabsController>();
280             if (jsTabsController) {
281                 jsTabsController->SetInstanceId(Container::CurrentId());
282                 tabController = jsTabsController->GetController();
283                 jsTabsController->SetTabsController(tabsController);
284             }
285         }
286         JSRef<JSVal> indexVal = obj->GetProperty("index");
287         if (indexVal->IsNumber()) {
288             index = indexVal->ToNumber<int32_t>();
289             index = index < 0 ? 0 : index;
290             if (!tabController) {
291                 tabController = JSTabsController::CreateController();
292             }
293 #ifndef NG_BUILD
294             tabController->SetInitialIndex(index);
295 #endif
296             changeEventVal = obj->GetProperty("$index");
297         } else if (indexVal->IsObject()) {
298             JSRef<JSObject> indexObj = JSRef<JSObject>::Cast(indexVal);
299             auto indexValueProperty = indexObj->GetProperty("value");
300             if (indexValueProperty->IsNumber()) {
301                 index = indexValueProperty->ToNumber<int32_t>();
302                 index = index < 0 ? 0 : index;
303             }
304             changeEventVal = indexObj->GetProperty("changeEvent");
305         }
306     }
307 
308     TabsModel::GetInstance()->Create(barPosition, index, tabController, tabsController);
309     ParseTabsIndexObject(info, changeEventVal);
310     SetBarModifier(info, jsValue);
311 }
312 
Pop()313 void JSTabs::Pop()
314 {
315     if (ViewStackModel::GetInstance()->IsPrebuilding()) {
316         return ViewStackModel::GetInstance()->PushPrebuildCompCmd("[JSTabs][pop]", &JSTabs::Pop);
317     }
318     TabsModel::GetInstance()->Pop();
319 }
320 
SetBarPosition(const JSCallbackInfo & info)321 void JSTabs::SetBarPosition(const JSCallbackInfo& info)
322 {
323     BarPosition barVal = BarPosition::START;
324     if (info.Length() > 0 && info[0]->IsNumber()) {
325         auto barPositionVal = info[0]->ToNumber<int32_t>();
326         if (barPositionVal >= 0 && barPositionVal < static_cast<int32_t>(BAR_POSITIONS.size())) {
327             barVal = BAR_POSITIONS[barPositionVal];
328         }
329     }
330 
331     TabsModel::GetInstance()->SetTabBarPosition(barVal);
332 }
333 
SetVertical(const std::string & value)334 void JSTabs::SetVertical(const std::string& value)
335 {
336     TabsModel::GetInstance()->SetIsVertical(StringToBool(value));
337 }
338 
SetScrollable(const std::string & value)339 void JSTabs::SetScrollable(const std::string& value)
340 {
341     if (value == "undefined") {
342         TabsModel::GetInstance()->SetScrollable(true);
343         return;
344     }
345     TabsModel::GetInstance()->SetScrollable(StringToBool(value));
346 }
347 
SetBarMode(const JSCallbackInfo & info)348 void JSTabs::SetBarMode(const JSCallbackInfo& info)
349 {
350     TabBarMode barMode = TabBarMode::FIXED;
351     if (info.Length() < 1) {
352         TabsModel::GetInstance()->SetTabBarMode(barMode);
353         return;
354     }
355     auto barModeInfo = info[0];
356     if (barModeInfo->IsString()) {
357         barMode = ConvertStrToTabBarMode(barModeInfo->ToString());
358     }
359     if (barMode == TabBarMode::SCROLLABLE) {
360         if (info.Length() > 1 && info[1]->IsObject()) {
361             SetScrollableBarModeOptions(info[1]);
362         } else {
363             TabsModel::GetInstance()->ResetScrollableBarModeOptions();
364         }
365     }
366     TabsModel::GetInstance()->SetTabBarMode(barMode);
367 }
368 
SetBarWidth(const JSCallbackInfo & info)369 void JSTabs::SetBarWidth(const JSCallbackInfo& info)
370 {
371     if (info.Length() < 1) {
372         return;
373     }
374 
375     CalcDimension width = Dimension(-1.0, DimensionUnit::VP);
376     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
377         if (!ParseJsDimensionVpNG(info[0], width)) {
378             width = Dimension(-1.0, DimensionUnit::VP);
379             TabsModel::GetInstance()->SetTabBarWidth(width);
380             return;
381         }
382     } else {
383         ParseJsDimensionVp(info[0], width);
384     }
385 
386     TabsModel::GetInstance()->SetTabBarWidth(width);
387 }
388 
SetBarHeight(const JSCallbackInfo & info)389 void JSTabs::SetBarHeight(const JSCallbackInfo& info)
390 {
391     if (info.Length() < 1) {
392         return;
393     }
394     CalcDimension height = Dimension(-1.0, DimensionUnit::VP);
395     bool adaptiveHeight = false;
396     auto barHeightInfo = info[0];
397     if (barHeightInfo->IsString() && barHeightInfo->ToString() == "auto") {
398         adaptiveHeight = true;
399     } else {
400         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
401             if (!ParseJsDimensionVpNG(barHeightInfo, height)) {
402                 height = Dimension(-1.0, DimensionUnit::VP);
403             }
404         } else {
405             ParseJsDimensionVp(barHeightInfo, height);
406         }
407     }
408     TabsModel::GetInstance()->SetBarAdaptiveHeight(adaptiveHeight);
409     TabsModel::GetInstance()->SetTabBarHeight(height);
410 }
411 
SetWidth(const JSCallbackInfo & info)412 void JSTabs::SetWidth(const JSCallbackInfo& info)
413 {
414     JSViewAbstract::JsWidth(info);
415     if (info.Length() < 1) {
416         return;
417     }
418     auto widthInfo = info[0];
419     if (widthInfo->IsString() && widthInfo->ToString().empty()) {
420         return;
421     }
422     if (widthInfo->IsString() && widthInfo->ToString() == "auto") {
423         ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true);
424         TabsModel::GetInstance()->SetWidthAuto(true);
425         return;
426     }
427 
428     TabsModel::GetInstance()->SetWidthAuto(false);
429 }
430 
SetHeight(const JSCallbackInfo & info)431 void JSTabs::SetHeight(const JSCallbackInfo& info)
432 {
433     JSViewAbstract::JsHeight(info);
434     if (info.Length() < 1) {
435         return;
436     }
437     auto heightInfo = info[0];
438     if (heightInfo->IsString() && heightInfo->ToString().empty()) {
439         return;
440     }
441     if (heightInfo->IsString() && heightInfo->ToString() == "auto") {
442         ViewAbstractModel::GetInstance()->ClearWidthOrHeight(false);
443         TabsModel::GetInstance()->SetHeightAuto(true);
444         return;
445     }
446 
447     TabsModel::GetInstance()->SetHeightAuto(false);
448 }
449 
SetIndex(int32_t index)450 void JSTabs::SetIndex(int32_t index)
451 {
452     TabsModel::GetInstance()->SetIndex(index);
453 }
454 
SetAnimationDuration(const JSCallbackInfo & info)455 void JSTabs::SetAnimationDuration(const JSCallbackInfo& info)
456 {
457     if (info.Length() <= 0) {
458         TabsModel::GetInstance()->SetAnimationDuration(-1);
459         return;
460     }
461     auto animationDurationInfo = info[0];
462     if ((!animationDurationInfo->IsNull() && !animationDurationInfo->IsNumber()) ||
463         (animationDurationInfo->IsNull() && Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
464         TabsModel::GetInstance()->SetAnimationDuration(-1);
465         return;
466     }
467     auto value = animationDurationInfo->IsNumber() ? animationDurationInfo->ToNumber<int32_t>() : 0;
468     TabsModel::GetInstance()->SetAnimationDuration(value);
469 }
470 
SetFadingEdge(const JSCallbackInfo & info)471 void JSTabs::SetFadingEdge(const JSCallbackInfo& info)
472 {
473     bool fadingEdge = true;
474     if (info.Length() > 0) {
475         ParseJsBool(info[0], fadingEdge);
476     }
477     TabsModel::GetInstance()->SetFadingEdge(fadingEdge);
478 }
479 
SetBarOverlap(const JSCallbackInfo & info)480 void JSTabs::SetBarOverlap(const JSCallbackInfo& info)
481 {
482     bool barOverlap = false;
483     if (info.Length() > 0) {
484         ParseJsBool(info[0], barOverlap);
485     }
486     TabsModel::GetInstance()->SetBarOverlap(barOverlap);
487 }
488 
SetBarBackgroundColor(const JSCallbackInfo & info)489 void JSTabs::SetBarBackgroundColor(const JSCallbackInfo& info)
490 {
491     Color backgroundColor = Color::BLACK.BlendOpacity(0.0f);
492     if (info.Length() > 0) {
493         ConvertFromJSValue(info[0], backgroundColor);
494     }
495     TabsModel::GetInstance()->SetBarBackgroundColor(backgroundColor);
496 }
497 
SetBarBackgroundBlurStyle(const JSCallbackInfo & info)498 void JSTabs::SetBarBackgroundBlurStyle(const JSCallbackInfo& info)
499 {
500     if (info.Length() == 0) {
501         return;
502     }
503     BlurStyleOption styleOption;
504     if (info[0]->IsNumber()) {
505         auto blurStyle = info[0]->ToNumber<int32_t>();
506         if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
507             blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
508             styleOption.blurStyle = static_cast<BlurStyle>(blurStyle);
509         }
510     }
511     if (info.Length() > 1 && info[1]->IsObject()) {
512         JSRef<JSObject> jsOption = JSRef<JSObject>::Cast(info[1]);
513         ParseBlurStyleOption(jsOption, styleOption);
514     }
515     TabsModel::GetInstance()->SetBarBackgroundBlurStyle(styleOption);
516 }
517 
SetDivider(const JSCallbackInfo & info)518 void JSTabs::SetDivider(const JSCallbackInfo& info)
519 {
520     TabsItemDivider divider;
521     CalcDimension dividerStrokeWidth;
522     CalcDimension dividerStartMargin;
523     CalcDimension dividerEndMargin;
524     RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
525     CHECK_NULL_VOID(tabTheme);
526 
527     if (info.Length() > 0) {
528         auto dividerInfo = info[0];
529         JSRef<JSObject> obj = JSRef<JSObject>::New();
530         if (dividerInfo->IsObject()) {
531             obj = JSRef<JSObject>::Cast(dividerInfo);
532         }
533         if (dividerInfo->IsNull()) {
534             divider.isNull = true;
535         } else {
536             if (!dividerInfo->IsObject() || !ParseJsDimensionVp(obj->GetProperty("strokeWidth"), dividerStrokeWidth) ||
537                 dividerStrokeWidth.Value() < 0.0f || dividerStrokeWidth.Unit() == DimensionUnit::PERCENT) {
538                 divider.strokeWidth.Reset();
539             } else {
540                 divider.strokeWidth = dividerStrokeWidth;
541             }
542             if (!dividerInfo->IsObject() || !ConvertFromJSValue(obj->GetProperty("color"), divider.color)) {
543                 divider.color = tabTheme->GetDividerColor();
544             }
545             if (!dividerInfo->IsObject() || !ParseJsDimensionVp(obj->GetProperty("startMargin"), dividerStartMargin) ||
546                 dividerStartMargin.Value() < 0.0f || dividerStartMargin.Unit() == DimensionUnit::PERCENT) {
547                 divider.startMargin.Reset();
548             } else {
549                 divider.startMargin = dividerStartMargin;
550             }
551             if (!dividerInfo->IsObject() || !ParseJsDimensionVp(obj->GetProperty("endMargin"), dividerEndMargin) ||
552                 dividerEndMargin.Value() < 0.0f || dividerEndMargin.Unit() == DimensionUnit::PERCENT) {
553                 divider.endMargin.Reset();
554             } else {
555                 divider.endMargin = dividerEndMargin;
556             }
557         }
558     }
559     TabsModel::GetInstance()->SetDivider(divider);
560 }
561 
SetClip(const JSCallbackInfo & info)562 void JSTabs::SetClip(const JSCallbackInfo& info)
563 {
564     if (info[0]->IsObject() || !Container::IsCurrentUseNewPipeline()) {
565         JSViewAbstract::JsClip(info);
566         return;
567     }
568     if (info[0]->IsBoolean()) {
569         TabsModel::GetInstance()->SetClipEdge(info[0]->ToBoolean());
570     }
571 }
572 
SetScrollableBarModeOptions(const JSRef<JSVal> & info)573 void JSTabs::SetScrollableBarModeOptions(const JSRef<JSVal>& info)
574 {
575     ScrollableBarModeOptions option;
576     auto optionParam = JSRef<JSObject>::Cast(info);
577     CalcDimension margin = Dimension(0.0, DimensionUnit::VP);
578     if (!ParseJsDimensionVp(optionParam->GetProperty("margin"), margin) || Negative(margin.Value()) ||
579         margin.Unit() == DimensionUnit::PERCENT) {
580         option.margin = 0.0_vp;
581     } else {
582         option.margin = margin;
583     }
584 
585     auto nonScrollableLayoutStyle = optionParam->GetProperty("nonScrollableLayoutStyle");
586     int32_t layoutStyle;
587     if (!ConvertFromJSValue(nonScrollableLayoutStyle, layoutStyle) ||
588         layoutStyle < static_cast<int32_t>(LayoutStyle::ALWAYS_CENTER) ||
589         layoutStyle > static_cast<int32_t>(LayoutStyle::SPACE_BETWEEN_OR_CENTER)) {
590         option.nonScrollableLayoutStyle = std::nullopt;
591     } else {
592         option.nonScrollableLayoutStyle = (static_cast<LayoutStyle>(layoutStyle));
593     }
594     TabsModel::GetInstance()->SetScrollableBarModeOptions(option);
595 }
596 
SetBarGridAlign(const JSCallbackInfo & info)597 void JSTabs::SetBarGridAlign(const JSCallbackInfo& info)
598 {
599     BarGridColumnOptions columnOption;
600     if (info.Length() > 0 && info[0]->IsObject()) {
601         auto gridParam = JSRef<JSObject>::Cast(info[0]);
602         auto sm = gridParam->GetProperty("sm");
603         if (sm->IsNumber() && sm->ToNumber<int32_t>() >= 0 && sm->ToNumber<int32_t>() <= SM_COLUMN_NUM &&
604             sm->ToNumber<int32_t>() % 2 == 0) {
605             columnOption.sm = sm->ToNumber<int32_t>();
606         }
607         auto md = gridParam->GetProperty("md");
608         if (md->IsNumber() && md->ToNumber<int32_t>() >= 0 && md->ToNumber<int32_t>() <= MD_COLUMN_NUM &&
609             md->ToNumber<int32_t>() % 2 == 0) {
610             columnOption.md = md->ToNumber<int32_t>();
611         }
612         auto lg = gridParam->GetProperty("lg");
613         if (lg->IsNumber() && lg->ToNumber<int32_t>() >= 0 && lg->ToNumber<int32_t>() <= LG_COLUMN_NUM &&
614             lg->ToNumber<int32_t>() % 2 == 0) {
615             columnOption.lg = lg->ToNumber<int32_t>();
616         }
617         CalcDimension columnGutter;
618         if (ParseJsDimensionVp(gridParam->GetProperty("gutter"), columnGutter) && NonNegative(columnGutter.Value()) &&
619             columnGutter.Unit() != DimensionUnit::PERCENT) {
620             columnOption.gutter = columnGutter;
621         }
622         CalcDimension columnMargin;
623         if (ParseJsDimensionVp(gridParam->GetProperty("margin"), columnMargin) && NonNegative(columnMargin.Value()) &&
624             columnMargin.Unit() != DimensionUnit::PERCENT) {
625             columnOption.margin = columnMargin;
626         }
627     }
628     TabsModel::GetInstance()->SetBarGridAlign(columnOption);
629 }
630 
SetCustomContentTransition(const JSCallbackInfo & info)631 void JSTabs::SetCustomContentTransition(const JSCallbackInfo& info)
632 {
633     if (info.Length() != 1) {
634         return;
635     }
636 
637     auto customContentTransitionInfo = info[0];
638     if (customContentTransitionInfo->IsUndefined() || !customContentTransitionInfo->IsFunction()) {
639         TabsModel::GetInstance()->SetIsCustomAnimation(false);
640         return;
641     }
642 
643     RefPtr<JsTabsFunction> jsCustomAnimationFunc =
644         AceType::MakeRefPtr<JsTabsFunction>(JSRef<JSFunc>::Cast(customContentTransitionInfo));
645     auto onCustomAnimation = [execCtx = info.GetExecutionContext(), func = std::move(jsCustomAnimationFunc)](
646                                  int32_t from, int32_t to) -> TabContentAnimatedTransition {
647         TabContentAnimatedTransition transitionInfo;
648         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, transitionInfo);
649 
650         auto ret = func->Execute(from, to);
651         if (!ret->IsObject()) {
652             return transitionInfo;
653         }
654 
655         auto transitionObj = JSRef<JSObject>::Cast(ret);
656         JSRef<JSVal> timeoutProperty = transitionObj->GetProperty("timeout");
657         if (timeoutProperty->IsNumber()) {
658             auto timeout = timeoutProperty->ToNumber<int32_t>();
659             transitionInfo.timeout = timeout < 0 ? DEFAULT_CUSTOM_ANIMATION_TIMEOUT : timeout;
660         } else {
661             transitionInfo.timeout = DEFAULT_CUSTOM_ANIMATION_TIMEOUT;
662         }
663 
664         JSRef<JSVal> transition = transitionObj->GetProperty("transition");
665         if (transition->IsFunction()) {
666             RefPtr<JsTabsFunction> jsOnTransition =
667                 AceType::MakeRefPtr<JsTabsFunction>(JSRef<JSFunc>::Cast(transition));
668             auto onTransition = [execCtx, func = std::move(jsOnTransition)](
669                                     const RefPtr<TabContentTransitionProxy>& proxy) {
670                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
671                 ACE_SCORING_EVENT("onTransition");
672                 func->Execute(proxy);
673             };
674 
675             transitionInfo.transition = std::move(onTransition);
676         }
677 
678         return transitionInfo;
679     };
680     TabsModel::GetInstance()->SetIsCustomAnimation(true);
681     TabsModel::GetInstance()->SetOnCustomAnimation(std::move(onCustomAnimation));
682 }
683 
SetOnContentWillChange(const JSCallbackInfo & info)684 void JSTabs::SetOnContentWillChange(const JSCallbackInfo& info)
685 {
686     if (!info[0]->IsFunction()) {
687         return;
688     }
689 
690     auto handler = AceType::MakeRefPtr<JsTabsFunction>(JSRef<JSFunc>::Cast(info[0]));
691     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(handler)]
692         (int32_t currentIndex, int32_t comingIndex) -> bool {
693         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
694         ACE_SCORING_EVENT("Tabs.onContentWillChange");
695         auto ret = func->Execute(currentIndex, comingIndex);
696         if (!ret->IsBoolean()) {
697             return true;
698         }
699         return ret->ToBoolean();
700     };
701     TabsModel::GetInstance()->SetOnContentWillChange(std::move(callback));
702 }
703 
SetAnimateMode(const JSCallbackInfo & info)704 void JSTabs::SetAnimateMode(const JSCallbackInfo& info)
705 {
706     JSRef<JSVal> args = info[0];
707     if (!args->IsNumber()) {
708         TabsModel::GetInstance()->SetAnimateMode(TabAnimateMode::CONTENT_FIRST);
709         return;
710     }
711     uint32_t value = args->ToNumber<uint32_t>();
712     if (value >= static_cast<uint32_t>(TabAnimateMode::MAX_VALUE)) {
713         TabsModel::GetInstance()->SetAnimateMode(TabAnimateMode::CONTENT_FIRST);
714         return;
715     }
716     TabsModel::GetInstance()->SetAnimateMode(static_cast<TabAnimateMode>(value));
717 }
718 
SetEdgeEffect(const JSCallbackInfo & info)719 void JSTabs::SetEdgeEffect(const JSCallbackInfo& info)
720 {
721     auto edgeEffect = EdgeEffect::SPRING;
722     if (info.Length() > 0) {
723         edgeEffect = JSScrollable::ParseEdgeEffect(info[0], EdgeEffect::SPRING);
724     }
725     TabsModel::GetInstance()->SetEdgeEffect(edgeEffect);
726 }
727 
SetBarBackgroundEffect(const JSCallbackInfo & info)728 void JSTabs::SetBarBackgroundEffect(const JSCallbackInfo& info)
729 {
730     if (info.Length() == 0) {
731         return;
732     }
733     EffectOption option;
734     if (info[0]->IsObject()) {
735         JSRef<JSObject> jsOption = JSRef<JSObject>::Cast(info[0]);
736         ParseEffectOption(jsOption, option);
737     }
738     TabsModel::GetInstance()->SetBarBackgroundEffect(option);
739 }
740 
SetPageFlipMode(const JSCallbackInfo & info)741 void JSTabs::SetPageFlipMode(const JSCallbackInfo& info)
742 {
743     // default value
744     int32_t value = 0;
745     if (info.Length() < 1 || !info[0]->IsNumber()) {
746         TabsModel::GetInstance()->SetPageFlipMode(value);
747         return;
748     }
749     JSViewAbstract::ParseJsInt32(info[0], value);
750     TabsModel::GetInstance()->SetPageFlipMode(value);
751 }
752 
SetBarModifier(const JSCallbackInfo & info,const JsiRef<JsiValue> & jsValue)753 void JSTabs::SetBarModifier(const JSCallbackInfo& info, const JsiRef<JsiValue>& jsValue)
754 {
755     if (!jsValue->IsObject()) {
756         return;
757     }
758     JSRef<JSObject> obj = JSRef<JSObject>::Cast(jsValue);
759     JSRef<JSVal> val = obj->GetProperty("barModifier");
760     if (!val->IsObject()) {
761         return;
762     }
763     JSRef<JSObject> modifierObj = JSRef<JSObject>::Cast(val);
764     auto vm = info.GetVm();
765     auto globalObj = JSNApi::GetGlobalObject(vm);
766     auto globalFunc = globalObj->Get(vm, panda::StringRef::NewFromUtf8(vm, "applyCommonModifierToNode"));
767     JsiValue jsiValue(globalFunc);
768     JsiRef<JsiValue> globalFuncRef = JsiRef<JsiValue>::Make(jsiValue);
769     std::function<void(WeakPtr<NG::FrameNode>)> onApply = nullptr;
770     if (globalFuncRef->IsFunction()) {
771         RefPtr<JsFunction> jsFunc =
772             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(globalFuncRef));
773         onApply = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc),
774                       modifierParam = std::move(modifierObj)](WeakPtr<NG::FrameNode> frameNode) {
775             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
776             CHECK_NULL_VOID(func);
777             auto node = frameNode.Upgrade();
778             CHECK_NULL_VOID(node);
779             JSRef<JSVal> params[2];
780             params[0] = modifierParam;
781             params[1] = JSRef<JSVal>::Make(panda::NativePointerRef::New(execCtx.vm_, AceType::RawPtr(node)));
782             PipelineContext::SetCallBackNode(node);
783             func->ExecuteJS(2, params);
784         };
785     }
786     TabsModel::GetInstance()->SetBarModifier(std::move(onApply));
787 }
788 
SetCachedMaxCount(const JSCallbackInfo & info)789 void JSTabs::SetCachedMaxCount(const JSCallbackInfo& info)
790 {
791     if (info.Length() <= 1) {
792         return;
793     }
794 
795     std::optional<int32_t> cachedMaxCount;
796     if (info[0]->IsNumber()) {
797         auto count = info[0]->ToNumber<int32_t>();
798         if (count >= 0) {
799             cachedMaxCount = count;
800         }
801     }
802     auto cacheMode = TabsCacheMode::CACHE_BOTH_SIDE;
803     if (info[1]->IsNumber()) {
804         auto mode = info[1]->ToNumber<int32_t>();
805         if (mode >= static_cast<int32_t>(TabsCacheMode::CACHE_BOTH_SIDE) &&
806             mode <= static_cast<int32_t>(TabsCacheMode::CACHE_LATEST_SWITCHED)) {
807             cacheMode = static_cast<TabsCacheMode>(mode);
808         }
809     }
810     TabsModel::GetInstance()->SetCachedMaxCount(cachedMaxCount, cacheMode);
811 }
812 
JSBind(BindingTarget globalObj)813 void JSTabs::JSBind(BindingTarget globalObj)
814 {
815     JsTabContentTransitionProxy::JSBind(globalObj);
816     JSClass<JSTabs>::Declare("Tabs");
817     JSClass<JSTabs>::StaticMethod("create", &JSTabs::Create);
818     JSClass<JSTabs>::StaticMethod("pop", &JSTabs::Pop);
819     JSClass<JSTabs>::StaticMethod("vertical", &JSTabs::SetVertical);
820     JSClass<JSTabs>::StaticMethod("barPosition", &JSTabs::SetBarPosition);
821     JSClass<JSTabs>::StaticMethod("barBackgroundBlurStyle", &JSTabs::SetBarBackgroundBlurStyle);
822     JSClass<JSTabs>::StaticMethod("scrollable", &JSTabs::SetScrollable);
823     JSClass<JSTabs>::StaticMethod("barMode", &JSTabs::SetBarMode);
824     JSClass<JSTabs>::StaticMethod("barWidth", &JSTabs::SetBarWidth);
825     JSClass<JSTabs>::StaticMethod("barHeight", &JSTabs::SetBarHeight);
826     JSClass<JSTabs>::StaticMethod("width", &JSTabs::SetWidth);
827     JSClass<JSTabs>::StaticMethod("height", &JSTabs::SetHeight);
828     JSClass<JSTabs>::StaticMethod("index", &JSTabs::SetIndex);
829     JSClass<JSTabs>::StaticMethod("animationDuration", &JSTabs::SetAnimationDuration);
830     JSClass<JSTabs>::StaticMethod("divider", &JSTabs::SetDivider);
831     JSClass<JSTabs>::StaticMethod("onChange", &JSTabs::SetOnChange);
832     JSClass<JSTabs>::StaticMethod("onTabBarClick", &JSTabs::SetOnTabBarClick);
833     JSClass<JSTabs>::StaticMethod("onUnselected", &JSTabs::SetOnUnselected);
834     JSClass<JSTabs>::StaticMethod("onAnimationStart", &JSTabs::SetOnAnimationStart);
835     JSClass<JSTabs>::StaticMethod("onAnimationEnd", &JSTabs::SetOnAnimationEnd);
836     JSClass<JSTabs>::StaticMethod("onGestureSwipe", &JSTabs::SetOnGestureSwipe);
837     JSClass<JSTabs>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
838     JSClass<JSTabs>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
839     JSClass<JSTabs>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
840     JSClass<JSTabs>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
841     JSClass<JSTabs>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
842     JSClass<JSTabs>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
843     JSClass<JSTabs>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
844     JSClass<JSTabs>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
845     JSClass<JSTabs>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
846     JSClass<JSTabs>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
847     JSClass<JSTabs>::StaticMethod("fadingEdge", &JSTabs::SetFadingEdge);
848     JSClass<JSTabs>::StaticMethod("barOverlap", &JSTabs::SetBarOverlap);
849     JSClass<JSTabs>::StaticMethod("barBackgroundColor", &JSTabs::SetBarBackgroundColor);
850     JSClass<JSTabs>::StaticMethod("clip", &JSTabs::SetClip);
851     JSClass<JSTabs>::StaticMethod("barGridAlign", &JSTabs::SetBarGridAlign);
852     JSClass<JSTabs>::StaticMethod("customContentTransition", &JSTabs::SetCustomContentTransition);
853     JSClass<JSTabs>::StaticMethod("onContentWillChange", &JSTabs::SetOnContentWillChange);
854     JSClass<JSTabs>::StaticMethod("animationMode", &JSTabs::SetAnimateMode);
855     JSClass<JSTabs>::StaticMethod("edgeEffect", &JSTabs::SetEdgeEffect);
856     JSClass<JSTabs>::StaticMethod("barBackgroundEffect", &JSTabs::SetBarBackgroundEffect);
857     JSClass<JSTabs>::StaticMethod("pageFlipMode", &JSTabs::SetPageFlipMode);
858     JSClass<JSTabs>::StaticMethod("cachedMaxCount", &JSTabs::SetCachedMaxCount);
859     JSClass<JSTabs>::StaticMethod("onSelected", &JSTabs::SetOnSelected);
860 
861     JSClass<JSTabs>::InheritAndBind<JSContainerBase>(globalObj);
862 }
863 
864 } // namespace OHOS::Ace::Framework
865