1 /*
2 * Copyright (c) 2023 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 "bridge/declarative_frontend/jsview/js_navigation_stack.h"
17
18 #include "bridge/common/utils/engine_helper.h"
19 #include "bridge/declarative_frontend/engine/js_converter.h"
20 #include "bridge/declarative_frontend/engine/functions/js_function.h"
21 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
22 #include "bridge/declarative_frontend/jsview/js_nav_path_stack.h"
23 #include "bridge/declarative_frontend/jsview/js_navdestination_context.h"
24 #include "core/components_ng/base/ui_node.h"
25 #include "core/components_ng/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/custom/custom_node.h"
27 #include "core/components_ng/pattern/navrouter/navdestination_model.h"
28 #include "core/components_v2/inspector/inspector_constants.h"
29 #include "frameworks/base/json/json_util.h"
30
31 namespace OHOS::Ace::Framework {
32 namespace {
33 constexpr int32_t ARGC_COUNT_TWO = 2;
34 constexpr int32_t MAX_PARSE_DEPTH = 3;
35 constexpr uint32_t MAX_PARSE_LENGTH = 1024;
36 constexpr uint32_t MAX_PARSE_PROPERTY_SIZE = 15;
37 constexpr int32_t INVALID_DESTINATION_MODE = -1;
38 constexpr char JS_STRINGIFIED_UNDEFINED[] = "undefined";
39 constexpr char JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC[] = "getNativeStack";
40 constexpr char JS_NAV_PATH_STACK_SETPARENT_FUNC[] = "setParent";
41
GetNapiEnv()42 napi_env GetNapiEnv()
43 {
44 auto engine = EngineHelper::GetCurrentEngine();
45 CHECK_NULL_RETURN(engine, nullptr);
46 NativeEngine* nativeEngine = engine->GetNativeEngine();
47 CHECK_NULL_RETURN(nativeEngine, nullptr);
48 return reinterpret_cast<napi_env>(nativeEngine);
49 }
50 }
51
GetName()52 std::string JSRouteInfo::GetName()
53 {
54 return name_;
55 }
56
SetName(const std::string & name)57 void JSRouteInfo::SetName(const std::string& name)
58 {
59 name_ = name;
60 }
61
SetParam(const JSRef<JSVal> & param)62 void JSRouteInfo::SetParam(const JSRef<JSVal>& param)
63 {
64 param_ = param;
65 }
66
GetParam() const67 JSRef<JSVal> JSRouteInfo::GetParam() const
68 {
69 return param_;
70 }
71
RemoveByIndexes(const std::vector<int32_t> & indexes)72 void JSNavigationStack::RemoveByIndexes(const std::vector<int32_t>& indexes)
73 {
74 if (indexes.empty()) {
75 return;
76 }
77 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
78 if (dataSourceObj_->IsEmpty()) {
79 return;
80 }
81 auto remove = dataSourceObj_->GetProperty("removeByIndexes");
82 if (!remove->IsFunction()) {
83 return;
84 }
85 auto removeFunc = JSRef<JSFunc>::Cast(remove);
86 auto indexArr = JSRef<JSArray>::New();
87 if (indexArr->IsEmpty()) {
88 return;
89 }
90 for (int32_t idx = 0; idx < static_cast<int32_t>(indexes.size()); ++idx) {
91 indexArr->SetValueAt(idx, JSRef<JSVal>::Make(ToJSValue(indexes[idx])));
92 }
93 JSRef<JSVal> params[1];
94 params[0] = indexArr;
95 removeFunc->Call(dataSourceObj_, 1, params);
96 }
97
SetDataSourceObj(const JSRef<JSObject> & dataSourceObj)98 void JSNavigationStack::SetDataSourceObj(const JSRef<JSObject>& dataSourceObj)
99 {
100 // clean callback from old JSNavPathStack
101 UpdateOnStateChangedCallback(dataSourceObj_, nullptr);
102 dataSourceObj_ = dataSourceObj;
103 // add callback to new JSNavPathStack
104 RemoveStack();
105 UpdateOnStateChangedCallback(dataSourceObj_, onStateChangedCallback_);
106 }
107
GetDataSourceObj()108 const JSRef<JSObject>& JSNavigationStack::GetDataSourceObj()
109 {
110 return dataSourceObj_;
111 }
112
SetNavDestBuilderFunc(const JSRef<JSFunc> & navDestBuilderFunc)113 void JSNavigationStack::SetNavDestBuilderFunc(const JSRef<JSFunc>& navDestBuilderFunc)
114 {
115 navDestBuilderFunc_ = navDestBuilderFunc;
116 }
117
IsEmpty()118 bool JSNavigationStack::IsEmpty()
119 {
120 return dataSourceObj_->IsEmpty();
121 }
122
Pop()123 void JSNavigationStack::Pop()
124 {
125 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
126 if (dataSourceObj_->IsEmpty()) {
127 return;
128 }
129 auto popFunc = dataSourceObj_->GetProperty("pop");
130 if (!popFunc->IsFunction()) {
131 return;
132 }
133 auto func = JSRef<JSFunc>::Cast(popFunc);
134 JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
135 }
136
Push(const std::string & name,const RefPtr<NG::RouteInfo> & routeInfo)137 void JSNavigationStack::Push(const std::string& name, const RefPtr<NG::RouteInfo>& routeInfo)
138 {
139 // obtain param from NavPathStack
140 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
141 JSRef<JSVal> param;
142 if (routeInfo) {
143 auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
144 param = jsRouteInfo->GetParam();
145 } else {
146 auto getParamByNameFunc = dataSourceObj_->GetProperty("getParamByName");
147 if (getParamByNameFunc->IsFunction()) {
148 auto getFunc = JSRef<JSFunc>::Cast(getParamByNameFunc);
149 JSRef<JSVal> params[1];
150 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
151 auto funcArray = getFunc->Call(dataSourceObj_, 1, params);
152 if (funcArray->IsArray()) {
153 auto result = JSRef<JSArray>::Cast(funcArray);
154 param = result->GetValueAt(0);
155 }
156 }
157 }
158 auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
159 if (pushNameFunc->IsFunction()) {
160 auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
161 JSRef<JSVal> params[2];
162 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
163 params[1] = param;
164 pushFunc->Call(dataSourceObj_, 2, params);
165 }
166 }
167
PushName(const std::string & name,const JSRef<JSVal> & param)168 void JSNavigationStack::PushName(const std::string& name, const JSRef<JSVal>& param)
169 {
170 // obtain param from routeInfo
171 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
172 auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
173 if (pushNameFunc->IsFunction()) {
174 auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
175 JSRef<JSVal> params[2];
176 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
177 params[1] = param;
178 pushFunc->Call(dataSourceObj_, 2, params);
179 }
180 }
181
Push(const std::string & name,int32_t index)182 void JSNavigationStack::Push(const std::string& name, int32_t index)
183 {
184 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
185 auto getParamByIndexFunc = dataSourceObj_->GetProperty("getParamByIndex");
186 if (!getParamByIndexFunc->IsFunction()) {
187 return ;
188 }
189 auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
190 if (!pushNameFunc->IsFunction()) {
191 return ;
192 }
193 auto getFunc = JSRef<JSFunc>::Cast(getParamByIndexFunc);
194 auto param = JSRef<JSVal>::Cast(getFunc->Call(dataSourceObj_));
195 auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
196 JSRef<JSVal> params[ARGC_COUNT_TWO];
197 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
198 params[1] = param;
199 pushFunc->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
200 }
201
RemoveName(const std::string & name)202 void JSNavigationStack::RemoveName(const std::string& name)
203 {
204 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
205 if (dataSourceObj_->IsEmpty()) {
206 return;
207 }
208 auto removeByNameFunc = dataSourceObj_->GetProperty("removeByName");
209 if (!removeByNameFunc->IsFunction()) {
210 return;
211 }
212 auto func = JSRef<JSFunc>::Cast(removeByNameFunc);
213 JSRef<JSVal> params[1];
214 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
215 func->Call(dataSourceObj_, 1, params);
216 }
217
RemoveIndex(int32_t index)218 void JSNavigationStack::RemoveIndex(int32_t index)
219 {
220 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
221 if (dataSourceObj_->IsEmpty()) {
222 return;
223 }
224 auto removeIndexFunc = dataSourceObj_->GetProperty("removeIndex");
225 if (removeIndexFunc->IsFunction()) {
226 auto func = JSRef<JSFunc>::Cast(removeIndexFunc);
227 JSRef<JSVal> params[1];
228 params[0] = JSRef<JSVal>::Make(ToJSValue(index));
229 func->Call(dataSourceObj_, 1, params);
230 }
231 }
232
Clear()233 void JSNavigationStack::Clear()
234 {
235 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
236 if (dataSourceObj_->IsEmpty()) {
237 return;
238 }
239 auto clearFunc = dataSourceObj_->GetProperty("clear");
240 if (!clearFunc->IsFunction()) {
241 return;
242 }
243 auto func = JSRef<JSFunc>::Cast(clearFunc);
244 func->Call(dataSourceObj_);
245 }
246
GetAllPathName()247 std::vector<std::string> JSNavigationStack::GetAllPathName()
248 {
249 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
250 if (dataSourceObj_->IsEmpty()) {
251 return {};
252 }
253 auto getAllPathNameFunc = dataSourceObj_->GetProperty("getAllPathName");
254 if (!getAllPathNameFunc->IsFunction()) {
255 return {};
256 }
257 auto func = JSRef<JSFunc>::Cast(getAllPathNameFunc);
258 auto funcArray = func->Call(dataSourceObj_);
259 if (!funcArray->IsArray()) {
260 return {};
261 }
262 auto array = JSRef<JSArray>::Cast(funcArray);
263 if (array->IsEmpty()) {
264 return {};
265 }
266 std::vector<std::string> pathNames;
267 for (size_t i = 0; i < array->Length(); i++) {
268 auto value = array->GetValueAt(i);
269 if (value->IsString()) {
270 pathNames.emplace_back(value->ToString());
271 }
272 }
273
274 return pathNames;
275 }
276
GetAllPathIndex()277 std::vector<int32_t> JSNavigationStack::GetAllPathIndex()
278 {
279 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
280 if (dataSourceObj_->IsEmpty()) {
281 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "getAllPathIndex failed, dataSourceObj is empty!");
282 return {};
283 }
284 auto getAllPathIndexFunc = dataSourceObj_->GetProperty("getAllPathIndex");
285 if (!getAllPathIndexFunc->IsFunction()) {
286 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "getAllPathIndex is not a function in dataSourceObj!");
287 return {};
288 }
289 auto func = JSRef<JSFunc>::Cast(getAllPathIndexFunc);
290 auto funcArray = func->Call(dataSourceObj_);
291 if (!funcArray->IsArray()) {
292 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "getAllPathIndexFunc return value is not array!");
293 return {};
294 }
295 auto array = JSRef<JSArray>::Cast(funcArray);
296 if (array->IsEmpty()) {
297 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "getAllPathIndex return value is empyt!");
298 return {};
299 }
300 std::vector<int32_t> pathIndex;
301 for (size_t i = 0; i < array->Length(); i++) {
302 auto value = array->GetValueAt(i);
303 if (value->IsNumber()) {
304 pathIndex.emplace_back(value->ToNumber<int32_t>());
305 }
306 }
307
308 return pathIndex;
309 }
310
InitNavPathIndex(const std::vector<std::string> & pathNames)311 void JSNavigationStack::InitNavPathIndex(const std::vector<std::string>& pathNames)
312 {
313 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
314 if (dataSourceObj_->IsEmpty()) {
315 return;
316 }
317
318 JSRef<JSArray> nameArray = JSRef<JSArray>::New();
319 JSRef<JSVal> params[1];
320 for (size_t i = 0; i < pathNames.size(); i++) {
321 JSRef<JSVal> info = JSRef<JSVal>::Make(ToJSValue(pathNames[i]));
322 nameArray->SetValueAt(i, info);
323 }
324 params[0] = nameArray;
325 auto initNavPathIndexFunc = dataSourceObj_->GetProperty("initNavPathIndex");
326 if (!initNavPathIndexFunc->IsFunction()) {
327 return;
328 }
329 auto func = JSRef<JSFunc>::Cast(initNavPathIndexFunc);
330 func->Call(dataSourceObj_, 1, params);
331 }
332
SetDestinationIdToJsStack(int32_t index,const std::string & navDestinationId)333 void JSNavigationStack::SetDestinationIdToJsStack(int32_t index, const std::string& navDestinationId)
334 {
335 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
336 auto pathInfo = GetJsPathInfo(index);
337 if (pathInfo->IsEmpty()) {
338 return;
339 }
340 pathInfo->SetProperty<std::string>("navDestinationId", navDestinationId);
341 }
342
CreateHomeDestination(const WeakPtr<NG::UINode> & customNode,RefPtr<NG::UINode> & node)343 bool JSNavigationStack::CreateHomeDestination(const WeakPtr<NG::UINode>& customNode, RefPtr<NG::UINode>& node)
344 {
345 if (!homePathInfo_.has_value()) {
346 return false;
347 }
348 RefPtr<NG::UINode> targetNode = nullptr;
349 RefPtr<NG::NavDestinationGroupNode> desNode = nullptr;
350 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
351 NG::ScopedViewStackProcessor scopedViewStackProcessor;
352 if (ERROR_CODE_NO_ERROR != LoadDestination(
353 homePathInfo_.value().name, homePathInfo_.value().param, customNode, targetNode, desNode)) {
354 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "failed to create , create empty node");
355 targetNode = AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
356 GetNavDestinationNodeInUINode(targetNode, desNode);
357 }
358 CHECK_NULL_RETURN(targetNode, false);
359 CHECK_NULL_RETURN(desNode, false);
360 node = targetNode;
361 auto pattern = desNode->GetPattern<NG::NavDestinationPattern>();
362 if (pattern) {
363 pattern->SetName(homePathInfo_.value().name);
364 pattern->SetIndex(-1);
365 auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(homePathInfo_.value().name, homePathInfo_.value().param);
366 pattern->SetNavPathInfo(pathInfo);
367 pattern->SetNavigationStack(WeakClaim(this));
368 }
369 homeDestinationNode_ = WeakPtr(desNode);
370 return true;
371 }
372
CreateNodeByIndex(int32_t index,const WeakPtr<NG::UINode> & customNode,RefPtr<NG::UINode> & node)373 bool JSNavigationStack::CreateNodeByIndex(int32_t index, const WeakPtr<NG::UINode>& customNode,
374 RefPtr<NG::UINode>& node)
375 {
376 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
377 auto pathInfo = GetJsPathInfo(index);
378 if (pathInfo->IsEmpty()) {
379 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "create node failed, pathInfo is null");
380 return false;
381 }
382 auto name = pathInfo->GetPropertyValue<std::string>("name", "");
383 auto param = pathInfo->GetProperty("param");
384 RefPtr<NG::UINode> targetNode;
385 RefPtr<NG::NavDestinationGroupNode> desNode;
386 NG::ScopedViewStackProcessor scopedViewStackProcessor;
387 int32_t errorCode = LoadDestination(name, param, customNode, targetNode, desNode);
388 if (errorCode == ERROR_CODE_NO_ERROR && desNode) {
389 auto navDestinationPattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
390 if (navDestinationPattern) {
391 SetDestinationIdToJsStack(index, std::to_string(navDestinationPattern->GetNavDestinationId()));
392 }
393 }
394 // isRemove true, set destination info, false, current destination create failed
395 bool isRemove = RemoveDestinationIfNeeded(pathInfo, errorCode, index);
396 if (!isRemove) {
397 return false;
398 }
399 if (errorCode != ERROR_CODE_NO_ERROR) {
400 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "can't find target destination by index, create empty node");
401 node = AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
402 GetNavDestinationNodeInUINode(node, desNode);
403 CHECK_NULL_RETURN(desNode, true);
404 auto navDestinationPattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
405 CHECK_NULL_RETURN(navDestinationPattern, true);
406 SetDestinationIdToJsStack(index, std::to_string(navDestinationPattern->GetNavDestinationId()));
407 return true;
408 }
409 node = targetNode;
410 auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
411 if (pattern) {
412 pattern->SetName(name);
413 pattern->SetIndex(index);
414 auto onPop = GetOnPopByIndex(index);
415 auto isEntry = GetIsEntryByIndex(index);
416 TAG_LOGD(AceLogTag::ACE_NAVIGATION, "create destination node, isEntry %{public}d", isEntry);
417 auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
418 pattern->SetNavPathInfo(pathInfo);
419 pattern->SetNavigationStack(WeakClaim(this));
420 }
421 return true;
422 }
423
CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo> & routeInfo,const WeakPtr<NG::UINode> & customNode)424 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo>& routeInfo,
425 const WeakPtr<NG::UINode>& customNode)
426 {
427 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
428 auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
429 if (!jsRouteInfo) {
430 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "route info is invalid");
431 return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
432 }
433 auto name = jsRouteInfo->GetName();
434 auto param = jsRouteInfo->GetParam();
435 RefPtr<NG::UINode> node;
436 RefPtr<NG::NavDestinationGroupNode> desNode;
437 int32_t errorCode = LoadDestination(name, param, customNode, node, desNode);
438 if (errorCode == ERROR_CODE_NO_ERROR) {
439 auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
440 if (pattern) {
441 auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param);
442 pattern->SetNavPathInfo(pathInfo);
443 pattern->SetName(name);
444 pattern->SetNavigationStack(WeakClaim(this));
445 }
446 return node;
447 }
448 return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
449 }
450
SetJSExecutionContext(const JSExecutionContext & context)451 void JSNavigationStack::SetJSExecutionContext(const JSExecutionContext& context)
452 {
453 executionContext_ = context;
454 }
455
GetNameByIndex(int32_t index)456 std::string JSNavigationStack::GetNameByIndex(int32_t index)
457 {
458 auto pathNames = GetAllPathName();
459 if (index < 0 || index >= static_cast<int32_t>(pathNames.size())) {
460 return "";
461 }
462
463 return pathNames[index];
464 }
465
GetParamByIndex(int32_t index) const466 JSRef<JSVal> JSNavigationStack::GetParamByIndex(int32_t index) const
467 {
468 if (dataSourceObj_->IsEmpty()) {
469 return JSRef<JSVal>::Make();
470 }
471 auto getParamByIndexFunc = dataSourceObj_->GetProperty("getParamByIndex");
472 if (!getParamByIndexFunc->IsFunction()) {
473 return JSRef<JSVal>::Make();
474 }
475 auto func = JSRef<JSFunc>::Cast(getParamByIndexFunc);
476 JSRef<JSVal> params[1];
477 params[0] = JSRef<JSVal>::Make(ToJSValue(index));
478 return func->Call(dataSourceObj_, 1, params);
479 }
480
GetOnPopByIndex(int32_t index) const481 JSRef<JSVal> JSNavigationStack::GetOnPopByIndex(int32_t index) const
482 {
483 if (dataSourceObj_->IsEmpty()) {
484 return JSRef<JSVal>::Make();
485 }
486 auto getOnPopByIndexFunc = dataSourceObj_->GetProperty("getOnPopByIndex");
487 if (!getOnPopByIndexFunc->IsFunction()) {
488 return JSRef<JSVal>::Make();
489 }
490 auto func = JSRef<JSFunc>::Cast(getOnPopByIndexFunc);
491 JSRef<JSVal> params[1];
492 params[0] = JSRef<JSVal>::Make(ToJSValue(index));
493 return func->Call(dataSourceObj_, 1, params);
494 }
495
GetIsEntryByIndex(int32_t index)496 bool JSNavigationStack::GetIsEntryByIndex(int32_t index)
497 {
498 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
499 if (dataSourceObj_->IsEmpty()) {
500 return false;
501 }
502 auto getIsEntryFunc = dataSourceObj_->GetProperty("getIsEntryByIndex");
503 if (!getIsEntryFunc->IsFunction()) {
504 return false;
505 }
506 auto func = JSRef<JSFunc>::Cast(getIsEntryFunc);
507 JSRef<JSVal> params[1];
508 params[0] = JSRef<JSVal>::Make(ToJSValue(index));
509 auto result = func->Call(dataSourceObj_, 1, params);
510 if (!result->IsBoolean()) {
511 return false;
512 }
513 return result->ToBoolean();
514 }
515
SetIsEntryByIndex(int32_t index,bool isEntry)516 void JSNavigationStack::SetIsEntryByIndex(int32_t index, bool isEntry)
517 {
518 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
519 if (dataSourceObj_->IsEmpty()) {
520 return;
521 }
522 auto setIsEntryFunc = dataSourceObj_->GetProperty("setIsEntryByIndex");
523 if (!setIsEntryFunc->IsFunction()) {
524 return;
525 }
526 auto func = JSRef<JSFunc>::Cast(setIsEntryFunc);
527 JSRef<JSVal> params[ARGC_COUNT_TWO];
528 params[0] = JSRef<JSVal>::Make(ToJSValue(index));
529 params[1] = JSRef<JSVal>::Make(ToJSValue(isEntry));
530 func->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
531 }
532
GetNavDestinationNodeInUINode(RefPtr<NG::UINode> node,RefPtr<NG::NavDestinationGroupNode> & desNode)533 bool JSNavigationStack::GetNavDestinationNodeInUINode(
534 RefPtr<NG::UINode> node, RefPtr<NG::NavDestinationGroupNode>& desNode)
535 {
536 RefPtr<NG::CustomNode> customNode;
537 while (node) {
538 if (node->GetTag() == V2::JS_VIEW_ETS_TAG) {
539 customNode = AceType::DynamicCast<NG::CustomNode>(node);
540 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "render current custom node: %{public}s",
541 customNode->GetCustomTag().c_str());
542 // record parent navigationNode before customNode is rendered in case of navDestinationNode
543 auto navigationNode = GetNavigationNode();
544 customNode->SetNavigationNode(navigationNode);
545 // render, and find deep further
546 customNode->Render();
547 } else if (node->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
548 desNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(node);
549 if (desNode) {
550 desNode->SetNavDestinationCustomNode(AceType::WeakClaim(AceType::RawPtr(customNode)));
551 }
552 return true;
553 }
554 auto children = node->GetChildren();
555 node = children.front();
556 }
557 return false;
558 }
559
GetReplaceValue() const560 int32_t JSNavigationStack::GetReplaceValue() const
561 {
562 if (dataSourceObj_->IsEmpty()) {
563 return false;
564 }
565 auto replace = dataSourceObj_->GetProperty("isReplace");
566 return replace->ToNumber<int32_t>();
567 }
568
UpdateReplaceValue(int32_t replaceValue) const569 void JSNavigationStack::UpdateReplaceValue(int32_t replaceValue) const
570 {
571 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
572 if (dataSourceObj_->IsEmpty()) {
573 return;
574 }
575 auto setIsReplaceFunc = dataSourceObj_->GetProperty("setIsReplace");
576 if (!setIsReplaceFunc->IsFunction()) {
577 return;
578 }
579 auto replaceFunc = JSRef<JSFunc>::Cast(setIsReplaceFunc);
580 JSRef<JSVal> params[1];
581 params[0] = JSRef<JSVal>::Make(ToJSValue(replaceValue));
582 replaceFunc->Call(dataSourceObj_, 1, params);
583 }
584
GetRouteParam() const585 std::string JSNavigationStack::GetRouteParam() const
586 {
587 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, "");
588 auto size = GetSize();
589 if (size > 0) {
590 auto param = GetParamByIndex(size - 1);
591 return ConvertParamToString(param, true);
592 }
593 return "";
594 }
595
GetSize() const596 int32_t JSNavigationStack::GetSize() const
597 {
598 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, 0);
599 if (dataSourceObj_->IsEmpty()) {
600 return 0;
601 }
602 auto sizeFunc = dataSourceObj_->GetProperty("size");
603 if (!sizeFunc->IsFunction()) {
604 return 0;
605 }
606 auto func = JSRef<JSFunc>::Cast(sizeFunc);
607 auto jsValue = JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
608 if (jsValue->IsNumber()) {
609 return jsValue->ToNumber<int32_t>();
610 }
611 return 0;
612 }
613
ConvertParamToString(const JSRef<JSVal> & param,bool needLimit) const614 std::string JSNavigationStack::ConvertParamToString(const JSRef<JSVal>& param, bool needLimit) const
615 {
616 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, "");
617 if (param->IsBoolean()) {
618 bool ret = param->ToBoolean();
619 return ret ? "true" : "false";
620 } else if (param->IsNumber()) {
621 double ret = param->ToNumber<double>();
622 std::ostringstream oss;
623 oss << ret;
624 return oss.str();
625 } else if (param->IsString()) {
626 std::string ret = param->ToString();
627 if (needLimit && ret.size() > MAX_PARSE_LENGTH) {
628 return ret.substr(0, MAX_PARSE_LENGTH);
629 }
630 return ret;
631 } else if (param->IsObject()) {
632 JSRef<JSObject> obj = JSRef<JSObject>::Cast(param);
633 auto jsonObj = JsonUtil::Create(true);
634 ParseJsObject(jsonObj, obj, MAX_PARSE_DEPTH, needLimit);
635 return jsonObj->ToString();
636 }
637 return "";
638 }
639
ParseJsObject(std::unique_ptr<JsonValue> & json,const JSRef<JSObject> & obj,int32_t depthLimit,bool needLimit) const640 void JSNavigationStack::ParseJsObject(
641 std::unique_ptr<JsonValue>& json, const JSRef<JSObject>& obj, int32_t depthLimit, bool needLimit) const
642 {
643 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
644 if (depthLimit == 0) {
645 return;
646 }
647 depthLimit--;
648 auto propertyNames = obj->GetPropertyNames();
649 if (!propertyNames->IsArray()) {
650 return;
651 }
652 size_t size = propertyNames->Length();
653 if (needLimit && size > MAX_PARSE_PROPERTY_SIZE) {
654 size = MAX_PARSE_PROPERTY_SIZE;
655 }
656 for (size_t i = 0; i < size; i++) {
657 JSRef<JSVal> name = propertyNames->GetValueAt(i);
658 if (!name->IsString()) {
659 continue;
660 }
661 auto propertyName = name->ToString();
662 auto key = propertyName.c_str();
663 JSRef<JSVal> value = obj->GetProperty(key);
664 if (value->IsBoolean()) {
665 bool ret = value->ToBoolean();
666 json->Put(key, ret ? "true" : "false");
667 } else if (value->IsNumber()) {
668 double ret = value->ToNumber<double>();
669 std::ostringstream oss;
670 oss << ret;
671 json->Put(key, oss.str().c_str());
672 } else if (value->IsString()) {
673 std::string ret = value->ToString();
674 if (needLimit && ret.size() > MAX_PARSE_LENGTH) {
675 json->Put(key, ret.substr(0, MAX_PARSE_LENGTH).c_str());
676 } else {
677 json->Put(key, ret.c_str());
678 }
679 } else if (value->IsObject()) {
680 JSRef<JSObject> childObj = JSRef<JSObject>::Cast(value);
681 auto childJson = JsonUtil::Create(true);
682 ParseJsObject(childJson, childObj, depthLimit, needLimit);
683 json->Put(key, childJson);
684 }
685 }
686 }
687
GetAnimatedValue() const688 bool JSNavigationStack::GetAnimatedValue() const
689 {
690 if (dataSourceObj_->IsEmpty()) {
691 return true;
692 }
693 auto animated = dataSourceObj_->GetProperty("animated");
694 return animated->ToBoolean();
695 }
696
UpdateAnimatedValue(bool animated)697 void JSNavigationStack::UpdateAnimatedValue(bool animated)
698 {
699 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
700 if (dataSourceObj_->IsEmpty()) {
701 return;
702 }
703 auto setAnimatedFunc = dataSourceObj_->GetProperty("setAnimated");
704 if (!setAnimatedFunc->IsFunction()) {
705 return;
706 }
707 auto animatedFunc = JSRef<JSFunc>::Cast(setAnimatedFunc);
708 JSRef<JSVal> params[1];
709 params[0] = JSRef<JSVal>::Make(ToJSValue(animated));
710 animatedFunc->Call(dataSourceObj_, 1, params);
711 }
712
713
GetDisableAnimation() const714 bool JSNavigationStack::GetDisableAnimation() const
715 {
716 if (dataSourceObj_->IsEmpty()) {
717 return false;
718 }
719 auto disableAllAnimation = dataSourceObj_->GetProperty("disableAllAnimation");
720 return disableAllAnimation->ToBoolean();
721 }
722
UpdateOnStateChangedCallback(JSRef<JSObject> obj,std::function<void ()> callback)723 void JSNavigationStack::UpdateOnStateChangedCallback(JSRef<JSObject> obj, std::function<void()> callback)
724 {
725 if (obj->IsEmpty()) {
726 return;
727 }
728
729 auto property = obj->GetProperty(JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC);
730 if (!property->IsFunction()) {
731 return;
732 }
733
734 auto getNativeStackFunc = JSRef<JSFunc>::Cast(property);
735 auto nativeStack = getNativeStackFunc->Call(obj);
736 if (nativeStack->IsEmpty() || !nativeStack->IsObject()) {
737 return;
738 }
739
740 auto nativeStackObj = JSRef<JSObject>::Cast(nativeStack);
741 JSNavPathStack* stack = nativeStackObj->Unwrap<JSNavPathStack>();
742 CHECK_NULL_VOID(stack);
743 stack->SetOnStateChangedCallback(callback);
744 // When switching the navigation stack, it is necessary to immediately trigger a refresh
745 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation necessary to immediately trigger a refresh");
746 stack->OnStateChanged();
747 stack->SetOnPopCallback([weakStack = AceType::WeakClaim(this)](const JSRef<JSVal>& param) {
748 auto navigationStack = weakStack.Upgrade();
749 CHECK_NULL_VOID(navigationStack);
750 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(navigationStack->executionContext_);
751 // Firstly, check if there is a NavDestination in the stack that can respond to pop/popToIndex/popToName
752 if (navigationStack->ExecutePopCallbackInStack(param)) {
753 return;
754 }
755 // Otherwise, check if there is a home NavDestination that can respond to pop/popToIndex/popToName
756 navigationStack->ExecutePopCallbackForHomeNavDestination(param);
757 });
758 stack->SetIsHomeNameCallback([weakStack = AceType::WeakClaim(this)](const std::string& name) -> bool {
759 auto navigationStack = weakStack.Upgrade();
760 CHECK_NULL_RETURN(navigationStack, false);
761 if (!navigationStack->homePathInfo_.has_value()) {
762 return false;
763 }
764 return navigationStack->homePathInfo_.value().name == name;
765 });
766 }
767
ExecutePopCallbackInStack(const JSRef<JSVal> & param)768 bool JSNavigationStack::ExecutePopCallbackInStack(const JSRef<JSVal>& param)
769 {
770 auto size = GetSize();
771 if (size == 0) {
772 return false;
773 }
774 auto pathInfo = GetJsPathInfo(size - 1);
775 if (pathInfo->IsEmpty()) {
776 return false;
777 }
778 auto navDestinationId = pathInfo->GetProperty("navDestinationId");
779 if (!navDestinationId->IsString()) {
780 return false;
781 }
782 auto id = navDestinationId->ToString();
783 auto navPathList = GetAllNavDestinationNodes();
784 for (auto iter : navPathList) {
785 if (ExecutePopCallback(iter.second, std::atoi(id.c_str()), param)) {
786 return true;
787 }
788 }
789 return false;
790 }
791
ExecutePopCallbackForHomeNavDestination(const JSRef<JSVal> & param)792 void JSNavigationStack::ExecutePopCallbackForHomeNavDestination(const JSRef<JSVal>& param)
793 {
794 auto homeDest = homeDestinationNode_.Upgrade();
795 CHECK_NULL_VOID(homeDest);
796 auto destPattern = homeDest->GetPattern<NG::NavDestinationPattern>();
797 CHECK_NULL_VOID(destPattern);
798 ExecutePopCallback(homeDest, destPattern->GetNavDestinationId(), param);
799 }
800
OnAttachToParent(RefPtr<NG::NavigationStack> parent)801 void JSNavigationStack::OnAttachToParent(RefPtr<NG::NavigationStack> parent)
802 {
803 auto parentStack = AceType::DynamicCast<JSNavigationStack>(parent);
804 if (!parentStack) {
805 return;
806 }
807
808 SetJSParentStack(JSRef<JSVal>::Cast(parentStack->GetDataSourceObj()));
809 }
810
OnDetachFromParent()811 void JSNavigationStack::OnDetachFromParent()
812 {
813 JSRef<JSVal> undefined(JSVal::Undefined());
814 SetJSParentStack(undefined);
815 }
816
SetJSParentStack(JSRef<JSVal> parent)817 void JSNavigationStack::SetJSParentStack(JSRef<JSVal> parent)
818 {
819 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
820 if (dataSourceObj_->IsEmpty()) {
821 return;
822 }
823
824 auto property = dataSourceObj_->GetProperty(JS_NAV_PATH_STACK_SETPARENT_FUNC);
825 if (!property->IsFunction()) {
826 return;
827 }
828
829 auto func = JSRef<JSFunc>::Cast(property);
830 JSRef<JSVal> params[1];
831 params[0] = parent;
832 func->Call(dataSourceObj_, 1, params);
833 }
834
RemoveInvalidPage(int32_t index)835 void JSNavigationStack::RemoveInvalidPage(int32_t index)
836 {
837 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
838 if (dataSourceObj_->IsEmpty()) {
839 return;
840 }
841 auto removeInvalidPage = dataSourceObj_->GetProperty("removeInvalidPage");
842 if (removeInvalidPage->IsFunction()) {
843 auto func = JSRef<JSFunc>::Cast(removeInvalidPage);
844 JSRef<JSVal> params[1] = { JSRef<JSVal>::Make(ToJSValue(index)) };
845 func->Call(dataSourceObj_, 1, params);
846 }
847 }
848
DumpStackInfo() const849 std::vector<std::string> JSNavigationStack::DumpStackInfo() const
850 {
851 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
852 std::vector<std::string> dumpInfos;
853 for (size_t i = 0; i < navPathList_.size(); ++i) {
854 const auto& name = navPathList_[i].first;
855 std::string info = "[" + std::to_string(i) + "]{ name: \"" + name + "\"";
856 std::string param = ConvertParamToString(GetParamByIndex(i));
857 if (param.length() > 0) {
858 info += ", param: " + param;
859 }
860 info += " }";
861 dumpInfos.push_back(std::move(info));
862 }
863 return dumpInfos;
864 }
865
FireNavigationInterception(bool isBefore,const RefPtr<NG::NavDestinationContext> & from,const RefPtr<NG::NavDestinationContext> & to,NG::NavigationOperation operation,bool isAnimated)866 void JSNavigationStack::FireNavigationInterception(bool isBefore, const RefPtr<NG::NavDestinationContext>& from,
867 const RefPtr<NG::NavDestinationContext>& to, NG::NavigationOperation operation, bool isAnimated)
868 {
869 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
870 std::string targetName = isBefore ? "willShow" : "didShow";
871 JSRef<JSFunc> targetFunc;
872 if (!CheckAndGetInterceptionFunc(targetName, targetFunc)) {
873 return;
874 }
875 const uint8_t argsNum = 4;
876 JSRef<JSVal> params[argsNum];
877 auto preDestination = AceType::DynamicCast<NG::NavDestinationContext>(from);
878 if (!preDestination) {
879 params[0] = JSRef<JSVal>::Make(ToJSValue("navBar"));
880 } else if (preDestination->GetIsEmpty()) {
881 params[0] = JSRef<JSObject>::New();
882 } else {
883 JSRef<JSObject> preObj = JSClass<JSNavDestinationContext>::NewInstance();
884 auto preProxy = Referenced::Claim(preObj->Unwrap<JSNavDestinationContext>());
885 preProxy->SetNavDestinationContext(from);
886 params[0] = preObj;
887 }
888
889 auto topDestination = AceType::DynamicCast<NG::NavDestinationContext>(to);
890 if (!topDestination) {
891 params[1] = JSRef<JSVal>::Make(ToJSValue("navBar"));
892 } else if (topDestination->GetIsEmpty()) {
893 params[1] = JSRef<JSObject>::New();
894 } else {
895 JSRef<JSObject> topObj = JSClass<JSNavDestinationContext>::NewInstance();
896 auto topProxy = Referenced::Claim(topObj->Unwrap<JSNavDestinationContext>());
897 topProxy->SetNavDestinationContext(to);
898 params[1] = topObj;
899 }
900 const uint8_t operationIndex = 2;
901 params[operationIndex] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(operation)));
902 const uint8_t animatedIndex = 3;
903 params[animatedIndex] = JSRef<JSVal>::Make(ToJSValue(isAnimated));
904 targetFunc->Call(JSRef<JSObject>(), argsNum, params);
905 }
906
FireNavigationModeChange(NG::NavigationMode mode)907 void JSNavigationStack::FireNavigationModeChange(NG::NavigationMode mode)
908 {
909 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
910 JSRef<JSFunc> modeFunc;
911 if (!CheckAndGetInterceptionFunc("modeChange", modeFunc)) {
912 return;
913 }
914 JSRef<JSVal> params[1];
915 params[0] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(mode)));
916 modeFunc->Call(JSRef<JSObject>(), 1, params);
917 }
918
CheckAndGetInterceptionFunc(const std::string & name,JSRef<JSFunc> & func)919 bool JSNavigationStack::CheckAndGetInterceptionFunc(const std::string& name, JSRef<JSFunc>& func)
920 {
921 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
922 if (dataSourceObj_->IsEmpty()) {
923 return false;
924 }
925 JSRef<JSVal> delegateProp = dataSourceObj_->GetProperty("interception");
926 if (!delegateProp->IsObject()) {
927 return false;
928 }
929 JSRef<JSObject> delegate = JSRef<JSObject>::Cast(delegateProp);
930 JSRef<JSVal> funcProp = delegate->GetProperty(name.c_str());
931 if (!funcProp->IsFunction()) {
932 return false;
933 }
934 func = JSRef<JSFunc>::Cast(funcProp);
935 return true;
936 }
937
LoadDestinationByBuilder(const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node,RefPtr<NG::NavDestinationGroupNode> & desNode)938 bool JSNavigationStack::LoadDestinationByBuilder(const std::string& name, const JSRef<JSVal>& param,
939 RefPtr<NG::UINode>& node, RefPtr<NG::NavDestinationGroupNode>& desNode)
940 {
941 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
942 if (navDestBuilderFunc_->IsEmpty()) {
943 TAG_LOGW(AceLogTag::ACE_NAVIGATION, "Builder function is empty");
944 return false;
945 }
946 auto builderObj = JSRef<JSObject>::Cast(navDestBuilderFunc_);
947 const int32_t number = builderObj->GetProperty("length")->ToNumber<int32_t>();
948 JSRef<JSVal> params[number];
949 if (number >= 1) {
950 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
951 }
952 if (number >= ARGC_COUNT_TWO) {
953 params[1] = param;
954 }
955 navDestBuilderFunc_->Call(JSRef<JSObject>(), number, params);
956 node = NG::ViewStackProcessor::GetInstance()->Finish();
957 return GetNavDestinationNodeInUINode(node, desNode);
958 }
959
LoadDestination(const std::string & name,const JSRef<JSVal> & param,const WeakPtr<NG::UINode> & customNode,RefPtr<NG::UINode> & node,RefPtr<NG::NavDestinationGroupNode> & desNode)960 int32_t JSNavigationStack::LoadDestination(const std::string& name, const JSRef<JSVal>& param,
961 const WeakPtr<NG::UINode>& customNode, RefPtr<NG::UINode>& node,
962 RefPtr<NG::NavDestinationGroupNode>& desNode)
963 {
964 NG::ScopedViewStackProcessor scopedViewStackProcessor;
965 // execute navdestination attribute builder
966 if (LoadDestinationByBuilder(name, param, node, desNode)) {
967 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "load destination by buildermap");
968 return ERROR_CODE_NO_ERROR;
969 }
970 // deal route config and execute route config builder
971 auto container = Container::Current();
972 CHECK_NULL_RETURN(container, ERROR_CODE_INTERNAL_ERROR);
973 auto navigationRoute = container->GetNavigationRoute();
974 if (!navigationRoute) {
975 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation route is invalid");
976 return ERROR_CODE_INTERNAL_ERROR;
977 }
978 if (!navigationRoute->HasLoaded(name) && navigationRoute->LoadPage(name) != 0) {
979 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "load page failed: %{public}s", name.c_str());
980 return navDestBuilderFunc_->IsEmpty() ? ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED
981 : ERROR_CODE_DESTINATION_NOT_FOUND;
982 }
983 int32_t result = ExecuteBuilderByConfig(name, customNode, param);
984 if (result != ERROR_CODE_NO_ERROR) {
985 return result;
986 }
987 node = NG::ViewStackProcessor::GetInstance()->Finish();
988 if (!GetNavDestinationNodeInUINode(node, desNode)) {
989 return ERROR_CODE_DESTINATION_NOT_FOUND;
990 }
991 return ERROR_CODE_NO_ERROR;
992 }
993
ExecuteBuilderByConfig(const std::string & name,const WeakPtr<NG::UINode> & customNode,const JSRef<JSVal> & param)994 int32_t JSNavigationStack::ExecuteBuilderByConfig(const std::string& name,
995 const WeakPtr<NG::UINode>& customNode, const JSRef<JSVal>& param)
996 {
997 auto parentCustomNode = AceType::DynamicCast<NG::CustomNode>(customNode.Upgrade());
998 CHECK_NULL_RETURN(parentCustomNode, ERROR_CODE_INTERNAL_ERROR);
999 auto thisObjTmp = parentCustomNode->FireThisFunc();
1000 CHECK_NULL_RETURN(thisObjTmp, ERROR_CODE_INTERNAL_ERROR);
1001 JSRef<JSObject> thisObj = *(JSRef<JSObject>*)(thisObjTmp);
1002 auto engine = AceType::DynamicCast<Framework::JsiDeclarativeEngine>(EngineHelper::GetCurrentEngine());
1003 CHECK_NULL_RETURN(engine, ERROR_CODE_INTERNAL_ERROR);
1004 JSRef<JSObject> wrapBuilder = JSRef<JSObject>::Make(engine->GetNavigationBuilder(name).ToLocal());
1005 if (wrapBuilder->IsEmpty()) {
1006 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "wrap builder is empty: %{public}s", name.c_str());
1007 return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
1008 }
1009 auto builderProp = wrapBuilder->GetProperty("builder");
1010 if (!builderProp->IsFunction()) {
1011 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get builder failed: %{public}s", name.c_str());
1012 return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
1013 }
1014 auto builderObj = JSRef<JSObject>::Cast(builderProp);
1015 const int32_t number = builderObj->GetProperty("length")->ToNumber<int32_t>();
1016 JSRef<JSVal> params[number];
1017 if (number >= 1) {
1018 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
1019 }
1020 if (number >= ARGC_COUNT_TWO) {
1021 params[1] = param;
1022 }
1023 auto builder = JSRef<JSFunc>::Cast(builderProp);
1024 builder->Call(thisObj, number, params);
1025 return ERROR_CODE_NO_ERROR;
1026 }
1027
GetJsIndexFromNativeIndex(int32_t index)1028 int32_t JSNavigationStack::GetJsIndexFromNativeIndex(int32_t index)
1029 {
1030 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, -1);
1031 if (dataSourceObj_->IsEmpty()) {
1032 return -1;
1033 }
1034 auto getIndexFunc = dataSourceObj_->GetProperty("getJsIndexFromNativeIndex");
1035 if (!getIndexFunc->IsFunction()) {
1036 return -1;
1037 }
1038 auto func = JSRef<JSFunc>::Cast(getIndexFunc);
1039 JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(index));
1040 auto res = func->Call(dataSourceObj_, 1, ¶m);
1041 if (res->IsNumber()) {
1042 return res->ToNumber<int32_t>();
1043 }
1044 return -1;
1045 }
1046
MoveIndexToTop(int32_t index)1047 void JSNavigationStack::MoveIndexToTop(int32_t index)
1048 {
1049 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1050 if (dataSourceObj_->IsEmpty()) {
1051 return;
1052 }
1053 auto moveIndexToTopFunc = dataSourceObj_->GetProperty("moveIndexToTop");
1054 if (!moveIndexToTopFunc->IsFunction()) {
1055 return;
1056 }
1057 auto func = JSRef<JSFunc>::Cast(moveIndexToTopFunc);
1058 JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(index));
1059 func->Call(dataSourceObj_, 1, ¶m);
1060 }
1061
UpdatePathInfoIfNeeded(RefPtr<NG::UINode> & uiNode,int32_t index)1062 void JSNavigationStack::UpdatePathInfoIfNeeded(RefPtr<NG::UINode>& uiNode, int32_t index)
1063 {
1064 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1065 bool needUpdate = GetNeedUpdatePathInfo(index);
1066 if (!needUpdate) {
1067 return;
1068 }
1069 SetNeedUpdatePathInfo(index, false);
1070 RefPtr<NG::NavDestinationGroupNode> desNode;
1071 if (!GetNavDestinationNodeInUINode(uiNode, desNode)) {
1072 return;
1073 }
1074 auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
1075 if (!pattern) {
1076 return;
1077 }
1078
1079 auto name = GetNameByIndex(index);
1080 auto param = GetParamByIndex(index);
1081 auto onPop = GetOnPopByIndex(index);
1082 auto isEntry = GetIsEntryByIndex(index);
1083 TAG_LOGD(AceLogTag::ACE_NAVIGATION, "update destination node info, isEntry %{public}d", isEntry);
1084 auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
1085 pattern->SetNavPathInfo(pathInfo);
1086 }
1087
GetNeedUpdatePathInfo(int32_t index)1088 bool JSNavigationStack::GetNeedUpdatePathInfo(int32_t index)
1089 {
1090 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1091 auto path = GetJsPathInfo(index);
1092 if (path->IsEmpty()) {
1093 return false;
1094 }
1095 auto needUpdate = path->GetProperty("needUpdate");
1096 if (!needUpdate->IsBoolean()) {
1097 return false;
1098 }
1099 return needUpdate->ToBoolean();
1100 }
1101
SetNeedUpdatePathInfo(int32_t index,bool need)1102 void JSNavigationStack::SetNeedUpdatePathInfo(int32_t index, bool need)
1103 {
1104 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1105 auto path = GetJsPathInfo(index);
1106 if (path->IsEmpty()) {
1107 return;
1108 }
1109 path->SetProperty<bool>("needUpdate", need);
1110 }
1111
RecoveryNavigationStack()1112 void JSNavigationStack::RecoveryNavigationStack()
1113 {
1114 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1115 navPathList_ = preNavPathList_;
1116 if (dataSourceObj_->IsEmpty()) {
1117 return;
1118 }
1119 JSRef<JSArray> pathArray = JSRef<JSArray>::New();
1120 for (int32_t index = 0; index < static_cast<int32_t>(navPathList_.size()); index++) {
1121 auto node = navPathList_[index].second;
1122 auto navDestinationGroupNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(
1123 NG::NavigationGroupNode::GetNavDestinationNode(node));
1124 if (!navDestinationGroupNode) {
1125 continue;
1126 }
1127 auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(navDestinationGroupNode->GetPattern());
1128 if (!pattern) {
1129 continue;
1130 }
1131 auto context = pattern->GetNavDestinationContext();
1132 if (!context) {
1133 continue;
1134 }
1135 JSRef<JSObject> item = CreatePathInfoWithNecessaryProperty(context);
1136 pathArray->SetValueAt(index, item);
1137 }
1138 dataSourceObj_->SetPropertyObject("pathArray", pathArray);
1139 }
1140
NeedBuildNewInstance(int32_t index)1141 bool JSNavigationStack::NeedBuildNewInstance(int32_t index)
1142 {
1143 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1144 auto pathInfo = GetJsPathInfo(index);
1145 if (pathInfo->IsEmpty()) {
1146 return false;
1147 }
1148 auto needBuildNewInstance = pathInfo->GetProperty("needBuildNewInstance");
1149 if (!needBuildNewInstance->IsBoolean()) {
1150 return false;
1151 }
1152 return needBuildNewInstance->ToBoolean();
1153 }
1154
SetNeedBuildNewInstance(int32_t index,bool need)1155 void JSNavigationStack::SetNeedBuildNewInstance(int32_t index, bool need)
1156 {
1157 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1158 auto pathInfo = GetJsPathInfo(index);
1159 if (pathInfo->IsEmpty()) {
1160 return;
1161 }
1162 pathInfo->SetProperty<bool>("needBuildNewInstance", need);
1163 }
1164
GetJsPathArray() const1165 JSRef<JSArray> JSNavigationStack::GetJsPathArray() const
1166 {
1167 if (dataSourceObj_->IsEmpty()) {
1168 return JSRef<JSArray>();
1169 }
1170 auto objArray = dataSourceObj_->GetProperty("pathArray");
1171 if (!objArray->IsArray()) {
1172 TAG_LOGW(AceLogTag::ACE_NAVIGATION, "navPathArray invalid!");
1173 return JSRef<JSArray>();
1174 }
1175 return JSRef<JSArray>::Cast(objArray);
1176 }
1177
GetJsPathInfo(int32_t index) const1178 JSRef<JSObject> JSNavigationStack::GetJsPathInfo(int32_t index) const
1179 {
1180 auto navPathArray = GetJsPathArray();
1181 int32_t len = static_cast<int32_t>(navPathArray->Length());
1182 if (index < 0 || index >= len) {
1183 return JSRef<JSObject>();
1184 }
1185 auto pathInfo = navPathArray->GetValueAt(index);
1186 if (!pathInfo->IsObject()) {
1187 return JSRef<JSObject>();
1188 }
1189 return JSRef<JSObject>::Cast(pathInfo);
1190 }
1191
CreatePathInfoWithNecessaryProperty(const RefPtr<NG::NavDestinationContext> & context)1192 JSRef<JSObject> JSNavigationStack::CreatePathInfoWithNecessaryProperty(
1193 const RefPtr<NG::NavDestinationContext>& context)
1194 {
1195 auto pathInfo = JSRef<JSObject>::New();
1196 CHECK_NULL_RETURN(context, pathInfo);
1197 auto jsPathInfo = AceType::DynamicCast<JSNavPathInfo>(context->GetNavPathInfo());
1198 CHECK_NULL_RETURN(jsPathInfo, pathInfo);
1199
1200 pathInfo->SetProperty<std::string>("name", jsPathInfo->GetName());
1201 pathInfo->SetProperty<int32_t>("index", context->GetIndex());
1202 pathInfo->SetProperty<std::string>("navDestinationId", std::to_string(context->GetNavDestinationId()));
1203 pathInfo->SetProperty<bool>("isEntry", jsPathInfo->GetIsEntry());
1204 pathInfo->SetPropertyObject("param", jsPathInfo->GetParam());
1205 pathInfo->SetPropertyObject("onPop", jsPathInfo->GetOnPop());
1206 return pathInfo;
1207 }
1208
GetStringifyParamByIndex(int32_t index) const1209 std::string JSNavigationStack::GetStringifyParamByIndex(int32_t index) const
1210 {
1211 auto env = GetNapiEnv();
1212 if (!env) {
1213 return JS_STRINGIFIED_UNDEFINED;
1214 }
1215 napi_handle_scope scope = nullptr;
1216 napi_open_handle_scope(env, &scope);
1217 if (scope == nullptr) {
1218 return JS_STRINGIFIED_UNDEFINED;
1219 }
1220 if (dataSourceObj_->IsEmpty()) {
1221 napi_close_handle_scope(env, scope);
1222 return JS_STRINGIFIED_UNDEFINED;
1223 }
1224 napi_value navPathStack = JsConverter::ConvertJsValToNapiValue(dataSourceObj_);
1225 napi_value getParamByIndex;
1226 napi_get_named_property(env, navPathStack, "getParamByIndex", &getParamByIndex);
1227 napi_value napiIndex;
1228 napi_create_int32(env, index, &napiIndex);
1229 napi_value param;
1230 napi_call_function(env, navPathStack, getParamByIndex, 1, &napiIndex, ¶m);
1231
1232 napi_value globalValue;
1233 napi_get_global(env, &globalValue);
1234 napi_value jsonClass;
1235 napi_get_named_property(env, globalValue, "JSON", &jsonClass);
1236 napi_value stringifyFunc;
1237 napi_get_named_property(env, jsonClass, "stringify", &stringifyFunc);
1238 napi_value stringifyParam;
1239 if (napi_call_function(env, jsonClass, stringifyFunc, 1, ¶m, &stringifyParam) != napi_ok) {
1240 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Can not stringify current param!");
1241 napi_get_and_clear_last_exception(env, &stringifyParam);
1242 napi_close_handle_scope(env, scope);
1243 return JS_STRINGIFIED_UNDEFINED;
1244 }
1245 size_t len = 0;
1246 napi_get_value_string_utf8(env, stringifyParam, nullptr, 0, &len);
1247 std::unique_ptr<char[]> paramChar = std::make_unique<char[]>(len + 1);
1248 napi_get_value_string_utf8(env, stringifyParam, paramChar.get(), len + 1, &len);
1249 napi_close_handle_scope(env, scope);
1250 return paramChar.get();
1251 }
1252
GetSerializedParamSafely(int32_t index) const1253 std::string JSNavigationStack::GetSerializedParamSafely(int32_t index) const
1254 {
1255 std::string serializedEmpty = "{}";
1256 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, serializedEmpty);
1257 auto getSerializedParamSafelyFunc = dataSourceObj_->GetProperty("getSerializedParamSafely");
1258 if (!getSerializedParamSafelyFunc->IsFunction()) {
1259 return serializedEmpty;
1260 }
1261 JSRef<JSVal> arg[1] = { JSRef<JSVal>::Make(ToJSValue(index)) };
1262 auto serializedParam = JSRef<JSFunc>::Cast(getSerializedParamSafelyFunc)->Call(dataSourceObj_, 1, arg);
1263 if (!serializedParam->IsString() || serializedParam->ToString().empty()) {
1264 TAG_LOGW(AceLogTag::ACE_NAVIGATION,
1265 "current navDestination(index: %{public}d)'s param can't be serialized or is empty!", index);
1266 }
1267 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "serialize navDestination param success! its index: %{public}d", index);
1268 return serializedParam->ToString();
1269 }
1270
SetPathArray(const std::vector<NG::NavdestinationRecoveryInfo> & navdestinationsInfo)1271 void JSNavigationStack::SetPathArray(const std::vector<NG::NavdestinationRecoveryInfo>& navdestinationsInfo)
1272 {
1273 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1274 JSRef<JSArray> newPathArray = JSRef<JSArray>::New();
1275 for (int32_t index = 0; index < static_cast<int32_t>(navdestinationsInfo.size()); ++index) {
1276 auto infoName = navdestinationsInfo[index].name;
1277 auto infoParam = navdestinationsInfo[index].param;
1278 auto infoMode = navdestinationsInfo[index].mode;
1279
1280 JSRef<JSObject> navPathInfo = JSRef<JSObject>::New();
1281 navPathInfo->SetProperty<std::string>("name", infoName);
1282 if (!infoParam.empty() && infoParam != JS_STRINGIFIED_UNDEFINED) {
1283 navPathInfo->SetPropertyObject("param", JSRef<JSObject>::New()->ToJsonObject(infoParam.c_str()));
1284 }
1285 navPathInfo->SetProperty<bool>("fromRecovery", true);
1286 navPathInfo->SetProperty<int32_t>("mode", infoMode);
1287 newPathArray->SetValueAt(index, navPathInfo);
1288 }
1289 dataSourceObj_->SetPropertyObject("pathArray", newPathArray);
1290 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Set navPathArray by recovery info success");
1291 }
1292
CallPushDestinationInner(const NG::NavdestinationRecoveryInfo & navdestinationsInfo)1293 void JSNavigationStack::CallPushDestinationInner(const NG::NavdestinationRecoveryInfo& navdestinationsInfo)
1294 {
1295 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1296 if (dataSourceObj_->IsEmpty()) {
1297 return;
1298 }
1299 auto pushNavDestinationFunc = dataSourceObj_->GetProperty("pushDestination");
1300 if (!pushNavDestinationFunc->IsFunction()) {
1301 return;
1302 }
1303 auto infoName = navdestinationsInfo.name;
1304 auto infoParam = navdestinationsInfo.param;
1305 auto infoMode = navdestinationsInfo.mode;
1306
1307 JSRef<JSObject> navPathInfo = JSRef<JSObject>::New();
1308 navPathInfo->SetProperty<std::string>("name", infoName);
1309 if (!infoParam.empty() && infoParam != JS_STRINGIFIED_UNDEFINED) {
1310 navPathInfo->SetPropertyObject("param", JSRef<JSObject>::New()->ToJsonObject(infoParam.c_str()));
1311 }
1312 navPathInfo->SetProperty<int32_t>("mode", infoMode);
1313
1314 auto func = JSRef<JSFunc>::Cast(pushNavDestinationFunc);
1315 JSRef<JSVal> arg[1];
1316 arg[0] = navPathInfo;
1317 func->Call(dataSourceObj_, 1, arg);
1318 }
1319
IsFromRecovery(int32_t index)1320 bool JSNavigationStack::IsFromRecovery(int32_t index)
1321 {
1322 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1323 auto pathInfo = GetJsPathInfo(index);
1324 if (pathInfo->IsEmpty()) {
1325 return false;
1326 }
1327 auto fromRecovery = pathInfo->GetProperty("fromRecovery");
1328 if (!fromRecovery->IsBoolean()) {
1329 return false;
1330 }
1331 return fromRecovery->ToBoolean();
1332 }
1333
SetFromRecovery(int32_t index,bool fromRecovery)1334 void JSNavigationStack::SetFromRecovery(int32_t index, bool fromRecovery)
1335 {
1336 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1337 auto pathInfo = GetJsPathInfo(index);
1338 if (pathInfo->IsEmpty()) {
1339 return;
1340 }
1341 pathInfo->SetProperty<bool>("fromRecovery", fromRecovery);
1342 }
1343
GetRecoveredDestinationMode(int32_t index)1344 int32_t JSNavigationStack::GetRecoveredDestinationMode(int32_t index)
1345 {
1346 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, 0);
1347 auto pathInfo = GetJsPathInfo(index);
1348 if (pathInfo->IsEmpty()) {
1349 return INVALID_DESTINATION_MODE;
1350 }
1351 auto mode = pathInfo->GetProperty("mode");
1352 if (!mode->IsNumber()) {
1353 return INVALID_DESTINATION_MODE;
1354 }
1355 return mode->ToNumber<int32_t>();
1356 }
1357
ErrorToMessage(int32_t code)1358 std::string JSNavigationStack::ErrorToMessage(int32_t code)
1359 {
1360 switch (code) {
1361 case ERROR_CODE_INTERNAL_ERROR:
1362 return "Internal error. Create NavDestination failed, probably caused by wrong UIContext.";
1363 case ERROR_CODE_DESTINATION_NOT_FOUND:
1364 return "NavDestination not found.";
1365 case ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED:
1366 return "Builder function not registered.";
1367 case ERROR_CODE_PARAM_INVALID:
1368 return "Paramter error.";
1369 default:
1370 return "Error code is not supported.";
1371 }
1372 }
1373
RemoveDestinationIfNeeded(const JSRef<JSObject> & pathInfo,int32_t errorCode,int32_t index)1374 bool JSNavigationStack::RemoveDestinationIfNeeded(const JSRef<JSObject>& pathInfo, int32_t errorCode, int32_t index)
1375 {
1376 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1377 if (!pathInfo->HasProperty("promise")) {
1378 // not use pushDestination, return true
1379 return true;
1380 }
1381 auto promise = pathInfo->GetProperty("promise");
1382 if (!promise->IsFunction()) {
1383 return true;
1384 }
1385 auto promiseFunc = JSRef<JSFunc>::Cast(promise);
1386 if (errorCode == ERROR_CODE_NO_ERROR) {
1387 JSRef<JSVal> params[1];
1388 params[0] = JSRef<JSVal>::Make(ToJSValue(errorCode));
1389 promiseFunc->Call(dataSourceObj_, 1, params);
1390 return true;
1391 }
1392 // push destination failed, remove page in pathStack
1393 RemoveInvalidPage(index);
1394 const int32_t argc = 2;
1395 JSRef<JSVal> params[argc];
1396 JSRef<JSObject> errorInfo = JSRef<JSObject>::New();
1397 params[0] = JSRef<JSVal>::Make(ToJSValue(errorCode));
1398 params[1] = JSRef<JSVal>::Make(ToJSValue(ErrorToMessage(errorCode)));
1399 promiseFunc->Call(dataSourceObj_, argc, params);
1400 return false;
1401 }
1402
CheckIsReplacedDestination(int32_t index,std::string & replacedName,int32_t & replacedIndex)1403 bool JSNavigationStack::CheckIsReplacedDestination(int32_t index, std::string& replacedName, int32_t& replacedIndex)
1404 {
1405 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1406 auto pathInfo = GetJsPathInfo(index);
1407 if (pathInfo->IsEmpty()) {
1408 return false;
1409 }
1410 auto recoveryFromReplaceDestination = pathInfo->GetProperty("recoveryFromReplaceDestination");
1411 if (!recoveryFromReplaceDestination->IsBoolean() || !recoveryFromReplaceDestination->ToBoolean()) {
1412 return false;
1413 }
1414 auto jsReplacedName = pathInfo->GetProperty("name");
1415 if (!jsReplacedName->IsString()) {
1416 return false;
1417 }
1418 replacedName = jsReplacedName->ToString();
1419 auto jsReplacedIndex = pathInfo->GetProperty("index");
1420 if (!jsReplacedIndex->IsNumber()) {
1421 return false;
1422 }
1423 replacedIndex = jsReplacedIndex->ToNumber<int32_t>();
1424 return true;
1425 }
1426
SetRecoveryFromReplaceDestination(int32_t index,bool value)1427 void JSNavigationStack::SetRecoveryFromReplaceDestination(int32_t index, bool value)
1428 {
1429 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1430 auto pathInfo = GetJsPathInfo(index);
1431 if (pathInfo->IsEmpty()) {
1432 return;
1433 }
1434 pathInfo->SetProperty<bool>("recoveryFromReplaceDestination", value);
1435 }
1436
ExecutePopCallback(const RefPtr<NG::UINode> & uiNode,uint64_t navDestinationId,const JSRef<JSVal> & param)1437 bool JSNavigationStack::ExecutePopCallback(const RefPtr<NG::UINode>& uiNode,
1438 uint64_t navDestinationId, const JSRef<JSVal>& param)
1439 {
1440 auto navDestinationNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(
1441 NG::NavigationGroupNode::GetNavDestinationNode(uiNode));
1442 CHECK_NULL_RETURN(navDestinationNode, false);
1443 auto pattern = navDestinationNode->GetPattern<NG::NavDestinationPattern>();
1444 CHECK_NULL_RETURN(pattern, false);
1445 if (pattern->GetNavDestinationId() != navDestinationId) {
1446 return false;
1447 }
1448 auto navPathInfo = AceType::DynamicCast<JSNavPathInfo>(pattern->GetNavPathInfo());
1449 CHECK_NULL_RETURN(navPathInfo, false);
1450 auto callback = navPathInfo->GetNavDestinationPopCallback();
1451 if (callback->IsEmpty()) {
1452 return false;
1453 }
1454 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "fire onPop callback: %{public}s", pattern->GetName().c_str());
1455 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1456 JSRef<JSVal> params[1];
1457 params[0] = param;
1458 callback->Call(JSRef<JSObject>(), 1, params);
1459 return true;
1460 }
1461
HasSingletonMoved()1462 bool JSNavigationStack::HasSingletonMoved()
1463 {
1464 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1465 if (dataSourceObj_->IsEmpty()) {
1466 return false;
1467 }
1468 auto hasSingletonMoved = dataSourceObj_->GetProperty("hasSingletonMoved");
1469 if (!hasSingletonMoved->IsBoolean()) {
1470 TAG_LOGW(AceLogTag::ACE_NAVIGATION, "hasSingletonMoved invalid!");
1471 return false;
1472 }
1473 return hasSingletonMoved->ToBoolean();
1474 }
1475
IsTopFromSingletonMoved()1476 bool JSNavigationStack::IsTopFromSingletonMoved()
1477 {
1478 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1479 auto len = GetSize();
1480 if (len == 0) {
1481 return false;
1482 }
1483 auto top = GetJsPathInfo(len - 1);
1484 if (top->IsEmpty()) {
1485 return false;
1486 }
1487 auto isFromSingletonMoved = top->GetProperty("singletonMoved");
1488 if (!isFromSingletonMoved->IsBoolean()) {
1489 return false;
1490 }
1491 return isFromSingletonMoved->ToBoolean();
1492 }
1493
GetNavDestinationIdInt(int32_t index)1494 uint64_t JSNavigationStack::GetNavDestinationIdInt(int32_t index)
1495 {
1496 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, -1);
1497 auto pathInfo = GetJsPathInfo(index);
1498 if (pathInfo->IsEmpty()) {
1499 return -1;
1500 }
1501 auto id = pathInfo->GetProperty("navDestinationId");
1502 if (!id->IsString()) {
1503 return -1;
1504 }
1505 auto navDestinationIdStr = id->ToString();
1506 auto navDestinationId = std::atol(navDestinationIdStr.c_str());
1507 return navDestinationId;
1508 }
1509
GetIsForceSet(int32_t index)1510 bool JSNavigationStack::GetIsForceSet(int32_t index)
1511 {
1512 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1513 auto pathInfo = GetJsPathInfo(index);
1514 if (pathInfo->IsEmpty()) {
1515 return false;
1516 }
1517 auto isForceSet = pathInfo->GetProperty("isForceSet");
1518 if (!isForceSet->IsBoolean()) {
1519 return false;
1520 }
1521 return isForceSet->ToBoolean();
1522 }
1523
ResetIsForceSetFlag(int32_t index)1524 void JSNavigationStack::ResetIsForceSetFlag(int32_t index)
1525 {
1526 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1527 auto pathInfo = GetJsPathInfo(index);
1528 if (pathInfo->IsEmpty()) {
1529 return;
1530 }
1531 pathInfo->SetPropertyObject("isForceSet", JsiValue::Undefined());
1532 }
1533
ResetSingletonMoved()1534 void JSNavigationStack::ResetSingletonMoved()
1535 {
1536 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1537 if (dataSourceObj_->IsEmpty()) {
1538 return;
1539 }
1540 auto hasSingletonMoved = dataSourceObj_->GetProperty("hasSingletonMoved");
1541 if (!hasSingletonMoved->IsBoolean() || !hasSingletonMoved->ToBoolean()) {
1542 return;
1543 }
1544 auto len = GetSize();
1545 for (auto index = 0; index < len; index++) {
1546 auto info = GetJsPathInfo(index);
1547 if (info->IsEmpty()) {
1548 continue;
1549 }
1550 info->SetProperty<bool>("singletonMoved", false);
1551 }
1552 dataSourceObj_->SetProperty<bool>("hasSingletonMoved", false);
1553 }
1554
PushIntentNavDestination(const std::string & name,const std::string & params,bool needTransition)1555 void JSNavigationStack::PushIntentNavDestination(
1556 const std::string& name, const std::string& params, bool needTransition)
1557 {
1558 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1559 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push intent navDestination(%{public}s)", name.c_str());
1560 if (dataSourceObj_->IsEmpty()) {
1561 return;
1562 }
1563 auto pushIntentNavDestinationFunc = dataSourceObj_->GetProperty("pushIntentNavDestination");
1564 if (!pushIntentNavDestinationFunc->IsFunction()) {
1565 return;
1566 }
1567 auto func = JSRef<JSFunc>::Cast(pushIntentNavDestinationFunc);
1568 JSRef<JSVal> arg[3];
1569 arg[0] = JSRef<JSVal>::Make(ToJSValue(name));
1570 arg[1] = JSRef<JSVal>::Make(ToJSValue(params));
1571 arg[2] = JSRef<JSVal>::Make(ToJSValue(needTransition));
1572 func->Call(dataSourceObj_, 3, arg);
1573 }
1574 } // namespace OHOS::Ace::Framework
1575