• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param);
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, &param);
692         };
693         NavigationModel::GetInstance()->SetOnNavBarStateChange(std::move(onNavBarStateChange));
694     }
695     info.ReturnSelf();
696 }
697 
SetNavDestination(const JSCallbackInfo & info)698 void JSNavigation::SetNavDestination(const JSCallbackInfo& info)
699 {
700     if (info.Length() < 1) {
701         return;
702     }
703 
704     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, &param);
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