1 /*
2 * Copyright (c) 2022 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_navdestination.h"
17
18 #include "base/log/ace_scoring_log.h"
19 #include "base/memory/ace_type.h"
20 #include "base/utils/utils.h"
21 #include "base/system_bar/system_bar_style.h"
22 #include "bridge/declarative_frontend/engine/functions/js_function.h"
23 #include "bridge/declarative_frontend/engine/js_converter.h"
24 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
25 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
26 #include "bridge/declarative_frontend/engine/js_types.h"
27 #include "bridge/declarative_frontend/jsview/js_navdestination_context.h"
28 #include "bridge/declarative_frontend/jsview/js_navigation.h"
29 #include "bridge/declarative_frontend/jsview/js_navigation_utils.h"
30 #include "bridge/declarative_frontend/jsview/js_navdestination_scrollable_processor.h"
31 #include "bridge/declarative_frontend/jsview/js_utils.h"
32 #include "core/components_ng/base/view_stack_model.h"
33 #include "core/components_ng/base/view_stack_processor.h"
34 #include "core/components_ng/pattern/navigation/navigation_options.h"
35 #include "core/components_ng/pattern/navrouter/navdestination_model_ng.h"
36
37 namespace OHOS::Ace {
38 std::unique_ptr<NavDestinationModel> NavDestinationModel::instance_ = nullptr;
39 std::mutex NavDestinationModel::mutex_;
40
GetInstance()41 NavDestinationModel* NavDestinationModel::GetInstance()
42 {
43 if (!instance_) {
44 std::lock_guard<std::mutex> lock(mutex_);
45 instance_.reset(new NG::NavDestinationModelNG());
46 }
47 return instance_.get();
48 }
49
50 } // namespace OHOS::Ace
51
52 namespace OHOS::Ace::Framework {
53
54 namespace {
55 constexpr uint32_t SAFE_AREA_TYPE_LIMIT = 3;
56 constexpr uint32_t SAFE_AREA_EDGE_LIMIT = 4;
57 constexpr uint32_t SAFE_AREA_EDGE_SYSTEM = 0;
58 constexpr uint32_t SAFE_AREA_EDGE_TOP = 0;
59 constexpr uint32_t SAFE_AREA_EDGE_BOTTOM = 1;
60 constexpr int32_t PARAMATER_LENGTH_ONE = 1;
61 constexpr int32_t PARAMATER_LENGTH_TWO = 2;
62 constexpr uint32_t FIRST_INDEX = 0;
63 constexpr uint32_t SECOND_INDEX = 1;
64 constexpr int32_t JS_ENUM_TRANSITIONTYPE_NONE = 1;
65 constexpr int32_t JS_ENUM_TRANSITIONTYPE_TITLE = 2;
66 constexpr int32_t JS_ENUM_TRANSITIONTYPE_CONTENT = 3;
67 constexpr int32_t JS_ENUM_TRANSITIONTYPE_FADE = 4;
68 constexpr int32_t JS_ENUM_TRANSITIONTYPE_EXPLODE = 5;
69 constexpr int32_t JS_ENUM_TRANSITIONTYPE_SLIDE_RIGHT = 6;
70 constexpr int32_t JS_ENUM_TRANSITIONTYPE_SLIDE_BOTTOM = 7;
71
ParseTransitionType(int32_t value)72 NG::NavigationSystemTransitionType ParseTransitionType(int32_t value)
73 {
74 switch (value) {
75 case JS_ENUM_TRANSITIONTYPE_NONE:
76 return NG::NavigationSystemTransitionType::NONE;
77 case JS_ENUM_TRANSITIONTYPE_TITLE:
78 return NG::NavigationSystemTransitionType::TITLE;
79 case JS_ENUM_TRANSITIONTYPE_CONTENT:
80 return NG::NavigationSystemTransitionType::CONTENT;
81 case JS_ENUM_TRANSITIONTYPE_FADE:
82 return NG::NavigationSystemTransitionType::FADE;
83 case JS_ENUM_TRANSITIONTYPE_EXPLODE:
84 return NG::NavigationSystemTransitionType::EXPLODE;
85 case JS_ENUM_TRANSITIONTYPE_SLIDE_RIGHT:
86 return NG::NavigationSystemTransitionType::SLIDE_RIGHT;
87 case JS_ENUM_TRANSITIONTYPE_SLIDE_BOTTOM:
88 return NG::NavigationSystemTransitionType::SLIDE_BOTTOM;
89 default:
90 return NG::NavigationSystemTransitionType::DEFAULT;
91 }
92 }
93
ParseCommonTitle(const JSRef<JSObject> & jsObj)94 bool ParseCommonTitle(const JSRef<JSObject>& jsObj)
95 {
96 JSRef<JSVal> subtitle = jsObj->GetProperty("sub");
97 JSRef<JSVal> title = jsObj->GetProperty("main");
98 std::string mainTitle;
99 std::string subTitle;
100 bool hasSub = JSViewAbstract::ParseJsString(subtitle, subTitle);
101 bool hasMain = JSViewAbstract::ParseJsString(title, mainTitle);
102 if (hasSub || hasMain) {
103 return NG::NavDestinationModelNG::GetInstance()->ParseCommonTitle(
104 hasSub, hasMain, subTitle, mainTitle);
105 }
106 return false;
107 }
108 } // namespace
109
Create()110 void JSNavDestination::Create()
111 {
112 NavDestinationModel::GetInstance()->Create();
113 NavDestinationModel::GetInstance()->SetScrollableProcessor(
114 []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
115 }
116
Create(const JSCallbackInfo & info)117 void JSNavDestination::Create(const JSCallbackInfo& info)
118 {
119 if (info.Length() <= 0) {
120 NavDestinationModel::GetInstance()->Create();
121 NavDestinationModel::GetInstance()->SetScrollableProcessor(
122 []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
123 return;
124 }
125
126 std::string moduleName;
127 std::string pagePath;
128 if (info.Length() == 1) {
129 // input format: builder/pathInfo
130 if (info[0]->IsFunction()) {
131 // first parameter = builder
132 auto builderFunctionJS = info[0];
133 auto builderFunc = [context = info.GetExecutionContext(), builder = std::move(builderFunctionJS)]() {
134 JAVASCRIPT_EXECUTION_SCOPE(context)
135 JSRef<JSFunc>::Cast(builder)->Call(JSRef<JSObject>());
136 };
137 auto ctx = AceType::MakeRefPtr<NG::NavDestinationContext>();
138 auto navPathInfo = AceType::MakeRefPtr<JSNavPathInfo>();
139 ctx->SetNavPathInfo(navPathInfo);
140 NavDestinationModel::GetInstance()->Create(std::move(builderFunc), std::move(ctx));
141 NavDestinationModel::GetInstance()->SetScrollableProcessor(
142 []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
143 return;
144 } else if (info[0]->IsObject()) {
145 // first parameter = pathInfo{'moduleName': stringA, 'pagePath': stringB}
146 auto infoObj = JSRef<JSObject>::Cast(info[0]);
147 if (!infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->IsString() ||
148 !infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->IsString()) {
149 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "navDestination current pageInfo is invalid");
150 return;
151 }
152 moduleName = infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->ToString();
153 pagePath = infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->ToString();
154 NavDestinationModel::GetInstance()->Create();
155 NavDestinationModel::GetInstance()->SetScrollableProcessor(
156 []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
157 NavDestinationModel::GetInstance()->SetNavDestinationPathInfo(moduleName, pagePath);
158 return;
159 }
160 TAG_LOGE(AceLogTag::ACE_NAVIGATION,
161 "current input info is neither buildFunction or navDestination usefulInfo");
162 return;
163 } else if (info.Length() == 2) {
164 // parameter = builder(maybe empty) + pathInfo
165 if (!info[0]->IsFunction() || !info[1]->IsObject()) {
166 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "buider or pageInfo is invalid");
167 return;
168 }
169 auto builderFunctionJS = info[0];
170 auto builderFunc = [context = info.GetExecutionContext(), builder = std::move(builderFunctionJS)]() {
171 JAVASCRIPT_EXECUTION_SCOPE(context)
172 JSRef<JSFunc>::Cast(builder)->Call(JSRef<JSObject>());
173 };
174 auto ctx = AceType::MakeRefPtr<NG::NavDestinationContext>();
175 auto navPathInfo = AceType::MakeRefPtr<JSNavPathInfo>();
176 ctx->SetNavPathInfo(navPathInfo);
177
178 auto infoObj = JSRef<JSObject>::Cast(info[1]);
179 if (!infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->IsString() ||
180 !infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->IsString()) {
181 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "navDestination current pageInfo is invalid");
182 return;
183 }
184 moduleName = infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->ToString();
185 pagePath = infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->ToString();
186 NavDestinationModel::GetInstance()->Create(std::move(builderFunc), std::move(ctx));
187 NavDestinationModel::GetInstance()->SetScrollableProcessor(
188 []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
189 NavDestinationModel::GetInstance()->SetNavDestinationPathInfo(moduleName, pagePath);
190 }
191 }
192
SetHideTitleBar(const JSCallbackInfo & info)193 void JSNavDestination::SetHideTitleBar(const JSCallbackInfo& info)
194 {
195 bool isHide = false;
196 if (info.Length() > 0 && info[0]->IsBoolean()) {
197 isHide = info[0]->ToBoolean();
198 }
199 bool isAnimated = false;
200 if (info.Length() > 1 && info[1]->IsBoolean()) {
201 isAnimated = info[1]->ToBoolean();
202 }
203 NavDestinationModel::GetInstance()->SetHideTitleBar(isHide, isAnimated);
204 }
205
SetHideBackButton(const JSCallbackInfo & info)206 void JSNavDestination::SetHideBackButton(const JSCallbackInfo& info)
207 {
208 bool isHide = false;
209 if (info.Length() > 0 && info[0]->IsBoolean()) {
210 isHide = info[0]->ToBoolean();
211 }
212 NavDestinationModel::GetInstance()->SetHideBackButton(isHide);
213 }
214
SetTitle(const JSCallbackInfo & info)215 void JSNavDestination::SetTitle(const JSCallbackInfo& info)
216 {
217 // Resource and string type.
218 std::string title;
219 if (ParseJsString(info[0], title)) {
220 NavDestinationModel::GetInstance()->ParseCommonTitle(false, true, "", title);
221 } else if (info[0]->IsObject()) {
222 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
223 do {
224 // NavigationCommonTitle
225 if (ParseCommonTitle(jsObj)) {
226 break;
227 }
228 // CustomBuilder | NavigationCustomTitle
229 CalcDimension titleHeight;
230 if (!jsObj->HasProperty("height")) {
231 NavDestinationModel::GetInstance()->SetTitleHeight(titleHeight, false);
232 break;
233 }
234 JSRef<JSVal> height = jsObj->GetProperty("height");
235 bool isValid = JSContainerBase::ParseJsDimensionVpNG(height, titleHeight);
236 if (height->IsString()) {
237 std::string heightValue;
238 ParseJsString(height, heightValue);
239 if (heightValue == NG::TITLE_MAIN_WITH_SUB) {
240 NavDestinationModel::GetInstance()->SetTitleHeight(NG::DOUBLE_LINE_TITLEBAR_HEIGHT);
241 break;
242 }
243 if (heightValue == NG::TITLE_MAIN) {
244 NavDestinationModel::GetInstance()->SetTitleHeight(NG::SINGLE_LINE_TITLEBAR_HEIGHT);
245 break;
246 }
247 }
248 if (!isValid || titleHeight.Value() < 0) {
249 NavDestinationModel::GetInstance()->SetTitleHeight(Dimension(), true);
250 break;
251 }
252 NavDestinationModel::GetInstance()->SetTitleHeight(titleHeight);
253 } while (0);
254 JSRef<JSVal> builderObject = jsObj->GetProperty("builder");
255 if (builderObject->IsFunction()) {
256 ViewStackModel::GetInstance()->NewScope();
257 JsFunction jsBuilderFunc(info.This(), JSRef<JSFunc>::Cast(builderObject));
258 ACE_SCORING_EVENT("Navdestination.title.builder");
259 jsBuilderFunc.Execute();
260 auto customNode = ViewStackModel::GetInstance()->Finish();
261 NavDestinationModel::GetInstance()->SetCustomTitle(customNode);
262 }
263 } else {
264 NavDestinationModel::GetInstance()->ParseCommonTitle(false, false, "", "");
265 }
266
267 NG::NavigationTitlebarOptions options;
268 JSNavigationUtils::ParseTitleBarOptions(info, false, options);
269 NavDestinationModel::GetInstance()->SetTitlebarOptions(std::move(options));
270 }
271
SetBackButtonIcon(const JSCallbackInfo & info)272 void JSNavDestination::SetBackButtonIcon(const JSCallbackInfo& info)
273 {
274 // srcType、pixmap、string
275 if (info.Length() < 1) {
276 return;
277 }
278 std::string src;
279 auto noPixMap = ParseJsMedia(info[0], src);
280
281 RefPtr<PixelMap> pixMap = nullptr;
282 auto isValidImage = false;
283 #if defined(PIXEL_MAP_SUPPORTED)
284 if (!noPixMap) {
285 pixMap = CreatePixelMapFromNapiValue(info[0]);
286 }
287 #endif
288 if (noPixMap || pixMap != nullptr) {
289 isValidImage = true;
290 }
291 std::vector<std::string> nameList;
292 NG::ImageOption imageOption;
293 std::string bundleName;
294 std::string moduleName;
295 GetJsMediaBundleInfo(info[0], bundleName, moduleName);
296 nameList.emplace_back(bundleName);
297 nameList.emplace_back(moduleName);
298 imageOption.noPixMap = noPixMap;
299 imageOption.isValidImage = isValidImage;
300 std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
301 auto isSymbol = info[0]->IsObject() && src.empty() && pixMap == nullptr;
302 if (isSymbol) {
303 SetSymbolOptionApply(info, iconSymbol, info[0]);
304 }
305
306 NavDestinationModel::GetInstance()->SetBackButtonIcon(iconSymbol, src, imageOption, pixMap, nameList);
307 }
308
SetOnShown(const JSCallbackInfo & info)309 void JSNavDestination::SetOnShown(const JSCallbackInfo& info)
310 {
311 if (!info[0]->IsFunction()) {
312 return;
313 }
314
315 auto onShownCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
316 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
317 auto onShown = [execCtx = info.GetExecutionContext(), func = std::move(onShownCallback), node = targetNode]() {
318 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
319 ACE_SCORING_EVENT("NavDestination.onShown");
320 PipelineContext::SetCallBackNode(node);
321 JSRef<JSVal> params[1];
322 params[0] = JSRef<JSVal>::Make(ToJSValue("undefined"));
323 func->ExecuteJS(1, params);
324 };
325 NavDestinationModel::GetInstance()->SetOnShown(std::move(onShown));
326 info.ReturnSelf();
327 }
328
SetOnHidden(const JSCallbackInfo & info)329 void JSNavDestination::SetOnHidden(const JSCallbackInfo& info)
330 {
331 if (!info[0]->IsFunction()) {
332 return;
333 }
334 auto onHiddenCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
335 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
336 auto onHidden = [execCtx = info.GetExecutionContext(), func = std::move(onHiddenCallback), node = targetNode]() {
337 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
338 ACE_SCORING_EVENT("NavDestination.onHidden");
339 PipelineContext::SetCallBackNode(node);
340 func->ExecuteJS();
341 };
342 NavDestinationModel::GetInstance()->SetOnHidden(std::move(onHidden));
343 info.ReturnSelf();
344 }
345
SetOnBackPressed(const JSCallbackInfo & info)346 void JSNavDestination::SetOnBackPressed(const JSCallbackInfo& info)
347 {
348 if (!info[0]->IsFunction()) {
349 return;
350 }
351 auto onBackPressedCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
352 auto onBackPressed = [execCtx = info.GetExecutionContext(), func = std::move(onBackPressedCallback)]() -> bool {
353 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, false);
354 ACE_SCORING_EVENT("NavDestination.onBackPressed");
355 return (func->ExecuteJS())->ToBoolean();
356 };
357 NavDestinationModel::GetInstance()->SetOnBackPressed(std::move(onBackPressed));
358 info.ReturnSelf();
359 }
360
SetOnReady(const JSCallbackInfo & info)361 void JSNavDestination::SetOnReady(const JSCallbackInfo& info)
362 {
363 if (!info[0]->IsFunction()) {
364 return;
365 }
366 auto onReadyCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
367 auto onReady = [execCtx = info.GetExecutionContext(), func = std::move(onReadyCallback)](
368 RefPtr<NG::NavDestinationContext> context) {
369 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
370 auto jsContext = JSClass<JSNavDestinationContext>::NewInstance();
371 auto jsNavDestinationContext = Referenced::Claim(jsContext->Unwrap<JSNavDestinationContext>());
372 CHECK_NULL_VOID(jsNavDestinationContext);
373 jsNavDestinationContext->SetNavDestinationContext(context);
374 ACE_SCORING_EVENT("NavDestination.onReady");
375 JSRef<JSVal> params[1];
376 params[0] = jsContext;
377 func->ExecuteJS(1, params);
378 };
379 NavDestinationModel::GetInstance()->SetOnReady(std::move(onReady));
380 info.ReturnSelf();
381 }
382
SetMode(const JSCallbackInfo & info)383 void JSNavDestination::SetMode(const JSCallbackInfo& info)
384 {
385 if (!info[0]->IsNumber()) {
386 // set default back ground color
387 NavDestinationModel::GetInstance()->SetNavDestinationMode(NG::NavDestinationMode::STANDARD);
388 return;
389 }
390 auto mode = info[0]->ToNumber<int32_t>();
391 NavDestinationModel::GetInstance()->SetNavDestinationMode(static_cast<NG::NavDestinationMode>(mode));
392 }
393
SetMenus(const JSCallbackInfo & info)394 void JSNavDestination::SetMenus(const JSCallbackInfo& info)
395 {
396 if (info.Length() < 1) {
397 return;
398 }
399
400 if (info[0]->IsUndefined() || info[0]->IsArray()) {
401 std::vector<NG::BarItem> menuItems;
402 if (info[0]->IsUndefined()) {
403 menuItems = {};
404 } else {
405 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
406 JSNavigationUtils::ParseBarItems(targetNode, info, JSRef<JSArray>::Cast(info[0]), menuItems);
407 }
408 NavDestinationModel::GetInstance()->SetMenuItems(std::move(menuItems));
409 return;
410 } else if (info[0]->IsObject()) {
411 auto builderObject = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
412 if (builderObject->IsFunction()) {
413 ViewStackModel::GetInstance()->NewScope();
414 JsFunction jsBuilderFunc(info.This(), JSRef<JSObject>::Cast(builderObject));
415 ACE_SCORING_EVENT("NavDestiNation.menu.builder");
416 jsBuilderFunc.Execute();
417 auto customNode = ViewStackModel::GetInstance()->Finish();
418 NavDestinationModel::GetInstance()->SetCustomMenu(customNode);
419 }
420 }
421 }
422
SetBackgroundColor(const JSCallbackInfo & info)423 void JSNavDestination::SetBackgroundColor(const JSCallbackInfo& info)
424 {
425 Color backgroundColor;
426 bool isValid = ParseJsColor(info[0], backgroundColor);
427
428 NavDestinationModel::GetInstance()->SetBackgroundColor(backgroundColor, isValid);
429 }
430
SetWillAppear(const JSCallbackInfo & info)431 void JSNavDestination::SetWillAppear(const JSCallbackInfo& info)
432 {
433 if (!info[0]->IsFunction()) {
434 return;
435 }
436
437 auto willAppear = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
438 auto onWillAppear = [execCtx = info.GetExecutionContext(), func = std::move(willAppear)]() {
439 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
440 ACE_SCORING_EVENT("NavDestination.WillAppear");
441 func->ExecuteJS();
442 };
443 NavDestinationModel::GetInstance()->SetOnWillAppear(std::move(onWillAppear));
444 info.ReturnSelf();
445 }
446
SetWillHide(const JSCallbackInfo & info)447 void JSNavDestination::SetWillHide(const JSCallbackInfo& info)
448 {
449 if (!info[0]->IsFunction()) {
450 return;
451 }
452
453 auto willHideCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
454 auto onWillHide = [execCtx = info.GetExecutionContext(), func = std::move(willHideCallback)]() {
455 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
456 ACE_SCORING_EVENT("NavDestination.WillHide");
457 func->ExecuteJS();
458 };
459 NavDestinationModel::GetInstance()->SetOnWillHide(std::move(onWillHide));
460 info.ReturnSelf();
461 }
462
SetWillShow(const JSCallbackInfo & info)463 void JSNavDestination::SetWillShow(const JSCallbackInfo& info)
464 {
465 if (!info[0]->IsFunction()) {
466 return;
467 }
468
469 auto willShowCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
470 auto onWillShow = [execCtx = info.GetExecutionContext(), func = std::move(willShowCallback)]() {
471 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
472 ACE_SCORING_EVENT("NavDestination.WillShow");
473 func->ExecuteJS();
474 };
475 NavDestinationModel::GetInstance()->SetOnWillShow(std::move(onWillShow));
476 info.ReturnSelf();
477 }
478
SetWillDisAppear(const JSCallbackInfo & info)479 void JSNavDestination::SetWillDisAppear(const JSCallbackInfo& info)
480 {
481 if (!info[0]->IsFunction()) {
482 return;
483 }
484
485 auto WillDisAppear = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
486 auto onWillDisAppear = [execCtx = info.GetExecutionContext(), func = std::move(WillDisAppear)]() {
487 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
488 ACE_SCORING_EVENT("NavDestination.WillDisAppear");
489 func->ExecuteJS();
490 };
491 NavDestinationModel::GetInstance()->SetOnWillDisAppear(std::move(onWillDisAppear));
492 info.ReturnSelf();
493 }
494
SetIgnoreLayoutSafeArea(const JSCallbackInfo & info)495 void JSNavDestination::SetIgnoreLayoutSafeArea(const JSCallbackInfo& info)
496 {
497 NG::SafeAreaExpandOpts opts { .type = NG::SAFE_AREA_TYPE_SYSTEM, .edges = NG::SAFE_AREA_EDGE_ALL};
498 if (info.Length() >= PARAMATER_LENGTH_ONE && info[FIRST_INDEX]->IsArray()) {
499 auto paramArray = JSRef<JSArray>::Cast(info[0]);
500 uint32_t safeAreaType = NG::SAFE_AREA_TYPE_NONE;
501 for (size_t i = 0; i < paramArray->Length(); ++i) {
502 auto value = paramArray->GetValueAt(i);
503 if (!value->IsNumber() ||
504 value->ToNumber<uint32_t>() >= SAFE_AREA_TYPE_LIMIT ||
505 value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_SYSTEM) {
506 safeAreaType = NG::SAFE_AREA_TYPE_SYSTEM;
507 break;
508 }
509 }
510 opts.type = safeAreaType;
511 }
512
513 if (info.Length() >= PARAMATER_LENGTH_TWO && info[SECOND_INDEX]->IsArray()) {
514 auto paramArray = JSRef<JSArray>::Cast(info[1]);
515 uint32_t safeAreaEdge = NG::SAFE_AREA_EDGE_NONE;
516 for (size_t i = 0; i < paramArray->Length(); ++i) {
517 auto value = paramArray->GetValueAt(i);
518 if (!value->IsNumber() ||
519 value->ToNumber<uint32_t>() >= SAFE_AREA_EDGE_LIMIT) {
520 safeAreaEdge = NG::SAFE_AREA_EDGE_ALL;
521 break;
522 }
523 if (value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_TOP ||
524 value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_BOTTOM) {
525 safeAreaEdge |= (1 << value->ToNumber<uint32_t>());
526 }
527 }
528 opts.edges = safeAreaEdge;
529 }
530 NavDestinationModel::GetInstance()->SetIgnoreLayoutSafeArea(opts);
531 }
532
SetRecoverable(const JSCallbackInfo & info)533 void JSNavDestination::SetRecoverable(const JSCallbackInfo& info)
534 {
535 if (!info[0]->IsBoolean()) {
536 // the default value of navDestination's recoverable is true
537 NavDestinationModel::GetInstance()->SetRecoverable(true);
538 return;
539 }
540 auto recoverable = info[0]->ToBoolean();
541 NavDestinationModel::GetInstance()->SetRecoverable(recoverable);
542 }
543
SetToolBarConfiguration(const JSCallbackInfo & info)544 void JSNavDestination::SetToolBarConfiguration(const JSCallbackInfo& info)
545 {
546 if (info[0]->IsUndefined() || info[0]->IsArray()) {
547 std::vector<NG::BarItem> toolBarItems;
548 if (info[0]->IsArray()) {
549 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
550 JSNavigationUtils::ParseToolbarItemsConfiguration(
551 targetNode, info, JSRef<JSArray>::Cast(info[0]), toolBarItems);
552 }
553 NavDestinationModel::GetInstance()->SetToolbarConfiguration(std::move(toolBarItems));
554 } else if (info[0]->IsObject()) {
555 auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
556 if (builderFuncParam->IsFunction()) {
557 ViewStackModel::GetInstance()->NewScope();
558 JsFunction jsBuilderFunc(builderFuncParam);
559 jsBuilderFunc.Execute();
560 auto customNode = ViewStackModel::GetInstance()->Finish();
561 NavDestinationModel::GetInstance()->SetCustomToolBar(customNode);
562 }
563 }
564 NG::NavigationToolbarOptions options;
565 JSNavigationUtils::ParseToolbarOptions(info, options);
566 NavDestinationModel::GetInstance()->SetToolBarOptions(std::move(options));
567 }
568
SetHideToolBar(const JSCallbackInfo & info)569 void JSNavDestination::SetHideToolBar(const JSCallbackInfo& info)
570 {
571 bool isHide = false;
572 if (info.Length() > 0 && info[0]->IsBoolean()) {
573 isHide = info[0]->ToBoolean();
574 }
575 bool isAnimated = false;
576 if (info.Length() > 1 && info[1]->IsBoolean()) {
577 isAnimated = info[1]->ToBoolean();
578 }
579 NavDestinationModel::GetInstance()->SetHideToolBar(isHide, isAnimated);
580 }
581
BindToScrollable(const JSCallbackInfo & info)582 void JSNavDestination::BindToScrollable(const JSCallbackInfo& info)
583 {
584 auto bindFunc = [&info](const RefPtr<NG::NavDestinationScrollableProcessor>& processor) {
585 auto jsProcessor = AceType::DynamicCast<JSNavDestinationScrollableProcessor>(processor);
586 CHECK_NULL_VOID(jsProcessor);
587 jsProcessor->BindToScrollable(info);
588 };
589 NavDestinationModel::GetInstance()->UpdateBindingWithScrollable(std::move(bindFunc));
590 }
591
BindToNestedScrollable(const JSCallbackInfo & info)592 void JSNavDestination::BindToNestedScrollable(const JSCallbackInfo& info)
593 {
594 auto bindFunc = [&info](const RefPtr<NG::NavDestinationScrollableProcessor>& processor) {
595 auto jsProcessor = AceType::DynamicCast<JSNavDestinationScrollableProcessor>(processor);
596 CHECK_NULL_VOID(jsProcessor);
597 jsProcessor->BindToNestedScrollable(info);
598 };
599 NavDestinationModel::GetInstance()->UpdateBindingWithScrollable(std::move(bindFunc));
600 }
601
SetCustomTransition(const JSCallbackInfo & info)602 void JSNavDestination::SetCustomTransition(const JSCallbackInfo& info)
603 {
604 if (info.Length() != 1 || !info[0]->IsFunction()) {
605 NavDestinationModel::GetInstance()->SetCustomTransition(nullptr);
606 return;
607 }
608 auto jsTransitionDelegate = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(info[0]));
609 auto transitionDelegate = [execCtx = info.GetExecutionContext(), delegate = std::move(jsTransitionDelegate)](
610 NG::NavigationOperation operation, bool isEnter) -> std::optional<std::vector<NG::NavDestinationTransition>> {
611 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, std::nullopt);
612 JSRef<JSVal> params[2];
613 params[0] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(operation)));
614 params[1] = JSRef<JSVal>::Make(ToJSValue(isEnter));
615 auto ret = delegate->ExecuteJS(2, params);
616 if (!ret->IsArray()) {
617 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "NavDestination custom transition invalid!");
618 return std::nullopt;
619 }
620 std::vector<NG::NavDestinationTransition> allTransitions;
621 auto allTransitionObj = JSRef<JSArray>::Cast(ret);
622 for (size_t index = 0; index < allTransitionObj->Length(); ++index) {
623 auto transitionValue = allTransitionObj->GetValueAt(index);
624 if (!transitionValue->IsObject()) {
625 continue;
626 }
627 auto navDestinationTransition = JSNavigationUtils::ParseNavDestinationTransition(
628 JSRef<JSObject>::Cast(transitionValue), execCtx);
629 if (navDestinationTransition.has_value()) {
630 allTransitions.emplace_back(navDestinationTransition.value());
631 }
632 }
633 return allTransitions;
634 };
635
636 NavDestinationModel::GetInstance()->SetCustomTransition(std::move(transitionDelegate));
637 }
638
JSBind(BindingTarget globalObj)639 void JSNavDestination::JSBind(BindingTarget globalObj)
640 {
641 JSNavDestinationContext::JSBind(globalObj);
642 JSClass<JSNavDestination>::Declare("NavDestination");
643 JSClass<JSNavDestination>::StaticMethod("create", &JSNavDestination::Create);
644 JSClass<JSNavDestination>::StaticMethod("title", &JSNavDestination::SetTitle);
645 JSClass<JSNavDestination>::StaticMethod("hideTitleBar", &JSNavDestination::SetHideTitleBar);
646 JSClass<JSNavDestination>::StaticMethod("hideBackButton", &JSNavDestination::SetHideBackButton);
647 JSClass<JSNavDestination>::StaticMethod("backButtonIcon", &JSNavDestination::SetBackButtonIcon);
648 JSClass<JSNavDestination>::StaticMethod("backgroundColor", &JSNavDestination::SetBackgroundColor);
649 JSClass<JSNavDestination>::StaticMethod("onShown", &JSNavDestination::SetOnShown);
650 JSClass<JSNavDestination>::StaticMethod("onHidden", &JSNavDestination::SetOnHidden);
651 JSClass<JSNavDestination>::StaticMethod("onBackPressed", &JSNavDestination::SetOnBackPressed);
652 JSClass<JSNavDestination>::StaticMethod("onReady", &JSNavDestination::SetOnReady);
653 JSClass<JSNavDestination>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
654 JSClass<JSNavDestination>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
655 JSClass<JSNavDestination>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
656 JSClass<JSNavDestination>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
657 JSClass<JSNavDestination>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
658 JSClass<JSNavDestination>::StaticMethod("id", &JSViewAbstract::JsId);
659 JSClass<JSNavDestination>::StaticMethod("mode", &JSNavDestination::SetMode);
660 JSClass<JSNavDestination>::StaticMethod("menus", &JSNavDestination::SetMenus);
661 JSClass<JSNavDestination>::StaticMethod("onWillAppear", &JSNavDestination::SetWillAppear);
662 JSClass<JSNavDestination>::StaticMethod("onWillShow", &JSNavDestination::SetWillShow);
663 JSClass<JSNavDestination>::StaticMethod("toolbarConfiguration", &JSNavDestination::SetToolBarConfiguration);
664 JSClass<JSNavDestination>::StaticMethod("hideToolBar", &JSNavDestination::SetHideToolBar);
665 JSClass<JSNavDestination>::StaticMethod("onWillHide", &JSNavDestination::SetWillHide);
666 JSClass<JSNavDestination>::StaticMethod("onWillDisappear", &JSNavDestination::SetWillDisAppear);
667 JSClass<JSNavDestination>::StaticMethod("onResult", &JSNavDestination::SetResultCallback);
668 JSClass<JSNavDestination>::StaticMethod("ignoreLayoutSafeArea", &JSNavDestination::SetIgnoreLayoutSafeArea);
669 JSClass<JSNavDestination>::StaticMethod("systemBarStyle", &JSNavDestination::SetSystemBarStyle);
670 JSClass<JSNavDestination>::StaticMethod("systemTransition", &JSNavDestination::SetSystemTransition);
671 JSClass<JSNavDestination>::StaticMethod("recoverable", &JSNavDestination::SetRecoverable);
672 JSClass<JSNavDestination>::StaticMethod("bindToScrollable", &JSNavDestination::BindToScrollable);
673 JSClass<JSNavDestination>::StaticMethod("bindToNestedScrollable", &JSNavDestination::BindToNestedScrollable);
674 JSClass<JSNavDestination>::StaticMethod("customTransition", &JSNavDestination::SetCustomTransition);
675 JSClass<JSNavDestination>::InheritAndBind<JSContainerBase>(globalObj);
676 }
677
SetSystemBarStyle(const JSCallbackInfo & info)678 void JSNavDestination::SetSystemBarStyle(const JSCallbackInfo& info)
679 {
680 RefPtr<SystemBarStyle> style = nullptr;
681 if (info.Length() == 1 && info[0]->IsObject()) {
682 auto styleObj = JsConverter::ConvertJsValToNapiValue(info[0]);
683 auto env = GetCurrentEnv();
684 if (env) {
685 style = SystemBarStyle::CreateStyleFromJsObj(env, styleObj);
686 }
687 }
688 NavDestinationModel::GetInstance()->SetSystemBarStyle(style);
689 }
690
SetSystemTransition(const JSCallbackInfo & info)691 void JSNavDestination::SetSystemTransition(const JSCallbackInfo& info)
692 {
693 if (!info[0]->IsNumber()) {
694 NavDestinationModel::GetInstance()->SetSystemTransitionType(NG::NavigationSystemTransitionType::DEFAULT);
695 return;
696 }
697 auto value = info[0]->ToNumber<int32_t>();
698 NG::NavigationSystemTransitionType type = ParseTransitionType(value);
699 NavDestinationModel::GetInstance()->SetSystemTransitionType(type);
700 }
701
SetResultCallback(const JSCallbackInfo & info)702 void JSNavDestination::SetResultCallback(const JSCallbackInfo& info)
703 {
704 if (info.Length() < 1) {
705 return;
706 }
707 if (!info[0]->IsFunction()) {
708 return;
709 }
710 auto func = JSRef<JSFunc>::Cast(info[0]);
711 if (func->IsEmpty()) {
712 return;
713 }
714 auto setPopCallback = [func](const RefPtr<NG::NavPathInfo>& info) {
715 auto pathInfo = AceType::DynamicCast<JSNavPathInfo>(info);
716 CHECK_NULL_VOID(pathInfo);
717 pathInfo->SetNavDestinationPopCallback(func);
718 };
719 NavDestinationModel::GetInstance()->SetOnPop(setPopCallback);
720 }
721 } // namespace OHOS::Ace::Framework
722