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, ¶m);
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, ¶m);
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