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