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