1 /*
2  * Copyright (c) 2021-2024 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_navigation.h"
17 
18 #include <vector>
19 
20 #include "base/log/ace_scoring_log.h"
21 #include "base/memory/referenced.h"
22 #include "base/system_bar/system_bar_style.h"
23 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
24 #include "bridge/declarative_frontend/engine/functions/js_navigation_function.h"
25 #include "bridge/declarative_frontend/engine/js_converter.h"
26 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
27 #include "bridge/declarative_frontend/engine/js_types.h"
28 #include "bridge/declarative_frontend/jsview/js_nav_path_stack.h"
29 #include "bridge/declarative_frontend/jsview/js_navigation_stack.h"
30 #include "bridge/declarative_frontend/jsview/js_navigation_utils.h"
31 #include "bridge/declarative_frontend/jsview/js_utils.h"
32 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
33 #include "bridge/declarative_frontend/jsview/models/navigation_model_impl.h"
34 #include "core/components_ng/base/view_abstract_model.h"
35 #include "core/components_ng/base/view_stack_model.h"
36 #include "core/components_ng/base/view_stack_processor.h"
37 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
38 #include "core/components_ng/pattern/navigation/navigation_model_data.h"
39 #include "core/components_ng/pattern/navigation/navigation_model_ng.h"
40 #include "core/components_ng/pattern/navigation/navigation_options.h"
41 
42 namespace OHOS::Ace {
43 std::unique_ptr<NavigationModel> NavigationModel::instance_ = nullptr;
44 std::mutex NavigationModel::mutex_;
45 constexpr int32_t NAVIGATION_ANIMATION_TIMEOUT = 1000; // ms
46 
GetInstance()47 NavigationModel* NavigationModel::GetInstance()
48 {
49     if (!instance_) {
50         std::lock_guard<std::mutex> lock(mutex_);
51         if (!instance_) {
52 #ifdef NG_BUILD
53             instance_.reset(new NG::NavigationModelNG());
54 #else
55             if (Container::IsCurrentUseNewPipeline()) {
56                 instance_.reset(new NG::NavigationModelNG());
57             } else {
58                 instance_.reset(new Framework::NavigationModelImpl());
59             }
60 #endif
61         }
62     }
63     return instance_.get();
64 }
65 } // namespace OHOS::Ace
66 
67 namespace OHOS::Ace::Framework {
68 namespace {
69 constexpr int32_t TITLE_MODE_RANGE = 2;
70 constexpr int32_t NAVIGATION_MODE_RANGE = 2;
71 constexpr int32_t NAV_BAR_POSITION_RANGE = 1;
72 constexpr int32_t DEFAULT_NAV_BAR_WIDTH = 240;
73 constexpr Dimension DEFAULT_MIN_CONTENT_WIDTH = 360.0_vp;
74 constexpr uint32_t SAFE_AREA_TYPE_LIMIT = 3;
75 constexpr uint32_t SAFE_AREA_EDGE_LIMIT = 4;
76 constexpr uint32_t SAFE_AREA_EDGE_SYSTEM = 0;
77 constexpr uint32_t SAFE_AREA_EDGE_TOP = 0;
78 constexpr uint32_t SAFE_AREA_EDGE_BOTTOM = 1;
79 constexpr int32_t PARAMETER_LENGTH_ONE  = 1;
80 constexpr int32_t PARAMETER_LENGTH_TWO  = 2;
81 constexpr int32_t FIRST_INDEX  = 0;
82 constexpr int32_t SECOND_INDEX  = 1;
83 
TitleModeChangeEventToJSValue(const NavigationTitleModeChangeEvent & eventInfo)84 JSRef<JSVal> TitleModeChangeEventToJSValue(const NavigationTitleModeChangeEvent& eventInfo)
85 {
86     return JSRef<JSVal>::Make(ToJSValue(eventInfo.IsMiniBar() ? static_cast<int32_t>(NavigationTitleMode::MINI)
87                                                               : static_cast<int32_t>(NavigationTitleMode::FULL)));
88 }
89 } // namespace
90 
ParseToolBarItems(const JSCallbackInfo & info,std::list<RefPtr<AceType>> & items)91 void JSNavigation::ParseToolBarItems(const JSCallbackInfo& info, std::list<RefPtr<AceType>>& items)
92 {
93     JSRef<JSArray> jsArray = JSRef<JSArray>::Cast(info[0]);
94     auto length = jsArray->Length();
95     for (size_t i = 0; i < length; i++) {
96         auto item = jsArray->GetValueAt(i);
97         if (!item->IsObject()) {
98             continue;
99         }
100 
101         auto itemObject = JSRef<JSObject>::Cast(item);
102         auto toolBarItem = AceType::MakeRefPtr<ToolBarItem>();
103         auto itemValueObject = itemObject->GetProperty("value");
104         if (itemValueObject->IsString()) {
105             toolBarItem->value = itemValueObject->ToString();
106         }
107 
108         auto itemIconObject = itemObject->GetProperty("icon");
109         std::string icon;
110         ParseJsMedia(itemIconObject, icon);
111         toolBarItem->icon = icon;
112 
113         auto itemActionValue = itemObject->GetProperty("action");
114         if (itemActionValue->IsFunction()) {
115             auto onClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(itemActionValue));
116             auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
117             toolBarItem->action =
118                 EventMarker([func = std::move(onClickFunc), node = targetNode, execCtx = info.GetExecutionContext()]() {
119                     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
120                     ACE_SCORING_EVENT("Navigation.toolBarItemClick");
121                     PipelineContext::SetCallBackNode(node);
122                     func->Execute();
123                 });
124             auto onClickWithParamFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(itemActionValue));
125             toolBarItem->actionWithParam =
126                 EventMarker([func = std::move(onClickWithParamFunc), node = targetNode,
127                                 execCtx = info.GetExecutionContext()](const BaseEventInfo* info) {
128                     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
129                     ACE_SCORING_EVENT("Navigation.menuItemButtonClick");
130                     PipelineContext::SetCallBackNode(node);
131                     func->Execute();
132                 });
133         }
134         items.push_back(toolBarItem);
135     }
136 }
137 
ParseCommonTitle(const JSRef<JSObject> & jsObj)138 bool JSNavigation::ParseCommonTitle(const JSRef<JSObject>& jsObj)
139 {
140     JSRef<JSVal> subtitle = jsObj->GetProperty("sub");
141     JSRef<JSVal> title = jsObj->GetProperty("main");
142     std::string mainTitle;
143     std::string subTitle;
144     bool hasSub = ParseJsString(subtitle, subTitle);
145     bool hasMain = ParseJsString(title, mainTitle);
146     if (hasSub || hasMain) {
147         return NavigationModel::GetInstance()->ParseCommonTitle(
148             hasSub, hasMain, subTitle, mainTitle);
149     }
150     return false;
151 }
152 
Create(const JSCallbackInfo & info)153 void JSNavigation::Create(const JSCallbackInfo& info)
154 {
155     JSRef<JSObject> newObj;
156     std::string moduleName;
157     std::string pagePath;
158     if (info.Length() == 1) {
159         // input format: navPathStack/pathInfo
160         if (!info[0]->IsObject()) {
161             return;
162         }
163         // instance of NavPathStack
164         JSValueWrapper valueWrapper = info[0].Get().GetLocalHandle();
165         if (!JSNavPathStack::CheckIsValid(valueWrapper)) {
166             // first parameter = pathInfo{'moduleName': stringA, 'pagePath': stringB, 'isUserCreateStack': bool}
167             TAG_LOGE(AceLogTag::ACE_NAVIGATION, "current stack is not navPathStack");
168             auto infoObj = JSRef<JSObject>::Cast(info[0]);
169             if (!infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->IsString() ||
170                 !infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->IsString()) {
171                 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "current pageInfo is invalid");
172                 return;
173             }
174             moduleName = infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->ToString();
175             pagePath = infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->ToString();
176         } else {
177             // first parameter = navPathStack
178             newObj = JSRef<JSObject>::Cast(info[0]);
179         }
180     } else if (info.Length() == 2) {
181         // parameter = navPathStack(maybe empty) + pathInfo
182         if (!info[0]->IsObject() || !info[1]->IsObject()) {
183             TAG_LOGE(AceLogTag::ACE_NAVIGATION, "stack or pageInfo is invalid");
184             return;
185         }
186         // instance of NavPathStack
187         JSValueWrapper valueWrapper = info[0].Get().GetLocalHandle();
188         if (!JSNavPathStack::CheckIsValid(valueWrapper)) {
189             TAG_LOGE(AceLogTag::ACE_NAVIGATION, "current stack is not navPathStack");
190             return;
191         }
192         // pathInfo{'moduleName': stringA, 'pagePath': stringB, 'isUserCreateStack': bool}
193         auto infoObj = JSRef<JSObject>::Cast(info[1]);
194         auto isUserCreateStack = infoObj->GetProperty(NG::IS_USER_CREATE_STACK);
195         bool isUserDefined = true;
196         if (isUserCreateStack->IsBoolean()) {
197             isUserDefined = isUserCreateStack->ToBoolean();
198         }
199         if (isUserDefined) {
200             newObj = JSRef<JSObject>::Cast(info[0]);
201         }
202         if (!infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->IsString() ||
203             !infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->IsString()) {
204             TAG_LOGE(AceLogTag::ACE_NAVIGATION, "current pageInfo is invalid");
205             return;
206         }
207         moduleName = infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->ToString();
208         pagePath = infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->ToString();
209     }
210 
211     NavigationModel::GetInstance()->Create();
212     auto stackCreator = []() -> RefPtr<JSNavigationStack> { return AceType::MakeRefPtr<JSNavigationStack>(); };
213     auto stackUpdater = [&newObj, &info](RefPtr<NG::NavigationStack> stack) {
214         NavigationModel::GetInstance()->SetNavigationStackProvided(!newObj->IsEmpty());
215         auto jsStack = AceType::DynamicCast<JSNavigationStack>(stack);
216         CHECK_NULL_VOID(jsStack);
217         jsStack->SetJSExecutionContext(info.GetExecutionContext());
218         const auto& oldObj = jsStack->GetDataSourceObj();
219         if (oldObj->IsEmpty()) {
220             if (newObj->IsEmpty()) {
221                 newObj = JSNavPathStack::CreateNewNavPathStackJSObject();
222             }
223             auto nativeObj = JSClass<JSNavPathStack>::NewInstance();
224             JSNavPathStack::SetNativeNavPathStack(newObj, nativeObj);
225             jsStack->SetDataSourceObj(newObj);
226         } else if (!newObj->IsEmpty()) {
227             auto objStrictEqual = [](const JSRef<JSVal>& obja, const JSRef<JSVal>& objb) -> bool {
228                 return obja->GetLocalHandle()->IsStrictEquals(obja->GetEcmaVM(), objb->GetLocalHandle());
229             };
230             if (objStrictEqual(newObj, oldObj)) {
231                 return;
232             }
233             auto nativeObj = JSClass<JSNavPathStack>::NewInstance();
234             JSNavPathStack::SetNativeNavPathStack(newObj, nativeObj);
235             jsStack->SetDataSourceObj(newObj);
236         }
237     };
238     NavigationModel::GetInstance()->SetNavigationStackWithCreatorAndUpdater(stackCreator, stackUpdater);
239     NavigationModel::GetInstance()->SetNavigationPathInfo(moduleName, pagePath);
240 }
241 
JSBind(BindingTarget globalObj)242 void JSNavigation::JSBind(BindingTarget globalObj)
243 {
244     JsNavigationTransitionProxy::JSBind(globalObj);
245     JSClass<JSNavigation>::Declare("Navigation");
246     MethodOptions opt = MethodOptions::NONE;
247     JSClass<JSNavigation>::StaticMethod("create", &JSNavigation::Create);
248     JSClass<JSNavigation>::StaticMethod("title", &JSNavigation::SetTitle, opt);
249     JSClass<JSNavigation>::StaticMethod("subTitle", &JSNavigation::SetSubTitle, opt);
250     JSClass<JSNavigation>::StaticMethod("titleMode", &JSNavigation::SetTitleMode, opt);
251     JSClass<JSNavigation>::StaticMethod("hideTitleBar", &JSNavigation::SetHideTitleBar, opt);
252     JSClass<JSNavigation>::StaticMethod("hideBackButton", &JSNavigation::SetHideBackButton, opt);
253     JSClass<JSNavigation>::StaticMethod("hideToolBar", &JSNavigation::SetHideToolBar, opt);
254     JSClass<JSNavigation>::StaticMethod("toolBar", &JSNavigation::SetToolBar);
255     JSClass<JSNavigation>::StaticMethod("toolbarConfiguration", &JSNavigation::SetToolbarConfiguration);
256     JSClass<JSNavigation>::StaticMethod("menus", &JSNavigation::SetMenus);
257     JSClass<JSNavigation>::StaticMethod("menuCount", &JSNavigation::SetMenuCount);
258     JSClass<JSNavigation>::StaticMethod("onTitleModeChange", &JSNavigation::SetOnTitleModeChanged);
259     JSClass<JSNavigation>::StaticMethod("onNavigationModeChange", &JSNavigation::SetOnNavigationModeChange);
260     JSClass<JSNavigation>::StaticMethod("mode", &JSNavigation::SetUsrNavigationMode);
261     JSClass<JSNavigation>::StaticMethod("navBarWidth", &JSNavigation::SetNavBarWidth);
262     JSClass<JSNavigation>::StaticMethod("minContentWidth", &JSNavigation::SetMinContentWidth);
263     JSClass<JSNavigation>::StaticMethod("navBarWidthRange", &JSNavigation::SetNavBarWidthRange);
264     JSClass<JSNavigation>::StaticMethod("navBarPosition", &JSNavigation::SetNavBarPosition);
265     JSClass<JSNavigation>::StaticMethod("hideNavBar", &JSNavigation::SetHideNavBar);
266     JSClass<JSNavigation>::StaticMethod("backButtonIcon", &JSNavigation::SetBackButtonIcon);
267     JSClass<JSNavigation>::StaticMethod("onNavBarStateChange", &JSNavigation::SetOnNavBarStateChange);
268     JSClass<JSNavigation>::StaticMethod("navDestination", &JSNavigation::SetNavDestination);
269     JSClass<JSNavigation>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
270     JSClass<JSNavigation>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
271     JSClass<JSNavigation>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
272     JSClass<JSNavigation>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
273     JSClass<JSNavigation>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
274     JSClass<JSNavigation>::StaticMethod("customNavContentTransition", &JSNavigation::SetCustomNavContentTransition);
275     JSClass<JSNavigation>::StaticMethod("ignoreLayoutSafeArea", &JSNavigation::SetIgnoreLayoutSafeArea);
276     JSClass<JSNavigation>::StaticMethod("systemBarStyle", &JSNavigation::SetSystemBarStyle);
277     JSClass<JSNavigation>::StaticMethod("enableDragBar", &JSNavigation::SetEnableDragBar);
278     JSClass<JSNavigation>::StaticMethod("recoverable", &JSNavigation::SetRecoverable);
279     JSClass<JSNavigation>::InheritAndBind<JSContainerBase>(globalObj);
280 }
281 
SetTitle(const JSCallbackInfo & info)282 void JSNavigation::SetTitle(const JSCallbackInfo& info)
283 {
284     if (info.Length() < 1) {
285         return;
286     }
287     // Resource and string type.
288     std::string title;
289     if (ParseJsString(info[0], title)) {
290         NavigationModel::GetInstance()->ParseCommonTitle(false, true, "", title);
291     } else if (info[0]->IsObject()) {
292         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
293         do {
294             // NavigationCommonTitle
295             if (ParseCommonTitle(jsObj)) {
296                 break;
297             }
298             // CustomBuilder | NavigationCustomTitle
299             CalcDimension titleHeight;
300             if (!jsObj->HasProperty("height")) {
301                 NavigationModel::GetInstance()->SetTitleHeight(titleHeight, false);
302                 break;
303             }
304             JSRef<JSVal> height = jsObj->GetProperty("height");
305             bool isValid = JSContainerBase::ParseJsDimensionVpNG(height, titleHeight);
306             if (height->IsString()) {
307                 std::string heightValue;
308                 ParseJsString(height, heightValue);
309                 if (heightValue == NG::TITLE_MAIN_WITH_SUB) {
310                     NavigationModel::GetInstance()->SetTitleHeight(NG::DOUBLE_LINE_TITLEBAR_HEIGHT);
311                     break;
312                 }
313                 if (heightValue == NG::TITLE_MAIN) {
314                     NavigationModel::GetInstance()->SetTitleHeight(NG::SINGLE_LINE_TITLEBAR_HEIGHT);
315                     break;
316                 }
317             }
318             if (!isValid || titleHeight.Value() < 0) {
319                 NavigationModel::GetInstance()->SetTitleHeight(Dimension(), true);
320                 break;
321             }
322             NavigationModel::GetInstance()->SetTitleHeight(titleHeight);
323         } while (0);
324         JSRef<JSVal> builderObject = jsObj->GetProperty("builder");
325         if (builderObject->IsFunction()) {
326             ViewStackModel::GetInstance()->NewScope();
327             JsFunction jsBuilderFunc(info.This(), JSRef<JSFunc>::Cast(builderObject));
328             ACE_SCORING_EVENT("Navigation.title.builder");
329             jsBuilderFunc.Execute();
330             auto customNode = ViewStackModel::GetInstance()->Finish();
331             NavigationModel::GetInstance()->SetCustomTitle(customNode);
332         }
333     } else {
334         NavigationModel::GetInstance()->ParseCommonTitle(false, false, "", "");
335         return;
336     }
337 
338     NG::NavigationTitlebarOptions options;
339     JSNavigationUtils::ParseTitleBarOptions(info, true, options);
340     NavigationModel::GetInstance()->SetTitlebarOptions(std::move(options));
341 }
342 
SetTitleMode(int32_t value)343 void JSNavigation::SetTitleMode(int32_t value)
344 {
345     if (value >= 0 && value <= TITLE_MODE_RANGE) {
346         NavigationModel::GetInstance()->SetTitleMode(static_cast<NG::NavigationTitleMode>(value));
347     }
348 }
349 
SetSubTitle(const std::string & subTitle)350 void JSNavigation::SetSubTitle(const std::string& subTitle)
351 {
352     NavigationModel::GetInstance()->SetSubtitle(subTitle);
353 }
354 
SetHideTitleBar(const JSCallbackInfo & info)355 void JSNavigation::SetHideTitleBar(const JSCallbackInfo& info)
356 {
357     bool isHide = false;
358     if (info.Length() > 0 && info[0]->IsBoolean()) {
359         isHide = info[0]->ToBoolean();
360     }
361     bool isAnimated = false;
362     if (info.Length() > 1 && info[1]->IsBoolean()) {
363         isAnimated = info[1]->ToBoolean();
364     }
365     NavigationModel::GetInstance()->SetHideTitleBar(isHide, isAnimated);
366 }
367 
SetHideNavBar(bool hide)368 void JSNavigation::SetHideNavBar(bool hide)
369 {
370     NavigationModel::GetInstance()->SetHideNavBar(hide);
371 }
372 
SetBackButtonIcon(const JSCallbackInfo & info)373 void JSNavigation::SetBackButtonIcon(const JSCallbackInfo& info)
374 {
375     if (info.Length() < 1) {
376         return;
377     }
378     std::string src;
379     auto noPixMap = ParseJsMedia(info[0], src);
380     auto isValidImage = false;
381     RefPtr<PixelMap> pixMap = nullptr;
382 #if defined(PIXEL_MAP_SUPPORTED)
383     if (!noPixMap) {
384         pixMap = CreatePixelMapFromNapiValue(info[0]);
385     }
386 #endif
387     if (noPixMap || pixMap != nullptr) {
388         isValidImage = true;
389     }
390     std::vector<std::string> nameList;
391     NG::ImageOption imageOption;
392     std::string bundleName;
393     std::string moduleName;
394     GetJsMediaBundleInfo(info[0], bundleName, moduleName);
395     nameList.emplace_back(bundleName);
396     nameList.emplace_back(moduleName);
397     imageOption.noPixMap = noPixMap;
398     imageOption.isValidImage = isValidImage;
399     std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
400     auto isSymbol = info[0]->IsObject() && src.empty() && pixMap == nullptr;
401     if (isSymbol) {
402         SetSymbolOptionApply(info, iconSymbol, info[0]);
403     }
404     NavigationModel::GetInstance()->SetBackButtonIcon(iconSymbol, src, imageOption, pixMap, nameList);
405 }
406 
SetHideBackButton(bool hide)407 void JSNavigation::SetHideBackButton(bool hide)
408 {
409     NavigationModel::GetInstance()->SetHideBackButton(hide);
410 }
411 
SetHideToolBar(const JSCallbackInfo & info)412 void JSNavigation::SetHideToolBar(const JSCallbackInfo& info)
413 {
414     bool isHide = false;
415     if (info.Length() > 0 && info[0]->IsBoolean()) {
416         isHide = info[0]->ToBoolean();
417     }
418     bool isAnimated = false;
419     if (info.Length() > 1 && info[1]->IsBoolean()) {
420         isAnimated = info[1]->ToBoolean();
421     }
422     NavigationModel::GetInstance()->SetHideToolBar(isHide, isAnimated);
423 }
424 
SetToolBar(const JSCallbackInfo & info)425 void JSNavigation::SetToolBar(const JSCallbackInfo& info)
426 {
427     if (info.Length() < 1) {
428         return;
429     }
430     if (!info[0]->IsObject() && !info[0]->IsUndefined()) {
431         return;
432     }
433     if (info[0]->IsUndefined()) {
434         NavigationModel::GetInstance()->SetToolBarItems({});
435         return;
436     }
437     auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
438     if (builderFuncParam->IsFunction()) {
439         ViewStackModel::GetInstance()->NewScope();
440         JsFunction jsBuilderFunc(builderFuncParam);
441         jsBuilderFunc.Execute();
442         auto customNode = ViewStackModel::GetInstance()->Finish();
443         NavigationModel::GetInstance()->SetCustomToolBar(customNode);
444     }
445 
446     auto itemsValue = JSRef<JSObject>::Cast(info[0])->GetProperty("items");
447     if (!itemsValue->IsObject() || !itemsValue->IsArray()) {
448         return;
449     }
450     if (NavigationModel::GetInstance()->NeedSetItems()) {
451         std::vector<NG::BarItem> toolBarItems;
452         auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
453         JSNavigationUtils::ParseBarItems(targetNode, info, JSRef<JSArray>::Cast(itemsValue), toolBarItems);
454         NavigationModel::GetInstance()->SetToolBarItems(std::move(toolBarItems));
455         return;
456     }
457     std::list<RefPtr<AceType>> items;
458     NavigationModel::GetInstance()->GetToolBarItems(items);
459     ParseToolBarItems(info, items);
460 }
461 
SetToolbarConfiguration(const JSCallbackInfo & info)462 void JSNavigation::SetToolbarConfiguration(const JSCallbackInfo& info)
463 {
464     if (info[0]->IsUndefined() || info[0]->IsArray()) {
465         if (NavigationModel::GetInstance()->NeedSetItems()) {
466             std::vector<NG::BarItem> toolbarItems;
467             if (info[0]->IsUndefined()) {
468                 toolbarItems = {};
469             } else {
470                 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
471                 JSNavigationUtils::ParseToolbarItemsConfiguration(
472                     targetNode, info, JSRef<JSArray>::Cast(info[0]), toolbarItems);
473             }
474             NavigationModel::GetInstance()->SetToolbarConfiguration(std::move(toolbarItems));
475         } else {
476             std::list<RefPtr<AceType>> items;
477             NavigationModel::GetInstance()->GetToolBarItems(items);
478             ParseToolBarItems(info, items);
479         }
480     } else if (info[0]->IsObject()) {
481         auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
482         if (builderFuncParam->IsFunction()) {
483             ViewStackModel::GetInstance()->NewScope();
484             JsFunction jsBuilderFunc(builderFuncParam);
485             jsBuilderFunc.Execute();
486             auto customNode = ViewStackModel::GetInstance()->Finish();
487             NavigationModel::GetInstance()->SetCustomToolBar(customNode);
488         }
489     }
490 
491     NG::NavigationToolbarOptions options;
492     JSNavigationUtils::ParseToolbarOptions(info, options);
493     NavigationModel::GetInstance()->SetToolbarOptions(std::move(options));
494 }
495 
SetMenus(const JSCallbackInfo & info)496 void JSNavigation::SetMenus(const JSCallbackInfo& info)
497 {
498     if (info.Length() < 1) {
499         return;
500     }
501 
502     if (info[0]->IsUndefined() || info[0]->IsArray()) {
503         if (NavigationModel::GetInstance()->NeedSetItems()) {
504             std::vector<NG::BarItem> menuItems;
505             if (info[0]->IsUndefined()) {
506                 menuItems = {};
507             } else {
508                 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
509                 JSNavigationUtils::ParseBarItems(targetNode, info, JSRef<JSArray>::Cast(info[0]), menuItems);
510             }
511             NavigationModel::GetInstance()->SetMenuItems(std::move(menuItems));
512             return;
513         }
514         std::list<RefPtr<AceType>> items;
515         NavigationModel::GetInstance()->GetMenuItems(items);
516         ParseToolBarItems(info, items);
517     } else if (info[0]->IsObject()) {
518         auto builderObject = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
519         if (builderObject->IsFunction()) {
520             ViewStackModel::GetInstance()->NewScope();
521             JsFunction jsBuilderFunc(info.This(), JSRef<JSFunc>::Cast(builderObject));
522             ACE_SCORING_EVENT("Navigation.menu.builder");
523             jsBuilderFunc.Execute();
524             auto customNode = ViewStackModel::GetInstance()->Finish();
525             NavigationModel::GetInstance()->SetCustomMenu(customNode);
526         }
527     }
528 }
529 
SetMenuCount(int32_t menuCount)530 void JSNavigation::SetMenuCount(int32_t menuCount)
531 {
532     NavigationModel::GetInstance()->SetMenuCount(menuCount);
533 }
534 
SetOnTitleModeChanged(const JSCallbackInfo & info)535 void JSNavigation::SetOnTitleModeChanged(const JSCallbackInfo& info)
536 {
537     if (info.Length() < 1) {
538         return;
539     }
540     if (info[0]->IsFunction()) {
541         auto onTitleModeChangeCallback =
542             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
543         auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
544         auto onTitleModeChange = [execCtx = info.GetExecutionContext(), func = std::move(onTitleModeChangeCallback),
545                                      node = targetNode](NG::NavigationTitleMode mode) {
546             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
547             ACE_SCORING_EVENT("OnTitleModeChange");
548             PipelineContext::SetCallBackNode(node);
549             JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(mode));
550             func->ExecuteJS(1, &param);
551         };
552         auto changeHandler = AceType::MakeRefPtr<JsEventFunction<NavigationTitleModeChangeEvent, 1>>(
553             JSRef<JSFunc>::Cast(info[0]), TitleModeChangeEventToJSValue);
554         auto eventInfo = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler),
555                              node = targetNode](const BaseEventInfo* baseInfo) {
556             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
557             auto eventInfo = TypeInfoHelper::DynamicCast<NavigationTitleModeChangeEvent>(baseInfo);
558             if (!eventInfo) {
559                 return;
560             }
561             ACE_SCORING_EVENT("Navigation.onTitleModeChanged");
562             PipelineContext::SetCallBackNode(node);
563             func->Execute(*eventInfo);
564         };
565         NavigationModel::GetInstance()->SetOnTitleModeChange(std::move(onTitleModeChange), std::move(eventInfo));
566     }
567     info.ReturnSelf();
568 }
569 
SetUsrNavigationMode(const JSCallbackInfo & info)570 void JSNavigation::SetUsrNavigationMode(const JSCallbackInfo& info)
571 {
572     if (!info[0]->IsNumber()) {
573         NavigationModel::GetInstance()->SetUsrNavigationMode(NG::NavigationMode::AUTO);
574         return;
575     }
576     int32_t value = info[0]->ToNumber<int32_t>();
577     if (value >= 0 && value <= NAVIGATION_MODE_RANGE) {
578         NavigationModel::GetInstance()->SetUsrNavigationMode(static_cast<NG::NavigationMode>(value));
579     }
580 }
581 
SetNavBarPosition(int32_t value)582 void JSNavigation::SetNavBarPosition(int32_t value)
583 {
584     if (value >= 0 && value <= NAV_BAR_POSITION_RANGE) {
585         NavigationModel::GetInstance()->SetNavBarPosition(static_cast<NG::NavBarPosition>(value));
586     }
587 }
588 
SetNavBarWidth(const JSCallbackInfo & info)589 void JSNavigation::SetNavBarWidth(const JSCallbackInfo& info)
590 {
591     if (info.Length() < 1) {
592         return;
593     }
594 
595     CalcDimension navBarWidth;
596     if (!ParseJsDimensionVp(info[0], navBarWidth)) {
597         return;
598     }
599 
600     if (navBarWidth.Value() <= 0) {
601         navBarWidth.SetValue(DEFAULT_NAV_BAR_WIDTH);
602     }
603 
604     NavigationModel::GetInstance()->SetNavBarWidth(navBarWidth);
605 }
606 
SetMinContentWidth(const JSCallbackInfo & info)607 void JSNavigation::SetMinContentWidth(const JSCallbackInfo& info)
608 {
609     if (info.Length() < 1) {
610         return;
611     }
612 
613     CalcDimension minContentWidth;
614     if (!ParseJsDimensionVp(info[0], minContentWidth)) {
615         NavigationModel::GetInstance()->SetMinContentWidth(DEFAULT_MIN_CONTENT_WIDTH);
616         return;
617     }
618 
619     if (LessNotEqual(minContentWidth.Value(), 0.0)) {
620         minContentWidth = DEFAULT_MIN_CONTENT_WIDTH;
621     }
622 
623     NavigationModel::GetInstance()->SetMinContentWidth(minContentWidth);
624 }
625 
SetNavBarWidthRange(const JSCallbackInfo & info)626 void JSNavigation::SetNavBarWidthRange(const JSCallbackInfo& info)
627 {
628     if (info.Length() < 1) {
629         return;
630     }
631     if (info[0]->IsNull() || info[0]->IsUndefined()) {
632         NavigationModel::GetInstance()->SetMinNavBarWidth(NG::DEFAULT_MIN_NAV_BAR_WIDTH);
633         NavigationModel::GetInstance()->SetMaxNavBarWidth(NG::DEFAULT_MAX_NAV_BAR_WIDTH);
634         return;
635     }
636     if (!info[0]->IsArray()) {
637         return;
638     }
639     auto rangeArray = JSRef<JSArray>::Cast(info[0]);
640     JSRef<JSVal> min = rangeArray->GetValueAt(0);
641     JSRef<JSVal> max = rangeArray->GetValueAt(1);
642 
643     CalcDimension minNavBarWidth;
644     CalcDimension maxNavBarWidth;
645     if (min->IsNull() || min->IsUndefined() || !ParseJsDimensionVp(min, minNavBarWidth)) {
646         minNavBarWidth = NG::DEFAULT_MIN_NAV_BAR_WIDTH;
647     }
648     if (LessNotEqual(minNavBarWidth.Value(), 0.0)) {
649         minNavBarWidth.SetValue(0);
650     }
651     NavigationModel::GetInstance()->SetMinNavBarWidth(minNavBarWidth);
652 
653     if (max->IsNull() || max->IsUndefined() || !ParseJsDimensionVp(max, maxNavBarWidth)) {
654         maxNavBarWidth = NG::DEFAULT_MAX_NAV_BAR_WIDTH;
655     }
656     if (LessNotEqual(maxNavBarWidth.Value(), 0.0)) {
657         maxNavBarWidth.SetValue(0);
658     }
659     NavigationModel::GetInstance()->SetMaxNavBarWidth(maxNavBarWidth);
660 }
661 
SetOnNavBarStateChange(const JSCallbackInfo & info)662 void JSNavigation::SetOnNavBarStateChange(const JSCallbackInfo& info)
663 {
664     if (info.Length() < 1) {
665         return;
666     }
667 
668     if (info[0]->IsFunction()) {
669         auto onNavBarStateChangeCallback =
670             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
671         auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
672         auto onNavBarStateChange = [execCtx = info.GetExecutionContext(), func = std::move(onNavBarStateChangeCallback),
673                                        node = targetNode](bool isVisible) {
674             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
675             ACE_SCORING_EVENT("OnNavBarStateChange");
676             PipelineContext::SetCallBackNode(node);
677             JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(isVisible));
678             func->ExecuteJS(1, &param);
679         };
680         NavigationModel::GetInstance()->SetOnNavBarStateChange(std::move(onNavBarStateChange));
681     }
682     info.ReturnSelf();
683 }
684 
SetNavDestination(const JSCallbackInfo & info)685 void JSNavigation::SetNavDestination(const JSCallbackInfo& info)
686 {
687     if (info.Length() < 1) {
688         return;
689     }
690 
691     if (!info[0]->IsObject()) {
692         return;
693     }
694 
695     JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
696     auto builder = obj->GetProperty("builder");
697     if (!builder->IsFunction()) {
698         return;
699     }
700 
701     auto navigationStack = NavigationModel::GetInstance()->GetNavigationStack();
702     auto jsNavigationStack = AceType::DynamicCast<JSNavigationStack>(navigationStack);
703     if (jsNavigationStack) {
704         jsNavigationStack->SetNavDestBuilderFunc(JSRef<JSFunc>::Cast(builder));
705     }
706 }
707 
SetOnNavigationModeChange(const JSCallbackInfo & info)708 void JSNavigation::SetOnNavigationModeChange(const JSCallbackInfo& info)
709 {
710     if (info.Length() < 1) {
711         return;
712     }
713     if (!info[0]->IsFunction()) {
714         info.ReturnSelf();
715         return;
716     }
717     auto onModeChangeCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
718     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
719     auto onModeChange = [execCtx = info.GetExecutionContext(), func = std::move(onModeChangeCallback),
720                             node = targetNode](NG::NavigationMode mode) {
721         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
722         ACE_SCORING_EVENT("OnNavigationModeChange");
723         PipelineContext::SetCallBackNode(node);
724         JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(static_cast<int8_t>(mode)));
725         func->ExecuteJS(1, &param);
726     };
727     NavigationModel::GetInstance()->SetOnNavigationModeChange(std::move(onModeChange));
728     info.ReturnSelf();
729 }
730 
SetCustomNavContentTransition(const JSCallbackInfo & info)731 void JSNavigation::SetCustomNavContentTransition(const JSCallbackInfo& info)
732 {
733     if (info.Length() == 0 || !info[0]->IsFunction()) {
734         NavigationModel::GetInstance()->SetIsCustomAnimation(false);
735         return;
736     }
737     RefPtr<JsNavigationFunction> jsNavigationFunction =
738         AceType::MakeRefPtr<JsNavigationFunction>(JSRef<JSFunc>::Cast(info[0]));
739     auto onNavigationAnimation = [execCtx = info.GetExecutionContext(), func = std::move(jsNavigationFunction)](
740                                      RefPtr<NG::NavDestinationContext> from, RefPtr<NG::NavDestinationContext> to,
741                                      NG::NavigationOperation operation) -> NG::NavigationTransition {
742         NG::NavigationTransition transition;
743         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, transition);
744         auto ret = func->Execute(from, to, operation);
745         if (!ret->IsObject()) {
746             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom transition is invalid, do default animation");
747             transition.isValid = false;
748             return transition;
749         }
750 
751         auto transitionObj = JSRef<JSObject>::Cast(ret);
752         JSRef<JSVal> interactive = transitionObj->GetProperty("isInteractive");
753         if (interactive->IsBoolean()) {
754             transition.interactive = interactive->ToBoolean();
755         } else {
756             transition.interactive = false;
757         }
758         int32_t timeout = -1;
759         JSRef<JSVal> time = transitionObj->GetProperty("timeout");
760         if (time->IsNumber()) {
761             timeout = time->ToNumber<int32_t>();
762         }
763         if (!transition.interactive) {
764             timeout = timeout < 0 ? NAVIGATION_ANIMATION_TIMEOUT : timeout;
765         }
766         transition.timeout = timeout;
767         JSRef<JSVal> transitionContext = transitionObj->GetProperty("transition");
768         if (!transitionContext->IsFunction()) {
769             return transition;
770         }
771         auto jsOnTransition = AceType::MakeRefPtr<JsNavigationFunction>(JSRef<JSFunc>::Cast(transitionContext));
772         if (transitionContext->IsFunction()) {
773             auto onTransition = [execCtx, func = std::move(jsOnTransition)](
774                                     const RefPtr<NG::NavigationTransitionProxy>& proxy) {
775                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
776                 ACE_SCORING_EVENT("transition");
777                 func->Execute(proxy);
778             };
779             transition.transition = std::move(onTransition);
780         }
781         JSRef<JSVal> endCallback = transitionObj->GetProperty("onTransitionEnd");
782         if (endCallback->IsFunction()) {
783             auto onEndedCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(endCallback));
784             auto onEndTransition = [execCtx, func = std::move(onEndedCallback)](bool isSuccess) {
785                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
786                 ACE_SCORING_EVENT("onTransitionEnded");
787                 JSRef<JSVal> successVal = JSRef<JSVal>::Make(ToJSValue(isSuccess));
788                 func->ExecuteJS(1, &successVal);
789             };
790             transition.endCallback = std::move(onEndTransition);
791         }
792         return transition;
793     };
794     NavigationModel::GetInstance()->SetIsCustomAnimation(true);
795     NavigationModel::GetInstance()->SetCustomTransition(onNavigationAnimation);
796 }
797 
SetIgnoreLayoutSafeArea(const JSCallbackInfo & info)798 void JSNavigation::SetIgnoreLayoutSafeArea(const JSCallbackInfo& info)
799 {
800     NG::SafeAreaExpandOpts opts { .type = NG::SAFE_AREA_TYPE_SYSTEM, .edges = NG::SAFE_AREA_EDGE_ALL};
801     if (info.Length() >= PARAMETER_LENGTH_ONE && info[FIRST_INDEX]->IsArray()) {
802         auto paramArray = JSRef<JSArray>::Cast(info[0]);
803         uint32_t safeAreaType = NG::SAFE_AREA_TYPE_NONE;
804         for (size_t i = 0; i < paramArray->Length(); ++i) {
805             auto value = paramArray->GetValueAt(i);
806             if (!value->IsNumber() ||
807                 value->ToNumber<uint32_t>() >= SAFE_AREA_TYPE_LIMIT ||
808                 value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_SYSTEM) {
809                 safeAreaType = NG::SAFE_AREA_TYPE_SYSTEM;
810                 break;
811             }
812         }
813         opts.type = safeAreaType;
814     }
815 
816     if (info.Length() >= PARAMETER_LENGTH_TWO && info[SECOND_INDEX]->IsArray()) {
817         auto paramArray = JSRef<JSArray>::Cast(info[1]);
818         uint32_t safeAreaEdge = NG::SAFE_AREA_EDGE_NONE;
819         for (size_t i = 0; i < paramArray->Length(); ++i) {
820             auto value = paramArray->GetValueAt(i);
821             if (!value->IsNumber() ||
822                 value->ToNumber<uint32_t>() >= SAFE_AREA_EDGE_LIMIT) {
823                 safeAreaEdge = NG::SAFE_AREA_EDGE_ALL;
824                 break;
825             }
826             if (value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_TOP ||
827                 value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_BOTTOM) {
828                     safeAreaEdge |= (1 << value->ToNumber<uint32_t>());
829                 }
830         }
831         opts.edges = safeAreaEdge;
832     }
833     NavigationModel::GetInstance()->SetIgnoreLayoutSafeArea(opts);
834 }
835 
SetSystemBarStyle(const JSCallbackInfo & info)836 void JSNavigation::SetSystemBarStyle(const JSCallbackInfo& info)
837 {
838     RefPtr<SystemBarStyle> style = nullptr;
839     if (info.Length() == 1 && info[0]->IsObject()) {
840         auto styleObj = JsConverter::ConvertJsValToNapiValue(info[0]);
841         auto env = GetCurrentEnv();
842         if (env) {
843             style = SystemBarStyle::CreateStyleFromJsObj(env, styleObj);
844         }
845     }
846     NavigationModel::GetInstance()->SetSystemBarStyle(style);
847 }
848 
SetEnableDragBar(const JSCallbackInfo & info)849 void JSNavigation::SetEnableDragBar(const JSCallbackInfo& info)
850 {
851     if (!info[0]->IsBoolean()) {
852         // the default value of navigation's drag bar is false
853         NavigationModel::GetInstance()->SetEnableDragBar(false);
854         return;
855     }
856     auto enableDragBar = info[0]->ToBoolean();
857     NavigationModel::GetInstance()->SetEnableDragBar(enableDragBar);
858 }
859 
SetRecoverable(const JSCallbackInfo & info)860 void JSNavigation::SetRecoverable(const JSCallbackInfo& info)
861 {
862     if (!info[0]->IsBoolean()) {
863         // the default value of navigation's recoverable is false
864         NavigationModel::GetInstance()->SetRecoverable(false);
865         return;
866     }
867     auto recoverable = info[0]->ToBoolean();
868     NavigationModel::GetInstance()->SetRecoverable(recoverable);
869 }
870 } // namespace OHOS::Ace::Framework
871