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_tab_content.h"
17
18 #include <optional>
19
20 #include "base/log/ace_scoring_log.h"
21 #include "base/log/ace_trace.h"
22 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
23 #include "bridge/declarative_frontend/jsview/models/tab_content_model_impl.h"
24 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
25 #include "core/components/tab_bar/tab_theme.h"
26 #include "core/components_ng/base/view_stack_model.h"
27 #include "core/components_ng/pattern/tabs/tab_content_model_ng.h"
28 #include "core/components_ng/pattern/tabs/tabs_layout_property.h"
29 #include "core/components_ng/pattern/tabs/tabs_node.h"
30 #include "core/components_ng/property/measure_property.h"
31
32 namespace OHOS::Ace {
33
34 std::unique_ptr<TabContentModel> TabContentModel::instance_ = nullptr;
35 std::mutex TabContentModel::mutex_;
36
37 const std::vector<TextOverflow> TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS,
38 TextOverflow::MARQUEE };
39 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
40 const std::vector<TextHeightAdaptivePolicy> HEIGHT_ADAPTIVE_POLICIES = { TextHeightAdaptivePolicy::MAX_LINES_FIRST,
41 TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST, TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST };
42
GetInstance()43 TabContentModel* TabContentModel::GetInstance()
44 {
45 if (!instance_) {
46 std::lock_guard<std::mutex> lock(mutex_);
47 if (!instance_) {
48 #ifdef NG_BUILD
49 instance_.reset(new NG::TabContentModelNG());
50 #else
51 if (Container::IsCurrentUseNewPipeline()) {
52 instance_.reset(new NG::TabContentModelNG());
53 } else {
54 instance_.reset(new Framework::TabContentModelImpl());
55 }
56 #endif
57 }
58 }
59 return instance_.get();
60 }
61
62 } // namespace OHOS::Ace
63
64 namespace OHOS::Ace::Framework {
65
Create(const JSCallbackInfo & info)66 void JSTabContent::Create(const JSCallbackInfo& info)
67 {
68 if (Container::IsCurrentUsePartialUpdate()) {
69 CreateForPartialUpdate(info);
70 return;
71 }
72 TabContentModel::GetInstance()->Create();
73 }
74
CreateForPartialUpdate(const JSCallbackInfo & info)75 void JSTabContent::CreateForPartialUpdate(const JSCallbackInfo& info)
76 {
77 if (info.Length() <= 0 || !info[0]->IsFunction()) {
78 TabContentModel::GetInstance()->Create();
79 return;
80 }
81
82 JSRef<JSVal> builderFunctionJS = info[0];
83 auto builderFunc = [context = info.GetExecutionContext(), builder = std::move(builderFunctionJS)]() {
84 JAVASCRIPT_EXECUTION_SCOPE(context)
85 JSRef<JSFunc>::Cast(builder)->Call(JSRef<JSObject>());
86 };
87 TabContentModel::GetInstance()->Create(std::move(builderFunc));
88 }
89
SetTabBar(const JSCallbackInfo & info)90 void JSTabContent::SetTabBar(const JSCallbackInfo& info)
91 {
92 if (info.Length() <= 0) {
93 return;
94 }
95 auto tabBarInfo = info[0];
96
97 std::string infoStr;
98 if (ParseJsString(tabBarInfo, infoStr)) {
99 TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
100 TabContentModel::GetInstance()->SetTabBar(infoStr, std::nullopt, std::nullopt, nullptr, true);
101 TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
102 return;
103 }
104
105 if (!tabBarInfo->IsObject()) {
106 TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
107 TabContentModel::GetInstance()->SetTabBar(std::nullopt, std::nullopt, std::nullopt, nullptr, false);
108 TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
109 return;
110 }
111
112 auto paramObject = JSRef<JSObject>::Cast(tabBarInfo);
113 JSRef<JSVal> contentParam = paramObject->GetProperty("builderNode_");
114 if (contentParam->IsObject()) {
115 auto builderNodeObject = JSRef<JSObject>::Cast(contentParam);
116 JSRef<JSVal> nodeptr = builderNodeObject->GetProperty("nodePtr_");
117 if (!nodeptr.IsEmpty()) {
118 const auto* vm = nodeptr->GetEcmaVM();
119 auto* node = nodeptr->GetLocalHandle()->ToNativePointer(vm)->Value();
120 auto* frameNode = reinterpret_cast<NG::FrameNode*>(node);
121 CHECK_NULL_VOID(frameNode);
122 RefPtr<NG::FrameNode> refPtrFrameNode = AceType::Claim(frameNode);
123 CHECK_NULL_VOID(refPtrFrameNode);
124 TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
125 TabContentModel::GetInstance()->SetTabBar(std::nullopt, std::nullopt, std::nullopt, nullptr, false);
126 TabContentModel::GetInstance()->SetTabBarWithContent(refPtrFrameNode);
127 return;
128 }
129 }
130 JSRef<JSVal> builderFuncParam = paramObject->GetProperty("builder");
131 if (builderFuncParam->IsFunction()) {
132 auto tabBarBuilder = AceType::MakeRefPtr<JsFunction>(info.This(), JSRef<JSFunc>::Cast(builderFuncParam));
133 auto tabBarBuilderFunc = [execCtx = info.GetExecutionContext(),
134 tabBarBuilderFunc = std::move(tabBarBuilder)]() {
135 if (tabBarBuilderFunc) {
136 ACE_SCOPED_TRACE("JSTabContent::Execute TabBar builder");
137 JAVASCRIPT_EXECUTION_SCOPE(execCtx);
138 tabBarBuilderFunc->ExecuteJS();
139 }
140 };
141 TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
142 TabContentModel::GetInstance()->SetTabBar(
143 std::nullopt, std::nullopt, std::nullopt, std::move(tabBarBuilderFunc), false);
144 TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
145 return;
146 }
147 JSRef<JSVal> typeParam = paramObject->GetProperty("type");
148 if (typeParam->IsString()) {
149 auto type = typeParam->ToString();
150 if (type == "SubTabBarStyle") {
151 SetSubTabBarStyle(paramObject);
152 return;
153 }
154 if (type == "BottomTabBarStyle") {
155 SetBottomTabBarStyle(info);
156 return;
157 }
158 }
159
160 JSRef<JSVal> textParam = paramObject->GetProperty("text");
161 auto isTextEmpty = textParam->IsEmpty() || textParam->IsUndefined() || textParam->IsNull();
162 std::optional<std::string> textOpt = std::nullopt;
163 if (!isTextEmpty) {
164 std::string text;
165 if (ParseJsString(textParam, text)) {
166 textOpt = text;
167 }
168 }
169
170 JSRef<JSVal> iconParam = paramObject->GetProperty("icon");
171 auto isIconEmpty = iconParam->IsEmpty() || iconParam->IsUndefined() || iconParam->IsNull();
172 std::optional<std::string> iconOpt = std::nullopt;
173 if (!isIconEmpty) {
174 std::string icon;
175 if (ParseJsMedia(iconParam, icon)) {
176 iconOpt = icon;
177 }
178 }
179 TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
180 TabContentModel::GetInstance()->SetTabBar(textOpt, iconOpt, std::nullopt, nullptr, false);
181 TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
182 }
183
Pop()184 void JSTabContent::Pop()
185 {
186 if (ViewStackModel::GetInstance()->IsPrebuilding()) {
187 return ViewStackModel::GetInstance()->PushPrebuildCompCmd("[JSTabContent][pop]", &JSTabContent::Pop);
188 }
189 TabContentModel::GetInstance()->Pop();
190 }
191
SetIndicator(const JSRef<JSVal> & info)192 void JSTabContent::SetIndicator(const JSRef<JSVal>& info)
193 {
194 JSRef<JSObject> obj = JSRef<JSObject>::New();
195 if (info->IsObject()) {
196 obj = JSRef<JSObject>::Cast(info);
197 }
198 IndicatorStyle indicator;
199 CalcDimension indicatorHeight;
200 CalcDimension indicatorWidth;
201 CalcDimension indicatorBorderRadius;
202 CalcDimension indicatorMarginTop;
203 if (!info->IsObject() || !ConvertFromJSValue(obj->GetProperty("color"), indicator.color)) {
204 RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
205 if (tabTheme) {
206 indicator.color = tabTheme->GetActiveIndicatorColor();
207 }
208 }
209 if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("height"), indicatorHeight) ||
210 indicatorHeight.Value() < 0.0f || indicatorHeight.Unit() == DimensionUnit::PERCENT) {
211 RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
212 if (tabTheme) {
213 indicator.height = tabTheme->GetActiveIndicatorWidth();
214 }
215 } else {
216 indicator.height = indicatorHeight;
217 }
218 if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("width"), indicatorWidth) ||
219 indicatorWidth.Value() < 0.0f || indicatorWidth.Unit() == DimensionUnit::PERCENT) {
220 indicator.width = 0.0_vp;
221 } else {
222 indicator.width = indicatorWidth;
223 }
224 if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("borderRadius"), indicatorBorderRadius) ||
225 indicatorBorderRadius.Value() < 0.0f || indicatorBorderRadius.Unit() == DimensionUnit::PERCENT) {
226 indicator.borderRadius = 0.0_vp;
227 } else {
228 indicator.borderRadius = indicatorBorderRadius;
229 }
230 if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("marginTop"), indicatorMarginTop) ||
231 indicatorMarginTop.Value() < 0.0f || indicatorMarginTop.Unit() == DimensionUnit::PERCENT) {
232 RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
233 if (tabTheme) {
234 indicator.marginTop = tabTheme->GetSubTabIndicatorGap();
235 }
236 } else {
237 indicator.marginTop = indicatorMarginTop;
238 }
239 TabContentModel::GetInstance()->SetIndicator(indicator);
240 }
241
SetBoard(const JSRef<JSVal> & info)242 void JSTabContent::SetBoard(const JSRef<JSVal>& info)
243 {
244 JSRef<JSObject> obj = JSRef<JSObject>::New();
245 if (info->IsObject()) {
246 obj = JSRef<JSObject>::Cast(info);
247 }
248 BoardStyle board;
249 CalcDimension borderRadius;
250 if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("borderRadius"), borderRadius) ||
251 borderRadius.Value() < 0.0f || borderRadius.Unit() == DimensionUnit::PERCENT) {
252 RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
253 if (tabTheme) {
254 board.borderRadius = tabTheme->GetFocusIndicatorRadius();
255 }
256 } else {
257 board.borderRadius = borderRadius;
258 }
259 TabContentModel::GetInstance()->SetBoard(board);
260 }
261
SetSelectedMode(const JSRef<JSVal> & info)262 void JSTabContent::SetSelectedMode(const JSRef<JSVal>& info)
263 {
264 int32_t selectedMode;
265 if (!ConvertFromJSValue(info, selectedMode)) {
266 TabContentModel::GetInstance()->SetSelectedMode(SelectedMode::INDICATOR);
267 } else {
268 TabContentModel::GetInstance()->SetSelectedMode(static_cast<SelectedMode>(selectedMode));
269 }
270 }
271
GetFontContent(const JSRef<JSVal> font,LabelStyle & labelStyle,bool isSubTabStyle)272 void JSTabContent::GetFontContent(const JSRef<JSVal> font, LabelStyle& labelStyle, bool isSubTabStyle)
273 {
274 JSRef<JSObject> obj = JSRef<JSObject>::Cast(font);
275 JSRef<JSVal> size = obj->GetProperty("size");
276 CalcDimension fontSize;
277 if (ParseJsDimensionFp(size, fontSize) && NonNegative(fontSize.Value()) &&
278 fontSize.Unit() != DimensionUnit::PERCENT) {
279 labelStyle.fontSize = fontSize;
280 }
281
282 JSRef<JSVal> weight = obj->GetProperty("weight");
283 if (weight->IsString() || weight->IsNumber()) {
284 auto parseResult = ParseFontWeight(weight->ToString());
285 if (parseResult.first || !isSubTabStyle) {
286 labelStyle.fontWeight = parseResult.second;
287 }
288 }
289
290 JSRef<JSVal> family = obj->GetProperty("family");
291 std::vector<std::string> fontFamilies;
292 if (ParseJsFontFamilies(family, fontFamilies)) {
293 labelStyle.fontFamily = fontFamilies;
294 }
295
296 JSRef<JSVal> style = obj->GetProperty("style");
297 if (style->IsNumber()) {
298 int32_t value = style->ToNumber<int32_t>();
299 if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
300 labelStyle.fontStyle = FONT_STYLES[value];
301 }
302 }
303 }
304
SetLabelStyle(const JSRef<JSVal> & info,bool isSubTabStyle)305 void JSTabContent::SetLabelStyle(const JSRef<JSVal>& info, bool isSubTabStyle)
306 {
307 LabelStyle labelStyle;
308 if (!info->IsObject()) {
309 LOGW("info not is Object");
310 } else {
311 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info);
312 JSRef<JSVal> overflowValue = obj->GetProperty("overflow");
313 if (!overflowValue->IsNull() && overflowValue->IsNumber()) {
314 auto overflow = overflowValue->ToNumber<int32_t>();
315 if (overflow >= 0 && overflow < static_cast<int32_t>(TEXT_OVERFLOWS.size())) {
316 labelStyle.textOverflow = TEXT_OVERFLOWS[overflow];
317 }
318 }
319
320 JSRef<JSVal> maxLines = obj->GetProperty("maxLines");
321 if (!maxLines->IsNull() && maxLines->IsNumber() && maxLines->ToNumber<int32_t>() > 0) {
322 labelStyle.maxLines = maxLines->ToNumber<int32_t>();
323 }
324
325 JSRef<JSVal> minFontSizeValue = obj->GetProperty("minFontSize");
326 CalcDimension minFontSize;
327 if (ParseJsDimensionFp(minFontSizeValue, minFontSize) && NonNegative(minFontSize.Value()) &&
328 minFontSize.Unit() != DimensionUnit::PERCENT) {
329 labelStyle.minFontSize = minFontSize;
330 }
331
332 JSRef<JSVal> maxFontSizeValue = obj->GetProperty("maxFontSize");
333 CalcDimension maxFontSize;
334 if (ParseJsDimensionFp(maxFontSizeValue, maxFontSize) && NonNegative(maxFontSize.Value()) &&
335 maxFontSize.Unit() != DimensionUnit::PERCENT) {
336 labelStyle.maxFontSize = maxFontSize;
337 }
338
339 JSRef<JSVal> heightAdaptivePolicyValue = obj->GetProperty("heightAdaptivePolicy");
340 if (!heightAdaptivePolicyValue->IsNull() && heightAdaptivePolicyValue->IsNumber()) {
341 auto heightAdaptivePolicy = heightAdaptivePolicyValue->ToNumber<int32_t>();
342 if (heightAdaptivePolicy >= 0 &&
343 heightAdaptivePolicy < static_cast<int32_t>(HEIGHT_ADAPTIVE_POLICIES.size())) {
344 labelStyle.heightAdaptivePolicy = HEIGHT_ADAPTIVE_POLICIES[heightAdaptivePolicy];
345 }
346 }
347
348 JSRef<JSVal> font = obj->GetProperty("font");
349 if (!font->IsNull() && font->IsObject()) {
350 GetFontContent(font, labelStyle, isSubTabStyle);
351 }
352
353 GetLabelUnselectedContent(obj->GetProperty("unselectedColor"), labelStyle);
354
355 GetLabelSelectedContent(obj->GetProperty("selectedColor"), labelStyle);
356 }
357 CompleteParameters(labelStyle, isSubTabStyle);
358 TabContentModel::GetInstance()->SetLabelStyle(labelStyle);
359 }
360
SetIconStyle(const JSRef<JSVal> & info)361 void JSTabContent::SetIconStyle(const JSRef<JSVal>& info)
362 {
363 IconStyle iconStyle;
364 if (info->IsObject()) {
365 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info);
366 Color unselectedColor;
367 JSRef<JSVal> unselectedColorValue = obj->GetProperty("unselectedColor");
368 if (ConvertFromJSValue(unselectedColorValue, unselectedColor)) {
369 iconStyle.unselectedColor = unselectedColor;
370 }
371
372 Color selectedColor;
373 JSRef<JSVal> selectedColorValue = obj->GetProperty("selectedColor");
374 if (ConvertFromJSValue(selectedColorValue, selectedColor)) {
375 iconStyle.selectedColor = selectedColor;
376 }
377 }
378 TabContentModel::GetInstance()->SetIconStyle(iconStyle);
379 }
380
GetLabelUnselectedContent(const JSRef<JSVal> unselectedColorValue,LabelStyle & labelStyle)381 void JSTabContent::GetLabelUnselectedContent(const JSRef<JSVal> unselectedColorValue, LabelStyle& labelStyle)
382 {
383 Color unselectedColor;
384 if (ConvertFromJSValue(unselectedColorValue, unselectedColor)) {
385 labelStyle.unselectedColor = unselectedColor;
386 }
387 }
388
GetLabelSelectedContent(const JSRef<JSVal> selectedColorValue,LabelStyle & labelStyle)389 void JSTabContent::GetLabelSelectedContent(const JSRef<JSVal> selectedColorValue, LabelStyle& labelStyle)
390 {
391 Color selectedColor;
392 if (ConvertFromJSValue(selectedColorValue, selectedColor)) {
393 labelStyle.selectedColor = selectedColor;
394 }
395 }
396
ParseJsLengthMetrics(const JSRef<JSObject> & obj,CalcDimension & result)397 bool ParseJsLengthMetrics(const JSRef<JSObject>& obj, CalcDimension& result)
398 {
399 if (!obj->HasProperty("value")) {
400 return false;
401 }
402 auto value = obj->GetProperty("value");
403 if (!value->IsNumber()) {
404 return false;
405 }
406 auto unit = DimensionUnit::VP;
407 auto jsUnit = obj->GetProperty("unit");
408 if (jsUnit->IsNumber()) {
409 unit = static_cast<DimensionUnit>(jsUnit->ToNumber<int32_t>());
410 }
411 CalcDimension dimension(value->ToNumber<double>(), unit);
412 result = dimension;
413 return true;
414 }
415
SetPadding(const JSRef<JSVal> & info,bool isSubTabStyle)416 void JSTabContent::SetPadding(const JSRef<JSVal>& info, bool isSubTabStyle)
417 {
418 CalcDimension length;
419 NG::PaddingProperty padding;
420 bool useLocalizedPadding = false;
421 if (ParseJsDimensionVp(info, length) && NonNegative(length.Value()) && length.Unit() != DimensionUnit::PERCENT) {
422 padding.left = NG::CalcLength(length);
423 padding.right = NG::CalcLength(length);
424 padding.top = NG::CalcLength(length);
425 padding.bottom = NG::CalcLength(length);
426 TabContentModel::GetInstance()->SetPadding(padding);
427 return;
428 }
429
430 RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
431 if (tabTheme) {
432 if (isSubTabStyle) {
433 padding.top = NG::CalcLength(tabTheme->GetSubTabTopPadding());
434 padding.bottom = NG::CalcLength(tabTheme->GetSubTabBottomPadding());
435 padding.left = NG::CalcLength(tabTheme->GetSubTabHorizontalPadding());
436 padding.right = NG::CalcLength(tabTheme->GetSubTabHorizontalPadding());
437 } else {
438 padding.top = NG::CalcLength(0.0_vp);
439 padding.bottom = NG::CalcLength(0.0_vp);
440 padding.left = NG::CalcLength(tabTheme->GetBottomTabHorizontalPadding());
441 padding.right = NG::CalcLength(tabTheme->GetBottomTabHorizontalPadding());
442 }
443 }
444 if (info->IsObject()) {
445 JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info);
446 CalcDimension left;
447 if (ParseJsDimensionVp(paddingObj->GetProperty("left"), left) && NonNegative(left.Value()) &&
448 left.Unit() != DimensionUnit::PERCENT) {
449 padding.left = NG::CalcLength(left);
450 }
451 CalcDimension right;
452 if (ParseJsDimensionVp(paddingObj->GetProperty("right"), right) && NonNegative(right.Value()) &&
453 right.Unit() != DimensionUnit::PERCENT) {
454 padding.right = NG::CalcLength(right);
455 }
456 CalcDimension top;
457 if (ParseJsDimensionVp(paddingObj->GetProperty("top"), top) && NonNegative(top.Value()) &&
458 top.Unit() != DimensionUnit::PERCENT) {
459 padding.top = NG::CalcLength(top);
460 }
461 CalcDimension bottom;
462 if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottom) && NonNegative(bottom.Value()) &&
463 bottom.Unit() != DimensionUnit::PERCENT) {
464 padding.bottom = NG::CalcLength(bottom);
465 }
466 }
467 if (info->IsObject()) {
468 JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info);
469 CalcDimension start;
470 CalcDimension end;
471 CalcDimension top;
472 CalcDimension bottom;
473 if (paddingObj->GetProperty("start")->IsObject()) {
474 JSRef<JSObject> startObj = JSRef<JSObject>::Cast(paddingObj->GetProperty("start"));
475 if (ParseJsLengthMetrics(startObj, start)) {
476 padding.left = NG::CalcLength(start);
477 useLocalizedPadding = true;
478 }
479 }
480 if (paddingObj->GetProperty("end")->IsObject()) {
481 JSRef<JSObject> endObj = JSRef<JSObject>::Cast(paddingObj->GetProperty("end"));
482 if (ParseJsLengthMetrics(endObj, end)) {
483 padding.right = NG::CalcLength(end);
484 useLocalizedPadding = true;
485 }
486 }
487 if (paddingObj->GetProperty("top")->IsObject()) {
488 JSRef<JSObject> topObj = JSRef<JSObject>::Cast(paddingObj->GetProperty("top"));
489 if (ParseJsLengthMetrics(topObj, top)) {
490 padding.top = NG::CalcLength(top);
491 useLocalizedPadding = true;
492 }
493 }
494 if (paddingObj->GetProperty("bottom")->IsObject()) {
495 JSRef<JSObject> bottomObj = JSRef<JSObject>::Cast(paddingObj->GetProperty("bottom"));
496 if (ParseJsLengthMetrics(bottomObj, bottom)) {
497 padding.bottom = NG::CalcLength(bottom);
498 useLocalizedPadding = true;
499 }
500 }
501 }
502 TabContentModel::GetInstance()->SetPadding(padding);
503 TabContentModel::GetInstance()->SetUseLocalizedPadding(useLocalizedPadding);
504 }
505
SetId(const JSRef<JSVal> & info)506 void JSTabContent::SetId(const JSRef<JSVal>& info)
507 {
508 std::string id;
509 if (!ParseJsString(info, id)) {
510 return;
511 }
512 TabContentModel::GetInstance()->SetId(id);
513 }
514
CompleteParameters(LabelStyle & labelStyle,bool isSubTabStyle)515 void JSTabContent::CompleteParameters(LabelStyle& labelStyle, bool isSubTabStyle)
516 {
517 auto tabTheme = GetTheme<TabTheme>();
518 if (!tabTheme) {
519 return;
520 }
521 if (!labelStyle.maxLines.has_value()) {
522 labelStyle.maxLines = 1;
523 }
524 if (!labelStyle.minFontSize.has_value()) {
525 labelStyle.minFontSize = 0.0_vp;
526 }
527 if (!labelStyle.maxFontSize.has_value()) {
528 labelStyle.maxFontSize = 0.0_vp;
529 }
530 if (!labelStyle.fontSize.has_value()) {
531 if (isSubTabStyle) {
532 labelStyle.fontSize = tabTheme->GetSubTabTextDefaultFontSize();
533 } else if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
534 labelStyle.fontSize = tabTheme->GetBottomTabTextSize();
535 }
536 }
537 if (!labelStyle.fontWeight.has_value() && !isSubTabStyle) {
538 labelStyle.fontWeight = FontWeight::MEDIUM;
539 }
540 if (!labelStyle.fontStyle.has_value()) {
541 labelStyle.fontStyle = FontStyle::NORMAL;
542 }
543 if (!labelStyle.heightAdaptivePolicy.has_value()) {
544 labelStyle.heightAdaptivePolicy = TextHeightAdaptivePolicy::MAX_LINES_FIRST;
545 }
546 if (!labelStyle.textOverflow.has_value()) {
547 labelStyle.textOverflow = TextOverflow::ELLIPSIS;
548 }
549 }
550
SetBuilderNode(const JSRef<JSObject> & paramObject)551 void SetBuilderNode(const JSRef<JSObject>& paramObject)
552 {
553 JSRef<JSVal> contentParam = paramObject->GetProperty("content");
554 if (!contentParam->IsObject()) {
555 return;
556 }
557 auto contentObject = JSRef<JSObject>::Cast(contentParam);
558 JSRef<JSVal> builderNodeParam = contentObject->GetProperty("builderNode_");
559 if (!builderNodeParam->IsObject()) {
560 return;
561 }
562 auto builderNodeObject = JSRef<JSObject>::Cast(builderNodeParam);
563 JSRef<JSVal> nodeptr = builderNodeObject->GetProperty("nodePtr_");
564 if (nodeptr.IsEmpty()) {
565 return;
566 }
567 const auto* vm = nodeptr->GetEcmaVM();
568 CHECK_NULL_VOID(nodeptr->GetLocalHandle()->IsNativePointer(vm));
569 auto* node = nodeptr->GetLocalHandle()->ToNativePointer(vm)->Value();
570 auto* frameNode = reinterpret_cast<NG::FrameNode*>(node);
571 CHECK_NULL_VOID(frameNode);
572 RefPtr<NG::FrameNode> refPtrFrameNode = AceType::Claim(frameNode);
573 TabContentModel::GetInstance()->SetCustomStyleNode(refPtrFrameNode);
574 }
575
SetSubTabBarStyle(const JSRef<JSObject> & paramObject)576 void JSTabContent::SetSubTabBarStyle(const JSRef<JSObject>& paramObject)
577 {
578 JSRef<JSVal> contentParam = paramObject->GetProperty("content");
579 SetBuilderNode(paramObject);
580
581 auto isContentEmpty = contentParam->IsEmpty() || contentParam->IsUndefined() || contentParam->IsNull();
582 if (isContentEmpty) {
583 LOGW("The content param is empty");
584 }
585 std::optional<std::string> contentOpt;
586 std::string content;
587 if (ParseJsString(contentParam, content)) {
588 contentOpt = content;
589 }
590
591 JSRef<JSVal> indicatorParam = paramObject->GetProperty("indicator");
592 SetIndicator(indicatorParam);
593
594 JSRef<JSVal> selectedModeParam = paramObject->GetProperty("selectedMode");
595 SetSelectedMode(selectedModeParam);
596
597 JSRef<JSVal> boardParam = paramObject->GetProperty("board");
598 SetBoard(boardParam);
599
600 JSRef<JSVal> labelStyleParam = paramObject->GetProperty("labelStyle");
601 SetLabelStyle(labelStyleParam, true);
602
603 JSRef<JSVal> paddingParam = paramObject->GetProperty("padding");
604 SetPadding(paddingParam, true);
605
606 JSRef<JSVal> idParam = paramObject->GetProperty("id");
607 SetId(idParam);
608
609 TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::SUBTABBATSTYLE);
610 TabContentModel::GetInstance()->SetTabBar(contentOpt, std::nullopt, std::nullopt, nullptr, false);
611 TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
612 }
613
SetLayoutMode(const JSRef<JSVal> & info)614 void JSTabContent::SetLayoutMode(const JSRef<JSVal>& info)
615 {
616 int32_t layoutMode;
617 if (!ConvertFromJSValue(info, layoutMode)) {
618 TabContentModel::GetInstance()->SetLayoutMode(LayoutMode::VERTICAL);
619 } else {
620 TabContentModel::GetInstance()->SetLayoutMode(static_cast<LayoutMode>(layoutMode));
621 }
622 }
623
SetVerticalAlign(const JSRef<JSVal> & info)624 void JSTabContent::SetVerticalAlign(const JSRef<JSVal>& info)
625 {
626 auto align = FlexAlign::CENTER;
627 if (info->IsNumber()) {
628 auto value = info->ToNumber<int32_t>();
629 if (value >= static_cast<int32_t>(FlexAlign::FLEX_START) &&
630 value <= static_cast<int32_t>(FlexAlign::FLEX_END)) {
631 align = static_cast<FlexAlign>(value);
632 }
633 }
634 TabContentModel::GetInstance()->SetVerticalAlign(align);
635 }
636
SetSymmetricExtensible(const JSRef<JSVal> & info)637 void JSTabContent::SetSymmetricExtensible(const JSRef<JSVal>& info)
638 {
639 bool isExtensible = false;
640 ParseJsBool(info, isExtensible);
641 TabContentModel::GetInstance()->SetSymmetricExtensible(isExtensible);
642 }
643
SetBottomTabBarStyle(const JSCallbackInfo & info)644 void JSTabContent::SetBottomTabBarStyle(const JSCallbackInfo& info)
645 {
646 auto paramObject = JSRef<JSObject>::Cast(info[0]);
647 JSRef<JSVal> textParam = paramObject->GetProperty("text");
648 std::optional<std::string> textOpt = std::nullopt;
649 std::string text;
650 if (ParseJsString(textParam, text)) {
651 textOpt = text;
652 }
653
654 JSRef<JSVal> iconParam = paramObject->GetProperty("icon");
655 std::optional<std::string> iconOpt = std::nullopt;
656 std::string icon;
657 std::optional<TabBarSymbol> tabBarSymbol = std::nullopt;
658 if (ParseJsMedia(iconParam, icon)) {
659 iconOpt = icon;
660 } else if (iconParam->IsObject()) {
661 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(iconParam);
662 JSRef<JSVal> normalModifier = jsObj->GetProperty("normal");
663 JSRef<JSVal> selectedModifier = jsObj->GetProperty("selected");
664 if (normalModifier->IsObject()) {
665 TabBarSymbol symbolApply;
666 JSViewAbstract::SetTabBarSymbolOptionApply(info, symbolApply, normalModifier, selectedModifier);
667 if (selectedModifier->IsObject()) {
668 symbolApply.selectedFlag = true;
669 }
670 tabBarSymbol = symbolApply;
671 }
672 }
673
674 JSRef<JSVal> paddingParam = paramObject->GetProperty("padding");
675 SetPadding(paddingParam, false);
676
677 JSRef<JSVal> layoutParam = paramObject->GetProperty("layoutMode");
678 SetLayoutMode(layoutParam);
679
680 JSRef<JSVal> verticalAlignParam = paramObject->GetProperty("verticalAlign");
681 SetVerticalAlign(verticalAlignParam);
682
683 JSRef<JSVal> extensibleParam = paramObject->GetProperty("symmetricExtensible");
684 SetSymmetricExtensible(extensibleParam);
685
686 JSRef<JSVal> labelStyleParam = paramObject->GetProperty("labelStyle");
687 SetLabelStyle(labelStyleParam, false);
688
689 SetIconStyle(paramObject->GetProperty("iconStyle"));
690
691 JSRef<JSVal> idParam = paramObject->GetProperty("id");
692 SetId(idParam);
693
694 TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::BOTTOMTABBATSTYLE);
695 TabContentModel::GetInstance()->SetTabBar(textOpt, iconOpt, tabBarSymbol, nullptr, false);
696 TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
697 }
698
SetOnWillShow(const JSCallbackInfo & info)699 void JSTabContent::SetOnWillShow(const JSCallbackInfo& info)
700 {
701 if (info.Length() < 1 || !info[0]->IsFunction()) {
702 return;
703 }
704 auto willShowHandler = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
705 WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
706 auto onWillShow = [executionContext = info.GetExecutionContext(), func = std::move(willShowHandler)]() {
707 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
708 ACE_SCORING_EVENT("TabContent.onWillShow");
709 func->Execute();
710 };
711 TabContentModel::GetInstance()->SetOnWillShow(std::move(onWillShow));
712 }
713
SetOnWillHide(const JSCallbackInfo & info)714 void JSTabContent::SetOnWillHide(const JSCallbackInfo& info)
715 {
716 if (info.Length() < 1 || !info[0]->IsFunction()) {
717 return;
718 }
719 auto willHideHandler = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
720 WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
721 auto onWillHide = [executionContext = info.GetExecutionContext(), func = std::move(willHideHandler)]() {
722 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
723 ACE_SCORING_EVENT("TabContent.onWillHide");
724 func->Execute();
725 };
726 TabContentModel::GetInstance()->SetOnWillHide(std::move(onWillHide));
727 }
728
JSBind(BindingTarget globalObj)729 void JSTabContent::JSBind(BindingTarget globalObj)
730 {
731 JSClass<JSTabContent>::Declare("TabContent");
732 JSClass<JSTabContent>::StaticMethod("create", &JSTabContent::Create);
733 JSClass<JSTabContent>::StaticMethod("pop", &JSTabContent::Pop);
734 JSClass<JSTabContent>::StaticMethod("tabBar", &JSTabContent::SetTabBar);
735 JSClass<JSTabContent>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
736 JSClass<JSTabContent>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
737 JSClass<JSTabContent>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
738 JSClass<JSTabContent>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
739 JSClass<JSTabContent>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
740 JSClass<JSTabContent>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
741 JSClass<JSTabContent>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
742 JSClass<JSTabContent>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
743 JSClass<JSTabContent>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
744 JSClass<JSTabContent>::StaticMethod("width", &JSTabContent::SetTabContentWidth);
745 JSClass<JSTabContent>::StaticMethod("height", &JSTabContent::SetTabContentHeight);
746 JSClass<JSTabContent>::StaticMethod("size", &JSTabContent::SetTabContentSize);
747 JSClass<JSTabContent>::StaticMethod("onWillShow", &JSTabContent::SetOnWillShow);
748 JSClass<JSTabContent>::StaticMethod("onWillHide", &JSTabContent::SetOnWillHide);
749 JSClass<JSTabContent>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
750 JSClass<JSTabContent>::InheritAndBind<JSContainerBase>(globalObj);
751 }
752
753 } // namespace OHOS::Ace::Framework
754