1 /*
2 * Copyright (c) 2021-2022 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 "bridge/declarative_frontend/engine/functions/js_click_function.h"
23 #include "bridge/declarative_frontend/engine/functions/js_navigation_function.h"
24 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
25 #include "bridge/declarative_frontend/engine/js_types.h"
26 #include "bridge/declarative_frontend/jsview/js_nav_path_stack.h"
27 #include "bridge/declarative_frontend/jsview/js_navigation_stack.h"
28 #include "bridge/declarative_frontend/jsview/js_utils.h"
29 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
30 #include "bridge/declarative_frontend/jsview/models/navigation_model_impl.h"
31 #include "core/components_ng/base/view_abstract_model.h"
32 #include "core/components_ng/base/view_stack_model.h"
33 #include "core/components_ng/base/view_stack_processor.h"
34 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
35 #include "core/components_ng/pattern/navigation/navigation_model_data.h"
36 #include "core/components_ng/pattern/navigation/navigation_model_ng.h"
37 #include "core/components_ng/pattern/navigation/navigation_options.h"
38
39 namespace OHOS::Ace {
40 std::unique_ptr<NavigationModel> NavigationModel::instance_ = nullptr;
41 std::mutex NavigationModel::mutex_;
42 constexpr int32_t NAVIGATION_ANIMATION_TIMEOUT = 1000; // ms
43
GetInstance()44 NavigationModel* NavigationModel::GetInstance()
45 {
46 if (!instance_) {
47 std::lock_guard<std::mutex> lock(mutex_);
48 if (!instance_) {
49 #ifdef NG_BUILD
50 instance_.reset(new NG::NavigationModelNG());
51 #else
52 if (Container::IsCurrentUseNewPipeline()) {
53 instance_.reset(new NG::NavigationModelNG());
54 } else {
55 instance_.reset(new Framework::NavigationModelImpl());
56 }
57 #endif
58 }
59 }
60 return instance_.get();
61 }
62 } // namespace OHOS::Ace
63
64 namespace OHOS::Ace::Framework {
65 namespace {
66 constexpr int32_t TITLE_MODE_RANGE = 2;
67 constexpr int32_t NAVIGATION_MODE_RANGE = 2;
68 constexpr int32_t NAV_BAR_POSITION_RANGE = 1;
69 constexpr int32_t DEFAULT_NAV_BAR_WIDTH = 240;
70 constexpr Dimension DEFAULT_MIN_NAV_BAR_WIDTH = 240.0_vp;
71 constexpr Dimension DEFAULT_MIN_CONTENT_WIDTH = 360.0_vp;
72 constexpr char BACKGROUND_COLOR_PROPERTY[] = "backgroundColor";
73 constexpr char BACKGROUND_BLUR_STYLE_PROPERTY[] = "backgroundBlurStyle";
74
TitleModeChangeEventToJSValue(const NavigationTitleModeChangeEvent & eventInfo)75 JSRef<JSVal> TitleModeChangeEventToJSValue(const NavigationTitleModeChangeEvent& eventInfo)
76 {
77 return JSRef<JSVal>::Make(ToJSValue(eventInfo.IsMiniBar() ? static_cast<int32_t>(NavigationTitleMode::MINI)
78 : static_cast<int32_t>(NavigationTitleMode::FULL)));
79 }
80
ParseBackgroundOptions(const JSRef<JSVal> & obj,NG::NavigationBackgroundOptions & options)81 void ParseBackgroundOptions(const JSRef<JSVal>& obj, NG::NavigationBackgroundOptions& options)
82 {
83 options.color.reset();
84 options.blurStyle.reset();
85 if (!obj->IsObject()) {
86 return;
87 }
88 auto optObj = JSRef<JSObject>::Cast(obj);
89 auto colorProperty = optObj->GetProperty(BACKGROUND_COLOR_PROPERTY);
90 Color color;
91 if (JSViewAbstract::ParseJsColor(colorProperty, color)) {
92 options.color = color;
93 }
94 auto blurProperty = optObj->GetProperty(BACKGROUND_BLUR_STYLE_PROPERTY);
95 if (blurProperty->IsNumber()) {
96 auto blurStyle = blurProperty->ToNumber<int32_t>();
97 if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
98 blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
99 options.blurStyle = static_cast<BlurStyle>(blurStyle);
100 }
101 }
102 }
103
104 } // namespace
105
ParseToolBarItems(const JSRef<JSArray> & jsArray,std::list<RefPtr<AceType>> & items)106 void JSNavigation::ParseToolBarItems(const JSRef<JSArray>& jsArray, std::list<RefPtr<AceType>>& items)
107 {
108 auto length = jsArray->Length();
109 for (size_t i = 0; i < length; i++) {
110 auto item = jsArray->GetValueAt(i);
111 if (!item->IsObject()) {
112 continue;
113 }
114
115 auto itemObject = JSRef<JSObject>::Cast(item);
116 auto toolBarItem = AceType::MakeRefPtr<ToolBarItem>();
117 auto itemValueObject = itemObject->GetProperty("value");
118 if (itemValueObject->IsString()) {
119 toolBarItem->value = itemValueObject->ToString();
120 }
121 auto itemIconObject = itemObject->GetProperty("icon");
122 std::string icon;
123 ParseJsMedia(itemIconObject, icon);
124 toolBarItem->icon = icon;
125 auto itemActionValue = itemObject->GetProperty("action");
126 if (itemActionValue->IsFunction()) {
127 auto onClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(itemActionValue));
128 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
129 toolBarItem->action = EventMarker([func = std::move(onClickFunc), node = targetNode]() {
130 ACE_SCORING_EVENT("Navigation.toolBarItemClick");
131 PipelineContext::SetCallBackNode(node);
132 func->Execute();
133 });
134 auto onClickWithParamFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(itemActionValue));
135 toolBarItem->actionWithParam =
136 EventMarker([func = std::move(onClickWithParamFunc), node = targetNode](const BaseEventInfo* info) {
137 ACE_SCORING_EVENT("Navigation.menuItemButtonClick");
138 PipelineContext::SetCallBackNode(node);
139 func->Execute();
140 });
141 }
142 items.push_back(toolBarItem);
143 }
144 }
145
ParseBarItems(const JSCallbackInfo & info,const JSRef<JSArray> & jsArray,std::vector<NG::BarItem> & items)146 void JSNavigation::ParseBarItems(
147 const JSCallbackInfo& info, const JSRef<JSArray>& jsArray, std::vector<NG::BarItem>& items)
148 {
149 auto length = jsArray->Length();
150 for (size_t i = 0; i < length; i++) {
151 auto item = jsArray->GetValueAt(i);
152 if (!item->IsObject()) {
153 continue;
154 }
155 auto itemObject = JSRef<JSObject>::Cast(item);
156 NG::BarItem toolBarItem;
157 auto itemValueObject = itemObject->GetProperty("value");
158 if (itemValueObject->IsString()) {
159 toolBarItem.text = itemValueObject->ToString();
160 }
161
162 auto itemIconObject = itemObject->GetProperty("icon");
163 if (itemIconObject->IsString()) {
164 toolBarItem.icon = itemIconObject->ToString();
165 }
166
167 auto itemActionValue = itemObject->GetProperty("action");
168 if (itemActionValue->IsFunction()) {
169 RefPtr<JsFunction> onClickFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(itemActionValue));
170 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
171 auto onItemClick = [execCtx = info.GetExecutionContext(), func = std::move(onClickFunc),
172 node = targetNode]() {
173 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
174 if (func) {
175 PipelineContext::SetCallBackNode(node);
176 func->ExecuteJS();
177 }
178 };
179 toolBarItem.action = onItemClick;
180 }
181 items.push_back(toolBarItem);
182 }
183 }
184
ParseToolbarItemsConfiguration(const JSCallbackInfo & info,const JSRef<JSArray> & jsArray,std::vector<NG::BarItem> & items)185 void JSNavigation::ParseToolbarItemsConfiguration(
186 const JSCallbackInfo& info, const JSRef<JSArray>& jsArray, std::vector<NG::BarItem>& items)
187 {
188 auto length = jsArray->Length();
189 for (size_t i = 0; i < length; i++) {
190 auto item = jsArray->GetValueAt(i);
191 if (!item->IsObject()) {
192 continue;
193 }
194 NG::BarItem toolBarItem;
195 std::string text;
196 std::string icon;
197 std::string activeIcon;
198
199 auto itemObject = JSRef<JSObject>::Cast(item);
200 auto itemValueObject = itemObject->GetProperty("value");
201 if (ParseJsString(itemValueObject, text)) {
202 toolBarItem.text = text;
203 }
204
205 auto itemIconObject = itemObject->GetProperty("icon");
206 if (ParseJsMedia(itemIconObject, icon)) {
207 toolBarItem.icon = icon;
208 }
209
210 auto itemActionValue = itemObject->GetProperty("action");
211 if (itemActionValue->IsFunction()) {
212 RefPtr<JsFunction> onClickFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(itemActionValue));
213 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
214 auto onItemClick = [execCtx = info.GetExecutionContext(), func = std::move(onClickFunc),
215 node = targetNode]() {
216 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
217 if (func) {
218 PipelineContext::SetCallBackNode(node);
219 func->ExecuteJS();
220 }
221 };
222 toolBarItem.action = onItemClick;
223 }
224
225 auto itemStatusValue = itemObject->GetProperty("status");
226 if (itemStatusValue->IsNumber()) {
227 toolBarItem.status = static_cast<NG::NavToolbarItemStatus>(itemStatusValue->ToNumber<int32_t>());
228 }
229
230 auto itemActiveIconObject = itemObject->GetProperty("activeIcon");
231 if (ParseJsMedia(itemActiveIconObject, activeIcon)) {
232 toolBarItem.activeIcon = activeIcon;
233 }
234
235 items.push_back(toolBarItem);
236 }
237 }
238
ParseCommonTitle(const JSRef<JSObject> & jsObj)239 bool JSNavigation::ParseCommonTitle(const JSRef<JSObject>& jsObj)
240 {
241 JSRef<JSVal> subtitle = jsObj->GetProperty("sub");
242 JSRef<JSVal> title = jsObj->GetProperty("main");
243 bool hasSub = subtitle->IsString();
244 bool hasMain = title->IsString();
245 if (hasSub || hasMain) {
246 return NavigationModel::GetInstance()->ParseCommonTitle(
247 hasSub, hasMain, subtitle->ToString(), title->ToString());
248 }
249 return false;
250 }
251
Create(const JSCallbackInfo & info)252 void JSNavigation::Create(const JSCallbackInfo& info)
253 {
254 JSRef<JSObject> newObj;
255 if (info.Length() > 0) {
256 if (!info[0]->IsObject()) {
257 return;
258 }
259 newObj = JSRef<JSObject>::Cast(info[0]);
260 auto value = newObj->GetProperty("type");
261 if (value->ToString() != "NavPathStack") {
262 return;
263 }
264 }
265
266 NavigationModel::GetInstance()->Create();
267 auto stackCreator = []() -> RefPtr<JSNavigationStack> { return AceType::MakeRefPtr<JSNavigationStack>(); };
268 auto stackUpdater = [&newObj, &info](RefPtr<NG::NavigationStack> stack) {
269 NavigationModel::GetInstance()->SetNavigationStackProvided(!newObj->IsEmpty());
270 auto jsStack = AceType::DynamicCast<JSNavigationStack>(stack);
271 CHECK_NULL_VOID(jsStack);
272 const auto& oldObj = jsStack->GetDataSourceObj();
273 if (oldObj->IsEmpty()) {
274 if (newObj->IsEmpty()) {
275 newObj = JSNavPathStack::CreateNewNavPathStackJSObject();
276 }
277 auto nativeObj = JSClass<JSNavPathStack>::NewInstance();
278 JSNavPathStack::SetNativeNavPathStack(newObj, nativeObj);
279 jsStack->SetDataSourceObj(newObj);
280 } else if (!newObj->IsEmpty()) {
281 auto objStrictEqual = [](const JSRef<JSVal>& obja, const JSRef<JSVal>& objb) -> bool {
282 return obja->GetLocalHandle()->IsStrictEquals(obja->GetEcmaVM(), objb->GetLocalHandle());
283 };
284 if (objStrictEqual(newObj, oldObj)) {
285 return;
286 }
287 auto nativeObj = JSClass<JSNavPathStack>::NewInstance();
288 JSNavPathStack::SetNativeNavPathStack(newObj, nativeObj);
289 jsStack->SetDataSourceObj(newObj);
290 }
291 };
292 NavigationModel::GetInstance()->SetNavigationStackWithCreatorAndUpdater(stackCreator, stackUpdater);
293 }
294
JSBind(BindingTarget globalObj)295 void JSNavigation::JSBind(BindingTarget globalObj)
296 {
297 JsNavigationTransitionProxy::JSBind(globalObj);
298 JSClass<JSNavigation>::Declare("Navigation");
299 MethodOptions opt = MethodOptions::NONE;
300 JSClass<JSNavigation>::StaticMethod("create", &JSNavigation::Create);
301 JSClass<JSNavigation>::StaticMethod("title", &JSNavigation::SetTitle, opt);
302 JSClass<JSNavigation>::StaticMethod("subTitle", &JSNavigation::SetSubTitle, opt);
303 JSClass<JSNavigation>::StaticMethod("titleMode", &JSNavigation::SetTitleMode, opt);
304 JSClass<JSNavigation>::StaticMethod("hideTitleBar", &JSNavigation::SetHideTitleBar, opt);
305 JSClass<JSNavigation>::StaticMethod("hideBackButton", &JSNavigation::SetHideBackButton, opt);
306 JSClass<JSNavigation>::StaticMethod("hideToolBar", &JSNavigation::SetHideToolBar, opt);
307 JSClass<JSNavigation>::StaticMethod("toolBar", &JSNavigation::SetToolBar);
308 JSClass<JSNavigation>::StaticMethod("toolbarConfiguration", &JSNavigation::SetToolbarConfiguration);
309 JSClass<JSNavigation>::StaticMethod("menus", &JSNavigation::SetMenus);
310 JSClass<JSNavigation>::StaticMethod("menuCount", &JSNavigation::SetMenuCount);
311 JSClass<JSNavigation>::StaticMethod("onTitleModeChange", &JSNavigation::SetOnTitleModeChanged);
312 JSClass<JSNavigation>::StaticMethod("onNavigationModeChange", &JSNavigation::SetOnNavigationModeChange);
313 JSClass<JSNavigation>::StaticMethod("mode", &JSNavigation::SetUsrNavigationMode);
314 JSClass<JSNavigation>::StaticMethod("navBarWidth", &JSNavigation::SetNavBarWidth);
315 JSClass<JSNavigation>::StaticMethod("minContentWidth", &JSNavigation::SetMinContentWidth);
316 JSClass<JSNavigation>::StaticMethod("navBarWidthRange", &JSNavigation::SetNavBarWidthRange);
317 JSClass<JSNavigation>::StaticMethod("navBarPosition", &JSNavigation::SetNavBarPosition);
318 JSClass<JSNavigation>::StaticMethod("hideNavBar", &JSNavigation::SetHideNavBar);
319 JSClass<JSNavigation>::StaticMethod("backButtonIcon", &JSNavigation::SetBackButtonIcon);
320 JSClass<JSNavigation>::StaticMethod("onNavBarStateChange", &JSNavigation::SetOnNavBarStateChange);
321 JSClass<JSNavigation>::StaticMethod("navDestination", &JSNavigation::SetNavDestination);
322 JSClass<JSNavigation>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
323 JSClass<JSNavigation>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
324 JSClass<JSNavigation>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
325 JSClass<JSNavigation>::StaticMethod("customNavContentTransition", &JSNavigation::SetCustomNavContentTransition);
326 JSClass<JSNavigation>::InheritAndBind<JSContainerBase>(globalObj);
327 }
328
SetTitle(const JSCallbackInfo & info)329 void JSNavigation::SetTitle(const JSCallbackInfo& info)
330 {
331 if (info.Length() < 1) {
332 return;
333 }
334 // Resource and string type.
335 std::string title;
336 if (ParseJsString(info[0], title)) {
337 NavigationModel::GetInstance()->ParseCommonTitle(false, true, "", title);
338 } else if (info[0]->IsObject()) {
339 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
340 do {
341 // NavigationCommonTitle
342 if (ParseCommonTitle(jsObj)) {
343 break;
344 }
345 // CustomBuilder | NavigationCustomTitle
346 CalcDimension titleHeight;
347 if (!jsObj->HasProperty("height")) {
348 NavigationModel::GetInstance()->SetTitleHeight(titleHeight, false);
349 break;
350 }
351 JSRef<JSVal> height = jsObj->GetProperty("height");
352 bool isValid = JSContainerBase::ParseJsDimensionVpNG(height, titleHeight);
353 if (height->IsString()) {
354 std::string heightValue;
355 ParseJsString(height, heightValue);
356 if (heightValue == NG::TITLE_MAIN_WITH_SUB) {
357 NavigationModel::GetInstance()->SetTitleHeight(NG::DOUBLE_LINE_TITLEBAR_HEIGHT);
358 break;
359 }
360 if (heightValue == NG::TITLE_MAIN) {
361 NavigationModel::GetInstance()->SetTitleHeight(NG::SINGLE_LINE_TITLEBAR_HEIGHT);
362 break;
363 }
364 }
365 if (!isValid || titleHeight.Value() < 0) {
366 NavigationModel::GetInstance()->SetTitleHeight(Dimension(), true);
367 break;
368 }
369 NavigationModel::GetInstance()->SetTitleHeight(titleHeight);
370 } while (0);
371 JSRef<JSVal> builderObject = jsObj->GetProperty("builder");
372 if (builderObject->IsFunction()) {
373 ViewStackModel::GetInstance()->NewScope();
374 JsFunction jsBuilderFunc(info.This(), JSRef<JSObject>::Cast(builderObject));
375 ACE_SCORING_EVENT("Navigation.title.builder");
376 jsBuilderFunc.Execute();
377 auto customNode = ViewStackModel::GetInstance()->Finish();
378 NavigationModel::GetInstance()->SetCustomTitle(customNode);
379 }
380 } else {
381 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "SetTitle is undefined");
382 NavigationModel::GetInstance()->ParseCommonTitle(false, false, "", "");
383 return;
384 }
385
386 NG::NavigationTitlebarOptions options;
387 if (info.Length() > 1) {
388 ParseBackgroundOptions(info[1], options.bgOptions);
389 }
390 NavigationModel::GetInstance()->SetTitlebarOptions(std::move(options));
391 }
392
SetTitleMode(int32_t value)393 void JSNavigation::SetTitleMode(int32_t value)
394 {
395 if (value >= 0 && value <= TITLE_MODE_RANGE) {
396 NavigationModel::GetInstance()->SetTitleMode(static_cast<NG::NavigationTitleMode>(value));
397 }
398 }
399
SetSubTitle(const std::string & subTitle)400 void JSNavigation::SetSubTitle(const std::string& subTitle)
401 {
402 NavigationModel::GetInstance()->SetSubtitle(subTitle);
403 }
404
SetHideTitleBar(bool hide)405 void JSNavigation::SetHideTitleBar(bool hide)
406 {
407 NavigationModel::GetInstance()->SetHideTitleBar(hide);
408 }
409
SetHideNavBar(bool hide)410 void JSNavigation::SetHideNavBar(bool hide)
411 {
412 NavigationModel::GetInstance()->SetHideNavBar(hide);
413 }
414
SetBackButtonIcon(const JSCallbackInfo & info)415 void JSNavigation::SetBackButtonIcon(const JSCallbackInfo& info)
416 {
417 if (info.Length() < 1) {
418 return;
419 }
420 std::string src;
421 auto noPixMap = ParseJsMedia(info[0], src);
422
423 RefPtr<PixelMap> pixMap = nullptr;
424 #if defined(PIXEL_MAP_SUPPORTED)
425 if (!noPixMap) {
426 pixMap = CreatePixelMapFromNapiValue(info[0]);
427 }
428 #endif
429 std::string bundleName;
430 std::string moduleName;
431 GetJsMediaBundleInfo(info[0], bundleName, moduleName);
432 NavigationModel::GetInstance()->SetBackButtonIcon(src, noPixMap, pixMap, bundleName, moduleName);
433 }
434
SetHideBackButton(bool hide)435 void JSNavigation::SetHideBackButton(bool hide)
436 {
437 NavigationModel::GetInstance()->SetHideBackButton(hide);
438 }
439
SetHideToolBar(bool hide)440 void JSNavigation::SetHideToolBar(bool hide)
441 {
442 NavigationModel::GetInstance()->SetHideToolBar(hide);
443 }
444
SetToolBar(const JSCallbackInfo & info)445 void JSNavigation::SetToolBar(const JSCallbackInfo& info)
446 {
447 if (info.Length() < 1) {
448 return;
449 }
450 if (!info[0]->IsObject() && !info[0]->IsUndefined()) {
451 return;
452 }
453 if (info[0]->IsUndefined()) {
454 NavigationModel::GetInstance()->SetToolBarItems({});
455 return;
456 }
457 auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
458 if (builderFuncParam->IsFunction()) {
459 ViewStackModel::GetInstance()->NewScope();
460 JsFunction jsBuilderFunc(builderFuncParam);
461 jsBuilderFunc.Execute();
462 auto customNode = ViewStackModel::GetInstance()->Finish();
463 NavigationModel::GetInstance()->SetCustomToolBar(customNode);
464 }
465
466 auto itemsValue = JSRef<JSObject>::Cast(info[0])->GetProperty("items");
467 if (!itemsValue->IsObject() || !itemsValue->IsArray()) {
468 return;
469 }
470 if (NavigationModel::GetInstance()->NeedSetItems()) {
471 std::vector<NG::BarItem> toolBarItems;
472 ParseBarItems(info, JSRef<JSArray>::Cast(itemsValue), toolBarItems);
473 NavigationModel::GetInstance()->SetToolBarItems(std::move(toolBarItems));
474 return;
475 }
476 std::list<RefPtr<AceType>> items;
477 NavigationModel::GetInstance()->GetToolBarItems(items);
478 ParseToolBarItems(JSRef<JSArray>::Cast(itemsValue), items);
479 }
480
SetToolbarConfiguration(const JSCallbackInfo & info)481 void JSNavigation::SetToolbarConfiguration(const JSCallbackInfo& info)
482 {
483 if (info[0]->IsUndefined() || info[0]->IsArray()) {
484 if (NavigationModel::GetInstance()->NeedSetItems()) {
485 std::vector<NG::BarItem> toolbarItems;
486 if (info[0]->IsUndefined()) {
487 toolbarItems = {};
488 } else {
489 ParseToolbarItemsConfiguration(info, JSRef<JSArray>::Cast(info[0]), toolbarItems);
490 }
491 NavigationModel::GetInstance()->SetToolbarConfiguration(std::move(toolbarItems));
492 } else {
493 std::list<RefPtr<AceType>> items;
494 NavigationModel::GetInstance()->GetToolBarItems(items);
495 ParseToolBarItems(JSRef<JSArray>::Cast(info[0]), items);
496 }
497 } else if (info[0]->IsObject()) {
498 auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
499 if (builderFuncParam->IsFunction()) {
500 ViewStackModel::GetInstance()->NewScope();
501 JsFunction jsBuilderFunc(builderFuncParam);
502 jsBuilderFunc.Execute();
503 auto customNode = ViewStackModel::GetInstance()->Finish();
504 NavigationModel::GetInstance()->SetCustomToolBar(customNode);
505 }
506 }
507
508 NG::NavigationToolbarOptions options;
509 if (info.Length() > 1) {
510 ParseBackgroundOptions(info[1], options.bgOptions);
511 }
512 NavigationModel::GetInstance()->SetToolbarOptions(std::move(options));
513 }
514
SetMenus(const JSCallbackInfo & info)515 void JSNavigation::SetMenus(const JSCallbackInfo& info)
516 {
517 if (info.Length() < 1) {
518 return;
519 }
520
521 if (info[0]->IsUndefined() || info[0]->IsArray()) {
522 if (NavigationModel::GetInstance()->NeedSetItems()) {
523 std::vector<NG::BarItem> menuItems;
524 if (info[0]->IsUndefined()) {
525 menuItems = {};
526 } else {
527 ParseBarItems(info, JSRef<JSArray>::Cast(info[0]), menuItems);
528 }
529 NavigationModel::GetInstance()->SetMenuItems(std::move(menuItems));
530 return;
531 }
532 std::list<RefPtr<AceType>> items;
533 NavigationModel::GetInstance()->GetMenuItems(items);
534 ParseToolBarItems(JSRef<JSArray>::Cast(info[0]), items);
535 } else if (info[0]->IsObject()) {
536 auto builderObject = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
537 if (builderObject->IsFunction()) {
538 ViewStackModel::GetInstance()->NewScope();
539 JsFunction jsBuilderFunc(info.This(), JSRef<JSObject>::Cast(builderObject));
540 ACE_SCORING_EVENT("Navigation.menu.builder");
541 jsBuilderFunc.Execute();
542 auto customNode = ViewStackModel::GetInstance()->Finish();
543 NavigationModel::GetInstance()->SetCustomMenu(customNode);
544 }
545 }
546 }
547
SetMenuCount(int32_t menuCount)548 void JSNavigation::SetMenuCount(int32_t menuCount)
549 {
550 NavigationModel::GetInstance()->SetMenuCount(menuCount);
551 }
552
SetOnTitleModeChanged(const JSCallbackInfo & info)553 void JSNavigation::SetOnTitleModeChanged(const JSCallbackInfo& info)
554 {
555 if (info.Length() < 1) {
556 return;
557 }
558 if (info[0]->IsFunction()) {
559 auto onTitleModeChangeCallback =
560 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
561 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
562 auto onTitleModeChange = [execCtx = info.GetExecutionContext(), func = std::move(onTitleModeChangeCallback),
563 node = targetNode](NG::NavigationTitleMode mode) {
564 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
565 ACE_SCORING_EVENT("OnTitleModeChange");
566 PipelineContext::SetCallBackNode(node);
567 JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(mode));
568 func->ExecuteJS(1, ¶m);
569 };
570 auto changeHandler = AceType::MakeRefPtr<JsEventFunction<NavigationTitleModeChangeEvent, 1>>(
571 JSRef<JSFunc>::Cast(info[0]), TitleModeChangeEventToJSValue);
572 auto eventInfo = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler),
573 node = targetNode](const BaseEventInfo* baseInfo) {
574 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
575 auto eventInfo = TypeInfoHelper::DynamicCast<NavigationTitleModeChangeEvent>(baseInfo);
576 if (!eventInfo) {
577 return;
578 }
579 ACE_SCORING_EVENT("Navigation.onTitleModeChanged");
580 PipelineContext::SetCallBackNode(node);
581 func->Execute(*eventInfo);
582 };
583 NavigationModel::GetInstance()->SetOnTitleModeChange(std::move(onTitleModeChange), std::move(eventInfo));
584 }
585 info.ReturnSelf();
586 }
587
SetUsrNavigationMode(const JSCallbackInfo & info)588 void JSNavigation::SetUsrNavigationMode(const JSCallbackInfo& info)
589 {
590 if (!info[0]->IsNumber()) {
591 NavigationModel::GetInstance()->SetUsrNavigationMode(NG::NavigationMode::AUTO);
592 return;
593 }
594 int32_t value = info[0]->ToNumber<int32_t>();
595 if (value >= 0 && value <= NAVIGATION_MODE_RANGE) {
596 NavigationModel::GetInstance()->SetUsrNavigationMode(static_cast<NG::NavigationMode>(value));
597 }
598 }
599
SetNavBarPosition(int32_t value)600 void JSNavigation::SetNavBarPosition(int32_t value)
601 {
602 if (value >= 0 && value <= NAV_BAR_POSITION_RANGE) {
603 NavigationModel::GetInstance()->SetNavBarPosition(static_cast<NG::NavBarPosition>(value));
604 }
605 }
606
SetNavBarWidth(const JSCallbackInfo & info)607 void JSNavigation::SetNavBarWidth(const JSCallbackInfo& info)
608 {
609 if (info.Length() < 1) {
610 return;
611 }
612
613 CalcDimension navBarWidth;
614 if (!ParseJsDimensionVp(info[0], navBarWidth)) {
615 return;
616 }
617
618 if (navBarWidth.Value() <= 0) {
619 navBarWidth.SetValue(DEFAULT_NAV_BAR_WIDTH);
620 }
621
622 NavigationModel::GetInstance()->SetNavBarWidth(navBarWidth);
623 }
624
SetMinContentWidth(const JSCallbackInfo & info)625 void JSNavigation::SetMinContentWidth(const JSCallbackInfo& info)
626 {
627 if (info.Length() < 1) {
628 return;
629 }
630
631 CalcDimension minContentWidth;
632 if (!ParseJsDimensionVp(info[0], minContentWidth)) {
633 NavigationModel::GetInstance()->SetMinContentWidth(DEFAULT_MIN_CONTENT_WIDTH);
634 return;
635 }
636
637 if (LessNotEqual(minContentWidth.Value(), 0.0)) {
638 minContentWidth = DEFAULT_MIN_CONTENT_WIDTH;
639 }
640
641 NavigationModel::GetInstance()->SetMinContentWidth(minContentWidth);
642 }
643
SetNavBarWidthRange(const JSCallbackInfo & info)644 void JSNavigation::SetNavBarWidthRange(const JSCallbackInfo& info)
645 {
646 if (info.Length() < 1) {
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
658 CalcDimension maxNavBarWidth;
659 ParseJsDimensionVp(max, maxNavBarWidth);
660
661 if (!ParseJsDimensionVp(min, minNavBarWidth)) {
662 minNavBarWidth.SetValue(DEFAULT_MIN_NAV_BAR_WIDTH.Value());
663 }
664 if (LessNotEqual(minNavBarWidth.Value(), 0.0)) {
665 minNavBarWidth.SetValue(0);
666 }
667 NavigationModel::GetInstance()->SetMinNavBarWidth(minNavBarWidth);
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 WeakPtr<NG::FrameNode> targetNode = 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 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
705 auto builder = obj->GetProperty("builder");
706 if (!builder->IsFunction()) {
707 return;
708 }
709
710 auto navigationStack = NavigationModel::GetInstance()->GetNavigationStack();
711 auto jsNavigationStack = AceType::DynamicCast<JSNavigationStack>(navigationStack);
712 if (jsNavigationStack) {
713 jsNavigationStack->SetJSExecutionContext(info.GetExecutionContext());
714 jsNavigationStack->SetNavDestBuilderFunc(JSRef<JSFunc>::Cast(builder));
715 }
716 }
717
SetOnNavigationModeChange(const JSCallbackInfo & info)718 void JSNavigation::SetOnNavigationModeChange(const JSCallbackInfo& info)
719 {
720 if (info.Length() < 1) {
721 return;
722 }
723 if (!info[0]->IsFunction()) {
724 info.ReturnSelf();
725 return;
726 }
727 auto onModeChangeCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
728 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
729 auto onModeChange = [execCtx = info.GetExecutionContext(), func = std::move(onModeChangeCallback),
730 node = targetNode](NG::NavigationMode mode) {
731 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
732 ACE_SCORING_EVENT("OnNavigationModeChange");
733 PipelineContext::SetCallBackNode(node);
734 JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(static_cast<int8_t>(mode)));
735 func->ExecuteJS(1, ¶m);
736 };
737 NavigationModel::GetInstance()->SetOnNavigationModeChange(std::move(onModeChange));
738 info.ReturnSelf();
739 }
740
SetCustomNavContentTransition(const JSCallbackInfo & info)741 void JSNavigation::SetCustomNavContentTransition(const JSCallbackInfo& info)
742 {
743 if (info.Length() == 0 || !info[0]->IsFunction()) {
744 NavigationModel::GetInstance()->SetIsCustomAnimation(false);
745 return;
746 }
747 RefPtr<JsNavigationFunction> jsNavigationFunction =
748 AceType::MakeRefPtr<JsNavigationFunction>(JSRef<JSFunc>::Cast(info[0]));
749 auto onNavigationAnimation = [execCtx = info.GetExecutionContext(), func = std::move(jsNavigationFunction)](
750 NG::NavContentInfo from, NG::NavContentInfo to,
751 NG::NavigationOperation operation) -> NG::NavigationTransition {
752 NG::NavigationTransition transition;
753 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, transition);
754 auto ret = func->Execute(from, to, operation);
755 if (!ret->IsObject()) {
756 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom transition is invalid, do default animation");
757 transition.isValid = false;
758 return transition;
759 }
760
761 auto transitionObj = JSRef<JSObject>::Cast(ret);
762 JSRef<JSVal> time = transitionObj->GetProperty("timeout");
763 if (time->IsNumber()) {
764 auto timeout = time->ToNumber<int32_t>();
765 transition.timeout = (timeout >= 0) ? timeout : NAVIGATION_ANIMATION_TIMEOUT;
766 } else {
767 transition.timeout = NAVIGATION_ANIMATION_TIMEOUT;
768 }
769 JSRef<JSVal> transitionContext = transitionObj->GetProperty("transition");
770 auto jsOnTransition = AceType::MakeRefPtr<JsNavigationFunction>(JSRef<JSFunc>::Cast(transitionContext));
771 if (transitionContext->IsFunction()) {
772 auto onTransition = [execCtx, func = std::move(jsOnTransition)](
773 const RefPtr<NG::NavigationTransitionProxy>& proxy) {
774 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
775 ACE_SCORING_EVENT("transition");
776 func->Execute(proxy);
777 };
778 transition.transition = std::move(onTransition);
779 }
780 JSRef<JSVal> endCallback = transitionObj->GetProperty("onTransitionEnd");
781 if (endCallback->IsFunction()) {
782 auto onEndedCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(endCallback));
783 auto onEndTransition = [execCtx, func = std::move(onEndedCallback)](bool isSuccess) {
784 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
785 ACE_SCORING_EVENT("onTransitionEnded");
786 JSRef<JSVal> successVal = JSRef<JSVal>::Make(ToJSValue(isSuccess));
787 func->ExecuteJS(1, &successVal);
788 };
789 transition.endCallback = std::move(onEndTransition);
790 }
791 return transition;
792 };
793 NavigationModel::GetInstance()->SetIsCustomAnimation(true);
794 NavigationModel::GetInstance()->SetCustomTransition(onNavigationAnimation);
795 }
796 } // namespace OHOS::Ace::Framework
797