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