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