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