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