• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/functions/js_function.h"
20 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
21 #include "bridge/declarative_frontend/jsview/js_nav_path_stack.h"
22 #include "bridge/declarative_frontend/jsview/js_navdestination_context.h"
23 #include "core/components_ng/base/ui_node.h"
24 #include "core/components_ng/base/view_stack_processor.h"
25 #include "core/components_ng/pattern/custom/custom_node.h"
26 #include "core/components_ng/pattern/navrouter/navdestination_model.h"
27 #include "core/components_v2/inspector/inspector_constants.h"
28 #include "frameworks/base/json/json_util.h"
29 
30 namespace OHOS::Ace::Framework {
31 namespace {
32 constexpr int32_t ARGC_COUNT_TWO = 2;
33 constexpr int32_t MAX_PARSE_DEPTH = 3;
34 constexpr uint32_t MAX_PARSE_LENGTH = 1024;
35 constexpr uint32_t MAX_PARSE_PROPERTY_SIZE = 15;
36 constexpr char JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC[] = "getNativeStack";
37 constexpr char JS_NAV_PATH_STACK_SETPARENT_FUNC[] = "setParent";
38 }
39 
GetName()40 std::string JSRouteInfo::GetName()
41 {
42     return name_;
43 }
44 
SetName(const std::string & name)45 void JSRouteInfo::SetName(const std::string& name)
46 {
47     name_ = name;
48 }
49 
SetParam(const JSRef<JSVal> & param)50 void JSRouteInfo::SetParam(const JSRef<JSVal>& param)
51 {
52     param_ = param;
53 }
54 
GetParam() const55 JSRef<JSVal> JSRouteInfo::GetParam() const
56 {
57     return param_;
58 }
59 
SetDataSourceObj(const JSRef<JSObject> & dataSourceObj)60 void JSNavigationStack::SetDataSourceObj(const JSRef<JSObject>& dataSourceObj)
61 {
62     // clean callback from old JSNavPathStack
63     UpdateOnStateChangedCallback(dataSourceObj_, nullptr);
64     UpdateCheckNavDestinationExistsFunc(dataSourceObj_, nullptr);
65     dataSourceObj_ = dataSourceObj;
66     // add callback to new JSNavPathStack
67     RemoveStack();
68     UpdateOnStateChangedCallback(dataSourceObj_, onStateChangedCallback_);
69     auto checkNavDestinationExistsFunc = [weakStack = WeakClaim(this)](const JSRef<JSObject>& info) -> int32_t {
70         auto stack = weakStack.Upgrade();
71         if (stack == nullptr) {
72             return ERROR_CODE_INTERNAL_ERROR;
73         }
74         auto errorCode = stack->CheckNavDestinationExists(info);
75         if (errorCode != ERROR_CODE_NO_ERROR) {
76             stack->RemoveInvalidPage(info);
77         }
78         return errorCode;
79     };
80     UpdateCheckNavDestinationExistsFunc(dataSourceObj_, checkNavDestinationExistsFunc);
81 }
82 
UpdateCheckNavDestinationExistsFunc(JSRef<JSObject> obj,std::function<int32_t (JSRef<JSObject>)> checkFunc)83 void JSNavigationStack::UpdateCheckNavDestinationExistsFunc(JSRef<JSObject> obj,
84     std::function<int32_t(JSRef<JSObject>)> checkFunc)
85 {
86     if (obj->IsEmpty()) {
87         return;
88     }
89 
90     auto property = obj->GetProperty(JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC);
91     if (!property->IsFunction()) {
92         return;
93     }
94 
95     auto getNativeStackFunc = JSRef<JSFunc>::Cast(property);
96     auto nativeStack = getNativeStackFunc->Call(obj);
97     if (nativeStack->IsEmpty() || !nativeStack->IsObject()) {
98         return;
99     }
100 
101     auto nativeStackObj = JSRef<JSObject>::Cast(nativeStack);
102     JSNavPathStack* stack = nativeStackObj->Unwrap<JSNavPathStack>();
103     CHECK_NULL_VOID(stack);
104 
105     stack->SetCheckNavDestinationExistsFunc(checkFunc);
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             auto funcArray = getFunc->Call(dataSourceObj_);
150             if (funcArray->IsArray()) {
151                 auto result = JSRef<JSArray>::Cast(funcArray);
152                 param = result->GetValueAt(0);
153             }
154         }
155     }
156     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
157     if (pushNameFunc->IsFunction()) {
158         auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
159         JSRef<JSVal> params[2];
160         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
161         params[1] = param;
162         pushFunc->Call(dataSourceObj_, 2, params);
163     }
164 }
165 
PushName(const std::string & name,const JSRef<JSVal> & param)166 void JSNavigationStack::PushName(const std::string& name, const JSRef<JSVal>& param)
167 {
168     // obtain param from routeInfo
169     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
170     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
171     if (pushNameFunc->IsFunction()) {
172         auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
173         JSRef<JSVal> params[2];
174         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
175         params[1] = param;
176         pushFunc->Call(dataSourceObj_, 2, params);
177     }
178 }
179 
Push(const std::string & name,int32_t index)180 void JSNavigationStack::Push(const std::string& name, int32_t index)
181 {
182     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
183     auto getParamByIndexFunc = dataSourceObj_->GetProperty("getParamByIndex");
184     if (!getParamByIndexFunc->IsFunction()) {
185         return ;
186     }
187     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
188     if (!pushNameFunc->IsFunction()) {
189         return ;
190     }
191     auto getFunc = JSRef<JSFunc>::Cast(getParamByIndexFunc);
192     auto param = JSRef<JSVal>::Cast(getFunc->Call(dataSourceObj_));
193     auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
194     JSRef<JSVal> params[ARGC_COUNT_TWO];
195     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
196     params[1] = param;
197     pushFunc->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
198 }
199 
RemoveName(const std::string & name)200 void JSNavigationStack::RemoveName(const std::string& name)
201 {
202     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
203     if (dataSourceObj_->IsEmpty()) {
204         return;
205     }
206     auto removeByNameFunc = dataSourceObj_->GetProperty("removeByName");
207     if (!removeByNameFunc->IsFunction()) {
208         return;
209     }
210     auto func = JSRef<JSFunc>::Cast(removeByNameFunc);
211     JSRef<JSVal> params[1];
212     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
213     func->Call(dataSourceObj_, 1, params);
214 }
215 
RemoveIndex(int32_t index)216 void JSNavigationStack::RemoveIndex(int32_t index)
217 {
218     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
219     if (dataSourceObj_->IsEmpty()) {
220         return;
221     }
222     auto removeIndexFunc = dataSourceObj_->GetProperty("removeIndex");
223     if (removeIndexFunc->IsFunction()) {
224         auto func = JSRef<JSFunc>::Cast(removeIndexFunc);
225         JSRef<JSVal> params[1];
226         params[0] = JSRef<JSVal>::Make(ToJSValue(index));
227         func->Call(dataSourceObj_, 1, params);
228     }
229 }
230 
Clear()231 void JSNavigationStack::Clear()
232 {
233     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
234     if (dataSourceObj_->IsEmpty()) {
235         return;
236     }
237     auto clearFunc = dataSourceObj_->GetProperty("clear");
238     if (!clearFunc->IsFunction()) {
239         return;
240     }
241     auto func = JSRef<JSFunc>::Cast(clearFunc);
242     func->Call(dataSourceObj_);
243 }
244 
GetAllPathName()245 std::vector<std::string> JSNavigationStack::GetAllPathName()
246 {
247     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
248     if (dataSourceObj_->IsEmpty()) {
249         return {};
250     }
251     auto getAllPathNameFunc = dataSourceObj_->GetProperty("getAllPathName");
252     if (!getAllPathNameFunc->IsFunction()) {
253         return {};
254     }
255     auto func = JSRef<JSFunc>::Cast(getAllPathNameFunc);
256     auto funcArray = func->Call(dataSourceObj_);
257     if (!funcArray->IsArray()) {
258         return {};
259     }
260     auto array = JSRef<JSArray>::Cast(funcArray);
261     if (array->IsEmpty()) {
262         return {};
263     }
264     std::vector<std::string> pathNames;
265     for (size_t i = 0; i < array->Length(); i++) {
266         auto value = array->GetValueAt(i);
267         if (value->IsString()) {
268             pathNames.emplace_back(value->ToString());
269         }
270     }
271 
272     return pathNames;
273 }
274 
GetAllPathIndex()275 std::vector<int32_t> JSNavigationStack::GetAllPathIndex()
276 {
277     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
278     if (dataSourceObj_->IsEmpty()) {
279         return {};
280     }
281     auto getAllPathIndexFunc = dataSourceObj_->GetProperty("getAllPathIndex");
282     if (!getAllPathIndexFunc->IsFunction()) {
283         return {};
284     }
285     auto func = JSRef<JSFunc>::Cast(getAllPathIndexFunc);
286     auto funcArray = func->Call(dataSourceObj_);
287     if (!funcArray->IsArray()) {
288         return {};
289     }
290     auto array = JSRef<JSArray>::Cast(funcArray);
291     if (array->IsEmpty()) {
292         return {};
293     }
294     std::vector<int32_t> pathIndex;
295     for (size_t i = 0; i < array->Length(); i++) {
296         auto value = array->GetValueAt(i);
297         if (value->IsNumber()) {
298             pathIndex.emplace_back(value->ToNumber<int32_t>());
299         }
300     }
301 
302     return pathIndex;
303 }
304 
InitNavPathIndex(const std::vector<std::string> & pathNames)305 void JSNavigationStack::InitNavPathIndex(const std::vector<std::string>& pathNames)
306 {
307     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
308     if (dataSourceObj_->IsEmpty()) {
309         return;
310     }
311 
312     JSRef<JSArray> nameArray = JSRef<JSArray>::New();
313     JSRef<JSVal> params[1];
314     for (size_t i = 0; i < pathNames.size(); i++) {
315         JSRef<JSVal> info = JSRef<JSVal>::Make(ToJSValue(pathNames[i]));
316         nameArray->SetValueAt(i, info);
317     }
318     params[0] = nameArray;
319     auto initNavPathIndexFunc = dataSourceObj_->GetProperty("initNavPathIndex");
320     if (!initNavPathIndexFunc->IsFunction()) {
321         return;
322     }
323     auto func = JSRef<JSFunc>::Cast(initNavPathIndexFunc);
324     func->Call(dataSourceObj_, 1, params);
325 }
326 
SetDestinationIdToJsStack(int32_t index,const std::string & navDestinationId)327 void JSNavigationStack::SetDestinationIdToJsStack(int32_t index, const std::string& navDestinationId)
328 {
329     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
330     auto pathInfo = GetJsPathInfo(index);
331     if (pathInfo->IsEmpty()) {
332         return;
333     }
334     pathInfo->SetProperty<std::string>("navDestinationId", navDestinationId);
335 }
336 
CallByPushDestination(int32_t index)337 bool JSNavigationStack::CallByPushDestination(int32_t index)
338 {
339     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
340     auto pathInfo = GetJsPathInfo(index);
341     if (pathInfo->IsEmpty()) {
342         return false;
343     }
344     auto isPushDestination = pathInfo->GetPropertyValue<bool>("pushDestination", false);
345     return isPushDestination;
346 }
347 
CreateNodeByIndex(int32_t index,const WeakPtr<NG::UINode> & customNode)348 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByIndex(int32_t index, const WeakPtr<NG::UINode>& customNode)
349 {
350     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
351     auto name = GetNameByIndex(index);
352     auto param = GetParamByIndex(index);
353     RefPtr<NG::UINode> node;
354     if (GetNodeFromPreBuildList(index, name, param, node)) {
355         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get node from prebuild list");
356         return node;
357     }
358     RefPtr<NG::NavDestinationGroupNode> desNode;
359     NG::ScopedViewStackProcessor scopedViewStackProcessor;
360     int32_t errorCode = LoadDestination(name, param, customNode, node, desNode);
361     if (errorCode != ERROR_CODE_NO_ERROR) {
362         if (CallByPushDestination(index)) {
363             return nullptr;
364         }
365         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "can't find target destination by index, create empty node");
366         return AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
367     }
368     auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
369     if (pattern) {
370         pattern->SetName(name);
371         pattern->SetIndex(index);
372         auto onPop = GetOnPopByIndex(index);
373         auto isEntry = GetIsEntryByIndex(index);
374         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "create destination node, isEntry %{public}d", isEntry);
375         auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
376         pattern->SetNavPathInfo(pathInfo);
377         pattern->SetNavigationStack(WeakClaim(this));
378     }
379     return node;
380 }
381 
CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo> & routeInfo,const WeakPtr<NG::UINode> & customNode)382 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo>& routeInfo,
383     const WeakPtr<NG::UINode>& customNode)
384 {
385     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
386     auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
387     if (!jsRouteInfo) {
388         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "route info is invalid");
389         return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
390     }
391     auto name = jsRouteInfo->GetName();
392     auto param = jsRouteInfo->GetParam();
393     RefPtr<NG::UINode> node;
394     RefPtr<NG::NavDestinationGroupNode> desNode;
395     int32_t errorCode = LoadDestination(name, param, customNode, node, desNode);
396     if (errorCode == ERROR_CODE_NO_ERROR) {
397         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
398         if (pattern) {
399             auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param);
400             pattern->SetNavPathInfo(pathInfo);
401             pattern->SetName(name);
402             pattern->SetNavigationStack(WeakClaim(this));
403         }
404         return node;
405     }
406     return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
407 }
408 
SetJSExecutionContext(const JSExecutionContext & context)409 void JSNavigationStack::SetJSExecutionContext(const JSExecutionContext& context)
410 {
411     executionContext_ = context;
412 }
413 
GetNameByIndex(int32_t index)414 std::string JSNavigationStack::GetNameByIndex(int32_t index)
415 {
416     auto pathNames = GetAllPathName();
417     if (index < 0 || index >= static_cast<int32_t>(pathNames.size())) {
418         return "";
419     }
420 
421     return pathNames[index];
422 }
423 
GetParamByIndex(int32_t index) const424 JSRef<JSVal> JSNavigationStack::GetParamByIndex(int32_t index) const
425 {
426     if (dataSourceObj_->IsEmpty()) {
427         return JSRef<JSVal>::Make();
428     }
429     auto getParamByIndexFunc = dataSourceObj_->GetProperty("getParamByIndex");
430     if (!getParamByIndexFunc->IsFunction()) {
431         return JSRef<JSVal>::Make();
432     }
433     auto func = JSRef<JSFunc>::Cast(getParamByIndexFunc);
434     JSRef<JSVal> params[1];
435     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
436     return func->Call(dataSourceObj_, 1, params);
437 }
438 
GetOnPopByIndex(int32_t index) const439 JSRef<JSVal> JSNavigationStack::GetOnPopByIndex(int32_t index) const
440 {
441     if (dataSourceObj_->IsEmpty()) {
442         return JSRef<JSVal>::Make();
443     }
444     auto getOnPopByIndexFunc = dataSourceObj_->GetProperty("getOnPopByIndex");
445     if (!getOnPopByIndexFunc->IsFunction()) {
446         return JSRef<JSVal>::Make();
447     }
448     auto func = JSRef<JSFunc>::Cast(getOnPopByIndexFunc);
449     JSRef<JSVal> params[1];
450     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
451     return func->Call(dataSourceObj_, 1, params);
452 }
453 
GetIsEntryByIndex(int32_t index)454 bool JSNavigationStack::GetIsEntryByIndex(int32_t index)
455 {
456     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
457     if (dataSourceObj_->IsEmpty()) {
458         return false;
459     }
460     auto getIsEntryFunc = dataSourceObj_->GetProperty("getIsEntryByIndex");
461     if (!getIsEntryFunc->IsFunction()) {
462         return false;
463     }
464     auto func = JSRef<JSFunc>::Cast(getIsEntryFunc);
465     JSRef<JSVal> params[1];
466     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
467     auto result = func->Call(dataSourceObj_, 1, params);
468     if (!result->IsBoolean()) {
469         return false;
470     }
471     return result->ToBoolean();
472 }
473 
SetIsEntryByIndex(int32_t index,bool isEntry)474 void JSNavigationStack::SetIsEntryByIndex(int32_t index, bool isEntry)
475 {
476     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
477     if (dataSourceObj_->IsEmpty()) {
478         return;
479     }
480     auto setIsEntryFunc = dataSourceObj_->GetProperty("setIsEntryByIndex");
481     if (!setIsEntryFunc->IsFunction()) {
482         return;
483     }
484     auto func = JSRef<JSFunc>::Cast(setIsEntryFunc);
485     JSRef<JSVal> params[ARGC_COUNT_TWO];
486     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
487     params[1] = JSRef<JSVal>::Make(ToJSValue(isEntry));
488     func->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
489 }
490 
GetNavDestinationNodeInUINode(RefPtr<NG::UINode> node,RefPtr<NG::NavDestinationGroupNode> & desNode)491 bool JSNavigationStack::GetNavDestinationNodeInUINode(
492     RefPtr<NG::UINode> node, RefPtr<NG::NavDestinationGroupNode>& desNode)
493 {
494     RefPtr<NG::CustomNode> customNode;
495     while (node) {
496         if (node->GetTag() == V2::JS_VIEW_ETS_TAG) {
497             customNode = AceType::DynamicCast<NG::CustomNode>(node);
498             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "render current custom node: %{public}s",
499                 customNode->GetCustomTag().c_str());
500             // record parent navigationNode before customNode is rendered in case of navDestinationNode
501             auto navigationNode = GetNavigationNode();
502             customNode->SetNavigationNode(navigationNode);
503             // render, and find deep further
504             customNode->Render();
505         } else if (node->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
506             desNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(node);
507             if (desNode) {
508                 desNode->SetNavDestinationCustomNode(AceType::WeakClaim(AceType::RawPtr(customNode)));
509             }
510             return true;
511         }
512         auto children = node->GetChildren();
513         if (children.size() != 1) {
514             TAG_LOGI(AceLogTag::ACE_NAVIGATION,
515                 "router map is invalid, child size is not one: %{public}zu", children.size());
516         }
517         node = children.front();
518     }
519     return false;
520 }
521 
GetReplaceValue() const522 int32_t JSNavigationStack::GetReplaceValue() const
523 {
524     if (dataSourceObj_->IsEmpty()) {
525         return false;
526     }
527     auto replace = dataSourceObj_->GetProperty("isReplace");
528     return replace->ToNumber<int32_t>();
529 }
530 
UpdateReplaceValue(int32_t replaceValue) const531 void JSNavigationStack::UpdateReplaceValue(int32_t replaceValue) const
532 {
533     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
534     if (dataSourceObj_->IsEmpty()) {
535         return;
536     }
537     auto setIsReplaceFunc = dataSourceObj_->GetProperty("setIsReplace");
538     if (!setIsReplaceFunc->IsFunction()) {
539         return;
540     }
541     auto replaceFunc = JSRef<JSFunc>::Cast(setIsReplaceFunc);
542     JSRef<JSVal> params[1];
543     params[0] = JSRef<JSVal>::Make(ToJSValue(replaceValue));
544     replaceFunc->Call(dataSourceObj_, 1, params);
545 }
546 
GetRouteParam() const547 std::string JSNavigationStack::GetRouteParam() const
548 {
549     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, "");
550     auto size = GetSize();
551     if (size > 0) {
552         auto param = GetParamByIndex(size - 1);
553         return ConvertParamToString(param, true);
554     }
555     return "";
556 }
557 
GetSize() const558 int32_t JSNavigationStack::GetSize() const
559 {
560     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, 0);
561     if (dataSourceObj_->IsEmpty()) {
562         return 0;
563     }
564     auto sizeFunc = dataSourceObj_->GetProperty("size");
565     if (!sizeFunc->IsFunction()) {
566         return 0;
567     }
568     auto func = JSRef<JSFunc>::Cast(sizeFunc);
569     auto jsValue = JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
570     if (jsValue->IsNumber()) {
571         return jsValue->ToNumber<int32_t>();
572     }
573     return 0;
574 }
575 
ConvertParamToString(const JSRef<JSVal> & param,bool needLimit) const576 std::string JSNavigationStack::ConvertParamToString(const JSRef<JSVal>& param, bool needLimit) const
577 {
578     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, "");
579     if (param->IsBoolean()) {
580         bool ret = param->ToBoolean();
581         return ret ? "true" : "false";
582     } else if (param->IsNumber()) {
583         double ret = param->ToNumber<double>();
584         std::ostringstream oss;
585         oss<< ret;
586         return oss.str();
587     } else if (param->IsString()) {
588         std::string ret = param->ToString();
589         if (needLimit && ret.size() > MAX_PARSE_LENGTH) {
590             return ret.substr(0, MAX_PARSE_LENGTH);
591         }
592         return ret;
593     } else if (param->IsObject()) {
594         JSRef<JSObject> obj = JSRef<JSObject>::Cast(param);
595         auto jsonObj = JsonUtil::Create(true);
596         ParseJsObject(jsonObj, obj, MAX_PARSE_DEPTH, needLimit);
597         return jsonObj->ToString();
598     }
599     return "";
600 }
601 
ParseJsObject(std::unique_ptr<JsonValue> & json,const JSRef<JSObject> & obj,int32_t depthLimit,bool needLimit) const602 void JSNavigationStack::ParseJsObject(
603     std::unique_ptr<JsonValue>& json, const JSRef<JSObject>& obj, int32_t depthLimit, bool needLimit) const
604 {
605     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
606     if (depthLimit == 0) {
607         return;
608     }
609     depthLimit--;
610     auto propertyNames = obj->GetPropertyNames();
611     if (!propertyNames->IsArray()) {
612         return;
613     }
614     size_t size = propertyNames->Length();
615     if (needLimit && size > MAX_PARSE_PROPERTY_SIZE) {
616         size = MAX_PARSE_PROPERTY_SIZE;
617     }
618     for (size_t i = 0; i < size; i++) {
619         JSRef<JSVal> name = propertyNames->GetValueAt(i);
620         if (!name->IsString()) {
621             continue;
622         }
623         auto propertyName = name->ToString();
624         auto key = propertyName.c_str();
625         JSRef<JSVal> value = obj->GetProperty(key);
626         if (value->IsBoolean()) {
627             bool ret = value->ToBoolean();
628             json->Put(key, ret ? "true" : "false");
629         } else if (value->IsNumber()) {
630             double ret = value->ToNumber<double>();
631             std::ostringstream oss;
632             oss << ret;
633             json->Put(key, oss.str().c_str());
634         } else if (value->IsString()) {
635             std::string ret = value->ToString();
636             if (needLimit && ret.size() > MAX_PARSE_LENGTH) {
637                 json->Put(key, ret.substr(0, MAX_PARSE_LENGTH).c_str());
638             } else {
639                 json->Put(key, ret.c_str());
640             }
641         } else if (value->IsObject()) {
642             JSRef<JSObject> childObj = JSRef<JSObject>::Cast(value);
643             auto childJson = JsonUtil::Create(true);
644             ParseJsObject(childJson, childObj, depthLimit, needLimit);
645             json->Put(key, childJson);
646         }
647     }
648 }
649 
GetAnimatedValue() const650 bool JSNavigationStack::GetAnimatedValue() const
651 {
652     if (dataSourceObj_->IsEmpty()) {
653         return true;
654     }
655     auto animated = dataSourceObj_->GetProperty("animated");
656     return animated->ToBoolean();
657 }
658 
UpdateAnimatedValue(bool animated)659 void JSNavigationStack::UpdateAnimatedValue(bool animated)
660 {
661     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
662     if (dataSourceObj_->IsEmpty()) {
663         return;
664     }
665     auto setAnimatedFunc = dataSourceObj_->GetProperty("setAnimated");
666     if (!setAnimatedFunc->IsFunction()) {
667         return;
668     }
669     auto animatedFunc = JSRef<JSFunc>::Cast(setAnimatedFunc);
670     JSRef<JSVal> params[1];
671     params[0] = JSRef<JSVal>::Make(ToJSValue(animated));
672     animatedFunc->Call(dataSourceObj_, 1, params);
673 }
674 
675 
GetDisableAnimation() const676 bool JSNavigationStack::GetDisableAnimation() const
677 {
678     if (dataSourceObj_->IsEmpty()) {
679         return false;
680     }
681     auto disableAllAnimation = dataSourceObj_->GetProperty("disableAllAnimation");
682     return disableAllAnimation->ToBoolean();
683 }
684 
UpdateOnStateChangedCallback(JSRef<JSObject> obj,std::function<void ()> callback)685 void JSNavigationStack::UpdateOnStateChangedCallback(JSRef<JSObject> obj, std::function<void()> callback)
686 {
687     if (obj->IsEmpty()) {
688         return;
689     }
690 
691     auto property = obj->GetProperty(JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC);
692     if (!property->IsFunction()) {
693         return;
694     }
695 
696     auto getNativeStackFunc = JSRef<JSFunc>::Cast(property);
697     auto nativeStack = getNativeStackFunc->Call(obj);
698     if (nativeStack->IsEmpty() || !nativeStack->IsObject()) {
699         return;
700     }
701 
702     auto nativeStackObj = JSRef<JSObject>::Cast(nativeStack);
703     JSNavPathStack* stack = nativeStackObj->Unwrap<JSNavPathStack>();
704     CHECK_NULL_VOID(stack);
705     stack->SetOnStateChangedCallback(callback);
706     // When switching the navigation stack, it is necessary to immediately trigger a refresh
707     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation necessary to immediately trigger a refresh");
708     stack->OnStateChanged();
709 }
710 
OnAttachToParent(RefPtr<NG::NavigationStack> parent)711 void JSNavigationStack::OnAttachToParent(RefPtr<NG::NavigationStack> parent)
712 {
713     auto parentStack = AceType::DynamicCast<JSNavigationStack>(parent);
714     if (!parentStack) {
715         return;
716     }
717 
718     SetJSParentStack(JSRef<JSVal>::Cast(parentStack->GetDataSourceObj()));
719 }
720 
OnDetachFromParent()721 void JSNavigationStack::OnDetachFromParent()
722 {
723     JSRef<JSVal> undefined(JSVal::Undefined());
724     SetJSParentStack(undefined);
725 }
726 
SetJSParentStack(JSRef<JSVal> parent)727 void JSNavigationStack::SetJSParentStack(JSRef<JSVal> parent)
728 {
729     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
730     if (dataSourceObj_->IsEmpty()) {
731         return;
732     }
733 
734     auto property = dataSourceObj_->GetProperty(JS_NAV_PATH_STACK_SETPARENT_FUNC);
735     if (!property->IsFunction()) {
736         return;
737     }
738 
739     auto func = JSRef<JSFunc>::Cast(property);
740     JSRef<JSVal> params[1];
741     params[0] = parent;
742     func->Call(dataSourceObj_, 1, params);
743 }
744 
RemoveInvalidPage(const JSRef<JSObject> & info)745 void JSNavigationStack::RemoveInvalidPage(const JSRef<JSObject>& info)
746 {
747     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
748     if (dataSourceObj_->IsEmpty()) {
749         return;
750     }
751     auto removeInvalidPage = dataSourceObj_->GetProperty("removeInvalidPage");
752     if (removeInvalidPage->IsFunction()) {
753         auto func = JSRef<JSFunc>::Cast(removeInvalidPage);
754         auto pathName = info->GetProperty("name");
755         auto param = info->GetProperty("param");
756         JSRef<JSVal> params[ARGC_COUNT_TWO] = { pathName, param };
757         func->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
758     }
759 }
760 
SaveNodeToPreBuildList(const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node)761 void JSNavigationStack::SaveNodeToPreBuildList(const std::string& name, const JSRef<JSVal>& param,
762     RefPtr<NG::UINode>& node)
763 {
764     preBuildNodeList_.emplace_back(name, param, node, GetSize() - 1);
765 }
766 
GetNodeFromPreBuildList(int32_t index,const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node)767 bool JSNavigationStack::GetNodeFromPreBuildList(int32_t index, const std::string& name,
768     const JSRef<JSVal>& param, RefPtr<NG::UINode>& node)
769 {
770     auto isJsObjEqual = [](const JSRef<JSVal>& objLeft, const JSRef<JSVal>& objRight) {
771         return (objLeft->IsEmpty() && objRight->IsEmpty()) ||
772             (objLeft->GetLocalHandle()->IsStrictEquals(objLeft->GetEcmaVM(), objRight->GetLocalHandle()));
773     };
774     for (auto it = preBuildNodeList_.begin(); it != preBuildNodeList_.end(); ++it) {
775         if (it->name == name && isJsObjEqual(it->param, param) && it->index == index) {
776             node = it->uiNode;
777             preBuildNodeList_.erase(it);
778             return true;
779         }
780     }
781     return false;
782 }
783 
ClearPreBuildNodeList()784 void JSNavigationStack::ClearPreBuildNodeList()
785 {
786     preBuildNodeList_.clear();
787 }
788 
CheckNavDestinationExists(const JSRef<JSObject> & navPathInfo)789 int32_t JSNavigationStack::CheckNavDestinationExists(const JSRef<JSObject>& navPathInfo)
790 {
791     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, ERROR_CODE_DESTINATION_NOT_FOUND);
792     auto pathName = navPathInfo->GetProperty("name");
793     auto param = navPathInfo->GetProperty("param");
794     JSRef<JSVal> params[ARGC_COUNT_TWO] = { pathName, param };
795     auto name = pathName->ToString();
796     RefPtr<NG::UINode> node;
797     auto navigationNode = AceType::DynamicCast<NG::NavigationGroupNode>(navigationNode_.Upgrade());
798     CHECK_NULL_RETURN(navigationNode, ERROR_CODE_INTERNAL_ERROR);
799     auto navigationPattern = AceType::DynamicCast<NG::NavigationPattern>(navigationNode->GetPattern());
800     CHECK_NULL_RETURN(navigationPattern, ERROR_CODE_INTERNAL_ERROR);
801     RefPtr<NG::NavDestinationGroupNode> desNode;
802     int32_t errorCode = LoadDestination(name, param, navigationPattern->GetParentCustomNode(),
803         node, desNode);
804     if (errorCode != ERROR_CODE_NO_ERROR) {
805         return errorCode;
806     }
807     auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
808     if (pattern) {
809         auto onPop = navPathInfo->GetProperty("onPop");
810         auto isEntryVal = navPathInfo->GetProperty("isEntry");
811         bool isEntry = isEntryVal->IsBoolean() ? isEntryVal->ToBoolean() : false;
812         auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
813         pattern->SetName(name);
814         pattern->SetIndex(GetSize() - 1);
815         pattern->SetNavPathInfo(pathInfo);
816         pattern->SetNavigationStack(WeakClaim(this));
817     }
818     SaveNodeToPreBuildList(name, param, node);
819     return ERROR_CODE_NO_ERROR;
820 }
821 
DumpStackInfo() const822 std::vector<std::string> JSNavigationStack::DumpStackInfo() const
823 {
824     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
825     std::vector<std::string> dumpInfos;
826     for (size_t i = 0; i < navPathList_.size(); ++i) {
827         const auto& name = navPathList_[i].first;
828         std::string info = "[" + std::to_string(i) + "]{ name: \"" + name + "\"";
829         std::string param = ConvertParamToString(GetParamByIndex(i));
830         if (param.length() > 0) {
831             info += ", param: " + param;
832         }
833         info += " }";
834         dumpInfos.push_back(std::move(info));
835     }
836     return dumpInfos;
837 }
838 
FireNavigationInterception(bool isBefore,const RefPtr<NG::NavDestinationContext> & from,const RefPtr<NG::NavDestinationContext> & to,NG::NavigationOperation operation,bool isAnimated)839 void JSNavigationStack::FireNavigationInterception(bool isBefore, const RefPtr<NG::NavDestinationContext>& from,
840     const RefPtr<NG::NavDestinationContext>& to, NG::NavigationOperation operation, bool isAnimated)
841 {
842     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
843     std::string targetName = isBefore ? "willShow" : "didShow";
844     JSRef<JSFunc> targetFunc;
845     if (!CheckAndGetInterceptionFunc(targetName, targetFunc)) {
846         return;
847     }
848     const uint8_t argsNum = 4;
849     JSRef<JSVal> params[argsNum];
850     auto preDestination = AceType::DynamicCast<NG::NavDestinationContext>(from);
851     if (!preDestination) {
852         params[0] = JSRef<JSVal>::Make(ToJSValue("navBar"));
853     } else if (preDestination->GetIsEmpty()) {
854         params[0] = JSRef<JSObject>::New();
855     } else {
856         JSRef<JSObject> preObj = JSClass<JSNavDestinationContext>::NewInstance();
857         auto preProxy = Referenced::Claim(preObj->Unwrap<JSNavDestinationContext>());
858         preProxy->SetNavDestinationContext(from);
859         params[0] = preObj;
860     }
861 
862     auto topDestination = AceType::DynamicCast<NG::NavDestinationContext>(to);
863     if (!topDestination) {
864         params[1] = JSRef<JSVal>::Make(ToJSValue("navBar"));
865     } else if (topDestination->GetIsEmpty()) {
866         params[1] = JSRef<JSObject>::New();
867     } else {
868         JSRef<JSObject> topObj = JSClass<JSNavDestinationContext>::NewInstance();
869         auto topProxy = Referenced::Claim(topObj->Unwrap<JSNavDestinationContext>());
870         topProxy->SetNavDestinationContext(to);
871         params[1] = topObj;
872     }
873     const uint8_t operationIndex = 2;
874     params[operationIndex] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(operation)));
875     const uint8_t animatedIndex = 3;
876     params[animatedIndex] = JSRef<JSVal>::Make(ToJSValue(isAnimated));
877     targetFunc->Call(JSRef<JSObject>(), argsNum, params);
878 }
879 
FireNavigationModeChange(NG::NavigationMode mode)880 void JSNavigationStack::FireNavigationModeChange(NG::NavigationMode mode)
881 {
882     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
883     JSRef<JSFunc> modeFunc;
884     if (!CheckAndGetInterceptionFunc("modeChange", modeFunc)) {
885         return;
886     }
887     JSRef<JSVal> params[1];
888     params[0] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(mode)));
889     modeFunc->Call(JSRef<JSObject>(), 1, params);
890 }
891 
CheckAndGetInterceptionFunc(const std::string & name,JSRef<JSFunc> & func)892 bool JSNavigationStack::CheckAndGetInterceptionFunc(const std::string& name, JSRef<JSFunc>& func)
893 {
894     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
895     if (dataSourceObj_->IsEmpty()) {
896         return false;
897     }
898     JSRef<JSVal> delegateProp = dataSourceObj_->GetProperty("interception");
899     if (!delegateProp->IsObject()) {
900         return false;
901     }
902     JSRef<JSObject> delegate = JSRef<JSObject>::Cast(delegateProp);
903     JSRef<JSVal> funcProp = delegate->GetProperty(name.c_str());
904     if (!funcProp->IsFunction()) {
905         return false;
906     }
907     func = JSRef<JSFunc>::Cast(funcProp);
908     return true;
909 }
910 
LoadDestinationByBuilder(const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node,RefPtr<NG::NavDestinationGroupNode> & desNode)911 bool JSNavigationStack::LoadDestinationByBuilder(const std::string& name, const JSRef<JSVal>& param,
912     RefPtr<NG::UINode>& node, RefPtr<NG::NavDestinationGroupNode>& desNode)
913 {
914     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
915     if (navDestBuilderFunc_->IsEmpty()) {
916         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "Builder function is empty");
917         return false;
918     }
919     auto builderObj = JSRef<JSObject>::Cast(navDestBuilderFunc_);
920     const int32_t number = builderObj->GetProperty("length")->ToNumber<int32_t>();
921     JSRef<JSVal> params[number];
922     if (number >= 1) {
923         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
924     }
925     if (number >= ARGC_COUNT_TWO) {
926         params[1] = param;
927     }
928     navDestBuilderFunc_->Call(JSRef<JSObject>(), number, params);
929     node = NG::ViewStackProcessor::GetInstance()->Finish();
930     return GetNavDestinationNodeInUINode(node, desNode);
931 }
932 
LoadDestination(const std::string & name,const JSRef<JSVal> & param,const WeakPtr<NG::UINode> & customNode,RefPtr<NG::UINode> & node,RefPtr<NG::NavDestinationGroupNode> & desNode)933 int32_t JSNavigationStack::LoadDestination(const std::string& name, const JSRef<JSVal>& param,
934     const WeakPtr<NG::UINode>& customNode, RefPtr<NG::UINode>& node,
935     RefPtr<NG::NavDestinationGroupNode>& desNode)
936 {
937     NG::ScopedViewStackProcessor scopedViewStackProcessor;
938     // execute navdestination attribute builder
939     if (LoadDestinationByBuilder(name, param, node, desNode)) {
940         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "load destination by buildermap");
941         return ERROR_CODE_NO_ERROR;
942     }
943     // deal route config and execute route config builder
944     auto container = Container::Current();
945     auto navigationRoute = container->GetNavigationRoute();
946     if (!navigationRoute->HasLoaded(name)) {
947         int32_t res = navigationRoute->LoadPage(name);
948         if (res != 0) {
949             TAG_LOGE(AceLogTag::ACE_NAVIGATION, "load page failed: %{public}s", name.c_str());
950             return navDestBuilderFunc_->IsEmpty() ? ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED
951                 : ERROR_CODE_DESTINATION_NOT_FOUND;
952         }
953     }
954     auto parentCustomNode = AceType::DynamicCast<NG::CustomNode>(customNode.Upgrade());
955     CHECK_NULL_RETURN(parentCustomNode, ERROR_CODE_INTERNAL_ERROR);
956     auto thisObjTmp = parentCustomNode->FireThisFunc();
957     CHECK_NULL_RETURN(thisObjTmp, ERROR_CODE_INTERNAL_ERROR);
958     JSRef<JSObject> thisObj = *(JSRef<JSObject>*)(thisObjTmp);
959     auto engine = AceType::DynamicCast<Framework::JsiDeclarativeEngine>(EngineHelper::GetCurrentEngine());
960     CHECK_NULL_RETURN(engine, ERROR_CODE_INTERNAL_ERROR);
961     JSRef<JSObject> wrapBuilder = JSRef<JSObject>::Make(engine->GetNavigationBuilder(name).ToLocal());
962     if (wrapBuilder->IsEmpty()) {
963         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "wrap builder is empty: %{public}s", name.c_str());
964         return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
965     }
966     auto builderProp = wrapBuilder->GetProperty("builder");
967     if (!builderProp->IsFunction()) {
968         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get builder failed: %{public}s", name.c_str());
969         return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
970     }
971     auto builderObj = JSRef<JSObject>::Cast(builderProp);
972     const int32_t number = builderObj->GetProperty("length")->ToNumber<int32_t>();
973     JSRef<JSVal> params[number];
974     if (number >= 1) {
975         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
976     }
977     if (number >= ARGC_COUNT_TWO) {
978         params[1] = param;
979     }
980     auto builder = JSRef<JSFunc>::Cast(builderProp);
981     builder->Call(thisObj, number, params);
982     node = NG::ViewStackProcessor::GetInstance()->Finish();
983     if (!GetNavDestinationNodeInUINode(node, desNode)) {
984         return ERROR_CODE_DESTINATION_NOT_FOUND;
985     }
986     return ERROR_CODE_NO_ERROR;
987 }
988 
GetJsIndexFromNativeIndex(int32_t index)989 int32_t JSNavigationStack::GetJsIndexFromNativeIndex(int32_t index)
990 {
991     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, -1);
992     if (dataSourceObj_->IsEmpty()) {
993         return -1;
994     }
995     auto getIndexFunc = dataSourceObj_->GetProperty("getJsIndexFromNativeIndex");
996     if (!getIndexFunc->IsFunction()) {
997         return -1;
998     }
999     auto func = JSRef<JSFunc>::Cast(getIndexFunc);
1000     JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(index));
1001     auto res = func->Call(dataSourceObj_, 1, &param);
1002     if (res->IsNumber()) {
1003         return res->ToNumber<int32_t>();
1004     }
1005     return -1;
1006 }
1007 
MoveIndexToTop(int32_t index)1008 void JSNavigationStack::MoveIndexToTop(int32_t index)
1009 {
1010     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1011     if (dataSourceObj_->IsEmpty()) {
1012         return;
1013     }
1014     auto moveIndexToTopFunc = dataSourceObj_->GetProperty("moveIndexToTop");
1015     if (!moveIndexToTopFunc->IsFunction()) {
1016         return;
1017     }
1018     auto func = JSRef<JSFunc>::Cast(moveIndexToTopFunc);
1019     JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(index));
1020     func->Call(dataSourceObj_, 1, &param);
1021 }
1022 
UpdatePathInfoIfNeeded(RefPtr<NG::UINode> & uiNode,int32_t index)1023 void JSNavigationStack::UpdatePathInfoIfNeeded(RefPtr<NG::UINode>& uiNode, int32_t index)
1024 {
1025     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1026     bool needUpdate = GetNeedUpdatePathInfo(index);
1027     if (!needUpdate) {
1028         return;
1029     }
1030     SetNeedUpdatePathInfo(index, false);
1031     RefPtr<NG::NavDestinationGroupNode> desNode;
1032     if (!GetNavDestinationNodeInUINode(uiNode, desNode)) {
1033         return;
1034     }
1035     auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
1036     if (!pattern) {
1037         return;
1038     }
1039 
1040     auto name = GetNameByIndex(index);
1041     auto param = GetParamByIndex(index);
1042     auto onPop = GetOnPopByIndex(index);
1043     auto isEntry = GetIsEntryByIndex(index);
1044     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "update destination node info, isEntry %{public}d", isEntry);
1045     auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
1046     pattern->SetNavPathInfo(pathInfo);
1047 }
1048 
GetNeedUpdatePathInfo(int32_t index)1049 bool JSNavigationStack::GetNeedUpdatePathInfo(int32_t index)
1050 {
1051     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1052     auto path = GetJsPathInfo(index);
1053     if (path->IsEmpty()) {
1054         return false;
1055     }
1056     auto needUpdate = path->GetProperty("needUpdate");
1057     if (!needUpdate->IsBoolean()) {
1058         return false;
1059     }
1060     return needUpdate->ToBoolean();
1061 }
1062 
SetNeedUpdatePathInfo(int32_t index,bool need)1063 void JSNavigationStack::SetNeedUpdatePathInfo(int32_t index, bool need)
1064 {
1065     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1066     auto path = GetJsPathInfo(index);
1067     if (path->IsEmpty()) {
1068         return;
1069     }
1070     path->SetProperty<bool>("needUpdate", need);
1071 }
1072 
RecoveryNavigationStack()1073 void JSNavigationStack::RecoveryNavigationStack()
1074 {
1075     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1076     navPathList_ = preNavPathList_;
1077     if (dataSourceObj_->IsEmpty()) {
1078         return;
1079     }
1080     JSRef<JSArray> pathArray = JSRef<JSArray>::New();
1081     for (int32_t index = 0; index < static_cast<int32_t>(navPathList_.size()); index++) {
1082         auto node = navPathList_[index].second;
1083         auto navDestinationGroupNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(
1084             NG::NavigationGroupNode::GetNavDestinationNode(node));
1085         if (!navDestinationGroupNode) {
1086             continue;
1087         }
1088         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(navDestinationGroupNode->GetPattern());
1089         if (!pattern) {
1090             continue;
1091         }
1092         auto context = pattern->GetNavDestinationContext();
1093         if (!context) {
1094             continue;
1095         }
1096         JSRef<JSObject> item = CreatePathInfoWithNecessaryProperty(context);
1097         pathArray->SetValueAt(index, item);
1098     }
1099     dataSourceObj_->SetPropertyObject("pathArray", pathArray);
1100 }
1101 
NeedBuildNewInstance(int32_t index)1102 bool JSNavigationStack::NeedBuildNewInstance(int32_t index)
1103 {
1104     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1105     auto pathInfo = GetJsPathInfo(index);
1106     if (pathInfo->IsEmpty()) {
1107         return false;
1108     }
1109     auto needBuildNewInstance = pathInfo->GetProperty("needBuildNewInstance");
1110     if (!needBuildNewInstance->IsBoolean()) {
1111         return false;
1112     }
1113     return needBuildNewInstance->ToBoolean();
1114 }
1115 
SetNeedBuildNewInstance(int32_t index,bool need)1116 void JSNavigationStack::SetNeedBuildNewInstance(int32_t index, bool need)
1117 {
1118     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1119     auto pathInfo = GetJsPathInfo(index);
1120     if (pathInfo->IsEmpty()) {
1121         return;
1122     }
1123     pathInfo->SetProperty<bool>("needBuildNewInstance", need);
1124 }
1125 
GetJsPathArray()1126 JSRef<JSArray> JSNavigationStack::GetJsPathArray()
1127 {
1128     if (dataSourceObj_->IsEmpty()) {
1129         return JSRef<JSArray>();
1130     }
1131     auto objArray = dataSourceObj_->GetProperty("pathArray");
1132     if (!objArray->IsArray()) {
1133         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "navPathArray invalid!");
1134         return JSRef<JSArray>();
1135     }
1136     return JSRef<JSArray>::Cast(objArray);
1137 }
1138 
GetJsPathInfo(int32_t index)1139 JSRef<JSObject> JSNavigationStack::GetJsPathInfo(int32_t index)
1140 {
1141     auto navPathArray = GetJsPathArray();
1142     int32_t len = static_cast<int32_t>(navPathArray->Length());
1143     if (index < 0 || index >= len) {
1144         return JSRef<JSObject>();
1145     }
1146     auto pathInfo = navPathArray->GetValueAt(index);
1147     if (!pathInfo->IsObject()) {
1148         return JSRef<JSObject>();
1149     }
1150     return JSRef<JSObject>::Cast(pathInfo);
1151 }
1152 
CreatePathInfoWithNecessaryProperty(const RefPtr<NG::NavDestinationContext> & context)1153 JSRef<JSObject> JSNavigationStack::CreatePathInfoWithNecessaryProperty(
1154     const RefPtr<NG::NavDestinationContext>& context)
1155 {
1156     auto pathInfo = JSRef<JSObject>::New();
1157     CHECK_NULL_RETURN(context, pathInfo);
1158     auto jsPathInfo = AceType::DynamicCast<JSNavPathInfo>(context->GetNavPathInfo());
1159     CHECK_NULL_RETURN(jsPathInfo, pathInfo);
1160 
1161     pathInfo->SetProperty<std::string>("name", jsPathInfo->GetName());
1162     pathInfo->SetProperty<int32_t>("index", context->GetIndex());
1163     pathInfo->SetProperty<std::string>("navDestinationId", std::to_string(context->GetNavDestinationId()));
1164     pathInfo->SetProperty<bool>("isEntry", jsPathInfo->GetIsEntry());
1165     pathInfo->SetPropertyObject("param", jsPathInfo->GetParam());
1166     pathInfo->SetPropertyObject("onPop", jsPathInfo->GetOnPop());
1167     return pathInfo;
1168 }
1169 
1170 } // namespace OHOS::Ace::Framework
1171