• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_navdestination.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "base/memory/ace_type.h"
20 #include "base/utils/utils.h"
21 #include "base/system_bar/system_bar_style.h"
22 #include "bridge/declarative_frontend/engine/functions/js_function.h"
23 #include "bridge/declarative_frontend/engine/js_converter.h"
24 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
25 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
26 #include "bridge/declarative_frontend/engine/js_types.h"
27 #include "bridge/declarative_frontend/jsview/js_navdestination_context.h"
28 #include "bridge/declarative_frontend/jsview/js_navigation.h"
29 #include "bridge/declarative_frontend/jsview/js_navigation_utils.h"
30 #include "bridge/declarative_frontend/jsview/js_navdestination_scrollable_processor.h"
31 #include "bridge/declarative_frontend/jsview/js_utils.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_options.h"
35 #include "core/components_ng/pattern/navrouter/navdestination_model_ng.h"
36 
37 namespace OHOS::Ace {
38 std::unique_ptr<NavDestinationModel> NavDestinationModel::instance_ = nullptr;
39 std::mutex NavDestinationModel::mutex_;
40 
GetInstance()41 NavDestinationModel* NavDestinationModel::GetInstance()
42 {
43     if (!instance_) {
44         std::lock_guard<std::mutex> lock(mutex_);
45         instance_.reset(new NG::NavDestinationModelNG());
46     }
47     return instance_.get();
48 }
49 
50 } // namespace OHOS::Ace
51 
52 namespace OHOS::Ace::Framework {
53 
54 namespace {
55 constexpr uint32_t SAFE_AREA_TYPE_LIMIT = 3;
56 constexpr uint32_t SAFE_AREA_EDGE_LIMIT = 4;
57 constexpr uint32_t SAFE_AREA_EDGE_SYSTEM = 0;
58 constexpr uint32_t SAFE_AREA_EDGE_TOP = 0;
59 constexpr uint32_t SAFE_AREA_EDGE_BOTTOM = 1;
60 constexpr int32_t PARAMATER_LENGTH_ONE = 1;
61 constexpr int32_t PARAMATER_LENGTH_TWO = 2;
62 constexpr uint32_t FIRST_INDEX = 0;
63 constexpr uint32_t SECOND_INDEX = 1;
64 constexpr int32_t JS_ENUM_TRANSITIONTYPE_NONE = 1;
65 constexpr int32_t JS_ENUM_TRANSITIONTYPE_TITLE = 2;
66 constexpr int32_t JS_ENUM_TRANSITIONTYPE_CONTENT = 3;
67 constexpr int32_t JS_ENUM_TRANSITIONTYPE_FADE = 4;
68 constexpr int32_t JS_ENUM_TRANSITIONTYPE_EXPLODE = 5;
69 constexpr int32_t JS_ENUM_TRANSITIONTYPE_SLIDE_RIGHT = 6;
70 constexpr int32_t JS_ENUM_TRANSITIONTYPE_SLIDE_BOTTOM = 7;
71 constexpr char MORE_BUTTON_OPTIONS_PROPERTY[] = "moreButtonOptions";
72 
ParseTransitionType(int32_t value)73 NG::NavigationSystemTransitionType ParseTransitionType(int32_t value)
74 {
75     switch (value) {
76         case JS_ENUM_TRANSITIONTYPE_NONE:
77             return NG::NavigationSystemTransitionType::NONE;
78         case JS_ENUM_TRANSITIONTYPE_TITLE:
79             return NG::NavigationSystemTransitionType::TITLE;
80         case JS_ENUM_TRANSITIONTYPE_CONTENT:
81             return NG::NavigationSystemTransitionType::CONTENT;
82         case JS_ENUM_TRANSITIONTYPE_FADE:
83             return NG::NavigationSystemTransitionType::FADE;
84         case JS_ENUM_TRANSITIONTYPE_EXPLODE:
85             return NG::NavigationSystemTransitionType::EXPLODE;
86         case JS_ENUM_TRANSITIONTYPE_SLIDE_RIGHT:
87             return NG::NavigationSystemTransitionType::SLIDE_RIGHT;
88         case JS_ENUM_TRANSITIONTYPE_SLIDE_BOTTOM:
89             return NG::NavigationSystemTransitionType::SLIDE_BOTTOM;
90         default:
91             return NG::NavigationSystemTransitionType::DEFAULT;
92     }
93 }
94 
ParseCommonTitle(const JSRef<JSObject> & jsObj)95 bool ParseCommonTitle(const JSRef<JSObject>& jsObj)
96 {
97     JSRef<JSVal> subtitle = jsObj->GetProperty("sub");
98     JSRef<JSVal> title = jsObj->GetProperty("main");
99     std::string mainTitle;
100     std::string subTitle;
101     bool hasSub = JSViewAbstract::ParseJsString(subtitle, subTitle);
102     bool hasMain = JSViewAbstract::ParseJsString(title, mainTitle);
103     if (hasSub || hasMain) {
104         return NG::NavDestinationModelNG::GetInstance()->ParseCommonTitle(
105             hasSub, hasMain, subTitle, mainTitle);
106     }
107     return false;
108 }
109 } // namespace
110 
Create()111 void JSNavDestination::Create()
112 {
113     NavDestinationModel::GetInstance()->Create();
114     NavDestinationModel::GetInstance()->SetScrollableProcessor(
115         []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
116 }
117 
Create(const JSCallbackInfo & info)118 void JSNavDestination::Create(const JSCallbackInfo& info)
119 {
120     if (info.Length() <= 0) {
121         NavDestinationModel::GetInstance()->Create();
122         NavDestinationModel::GetInstance()->SetScrollableProcessor(
123             []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
124         return;
125     }
126 
127     std::string moduleName;
128     std::string pagePath;
129     if (info.Length() == 1) {
130         // input format: builder/pathInfo
131         if (info[0]->IsFunction()) {
132             // first parameter = builder
133             auto builderFunctionJS = info[0];
134             auto builderFunc = [context = info.GetExecutionContext(), builder = std::move(builderFunctionJS)]() {
135                 JAVASCRIPT_EXECUTION_SCOPE(context)
136                 JSRef<JSFunc>::Cast(builder)->Call(JSRef<JSObject>());
137             };
138             auto ctx = AceType::MakeRefPtr<NG::NavDestinationContext>();
139             auto navPathInfo = AceType::MakeRefPtr<JSNavPathInfo>();
140             ctx->SetNavPathInfo(navPathInfo);
141             NavDestinationModel::GetInstance()->Create(std::move(builderFunc), std::move(ctx));
142             NavDestinationModel::GetInstance()->SetScrollableProcessor(
143                 []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
144             return;
145         } else if (info[0]->IsObject()) {
146             // first parameter = pathInfo{'moduleName': stringA, 'pagePath': stringB}
147             auto infoObj = JSRef<JSObject>::Cast(info[0]);
148             if (!infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->IsString() ||
149                 !infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->IsString()) {
150                 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "navDestination current pageInfo is invalid");
151                 return;
152             }
153             moduleName = infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->ToString();
154             pagePath = infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->ToString();
155             NavDestinationModel::GetInstance()->Create();
156             NavDestinationModel::GetInstance()->SetScrollableProcessor(
157                 []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
158             NavDestinationModel::GetInstance()->SetNavDestinationPathInfo(moduleName, pagePath);
159             return;
160         }
161         TAG_LOGE(AceLogTag::ACE_NAVIGATION,
162             "current input info is neither buildFunction or navDestination usefulInfo");
163         return;
164     } else if (info.Length() == 2) {
165         // parameter = builder(maybe empty) + pathInfo
166         if (!info[0]->IsFunction() || !info[1]->IsObject()) {
167             TAG_LOGE(AceLogTag::ACE_NAVIGATION, "buider or pageInfo is invalid");
168             return;
169         }
170         auto builderFunctionJS = info[0];
171         auto builderFunc = [context = info.GetExecutionContext(), builder = std::move(builderFunctionJS)]() {
172             JAVASCRIPT_EXECUTION_SCOPE(context)
173             JSRef<JSFunc>::Cast(builder)->Call(JSRef<JSObject>());
174         };
175         auto ctx = AceType::MakeRefPtr<NG::NavDestinationContext>();
176         auto navPathInfo = AceType::MakeRefPtr<JSNavPathInfo>();
177         ctx->SetNavPathInfo(navPathInfo);
178 
179         auto infoObj = JSRef<JSObject>::Cast(info[1]);
180         if (!infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->IsString() ||
181             !infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->IsString()) {
182             TAG_LOGE(AceLogTag::ACE_NAVIGATION, "navDestination current pageInfo is invalid");
183             return;
184         }
185         moduleName = infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->ToString();
186         pagePath = infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->ToString();
187         NavDestinationModel::GetInstance()->Create(std::move(builderFunc), std::move(ctx));
188         NavDestinationModel::GetInstance()->SetScrollableProcessor(
189             []() { return AceType::MakeRefPtr<JSNavDestinationScrollableProcessor>(); });
190         NavDestinationModel::GetInstance()->SetNavDestinationPathInfo(moduleName, pagePath);
191     }
192 }
193 
SetHideTitleBar(const JSCallbackInfo & info)194 void JSNavDestination::SetHideTitleBar(const JSCallbackInfo& info)
195 {
196     bool isHide = false;
197     if (info.Length() > 0 && info[0]->IsBoolean()) {
198         isHide = info[0]->ToBoolean();
199     }
200     bool isAnimated = false;
201     if (info.Length() > 1 && info[1]->IsBoolean()) {
202         isAnimated = info[1]->ToBoolean();
203     }
204     NavDestinationModel::GetInstance()->SetHideTitleBar(isHide, isAnimated);
205 }
206 
SetHideBackButton(const JSCallbackInfo & info)207 void JSNavDestination::SetHideBackButton(const JSCallbackInfo& info)
208 {
209     bool isHide = false;
210     if (info.Length() > 0 && info[0]->IsBoolean()) {
211         isHide = info[0]->ToBoolean();
212     }
213     NavDestinationModel::GetInstance()->SetHideBackButton(isHide);
214 }
215 
SetTitle(const JSCallbackInfo & info)216 void JSNavDestination::SetTitle(const JSCallbackInfo& info)
217 {
218     // Resource and string type.
219     std::string title;
220     if (ParseJsString(info[0], title)) {
221         NavDestinationModel::GetInstance()->ParseCommonTitle(false, true, "", title);
222     } else if (info[0]->IsObject()) {
223         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
224         do {
225             // NavigationCommonTitle
226             if (ParseCommonTitle(jsObj)) {
227                 break;
228             }
229             // CustomBuilder | NavigationCustomTitle
230             CalcDimension titleHeight;
231             if (!jsObj->HasProperty("height")) {
232                 NavDestinationModel::GetInstance()->SetTitleHeight(titleHeight, false);
233                 break;
234             }
235             JSRef<JSVal> height = jsObj->GetProperty("height");
236             bool isValid = JSContainerBase::ParseJsDimensionVpNG(height, titleHeight);
237             if (height->IsString()) {
238                 std::string heightValue;
239                 ParseJsString(height, heightValue);
240                 if (heightValue == NG::TITLE_MAIN_WITH_SUB) {
241                     NavDestinationModel::GetInstance()->SetTitleHeight(NG::DOUBLE_LINE_TITLEBAR_HEIGHT);
242                     break;
243                 }
244                 if (heightValue == NG::TITLE_MAIN) {
245                     NavDestinationModel::GetInstance()->SetTitleHeight(NG::SINGLE_LINE_TITLEBAR_HEIGHT);
246                     break;
247                 }
248             }
249             if (!isValid || titleHeight.Value() < 0) {
250                 NavDestinationModel::GetInstance()->SetTitleHeight(Dimension(), true);
251                 break;
252             }
253             NavDestinationModel::GetInstance()->SetTitleHeight(titleHeight);
254         } while (0);
255         JSRef<JSVal> builderObject = jsObj->GetProperty("builder");
256         if (builderObject->IsFunction()) {
257             ViewStackModel::GetInstance()->NewScope();
258             JsFunction jsBuilderFunc(info.This(), JSRef<JSFunc>::Cast(builderObject));
259             ACE_SCORING_EVENT("Navdestination.title.builder");
260             jsBuilderFunc.Execute();
261             auto customNode = ViewStackModel::GetInstance()->Finish();
262             NavDestinationModel::GetInstance()->SetCustomTitle(customNode);
263         }
264     } else {
265         NavDestinationModel::GetInstance()->ParseCommonTitle(false, false, "", "");
266     }
267 
268     NG::NavigationTitlebarOptions options;
269     JSNavigationUtils::ParseTitleBarOptions(info, false, options);
270     NavDestinationModel::GetInstance()->SetTitlebarOptions(std::move(options));
271 }
272 
SetBackButtonIcon(const JSCallbackInfo & info)273 void JSNavDestination::SetBackButtonIcon(const JSCallbackInfo& info)
274 {
275     // srcType、pixmap、string
276     if (info.Length() < 1) {
277         return;
278     }
279     std::string src;
280     auto noPixMap = ParseJsMedia(info[0], src);
281 
282     RefPtr<PixelMap> pixMap = nullptr;
283     auto isValidImage = false;
284 #if defined(PIXEL_MAP_SUPPORTED)
285     if (!noPixMap) {
286         pixMap = CreatePixelMapFromNapiValue(info[0]);
287     }
288 #endif
289     if (noPixMap || pixMap != nullptr) {
290         isValidImage = true;
291     }
292     std::vector<std::string> nameList;
293     NG::ImageOption imageOption;
294     std::string bundleName;
295     std::string moduleName;
296     GetJsMediaBundleInfo(info[0], bundleName, moduleName);
297     nameList.emplace_back(bundleName);
298     nameList.emplace_back(moduleName);
299     imageOption.noPixMap = noPixMap;
300     imageOption.isValidImage = isValidImage;
301     std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
302     auto isSymbol = info[0]->IsObject() && src.empty() && pixMap == nullptr;
303     if (isSymbol) {
304         SetSymbolOptionApply(info, iconSymbol, info[0]);
305     }
306     std::string backButtonAccessibilityText;
307     if (info.Length() > 1) {
308         if (!info[1]->IsNull() && !info[1]->IsUndefined()) {
309             std::string backButtonAccessibilityText;
310             ParseJsString(info[1], backButtonAccessibilityText);
311             NavDestinationModel::GetInstance()->SetBackButtonIcon(iconSymbol, src, imageOption, pixMap, nameList,
312                 true, backButtonAccessibilityText);
313             return;
314         }
315     }
316     NavDestinationModel::GetInstance()->SetBackButtonIcon(iconSymbol, src, imageOption, pixMap, nameList);
317 }
318 
SetOnShown(const JSCallbackInfo & info)319 void JSNavDestination::SetOnShown(const JSCallbackInfo& info)
320 {
321     if (!info[0]->IsFunction()) {
322         return;
323     }
324 
325     auto onShownCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
326     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
327     auto onShown = [execCtx = info.GetExecutionContext(), func = std::move(onShownCallback), node = targetNode]() {
328         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
329         ACE_SCORING_EVENT("NavDestination.onShown");
330         PipelineContext::SetCallBackNode(node);
331         JSRef<JSVal> params[1];
332         params[0] = JSRef<JSVal>::Make(ToJSValue("undefined"));
333         func->ExecuteJS(1, params);
334     };
335     NavDestinationModel::GetInstance()->SetOnShown(std::move(onShown));
336     info.ReturnSelf();
337 }
338 
SetOnHidden(const JSCallbackInfo & info)339 void JSNavDestination::SetOnHidden(const JSCallbackInfo& info)
340 {
341     if (!info[0]->IsFunction()) {
342         return;
343     }
344     auto onHiddenCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
345     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
346     auto onHidden = [execCtx = info.GetExecutionContext(), func = std::move(onHiddenCallback), node = targetNode]() {
347         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
348         ACE_SCORING_EVENT("NavDestination.onHidden");
349         PipelineContext::SetCallBackNode(node);
350         func->ExecuteJS();
351     };
352     NavDestinationModel::GetInstance()->SetOnHidden(std::move(onHidden));
353     info.ReturnSelf();
354 }
355 
SetOnBackPressed(const JSCallbackInfo & info)356 void JSNavDestination::SetOnBackPressed(const JSCallbackInfo& info)
357 {
358     if (!info[0]->IsFunction()) {
359         return;
360     }
361     auto onBackPressedCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
362     auto onBackPressed = [execCtx = info.GetExecutionContext(), func = std::move(onBackPressedCallback)]() -> bool {
363         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, false);
364         ACE_SCORING_EVENT("NavDestination.onBackPressed");
365         return (func->ExecuteJS())->ToBoolean();
366     };
367     NavDestinationModel::GetInstance()->SetOnBackPressed(std::move(onBackPressed));
368     info.ReturnSelf();
369 }
370 
SetOnReady(const JSCallbackInfo & info)371 void JSNavDestination::SetOnReady(const JSCallbackInfo& info)
372 {
373     if (!info[0]->IsFunction()) {
374         return;
375     }
376     auto onReadyCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
377     auto onReady = [execCtx = info.GetExecutionContext(), func = std::move(onReadyCallback)](
378                        RefPtr<NG::NavDestinationContext> context) {
379         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
380         auto jsContext = JSClass<JSNavDestinationContext>::NewInstance();
381         auto jsNavDestinationContext = Referenced::Claim(jsContext->Unwrap<JSNavDestinationContext>());
382         CHECK_NULL_VOID(jsNavDestinationContext);
383         jsNavDestinationContext->SetNavDestinationContext(context);
384         ACE_SCORING_EVENT("NavDestination.onReady");
385         JSRef<JSVal> params[1];
386         params[0] = jsContext;
387         func->ExecuteJS(1, params);
388     };
389     NavDestinationModel::GetInstance()->SetOnReady(std::move(onReady));
390     info.ReturnSelf();
391 }
392 
SetMode(const JSCallbackInfo & info)393 void JSNavDestination::SetMode(const JSCallbackInfo& info)
394 {
395     if (!info[0]->IsNumber()) {
396         // set default back ground color
397         NavDestinationModel::GetInstance()->SetNavDestinationMode(NG::NavDestinationMode::STANDARD);
398         return;
399     }
400     auto mode = info[0]->ToNumber<int32_t>();
401     NavDestinationModel::GetInstance()->SetNavDestinationMode(static_cast<NG::NavDestinationMode>(mode));
402 }
403 
SetMenus(const JSCallbackInfo & info)404 void JSNavDestination::SetMenus(const JSCallbackInfo& info)
405 {
406     if (info.Length() < 1) {
407         return;
408     }
409 
410     NG::NavigationMenuOptions options;
411     if (info.Length() > 1) {
412         auto optObj = JSRef<JSObject>::Cast(info[1]);
413         auto moreButtonProperty = optObj->GetProperty(MORE_BUTTON_OPTIONS_PROPERTY);
414         JSNavigationUtils::ParseMenuOptions(moreButtonProperty, options);
415     }
416     if (info[0]->IsUndefined() || info[0]->IsArray()) {
417         std::vector<NG::BarItem> menuItems;
418         if (info[0]->IsUndefined()) {
419             menuItems = {};
420         } else {
421             auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
422             JSNavigationUtils::ParseBarItems(targetNode, info, JSRef<JSArray>::Cast(info[0]), menuItems);
423         }
424         NavDestinationModel::GetInstance()->SetMenuItems(std::move(menuItems));
425         NavDestinationModel::GetInstance()->SetMenuOptions(std::move(options));
426         return;
427     } else if (info[0]->IsObject()) {
428         auto builderObject = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
429         if (builderObject->IsFunction()) {
430             ViewStackModel::GetInstance()->NewScope();
431             JsFunction jsBuilderFunc(info.This(), JSRef<JSObject>::Cast(builderObject));
432             ACE_SCORING_EVENT("NavDestiNation.menu.builder");
433             jsBuilderFunc.Execute();
434             auto customNode = ViewStackModel::GetInstance()->Finish();
435             NavDestinationModel::GetInstance()->SetCustomMenu(customNode);
436             NavDestinationModel::GetInstance()->SetMenuOptions(std::move(options));
437         }
438     }
439 }
440 
SetBackgroundColor(const JSCallbackInfo & info)441 void JSNavDestination::SetBackgroundColor(const JSCallbackInfo& info)
442 {
443     Color backgroundColor;
444     bool isValid = ParseJsColor(info[0], backgroundColor);
445 
446     NavDestinationModel::GetInstance()->SetBackgroundColor(backgroundColor, isValid);
447 }
448 
SetWillAppear(const JSCallbackInfo & info)449 void JSNavDestination::SetWillAppear(const JSCallbackInfo& info)
450 {
451     if (!info[0]->IsFunction()) {
452         return;
453     }
454 
455     auto willAppear = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
456     auto onWillAppear = [execCtx = info.GetExecutionContext(), func = std::move(willAppear)]() {
457         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
458         ACE_SCORING_EVENT("NavDestination.WillAppear");
459         func->ExecuteJS();
460     };
461     NavDestinationModel::GetInstance()->SetOnWillAppear(std::move(onWillAppear));
462     info.ReturnSelf();
463 }
464 
SetWillHide(const JSCallbackInfo & info)465 void JSNavDestination::SetWillHide(const JSCallbackInfo& info)
466 {
467     if (!info[0]->IsFunction()) {
468         return;
469     }
470 
471     auto willHideCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
472     auto onWillHide = [execCtx = info.GetExecutionContext(), func = std::move(willHideCallback)]() {
473         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
474         ACE_SCORING_EVENT("NavDestination.WillHide");
475         func->ExecuteJS();
476     };
477     NavDestinationModel::GetInstance()->SetOnWillHide(std::move(onWillHide));
478     info.ReturnSelf();
479 }
480 
SetWillShow(const JSCallbackInfo & info)481 void JSNavDestination::SetWillShow(const JSCallbackInfo& info)
482 {
483     if (!info[0]->IsFunction()) {
484         return;
485     }
486 
487     auto willShowCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
488     auto onWillShow = [execCtx = info.GetExecutionContext(), func = std::move(willShowCallback)]() {
489         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
490         ACE_SCORING_EVENT("NavDestination.WillShow");
491         func->ExecuteJS();
492     };
493     NavDestinationModel::GetInstance()->SetOnWillShow(std::move(onWillShow));
494     info.ReturnSelf();
495 }
496 
SetWillDisAppear(const JSCallbackInfo & info)497 void JSNavDestination::SetWillDisAppear(const JSCallbackInfo& info)
498 {
499     if (!info[0]->IsFunction()) {
500         return;
501     }
502 
503     auto WillDisAppear = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
504     auto onWillDisAppear = [execCtx = info.GetExecutionContext(), func = std::move(WillDisAppear)]() {
505         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
506         ACE_SCORING_EVENT("NavDestination.WillDisAppear");
507         func->ExecuteJS();
508     };
509     NavDestinationModel::GetInstance()->SetOnWillDisAppear(std::move(onWillDisAppear));
510     info.ReturnSelf();
511 }
512 
SetIgnoreLayoutSafeArea(const JSCallbackInfo & info)513 void JSNavDestination::SetIgnoreLayoutSafeArea(const JSCallbackInfo& info)
514 {
515     NG::SafeAreaExpandOpts opts { .type = NG::SAFE_AREA_TYPE_SYSTEM, .edges = NG::SAFE_AREA_EDGE_ALL};
516     if (info.Length() >= PARAMATER_LENGTH_ONE && info[FIRST_INDEX]->IsArray()) {
517         auto paramArray = JSRef<JSArray>::Cast(info[0]);
518         uint32_t safeAreaType = NG::SAFE_AREA_TYPE_NONE;
519         for (size_t i = 0; i < paramArray->Length(); ++i) {
520             auto value = paramArray->GetValueAt(i);
521             if (!value->IsNumber() ||
522                 value->ToNumber<uint32_t>() >= SAFE_AREA_TYPE_LIMIT ||
523                 value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_SYSTEM) {
524                 safeAreaType = NG::SAFE_AREA_TYPE_SYSTEM;
525                 break;
526             }
527         }
528         opts.type = safeAreaType;
529     }
530 
531     if (info.Length() >= PARAMATER_LENGTH_TWO && info[SECOND_INDEX]->IsArray()) {
532         auto paramArray = JSRef<JSArray>::Cast(info[1]);
533         uint32_t safeAreaEdge = NG::SAFE_AREA_EDGE_NONE;
534         for (size_t i = 0; i < paramArray->Length(); ++i) {
535             auto value = paramArray->GetValueAt(i);
536             if (!value->IsNumber() ||
537                 value->ToNumber<uint32_t>() >= SAFE_AREA_EDGE_LIMIT) {
538                 safeAreaEdge = NG::SAFE_AREA_EDGE_ALL;
539                 break;
540             }
541             if (value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_TOP ||
542                 value->ToNumber<uint32_t>() == SAFE_AREA_EDGE_BOTTOM) {
543                     safeAreaEdge |= (1 << value->ToNumber<uint32_t>());
544                 }
545         }
546         opts.edges = safeAreaEdge;
547     }
548     NavDestinationModel::GetInstance()->SetIgnoreLayoutSafeArea(opts);
549 }
550 
SetRecoverable(const JSCallbackInfo & info)551 void JSNavDestination::SetRecoverable(const JSCallbackInfo& info)
552 {
553     if (!info[0]->IsBoolean()) {
554         // the default value of navDestination's recoverable is true
555         NavDestinationModel::GetInstance()->SetRecoverable(true);
556         return;
557     }
558     auto recoverable = info[0]->ToBoolean();
559     NavDestinationModel::GetInstance()->SetRecoverable(recoverable);
560 }
561 
SetToolBarConfiguration(const JSCallbackInfo & info)562 void JSNavDestination::SetToolBarConfiguration(const JSCallbackInfo& info)
563 {
564     bool hideText = false;
565     JSNavigationUtils::ParseHideToolBarText(info, hideText);
566     NavDestinationModel::GetInstance()->SetHideItemText(hideText);
567     if (info[0]->IsUndefined() || info[0]->IsArray()) {
568         std::vector<NG::BarItem> toolBarItems;
569         if (info[0]->IsArray()) {
570             auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
571             JSNavigationUtils::ParseToolbarItemsConfiguration(
572                 targetNode, info, JSRef<JSArray>::Cast(info[0]), toolBarItems);
573         }
574         NG::MoreButtonOptions toolbarMoreButtonOptions;
575         if (info.Length() > 1) {
576             auto optObj = JSRef<JSObject>::Cast(info[1]);
577             auto moreButtonProperty = optObj->GetProperty(MORE_BUTTON_OPTIONS_PROPERTY);
578             JSNavigationUtils::ParseToolBarMoreButtonOptions(moreButtonProperty, toolbarMoreButtonOptions);
579         }
580         NavDestinationModel::GetInstance()->SetToolbarMorebuttonOptions(std::move(toolbarMoreButtonOptions));
581         NavDestinationModel::GetInstance()->SetToolbarConfiguration(std::move(toolBarItems));
582     } else if (info[0]->IsObject()) {
583         auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
584         if (builderFuncParam->IsFunction()) {
585             ViewStackModel::GetInstance()->NewScope();
586             JsFunction jsBuilderFunc(builderFuncParam);
587             jsBuilderFunc.Execute();
588             auto customNode = ViewStackModel::GetInstance()->Finish();
589             NavDestinationModel::GetInstance()->SetCustomToolBar(customNode);
590         }
591     }
592     NG::NavigationToolbarOptions options;
593     JSNavigationUtils::ParseToolbarOptions(info, options);
594     NavDestinationModel::GetInstance()->SetToolBarOptions(std::move(options));
595 }
596 
SetHideToolBar(const JSCallbackInfo & info)597 void JSNavDestination::SetHideToolBar(const JSCallbackInfo& info)
598 {
599     bool isHide = false;
600     if (info.Length() > 0 && info[0]->IsBoolean()) {
601         isHide = info[0]->ToBoolean();
602     }
603     bool isAnimated = false;
604     if (info.Length() > 1 && info[1]->IsBoolean()) {
605         isAnimated = info[1]->ToBoolean();
606     }
607     NavDestinationModel::GetInstance()->SetHideToolBar(isHide, isAnimated);
608 }
609 
BindToScrollable(const JSCallbackInfo & info)610 void JSNavDestination::BindToScrollable(const JSCallbackInfo& info)
611 {
612     auto bindFunc = [&info](const RefPtr<NG::NavDestinationScrollableProcessor>& processor) {
613         auto jsProcessor = AceType::DynamicCast<JSNavDestinationScrollableProcessor>(processor);
614         CHECK_NULL_VOID(jsProcessor);
615         jsProcessor->BindToScrollable(info);
616     };
617     NavDestinationModel::GetInstance()->UpdateBindingWithScrollable(std::move(bindFunc));
618 }
619 
BindToNestedScrollable(const JSCallbackInfo & info)620 void JSNavDestination::BindToNestedScrollable(const JSCallbackInfo& info)
621 {
622     auto bindFunc = [&info](const RefPtr<NG::NavDestinationScrollableProcessor>& processor) {
623         auto jsProcessor = AceType::DynamicCast<JSNavDestinationScrollableProcessor>(processor);
624         CHECK_NULL_VOID(jsProcessor);
625         jsProcessor->BindToNestedScrollable(info);
626     };
627     NavDestinationModel::GetInstance()->UpdateBindingWithScrollable(std::move(bindFunc));
628 }
629 
SetCustomTransition(const JSCallbackInfo & info)630 void JSNavDestination::SetCustomTransition(const JSCallbackInfo& info)
631 {
632     if (info.Length() != 1 || !info[0]->IsFunction()) {
633         NavDestinationModel::GetInstance()->SetCustomTransition(nullptr);
634         return;
635     }
636     auto jsTransitionDelegate = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(info[0]));
637     auto transitionDelegate = [execCtx = info.GetExecutionContext(), delegate = std::move(jsTransitionDelegate)](
638         NG::NavigationOperation operation, bool isEnter) -> std::optional<std::vector<NG::NavDestinationTransition>> {
639         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, std::nullopt);
640         JSRef<JSVal> params[2];
641         params[0] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(operation)));
642         params[1] = JSRef<JSVal>::Make(ToJSValue(isEnter));
643         auto ret = delegate->ExecuteJS(2, params);
644         if (!ret->IsArray()) {
645             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "NavDestination custom transition invalid!");
646             return std::nullopt;
647         }
648         std::vector<NG::NavDestinationTransition> allTransitions;
649         auto allTransitionObj = JSRef<JSArray>::Cast(ret);
650         for (size_t index = 0; index < allTransitionObj->Length(); ++index) {
651             auto transitionValue = allTransitionObj->GetValueAt(index);
652             if (!transitionValue->IsObject()) {
653                 continue;
654             }
655             auto navDestinationTransition = JSNavigationUtils::ParseNavDestinationTransition(
656                 JSRef<JSObject>::Cast(transitionValue), execCtx);
657             if (navDestinationTransition.has_value()) {
658                 allTransitions.emplace_back(navDestinationTransition.value());
659             }
660         }
661         return allTransitions;
662     };
663 
664     NavDestinationModel::GetInstance()->SetCustomTransition(std::move(transitionDelegate));
665 }
666 
JSBind(BindingTarget globalObj)667 void JSNavDestination::JSBind(BindingTarget globalObj)
668 {
669     JSNavDestinationContext::JSBind(globalObj);
670     JSClass<JSNavDestination>::Declare("NavDestination");
671     JSClass<JSNavDestination>::StaticMethod("create", &JSNavDestination::Create);
672     JSClass<JSNavDestination>::StaticMethod("title", &JSNavDestination::SetTitle);
673     JSClass<JSNavDestination>::StaticMethod("hideTitleBar", &JSNavDestination::SetHideTitleBar);
674     JSClass<JSNavDestination>::StaticMethod("hideBackButton", &JSNavDestination::SetHideBackButton);
675     JSClass<JSNavDestination>::StaticMethod("backButtonIcon", &JSNavDestination::SetBackButtonIcon);
676     JSClass<JSNavDestination>::StaticMethod("backgroundColor", &JSNavDestination::SetBackgroundColor);
677     JSClass<JSNavDestination>::StaticMethod("onShown", &JSNavDestination::SetOnShown);
678     JSClass<JSNavDestination>::StaticMethod("onHidden", &JSNavDestination::SetOnHidden);
679     JSClass<JSNavDestination>::StaticMethod("onBackPressed", &JSNavDestination::SetOnBackPressed);
680     JSClass<JSNavDestination>::StaticMethod("onReady", &JSNavDestination::SetOnReady);
681     JSClass<JSNavDestination>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
682     JSClass<JSNavDestination>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
683     JSClass<JSNavDestination>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
684     JSClass<JSNavDestination>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
685     JSClass<JSNavDestination>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
686     JSClass<JSNavDestination>::StaticMethod("id", &JSViewAbstract::JsId);
687     JSClass<JSNavDestination>::StaticMethod("mode", &JSNavDestination::SetMode);
688     JSClass<JSNavDestination>::StaticMethod("menus", &JSNavDestination::SetMenus);
689     JSClass<JSNavDestination>::StaticMethod("onWillAppear", &JSNavDestination::SetWillAppear);
690     JSClass<JSNavDestination>::StaticMethod("onWillShow", &JSNavDestination::SetWillShow);
691     JSClass<JSNavDestination>::StaticMethod("onWillHide", &JSNavDestination::SetWillHide);
692     JSClass<JSNavDestination>::StaticMethod("onWillDisappear", &JSNavDestination::SetWillDisAppear);
693     JSClass<JSNavDestination>::StaticMethod("onActive", &JSNavDestination::SetOnActive);
694     JSClass<JSNavDestination>::StaticMethod("onInactive", &JSNavDestination::SetOnInactive);
695     JSClass<JSNavDestination>::StaticMethod("onResult", &JSNavDestination::SetResultCallback);
696     JSClass<JSNavDestination>::StaticMethod("ignoreLayoutSafeArea", &JSNavDestination::SetIgnoreLayoutSafeArea);
697     JSClass<JSNavDestination>::StaticMethod("systemBarStyle", &JSNavDestination::SetSystemBarStyle);
698     JSClass<JSNavDestination>::StaticMethod("recoverable", &JSNavDestination::SetRecoverable);
699     JSClass<JSNavDestination>::StaticMethod("toolbarConfiguration", &JSNavDestination::SetToolBarConfiguration);
700     JSClass<JSNavDestination>::StaticMethod("hideToolBar", &JSNavDestination::SetHideToolBar);
701     JSClass<JSNavDestination>::StaticMethod("systemTransition", &JSNavDestination::SetSystemTransition);
702     JSClass<JSNavDestination>::StaticMethod("bindToScrollable", &JSNavDestination::BindToScrollable);
703     JSClass<JSNavDestination>::StaticMethod("bindToNestedScrollable", &JSNavDestination::BindToNestedScrollable);
704     JSClass<JSNavDestination>::StaticMethod("customTransition", &JSNavDestination::SetCustomTransition);
705     JSClass<JSNavDestination>::StaticMethod("onNewParam", &JSNavDestination::SetOnNewParam);
706     JSClass<JSNavDestination>::InheritAndBind<JSContainerBase>(globalObj);
707 }
708 
SetSystemBarStyle(const JSCallbackInfo & info)709 void JSNavDestination::SetSystemBarStyle(const JSCallbackInfo& info)
710 {
711     RefPtr<SystemBarStyle> style = nullptr;
712     if (info.Length() == 1 && info[0]->IsObject()) {
713         auto styleObj = JsConverter::ConvertJsValToNapiValue(info[0]);
714         auto env = GetCurrentEnv();
715         if (env) {
716             style = SystemBarStyle::CreateStyleFromJsObj(env, styleObj);
717         }
718     }
719     NavDestinationModel::GetInstance()->SetSystemBarStyle(style);
720 }
721 
SetSystemTransition(const JSCallbackInfo & info)722 void JSNavDestination::SetSystemTransition(const JSCallbackInfo& info)
723 {
724     if (!info[0]->IsNumber()) {
725         NavDestinationModel::GetInstance()->SetSystemTransitionType(NG::NavigationSystemTransitionType::DEFAULT);
726         return;
727     }
728     auto value = info[0]->ToNumber<int32_t>();
729     NG::NavigationSystemTransitionType type = ParseTransitionType(value);
730     NavDestinationModel::GetInstance()->SetSystemTransitionType(type);
731 }
732 
SetResultCallback(const JSCallbackInfo & info)733 void JSNavDestination::SetResultCallback(const JSCallbackInfo& info)
734 {
735     if (info.Length() < 1) {
736         return;
737     }
738     if (!info[0]->IsFunction()) {
739         return;
740     }
741     auto func = JSRef<JSFunc>::Cast(info[0]);
742     if (func->IsEmpty()) {
743         return;
744     }
745     auto setPopCallback = [func](const RefPtr<NG::NavPathInfo>& info) {
746         auto pathInfo = AceType::DynamicCast<JSNavPathInfo>(info);
747         CHECK_NULL_VOID(pathInfo);
748         pathInfo->SetNavDestinationPopCallback(func);
749     };
750     NavDestinationModel::GetInstance()->SetOnPop(setPopCallback);
751 }
752 
SetOnActive(const JSCallbackInfo & info)753 void JSNavDestination::SetOnActive(const JSCallbackInfo& info)
754 {
755     if (info.Length() <= 0) {
756         return;
757     }
758     if (!info[0]->IsFunction()) {
759         return;
760     }
761     auto onActive = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
762     auto onActiveCallback = [exeCtx = info.GetExecutionContext(), func = std::move(onActive)](int32_t reason) {
763         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(exeCtx);
764         ACE_SCORING_EVENT("NavDestination.OnActive");
765         JSRef<JSVal> params[1];
766         params[0] = JSRef<JSVal>::Make(ToJSValue(reason));
767         func->ExecuteJS(1, params);
768     };
769     NavDestinationModel::GetInstance()->SetOnActive(std::move(onActiveCallback));
770     info.ReturnSelf();
771 }
772 
SetOnInactive(const JSCallbackInfo & info)773 void JSNavDestination::SetOnInactive(const JSCallbackInfo& info)
774 {
775     if (info.Length() <= 0) {
776         return;
777     }
778     if (!info[0]->IsFunction()) {
779         return;
780     }
781     auto onInactive = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
782     auto onInactiveCallback = [execCtx = info.GetExecutionContext(), func = std::move(onInactive)](int32_t reason) {
783         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
784         ACE_SCORING_EVENT("NavDestination.OnInactive");
785         JSRef<JSVal> params[1];
786         params[0] = JSRef<JSVal>::Make(ToJSValue(reason));
787         func->ExecuteJS(1, params);
788     };
789     NavDestinationModel::GetInstance()->SetOnInactive(std::move(onInactiveCallback));
790     info.ReturnSelf();
791 }
792 
SetOnNewParam(const JSCallbackInfo & info)793 void JSNavDestination::SetOnNewParam(const JSCallbackInfo& info)
794 {
795     if (info.Length() <= 0 || !info[0]->IsFunction()) {
796         return;
797     }
798     auto onNewParam = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(info[0]));
799     auto onNewParamCallback = [execCtx = info.GetExecutionContext(), func = std::move(onNewParam)](napi_value param) {
800         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
801         ACE_SCORING_EVENT("NavDestination.onNewParam");
802         JSRef<JSVal> params[1];
803         params[0] = JsConverter::ConvertNapiValueToJsVal(param);
804         func->ExecuteJS(1, params);
805     };
806     NavDestinationModel::GetInstance()->SetOnNewParam(std::move(onNewParamCallback));
807     info.ReturnSelf();
808 }
809 } // namespace OHOS::Ace::Framework
810