• 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 char JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC[] = "getNativeStack";
35 constexpr char JS_NAV_PATH_STACK_SETPARENT_FUNC[] = "setParent";
36 }
37 
GetName()38 std::string JSRouteInfo::GetName()
39 {
40     return name_;
41 }
42 
SetName(const std::string & name)43 void JSRouteInfo::SetName(const std::string& name)
44 {
45     name_ = name;
46 }
47 
SetParam(const JSRef<JSVal> & param)48 void JSRouteInfo::SetParam(const JSRef<JSVal>& param)
49 {
50     param_ = param;
51 }
52 
GetParam() const53 JSRef<JSVal> JSRouteInfo::GetParam() const
54 {
55     return param_;
56 }
57 
SetDataSourceObj(const JSRef<JSObject> & dataSourceObj)58 void JSNavigationStack::SetDataSourceObj(const JSRef<JSObject>& dataSourceObj)
59 {
60     // clean callback from old JSNavPathStack
61     UpdateOnStateChangedCallback(dataSourceObj_, nullptr);
62     UpdateCheckNavDestinationExistsFunc(dataSourceObj_, nullptr);
63     dataSourceObj_ = dataSourceObj;
64     // add callback to new JSNavPathStack
65     UpdateOnStateChangedCallback(dataSourceObj_, onStateChangedCallback_);
66     auto checkNavDestinationExistsFunc = [weakStack = WeakClaim(this)](const JSRef<JSObject>& info) -> int32_t {
67         auto stack = weakStack.Upgrade();
68         if (stack == nullptr) {
69             return ERROR_CODE_INTERNAL_ERROR;
70         }
71         auto errorCode = stack->CheckNavDestinationExists(info);
72         if (errorCode != ERROR_CODE_NO_ERROR) {
73             stack->RemoveInvalidPage(info);
74         }
75         return errorCode;
76     };
77     UpdateCheckNavDestinationExistsFunc(dataSourceObj_, checkNavDestinationExistsFunc);
78 }
79 
UpdateCheckNavDestinationExistsFunc(JSRef<JSObject> obj,std::function<int32_t (JSRef<JSObject>)> checkFunc)80 void JSNavigationStack::UpdateCheckNavDestinationExistsFunc(JSRef<JSObject> obj,
81     std::function<int32_t(JSRef<JSObject>)> checkFunc)
82 {
83     if (obj->IsEmpty()) {
84         return;
85     }
86 
87     auto property = obj->GetProperty(JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC);
88     if (!property->IsFunction()) {
89         return;
90     }
91 
92     auto getNativeStackFunc = JSRef<JSFunc>::Cast(property);
93     auto nativeStack = getNativeStackFunc->Call(obj);
94     if (nativeStack->IsEmpty() || !nativeStack->IsObject()) {
95         return;
96     }
97 
98     auto nativeStackObj = JSRef<JSObject>::Cast(nativeStack);
99     JSNavPathStack* stack = nativeStackObj->Unwrap<JSNavPathStack>();
100     CHECK_NULL_VOID(stack);
101 
102     stack->SetCheckNavDestinationExistsFunc(checkFunc);
103 }
104 
GetDataSourceObj()105 const JSRef<JSObject>& JSNavigationStack::GetDataSourceObj()
106 {
107     return dataSourceObj_;
108 }
109 
SetNavDestBuilderFunc(const JSRef<JSFunc> & navDestBuilderFunc)110 void JSNavigationStack::SetNavDestBuilderFunc(const JSRef<JSFunc>& navDestBuilderFunc)
111 {
112     navDestBuilderFunc_ = navDestBuilderFunc;
113 }
114 
IsEmpty()115 bool JSNavigationStack::IsEmpty()
116 {
117     return dataSourceObj_->IsEmpty();
118 }
119 
Pop()120 void JSNavigationStack::Pop()
121 {
122     if (dataSourceObj_->IsEmpty()) {
123         return;
124     }
125     auto popFunc = dataSourceObj_->GetProperty("pop");
126     if (!popFunc->IsFunction()) {
127         return;
128     }
129     auto func = JSRef<JSFunc>::Cast(popFunc);
130     JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
131 }
132 
Push(const std::string & name,const RefPtr<NG::RouteInfo> & routeInfo)133 void JSNavigationStack::Push(const std::string& name, const RefPtr<NG::RouteInfo>& routeInfo)
134 {
135     // obtain param from NavPathStack
136     JSRef<JSVal> param;
137     if (routeInfo) {
138         auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
139         param = jsRouteInfo->GetParam();
140     } else {
141         auto getFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getParamByName"));
142         auto result = JSRef<JSArray>::Cast(getFunc->Call(dataSourceObj_));
143         param = result->GetValueAt(0);
144     }
145 
146     auto pushFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("pushName"));
147     JSRef<JSVal> params[2];
148     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
149     params[1] = param;
150     pushFunc->Call(dataSourceObj_, 2, params);
151 }
152 
PushName(const std::string & name,const JSRef<JSVal> & param)153 void JSNavigationStack::PushName(const std::string& name, const JSRef<JSVal>& param)
154 {
155     // obtain param from routeInfo
156     auto pushFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("pushName"));
157     JSRef<JSVal> params[2];
158     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
159     params[1] = param;
160     pushFunc->Call(dataSourceObj_, 2, params);
161 }
162 
Push(const std::string & name,int32_t index)163 void JSNavigationStack::Push(const std::string& name, int32_t index)
164 {
165     auto getFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getParamByIndex"));
166     auto param = JSRef<JSVal>::Cast(getFunc->Call(dataSourceObj_));
167     auto pushFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("pushName"));
168     JSRef<JSVal> params[2];
169     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
170     params[1] = param;
171     pushFunc->Call(dataSourceObj_, 2, params);
172 }
173 
RemoveName(const std::string & name)174 void JSNavigationStack::RemoveName(const std::string& name)
175 {
176     if (dataSourceObj_->IsEmpty()) {
177         return;
178     }
179     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("removeByName"));
180     JSRef<JSVal> params[1];
181     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
182     func->Call(dataSourceObj_, 1, params);
183 }
184 
RemoveIndex(int32_t index)185 void JSNavigationStack::RemoveIndex(int32_t index)
186 {
187     if (dataSourceObj_->IsEmpty()) {
188         return;
189     }
190     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("removeIndex"));
191     JSRef<JSVal> params[1];
192     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
193     func->Call(dataSourceObj_, 1, params);
194 }
195 
Clear()196 void JSNavigationStack::Clear()
197 {
198     if (dataSourceObj_->IsEmpty()) {
199         return;
200     }
201     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("clear"));
202     func->Call(dataSourceObj_);
203 }
204 
GetAllPathName()205 std::vector<std::string> JSNavigationStack::GetAllPathName()
206 {
207     if (dataSourceObj_->IsEmpty()) {
208         return {};
209     }
210     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getAllPathName"));
211     auto array = JSRef<JSArray>::Cast(func->Call(dataSourceObj_));
212     if (array->IsEmpty()) {
213         return {};
214     }
215     std::vector<std::string> pathNames;
216     for (size_t i = 0; i < array->Length(); i++) {
217         auto value = array->GetValueAt(i);
218         if (value->IsString()) {
219             pathNames.emplace_back(value->ToString());
220         }
221     }
222 
223     return pathNames;
224 }
225 
GetRemoveArray()226 std::vector<int32_t> JSNavigationStack::GetRemoveArray()
227 {
228     if (dataSourceObj_->IsEmpty()) {
229         return {};
230     }
231     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getRemoveArray"));
232     auto array = JSRef<JSArray>::Cast(func->Call(dataSourceObj_));
233     if (array->IsEmpty()) {
234         return {};
235     }
236     std::vector<int32_t> removeArrays;
237     for (size_t i = 0; i < array->Length(); i++) {
238         auto value = array->GetValueAt(i);
239         if (value->IsNumber()) {
240             removeArrays.emplace_back(value->ToNumber<int32_t>());
241         }
242     }
243 
244     return removeArrays;
245 }
246 
ClearRemoveArray()247 void JSNavigationStack::ClearRemoveArray()
248 {
249     if (dataSourceObj_->IsEmpty()) {
250         return;
251     }
252     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("clearRemoveArray"));
253     func->Call(dataSourceObj_);
254 }
255 
CreateNodeByIndex(int32_t index)256 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByIndex(int32_t index)
257 {
258     auto name = GetNameByIndex(index);
259     auto param = GetParamByIndex(index);
260     if (GetFlagByIndex(index)) {
261         auto node = GetNodeFromPreBuildList(name, param);
262         if (node != nullptr) {
263             return node;
264         }
265     }
266     JSRef<JSVal> params[2];
267     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
268     params[1] = param;
269     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
270     NG::ScopedViewStackProcessor scopedViewStackProcessor;
271     if (navDestBuilderFunc_->IsEmpty()) {
272         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navDestination builder function is nullptr, add default page");
273         return AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
274     }
275     navDestBuilderFunc_->Call(JSRef<JSObject>(), 2, params);
276     auto node = NG::ViewStackProcessor::GetInstance()->Finish();
277     if (node == nullptr) {
278         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "router map is invalid, current path name is %{public}s", name.c_str());
279     }
280     RefPtr<NG::NavDestinationGroupNode> desNode;
281     if (GetNavDestinationNodeInUINode(node, desNode)) {
282         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
283         if (pattern) {
284             auto onPop = GetOnPopByIndex(index);
285             auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop);
286             pattern->SetNavPathInfo(pathInfo);
287             pattern->SetNavigationStack(WeakClaim(this));
288         }
289         return node;
290     }
291     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't find target destination by index, create empty node");
292     return AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
293 }
294 
CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo> & routeInfo)295 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo>& routeInfo)
296 {
297     auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
298     auto name = jsRouteInfo->GetName();
299     auto param = jsRouteInfo->GetParam();
300     JSRef<JSVal> params[2];
301     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
302     params[1] = param;
303     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
304     NG::ScopedViewStackProcessor scopedViewStackProcessor;
305     navDestBuilderFunc_->Call(JSRef<JSObject>(), 2, params);
306     auto node = NG::ViewStackProcessor::GetInstance()->Finish();
307     if (node == nullptr) {
308         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "create destination by builder failed");
309     }
310     RefPtr<NG::NavDestinationGroupNode> desNode;
311     if (GetNavDestinationNodeInUINode(node, desNode)) {
312         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
313         if (pattern) {
314             auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param);
315             pattern->SetNavPathInfo(pathInfo);
316             pattern->SetNavigationStack(WeakClaim(this));
317         }
318         return node;
319     }
320     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't find navDestination by route info, create empty node");
321     return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
322 }
323 
SetJSExecutionContext(const JSExecutionContext & context)324 void JSNavigationStack::SetJSExecutionContext(const JSExecutionContext& context)
325 {
326     executionContext_ = context;
327 }
328 
GetNameByIndex(int32_t index)329 std::string JSNavigationStack::GetNameByIndex(int32_t index)
330 {
331     auto pathNames = GetAllPathName();
332     if (index < 0 || index >= static_cast<int32_t>(pathNames.size())) {
333         return "";
334     }
335 
336     return pathNames[index];
337 }
338 
GetParamByIndex(int32_t index) const339 JSRef<JSVal> JSNavigationStack::GetParamByIndex(int32_t index) const
340 {
341     if (dataSourceObj_->IsEmpty()) {
342         return JSRef<JSVal>::Make();
343     }
344     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getParamByIndex"));
345     JSRef<JSVal> params[1];
346     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
347     return func->Call(dataSourceObj_, 1, params);
348 }
349 
GetOnPopByIndex(int32_t index) const350 JSRef<JSVal> JSNavigationStack::GetOnPopByIndex(int32_t index) const
351 {
352     if (dataSourceObj_->IsEmpty()) {
353         return JSRef<JSVal>::Make();
354     }
355     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getOnPopByIndex"));
356     JSRef<JSVal> params[1];
357     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
358     return func->Call(dataSourceObj_, 1, params);
359 }
360 
GetNavDestinationNodeInUINode(RefPtr<NG::UINode> node,RefPtr<NG::NavDestinationGroupNode> & desNode)361 bool JSNavigationStack::GetNavDestinationNodeInUINode(
362     RefPtr<NG::UINode> node, RefPtr<NG::NavDestinationGroupNode>& desNode)
363 {
364     while (node) {
365         if (node->GetTag() == V2::JS_VIEW_ETS_TAG) {
366             auto customNode = AceType::DynamicCast<NG::CustomNode>(node);
367             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "render current custom node: %{public}s",
368                 customNode->GetCustomTag().c_str());
369             // render, and find deep further
370             customNode->Render();
371         } else if (node->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
372             desNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(node);
373             return true;
374         }
375         auto children = node->GetChildren();
376         if (children.size() != 1) {
377             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "router map is invalid, child size is more than one");
378         }
379         node = children.front();
380     }
381     return false;
382 }
383 
GetReplaceValue() const384 int32_t JSNavigationStack::GetReplaceValue() const
385 {
386     if (dataSourceObj_->IsEmpty()) {
387         return false;
388     }
389     auto replace = dataSourceObj_->GetProperty("isReplace");
390     return replace->ToNumber<int32_t>();
391 }
392 
UpdateReplaceValue(int32_t replaceValue) const393 void JSNavigationStack::UpdateReplaceValue(int32_t replaceValue) const
394 {
395     if (dataSourceObj_->IsEmpty()) {
396         return;
397     }
398     auto replaceFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("setIsReplace"));
399     JSRef<JSVal> params[1];
400     params[0] = JSRef<JSVal>::Make(ToJSValue(replaceValue));
401     replaceFunc->Call(dataSourceObj_, 1, params);
402 }
403 
GetAnimatedValue() const404 bool JSNavigationStack::GetAnimatedValue() const
405 {
406     if (dataSourceObj_->IsEmpty()) {
407         return true;
408     }
409     auto animated = dataSourceObj_->GetProperty("animated");
410     return animated->ToBoolean();
411 }
412 
UpdateAnimatedValue(bool animated)413 void JSNavigationStack::UpdateAnimatedValue(bool animated)
414 {
415     if (dataSourceObj_->IsEmpty()) {
416         return;
417     }
418     auto animatedFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("setAnimated"));
419     JSRef<JSVal> params[1];
420     params[0] = JSRef<JSVal>::Make(ToJSValue(animated));
421     animatedFunc->Call(dataSourceObj_, 1, params);
422 }
423 
424 
GetDisableAnimation() const425 bool JSNavigationStack::GetDisableAnimation() const
426 {
427     if (dataSourceObj_->IsEmpty()) {
428         return false;
429     }
430     auto disableAllAnimation = dataSourceObj_->GetProperty("disableAllAnimation");
431     return disableAllAnimation->ToBoolean();
432 }
433 
GetRouteParam() const434 std::string JSNavigationStack::GetRouteParam() const
435 {
436     auto size = GetSize();
437     if (size > 0) {
438         auto param = GetParamByIndex(size - 1);
439         return ConvertParamToString(param);
440     }
441     return "";
442 }
443 
GetSize() const444 int32_t JSNavigationStack::GetSize() const
445 {
446     if (dataSourceObj_->IsEmpty()) {
447         return 0;
448     }
449     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("size"));
450     auto jsValue = JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
451     if (jsValue->IsNumber()) {
452         return jsValue->ToNumber<int32_t>();
453     }
454     return 0;
455 }
456 
ConvertParamToString(const JSRef<JSVal> & param)457 std::string JSNavigationStack::ConvertParamToString(const JSRef<JSVal>& param)
458 {
459     if (param->IsBoolean()) {
460         bool ret = param->ToBoolean();
461         return ret ? "true" : "false";
462     } else if (param->IsNumber()) {
463         double ret = param->ToNumber<double>();
464         std::ostringstream oss;
465         oss<< ret;
466         return oss.str();
467     } else if (param->IsString()) {
468         std::string ret = param->ToString();
469         return ret;
470     } else if (param->IsObject()) {
471         JSRef<JSObject> obj = JSRef<JSObject>::Cast(param);
472         auto jsonObj = JsonUtil::Create(true);
473         ParseJsObject(jsonObj, obj, MAX_PARSE_DEPTH);
474         return jsonObj->ToString();
475     }
476     return "";
477 }
478 
ParseJsObject(std::unique_ptr<JsonValue> & json,const JSRef<JSObject> & obj,int32_t depthLimit)479 void JSNavigationStack::ParseJsObject(std::unique_ptr<JsonValue>& json, const JSRef<JSObject>& obj, int32_t depthLimit)
480 {
481     if (depthLimit == 0) {
482         return;
483     }
484     depthLimit--;
485     auto propertyNames = obj->GetPropertyNames();
486     if (!propertyNames->IsArray()) {
487         return;
488     }
489     for (size_t i = 0; i < propertyNames->Length(); i++) {
490         JSRef<JSVal> name = propertyNames->GetValueAt(i);
491         if (!name->IsString()) {
492             continue;
493         }
494         auto propertyName = name->ToString();
495         auto key = propertyName.c_str();
496         JSRef<JSVal> value = obj->GetProperty(key);
497         if (value->IsBoolean()) {
498             bool ret = value->ToBoolean();
499             json->Put(key, ret ? "true" : "false");
500         } else if (value->IsNumber()) {
501             double ret = value->ToNumber<double>();
502             std::ostringstream oss;
503             oss<< ret;
504             json->Put(key, oss.str().c_str());
505         } else if (value->IsString()) {
506             std::string ret = value->ToString();
507             json->Put(key, ret.c_str());
508         } else if (value->IsObject()) {
509             JSRef<JSObject> childObj = JSRef<JSObject>::Cast(value);
510             auto childJson = JsonUtil::Create(true);
511             ParseJsObject(childJson, childObj, depthLimit);
512             json->Put(key, childJson);
513         }
514     }
515 }
516 
UpdateOnStateChangedCallback(JSRef<JSObject> obj,std::function<void ()> callback)517 void JSNavigationStack::UpdateOnStateChangedCallback(JSRef<JSObject> obj, std::function<void()> callback)
518 {
519     if (obj->IsEmpty()) {
520         return;
521     }
522 
523     auto property = obj->GetProperty(JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC);
524     if (!property->IsFunction()) {
525         return;
526     }
527 
528     auto getNativeStackFunc = JSRef<JSFunc>::Cast(property);
529     auto nativeStack = getNativeStackFunc->Call(obj);
530     if (nativeStack->IsEmpty() || !nativeStack->IsObject()) {
531         return;
532     }
533 
534     auto nativeStackObj = JSRef<JSObject>::Cast(nativeStack);
535     JSNavPathStack* stack = nativeStackObj->Unwrap<JSNavPathStack>();
536     CHECK_NULL_VOID(stack);
537     stack->SetOnStateChangedCallback(callback);
538     // When switching the navigation stack, it is necessary to immediately trigger a refresh
539     stack->OnStateChanged();
540 }
541 
OnAttachToParent(RefPtr<NG::NavigationStack> parent)542 void JSNavigationStack::OnAttachToParent(RefPtr<NG::NavigationStack> parent)
543 {
544     auto parentStack = AceType::DynamicCast<JSNavigationStack>(parent);
545     if (!parentStack) {
546         return;
547     }
548 
549     SetJSParentStack(JSRef<JSVal>::Cast(parentStack->GetDataSourceObj()));
550 }
551 
OnDetachFromParent()552 void JSNavigationStack::OnDetachFromParent()
553 {
554     JSRef<JSVal> undefined(JSVal::Undefined());
555     SetJSParentStack(undefined);
556 }
557 
SetJSParentStack(JSRef<JSVal> parent)558 void JSNavigationStack::SetJSParentStack(JSRef<JSVal> parent)
559 {
560     if (dataSourceObj_->IsEmpty()) {
561         return;
562     }
563 
564     auto property = dataSourceObj_->GetProperty(JS_NAV_PATH_STACK_SETPARENT_FUNC);
565     if (!property->IsFunction()) {
566         return;
567     }
568 
569     auto func = JSRef<JSFunc>::Cast(property);
570     JSRef<JSVal> params[1];
571     params[0] = parent;
572     func->Call(dataSourceObj_, 1, params);
573 }
574 
RemoveInvalidPage(const JSRef<JSObject> & info)575 void JSNavigationStack::RemoveInvalidPage(const JSRef<JSObject>& info)
576 {
577     if (dataSourceObj_->IsEmpty()) {
578         return;
579     }
580     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("removeInvalidPage"));
581     auto pathName = info->GetProperty("name");
582     auto param = info->GetProperty("param");
583     JSRef<JSVal> params[ARGC_COUNT_TWO] = { pathName, param };
584     func->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
585 }
586 
SaveNodeToPreBuildList(const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node)587 void JSNavigationStack::SaveNodeToPreBuildList(const std::string& name, const JSRef<JSVal>& param,
588     RefPtr<NG::UINode>& node)
589 {
590     preBuildNodeList_.emplace_back(name, param, node);
591 }
592 
GetNodeFromPreBuildList(const std::string & name,const JSRef<JSVal> & param)593 RefPtr<NG::UINode> JSNavigationStack::GetNodeFromPreBuildList(const std::string& name, const JSRef<JSVal>& param)
594 {
595     auto isJsObjEqual = [](const JSRef<JSVal>& objLeft, const JSRef<JSVal>& objRight) {
596         return (objLeft->IsEmpty() && objRight->IsEmpty()) ||
597             (objLeft->GetLocalHandle()->IsStrictEquals(objLeft->GetEcmaVM(), objRight->GetLocalHandle()));
598     };
599     for (auto it = preBuildNodeList_.begin(); it != preBuildNodeList_.end(); ++it) {
600         if (it->name == name && isJsObjEqual(it->param, param)) {
601             auto uiNode = it->uiNode;
602             preBuildNodeList_.erase(it);
603             return uiNode;
604         }
605     }
606     return nullptr;
607 }
608 
ClearPreBuildNodeList()609 void JSNavigationStack::ClearPreBuildNodeList()
610 {
611     preBuildNodeList_.clear();
612 }
613 
CheckNavDestinationExists(const JSRef<JSObject> & navPathInfo)614 int32_t JSNavigationStack::CheckNavDestinationExists(const JSRef<JSObject>& navPathInfo)
615 {
616     if (navDestBuilderFunc_->IsEmpty()) {
617         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "navDestBuilderFunc_ is empty.");
618         return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
619     }
620 
621     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, ERROR_CODE_INTERNAL_ERROR);
622     NG::ScopedViewStackProcessor scopedViewStackProcessor;
623 
624     auto pathName = navPathInfo->GetProperty("name");
625     auto param = navPathInfo->GetProperty("param");
626     JSRef<JSVal> params[ARGC_COUNT_TWO] = { pathName, param };
627     navDestBuilderFunc_->Call(JSRef<JSObject>(), ARGC_COUNT_TWO, params);
628 
629     auto node = NG::ViewStackProcessor::GetInstance()->Finish();
630     RefPtr<NG::NavDestinationGroupNode> desNode;
631     if (GetNavDestinationNodeInUINode(node, desNode)) {
632         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
633         if (pattern) {
634             auto onPop = navPathInfo->GetProperty("onPop");
635             auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(pathName->ToString(), param, onPop);
636             pattern->SetNavPathInfo(pathInfo);
637             pattern->SetNavigationStack(WeakClaim(this));
638         }
639         SaveNodeToPreBuildList(pathName->ToString(), param, node);
640         return ERROR_CODE_NO_ERROR;
641     }
642     return ERROR_CODE_DESTINATION_NOT_FOUND;
643 }
644 
GetFlagByIndex(int32_t index) const645 bool JSNavigationStack::GetFlagByIndex(int32_t index) const
646 {
647     if (dataSourceObj_->IsEmpty()) {
648         return false;
649     }
650     auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getCheckNavDestinationFlagByIndex"));
651     JSRef<JSVal> params[1];
652     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
653     auto res = func->Call(dataSourceObj_, 1, params);
654     if (res->IsBoolean()) {
655         return res->ToBoolean();
656     }
657     return false;
658 }
659 } // namespace OHOS::Ace::Framework
660