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