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, ¶m);
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, ¶m);
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, ¶m);
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