• 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     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>::StaticMethod("enableModeChangeAnimation", &JSNavigation::SetEnableModeChangeAnimation);
280     JSClass<JSNavigation>::InheritAndBind<JSContainerBase>(globalObj);
281 }
282 
SetTitle(const JSCallbackInfo & info)283 void JSNavigation::SetTitle(const JSCallbackInfo& info)
284 {
285     if (info.Length() < 1) {
286         return;
287     }
288     // Resource and string type.
289     std::string title;
290     if (ParseJsString(info[0], title)) {
291         NavigationModel::GetInstance()->ParseCommonTitle(false, true, "", title);
292     } else if (info[0]->IsObject()) {
293         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
294         do {
295             // NavigationCommonTitle
296             if (ParseCommonTitle(jsObj)) {
297                 break;
298             }
299             // CustomBuilder | NavigationCustomTitle
300             CalcDimension titleHeight;
301             if (!jsObj->HasProperty("height")) {
302                 NavigationModel::GetInstance()->SetTitleHeight(titleHeight, false);
303                 break;
304             }
305             JSRef<JSVal> height = jsObj->GetProperty("height");
306             bool isValid = JSContainerBase::ParseJsDimensionVpNG(height, titleHeight);
307             if (height->IsString()) {
308                 std::string heightValue;
309                 ParseJsString(height, heightValue);
310                 if (heightValue == NG::TITLE_MAIN_WITH_SUB) {
311                     NavigationModel::GetInstance()->SetTitleHeight(NG::DOUBLE_LINE_TITLEBAR_HEIGHT);
312                     break;
313                 }
314                 if (heightValue == NG::TITLE_MAIN) {
315                     NavigationModel::GetInstance()->SetTitleHeight(NG::SINGLE_LINE_TITLEBAR_HEIGHT);
316                     break;
317                 }
318             }
319             if (!isValid || titleHeight.Value() < 0) {
320                 NavigationModel::GetInstance()->SetTitleHeight(Dimension(), true);
321                 break;
322             }
323             NavigationModel::GetInstance()->SetTitleHeight(titleHeight);
324         } while (0);
325         JSRef<JSVal> builderObject = jsObj->GetProperty("builder");
326         if (builderObject->IsFunction()) {
327             ViewStackModel::GetInstance()->NewScope();
328             JsFunction jsBuilderFunc(info.This(), JSRef<JSFunc>::Cast(builderObject));
329             ACE_SCORING_EVENT("Navigation.title.builder");
330             jsBuilderFunc.Execute();
331             auto customNode = ViewStackModel::GetInstance()->Finish();
332             NavigationModel::GetInstance()->SetCustomTitle(customNode);
333         }
334     } else {
335         NavigationModel::GetInstance()->ParseCommonTitle(false, false, "", "");
336         return;
337     }
338 
339     NG::NavigationTitlebarOptions options;
340     JSNavigationUtils::ParseTitleBarOptions(info, true, options);
341     NavigationModel::GetInstance()->SetTitlebarOptions(std::move(options));
342 }
343 
SetTitleMode(int32_t value)344 void JSNavigation::SetTitleMode(int32_t value)
345 {
346     if (value >= 0 && value <= TITLE_MODE_RANGE) {
347         NavigationModel::GetInstance()->SetTitleMode(static_cast<NG::NavigationTitleMode>(value));
348     }
349 }
350 
SetSubTitle(const std::string & subTitle)351 void JSNavigation::SetSubTitle(const std::string& subTitle)
352 {
353     NavigationModel::GetInstance()->SetSubtitle(subTitle);
354 }
355 
SetHideTitleBar(const JSCallbackInfo & info)356 void JSNavigation::SetHideTitleBar(const JSCallbackInfo& info)
357 {
358     bool isHide = false;
359     if (info.Length() > 0 && info[0]->IsBoolean()) {
360         isHide = info[0]->ToBoolean();
361     }
362     bool isAnimated = false;
363     if (info.Length() > 1 && info[1]->IsBoolean()) {
364         isAnimated = info[1]->ToBoolean();
365     }
366     NavigationModel::GetInstance()->SetHideTitleBar(isHide, isAnimated);
367 }
368 
SetEnableModeChangeAnimation(const JSCallbackInfo & info)369 void JSNavigation::SetEnableModeChangeAnimation(const JSCallbackInfo& info)
370 {
371     if (info.Length() < 1) {
372         return;
373     }
374     if (info[0]->IsBoolean()) {
375         NavigationModel::GetInstance()->SetEnableModeChangeAnimation(info[0]->ToBoolean());
376         return;
377     }
378     NavigationModel::GetInstance()->SetEnableModeChangeAnimation(true);
379 }
380 
SetHideNavBar(bool hide)381 void JSNavigation::SetHideNavBar(bool hide)
382 {
383     NavigationModel::GetInstance()->SetHideNavBar(hide);
384 }
385 
SetBackButtonIcon(const JSCallbackInfo & info)386 void JSNavigation::SetBackButtonIcon(const JSCallbackInfo& info)
387 {
388     if (info.Length() < 1) {
389         return;
390     }
391     std::string src;
392     auto noPixMap = ParseJsMedia(info[0], src);
393     auto isValidImage = false;
394     RefPtr<PixelMap> pixMap = nullptr;
395 #if defined(PIXEL_MAP_SUPPORTED)
396     if (!noPixMap) {
397         pixMap = CreatePixelMapFromNapiValue(info[0]);
398     }
399 #endif
400     if (noPixMap || pixMap != nullptr) {
401         isValidImage = true;
402     }
403     std::vector<std::string> nameList;
404     NG::ImageOption imageOption;
405     std::string bundleName;
406     std::string moduleName;
407     GetJsMediaBundleInfo(info[0], bundleName, moduleName);
408     nameList.emplace_back(bundleName);
409     nameList.emplace_back(moduleName);
410     imageOption.noPixMap = noPixMap;
411     imageOption.isValidImage = isValidImage;
412     std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
413     auto isSymbol = info[0]->IsObject() && src.empty() && pixMap == nullptr;
414     if (isSymbol) {
415         SetSymbolOptionApply(info, iconSymbol, info[0]);
416     }
417     NavigationModel::GetInstance()->SetBackButtonIcon(iconSymbol, src, imageOption, pixMap, nameList);
418 }
419 
SetHideBackButton(bool hide)420 void JSNavigation::SetHideBackButton(bool hide)
421 {
422     NavigationModel::GetInstance()->SetHideBackButton(hide);
423 }
424 
SetHideToolBar(const JSCallbackInfo & info)425 void JSNavigation::SetHideToolBar(const JSCallbackInfo& info)
426 {
427     bool isHide = false;
428     if (info.Length() > 0 && info[0]->IsBoolean()) {
429         isHide = info[0]->ToBoolean();
430     }
431     bool isAnimated = false;
432     if (info.Length() > 1 && info[1]->IsBoolean()) {
433         isAnimated = info[1]->ToBoolean();
434     }
435     NavigationModel::GetInstance()->SetHideToolBar(isHide, isAnimated);
436 }
437 
SetToolBar(const JSCallbackInfo & info)438 void JSNavigation::SetToolBar(const JSCallbackInfo& info)
439 {
440     if (info.Length() < 1) {
441         return;
442     }
443     if (!info[0]->IsObject() && !info[0]->IsUndefined()) {
444         return;
445     }
446     if (info[0]->IsUndefined()) {
447         NavigationModel::GetInstance()->SetToolBarItems({});
448         return;
449     }
450     auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
451     if (builderFuncParam->IsFunction()) {
452         ViewStackModel::GetInstance()->NewScope();
453         JsFunction jsBuilderFunc(builderFuncParam);
454         jsBuilderFunc.Execute();
455         auto customNode = ViewStackModel::GetInstance()->Finish();
456         NavigationModel::GetInstance()->SetCustomToolBar(customNode);
457     }
458 
459     auto itemsValue = JSRef<JSObject>::Cast(info[0])->GetProperty("items");
460     if (!itemsValue->IsObject() || !itemsValue->IsArray()) {
461         return;
462     }
463     if (NavigationModel::GetInstance()->NeedSetItems()) {
464         std::vector<NG::BarItem> toolBarItems;
465         auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
466         JSNavigationUtils::ParseBarItems(targetNode, info, JSRef<JSArray>::Cast(itemsValue), toolBarItems);
467         NavigationModel::GetInstance()->SetToolBarItems(std::move(toolBarItems));
468         return;
469     }
470     std::list<RefPtr<AceType>> items;
471     NavigationModel::GetInstance()->GetToolBarItems(items);
472     ParseToolBarItems(info, items);
473 }
474 
SetToolbarConfiguration(const JSCallbackInfo & info)475 void JSNavigation::SetToolbarConfiguration(const JSCallbackInfo& info)
476 {
477     if (info[0]->IsUndefined() || info[0]->IsArray()) {
478         if (NavigationModel::GetInstance()->NeedSetItems()) {
479             std::vector<NG::BarItem> toolbarItems;
480             if (info[0]->IsUndefined()) {
481                 toolbarItems = {};
482             } else {
483                 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
484                 JSNavigationUtils::ParseToolbarItemsConfiguration(
485                     targetNode, info, JSRef<JSArray>::Cast(info[0]), toolbarItems);
486             }
487             NavigationModel::GetInstance()->SetToolbarConfiguration(std::move(toolbarItems));
488         } else {
489             std::list<RefPtr<AceType>> items;
490             NavigationModel::GetInstance()->GetToolBarItems(items);
491             ParseToolBarItems(info, items);
492         }
493     } else if (info[0]->IsObject()) {
494         auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
495         if (builderFuncParam->IsFunction()) {
496             ViewStackModel::GetInstance()->NewScope();
497             JsFunction jsBuilderFunc(builderFuncParam);
498             jsBuilderFunc.Execute();
499             auto customNode = ViewStackModel::GetInstance()->Finish();
500             NavigationModel::GetInstance()->SetCustomToolBar(customNode);
501         }
502     }
503 
504     NG::NavigationToolbarOptions options;
505     JSNavigationUtils::ParseToolbarOptions(info, options);
506     NavigationModel::GetInstance()->SetToolbarOptions(std::move(options));
507 }
508 
SetMenus(const JSCallbackInfo & info)509 void JSNavigation::SetMenus(const JSCallbackInfo& info)
510 {
511     if (info.Length() < 1) {
512         return;
513     }
514 
515     if (info[0]->IsUndefined() || info[0]->IsArray()) {
516         if (NavigationModel::GetInstance()->NeedSetItems()) {
517             std::vector<NG::BarItem> menuItems;
518             if (info[0]->IsUndefined()) {
519                 menuItems = {};
520             } else {
521                 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
522                 JSNavigationUtils::ParseBarItems(targetNode, info, JSRef<JSArray>::Cast(info[0]), menuItems);
523             }
524             NavigationModel::GetInstance()->SetMenuItems(std::move(menuItems));
525             return;
526         }
527         std::list<RefPtr<AceType>> items;
528         NavigationModel::GetInstance()->GetMenuItems(items);
529         ParseToolBarItems(info, items);
530     } else if (info[0]->IsObject()) {
531         auto builderObject = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
532         if (builderObject->IsFunction()) {
533             ViewStackModel::GetInstance()->NewScope();
534             JsFunction jsBuilderFunc(info.This(), JSRef<JSFunc>::Cast(builderObject));
535             ACE_SCORING_EVENT("Navigation.menu.builder");
536             jsBuilderFunc.Execute();
537             auto customNode = ViewStackModel::GetInstance()->Finish();
538             NavigationModel::GetInstance()->SetCustomMenu(customNode);
539         }
540     }
541 }
542 
SetMenuCount(int32_t menuCount)543 void JSNavigation::SetMenuCount(int32_t menuCount)
544 {
545     NavigationModel::GetInstance()->SetMenuCount(menuCount);
546 }
547 
SetOnTitleModeChanged(const JSCallbackInfo & info)548 void JSNavigation::SetOnTitleModeChanged(const JSCallbackInfo& info)
549 {
550     if (info.Length() < 1) {
551         return;
552     }
553     if (info[0]->IsFunction()) {
554         auto onTitleModeChangeCallback =
555             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
556         auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
557         auto onTitleModeChange = [execCtx = info.GetExecutionContext(), func = std::move(onTitleModeChangeCallback),
558                                      node = targetNode](NG::NavigationTitleMode mode) {
559             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
560             ACE_SCORING_EVENT("OnTitleModeChange");
561             PipelineContext::SetCallBackNode(node);
562             JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(mode));
563             func->ExecuteJS(1, &param);
564         };
565         auto changeHandler = AceType::MakeRefPtr<JsEventFunction<NavigationTitleModeChangeEvent, 1>>(
566             JSRef<JSFunc>::Cast(info[0]), TitleModeChangeEventToJSValue);
567         auto eventInfo = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler),
568                              node = targetNode](const BaseEventInfo* baseInfo) {
569             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
570             auto eventInfo = TypeInfoHelper::DynamicCast<NavigationTitleModeChangeEvent>(baseInfo);
571             if (!eventInfo) {
572                 return;
573             }
574             ACE_SCORING_EVENT("Navigation.onTitleModeChanged");
575             PipelineContext::SetCallBackNode(node);
576             func->Execute(*eventInfo);
577         };
578         NavigationModel::GetInstance()->SetOnTitleModeChange(std::move(onTitleModeChange), std::move(eventInfo));
579     }
580     info.ReturnSelf();
581 }
582 
SetUsrNavigationMode(const JSCallbackInfo & info)583 void JSNavigation::SetUsrNavigationMode(const JSCallbackInfo& info)
584 {
585     if (!info[0]->IsNumber()) {
586         NavigationModel::GetInstance()->SetUsrNavigationMode(NG::NavigationMode::AUTO);
587         return;
588     }
589     int32_t value = info[0]->ToNumber<int32_t>();
590     if (value >= 0 && value <= NAVIGATION_MODE_RANGE) {
591         NavigationModel::GetInstance()->SetUsrNavigationMode(static_cast<NG::NavigationMode>(value));
592     }
593 }
594 
SetNavBarPosition(int32_t value)595 void JSNavigation::SetNavBarPosition(int32_t value)
596 {
597     if (value >= 0 && value <= NAV_BAR_POSITION_RANGE) {
598         NavigationModel::GetInstance()->SetNavBarPosition(static_cast<NG::NavBarPosition>(value));
599     }
600 }
601 
SetNavBarWidth(const JSCallbackInfo & info)602 void JSNavigation::SetNavBarWidth(const JSCallbackInfo& info)
603 {
604     if (info.Length() < 1) {
605         return;
606     }
607 
608     CalcDimension navBarWidth;
609     if (!ParseJsDimensionVp(info[0], navBarWidth)) {
610         return;
611     }
612 
613     if (navBarWidth.Value() <= 0) {
614         navBarWidth.SetValue(DEFAULT_NAV_BAR_WIDTH);
615     }
616 
617     NavigationModel::GetInstance()->SetNavBarWidth(navBarWidth);
618 }
619 
SetMinContentWidth(const JSCallbackInfo & info)620 void JSNavigation::SetMinContentWidth(const JSCallbackInfo& info)
621 {
622     if (info.Length() < 1) {
623         return;
624     }
625 
626     CalcDimension minContentWidth;
627     if (!ParseJsDimensionVp(info[0], minContentWidth)) {
628         NavigationModel::GetInstance()->SetMinContentWidth(DEFAULT_MIN_CONTENT_WIDTH);
629         return;
630     }
631 
632     if (LessNotEqual(minContentWidth.Value(), 0.0)) {
633         minContentWidth = DEFAULT_MIN_CONTENT_WIDTH;
634     }
635 
636     NavigationModel::GetInstance()->SetMinContentWidth(minContentWidth);
637 }
638 
SetNavBarWidthRange(const JSCallbackInfo & info)639 void JSNavigation::SetNavBarWidthRange(const JSCallbackInfo& info)
640 {
641     if (info.Length() < 1) {
642         return;
643     }
644     if (info[0]->IsNull() || info[0]->IsUndefined()) {
645         NavigationModel::GetInstance()->SetMinNavBarWidth(NG::DEFAULT_MIN_NAV_BAR_WIDTH);
646         NavigationModel::GetInstance()->SetMaxNavBarWidth(NG::DEFAULT_MAX_NAV_BAR_WIDTH);
647         return;
648     }
649     if (!info[0]->IsArray()) {
650         return;
651     }
652     auto rangeArray = JSRef<JSArray>::Cast(info[0]);
653     JSRef<JSVal> min = rangeArray->GetValueAt(0);
654     JSRef<JSVal> max = rangeArray->GetValueAt(1);
655 
656     CalcDimension minNavBarWidth;
657     CalcDimension maxNavBarWidth;
658     if (min->IsNull() || min->IsUndefined() || !ParseJsDimensionVp(min, minNavBarWidth)) {
659         minNavBarWidth = NG::DEFAULT_MIN_NAV_BAR_WIDTH;
660     }
661     if (LessNotEqual(minNavBarWidth.Value(), 0.0)) {
662         minNavBarWidth.SetValue(0);
663     }
664     NavigationModel::GetInstance()->SetMinNavBarWidth(minNavBarWidth);
665 
666     if (max->IsNull() || max->IsUndefined() || !ParseJsDimensionVp(max, maxNavBarWidth)) {
667         maxNavBarWidth = NG::DEFAULT_MAX_NAV_BAR_WIDTH;
668     }
669     if (LessNotEqual(maxNavBarWidth.Value(), 0.0)) {
670         maxNavBarWidth.SetValue(0);
671     }
672     NavigationModel::GetInstance()->SetMaxNavBarWidth(maxNavBarWidth);
673 }
674 
SetOnNavBarStateChange(const JSCallbackInfo & info)675 void JSNavigation::SetOnNavBarStateChange(const JSCallbackInfo& info)
676 {
677     if (info.Length() < 1) {
678         return;
679     }
680 
681     if (info[0]->IsFunction()) {
682         auto onNavBarStateChangeCallback =
683             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
684         auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
685         auto onNavBarStateChange = [execCtx = info.GetExecutionContext(), func = std::move(onNavBarStateChangeCallback),
686                                        node = targetNode](bool isVisible) {
687             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
688             ACE_SCORING_EVENT("OnNavBarStateChange");
689             PipelineContext::SetCallBackNode(node);
690             JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(isVisible));
691             func->ExecuteJS(1, &param);
692         };
693         NavigationModel::GetInstance()->SetOnNavBarStateChange(std::move(onNavBarStateChange));
694     }
695     info.ReturnSelf();
696 }
697 
SetNavDestination(const JSCallbackInfo & info)698 void JSNavigation::SetNavDestination(const JSCallbackInfo& info)
699 {
700     if (info.Length() < 1) {
701         return;
702     }
703 
704     if (!info[0]->IsObject()) {
705         return;
706     }
707 
708     JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
709     auto builder = obj->GetProperty("builder");
710     if (!builder->IsFunction()) {
711         return;
712     }
713 
714     auto navigationStack = NavigationModel::GetInstance()->GetNavigationStack();
715     auto jsNavigationStack = AceType::DynamicCast<JSNavigationStack>(navigationStack);
716     if (jsNavigationStack) {
717         jsNavigationStack->SetNavDestBuilderFunc(JSRef<JSFunc>::Cast(builder));
718     }
719 }
720 
SetOnNavigationModeChange(const JSCallbackInfo & info)721 void JSNavigation::SetOnNavigationModeChange(const JSCallbackInfo& info)
722 {
723     if (info.Length() < 1) {
724         return;
725     }
726     if (!info[0]->IsFunction()) {
727         info.ReturnSelf();
728         return;
729     }
730     auto onModeChangeCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
731     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
732     auto onModeChange = [execCtx = info.GetExecutionContext(), func = std::move(onModeChangeCallback),
733                             node = targetNode](NG::NavigationMode mode) {
734         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
735         ACE_SCORING_EVENT("OnNavigationModeChange");
736         PipelineContext::SetCallBackNode(node);
737         JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(static_cast<int8_t>(mode)));
738         func->ExecuteJS(1, &param);
739     };
740     NavigationModel::GetInstance()->SetOnNavigationModeChange(std::move(onModeChange));
741     info.ReturnSelf();
742 }
743 
SetCustomNavContentTransition(const JSCallbackInfo & info)744 void JSNavigation::SetCustomNavContentTransition(const JSCallbackInfo& info)
745 {
746     if (info.Length() == 0 || !info[0]->IsFunction()) {
747         NavigationModel::GetInstance()->SetIsCustomAnimation(false);
748         return;
749     }
750     RefPtr<JsNavigationFunction> jsNavigationFunction =
751         AceType::MakeRefPtr<JsNavigationFunction>(JSRef<JSFunc>::Cast(info[0]));
752     auto onNavigationAnimation = [execCtx = info.GetExecutionContext(), func = std::move(jsNavigationFunction)](
753                                      RefPtr<NG::NavDestinationContext> from, RefPtr<NG::NavDestinationContext> to,
754                                      NG::NavigationOperation operation) -> NG::NavigationTransition {
755         NG::NavigationTransition transition;
756         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, transition);
757         auto ret = func->Execute(from, to, operation);
758         if (!ret->IsObject()) {
759             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom transition is invalid, do default animation");
760             transition.isValid = false;
761             return transition;
762         }
763 
764         auto transitionObj = JSRef<JSObject>::Cast(ret);
765         JSRef<JSVal> interactive = transitionObj->GetProperty("isInteractive");
766         if (interactive->IsBoolean()) {
767             transition.interactive = interactive->ToBoolean();
768         } else {
769             transition.interactive = false;
770         }
771         int32_t timeout = -1;
772         JSRef<JSVal> time = transitionObj->GetProperty("timeout");
773         if (time->IsNumber()) {
774             timeout = time->ToNumber<int32_t>();
775         }
776         if (!transition.interactive) {
777             timeout = timeout < 0 ? NAVIGATION_ANIMATION_TIMEOUT : timeout;
778         }
779         transition.timeout = timeout;
780         JSRef<JSVal> transitionContext = transitionObj->GetProperty("transition");
781         if (!transitionContext->IsFunction()) {
782             return transition;
783         }
784         auto jsOnTransition = AceType::MakeRefPtr<JsNavigationFunction>(JSRef<JSFunc>::Cast(transitionContext));
785         if (transitionContext->IsFunction()) {
786             auto onTransition = [execCtx, func = std::move(jsOnTransition)](
787                                     const RefPtr<NG::NavigationTransitionProxy>& proxy) {
788                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
789                 ACE_SCORING_EVENT("transition");
790                 func->Execute(proxy);
791             };
792             transition.transition = std::move(onTransition);
793         }
794         JSRef<JSVal> endCallback = transitionObj->GetProperty("onTransitionEnd");
795         if (endCallback->IsFunction()) {
796             auto onEndedCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(endCallback));
797             auto onEndTransition = [execCtx, func = std::move(onEndedCallback)](bool isSuccess) {
798                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
799                 ACE_SCORING_EVENT("onTransitionEnded");
800                 JSRef<JSVal> successVal = JSRef<JSVal>::Make(ToJSValue(isSuccess));
801                 func->ExecuteJS(1, &successVal);
802             };
803             transition.endCallback = std::move(onEndTransition);
804         }
805         return transition;
806     };
807     NavigationModel::GetInstance()->SetIsCustomAnimation(true);
808     NavigationModel::GetInstance()->SetCustomTransition(onNavigationAnimation);
809 }
810 
SetIgnoreLayoutSafeArea(const JSCallbackInfo & info)811 void JSNavigation::SetIgnoreLayoutSafeArea(const JSCallbackInfo& info)
812 {
813     NG::SafeAreaExpandOpts opts { .type = NG::SAFE_AREA_TYPE_SYSTEM, .edges = NG::SAFE_AREA_EDGE_ALL};
814     if (info.Length() >= PARAMETER_LENGTH_ONE && info[FIRST_INDEX]->IsArray()) {
815         auto paramArray = JSRef<JSArray>::Cast(info[0]);
816         uint32_t safeAreaType = NG::SAFE_AREA_TYPE_NONE;
817         for (size_t i = 0; i < paramArray->Length(); ++i) {
818             auto value = paramArray->GetValueAt(i);
819             if (!value->IsNumber() ||
820                 value->ToNumber<uint32_t>() >= SAFE_AREA_TYPE_LIMIT ||
821                 value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_SYSTEM) {
822                 safeAreaType = NG::SAFE_AREA_TYPE_SYSTEM;
823                 break;
824             }
825         }
826         opts.type = safeAreaType;
827     }
828 
829     if (info.Length() >= PARAMETER_LENGTH_TWO && info[SECOND_INDEX]->IsArray()) {
830         auto paramArray = JSRef<JSArray>::Cast(info[1]);
831         uint32_t safeAreaEdge = NG::SAFE_AREA_EDGE_NONE;
832         for (size_t i = 0; i < paramArray->Length(); ++i) {
833             auto value = paramArray->GetValueAt(i);
834             if (!value->IsNumber() ||
835                 value->ToNumber<uint32_t>() >= SAFE_AREA_EDGE_LIMIT) {
836                 safeAreaEdge = NG::SAFE_AREA_EDGE_ALL;
837                 break;
838             }
839             if (value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_TOP ||
840                 value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_BOTTOM) {
841                     safeAreaEdge |= (1 << value->ToNumber<uint32_t>());
842                 }
843         }
844         opts.edges = safeAreaEdge;
845     }
846     NavigationModel::GetInstance()->SetIgnoreLayoutSafeArea(opts);
847 }
848 
SetSystemBarStyle(const JSCallbackInfo & info)849 void JSNavigation::SetSystemBarStyle(const JSCallbackInfo& info)
850 {
851     RefPtr<SystemBarStyle> style = nullptr;
852     if (info.Length() == 1 && info[0]->IsObject()) {
853         auto styleObj = JsConverter::ConvertJsValToNapiValue(info[0]);
854         auto env = GetCurrentEnv();
855         if (env) {
856             style = SystemBarStyle::CreateStyleFromJsObj(env, styleObj);
857         }
858     }
859     NavigationModel::GetInstance()->SetSystemBarStyle(style);
860 }
861 
SetEnableDragBar(const JSCallbackInfo & info)862 void JSNavigation::SetEnableDragBar(const JSCallbackInfo& info)
863 {
864     if (!info[0]->IsBoolean()) {
865         // the default value of navigation's drag bar is false
866         NavigationModel::GetInstance()->SetEnableDragBar(false);
867         return;
868     }
869     auto enableDragBar = info[0]->ToBoolean();
870     NavigationModel::GetInstance()->SetEnableDragBar(enableDragBar);
871 }
872 
SetRecoverable(const JSCallbackInfo & info)873 void JSNavigation::SetRecoverable(const JSCallbackInfo& info)
874 {
875     if (!info[0]->IsBoolean()) {
876         // the default value of navigation's recoverable is false
877         NavigationModel::GetInstance()->SetRecoverable(false);
878         return;
879     }
880     auto recoverable = info[0]->ToBoolean();
881     NavigationModel::GetInstance()->SetRecoverable(recoverable);
882 }
883 } // namespace OHOS::Ace::Framework
884