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 "core/components_ng/base/ui_node.h"
22 #include "core/components_ng/base/view_stack_processor.h"
23 #include "core/components_ng/pattern/custom/custom_node.h"
24 #include "core/components_ng/pattern/navrouter/navdestination_model.h"
25 #include "core/components_v2/inspector/inspector_constants.h"
26
27 namespace OHOS::Ace::Framework {
28
GetName()29 std::string JSRouteInfo::GetName()
30 {
31 return name_;
32 }
33
SetName(const std::string & name)34 void JSRouteInfo::SetName(const std::string& name)
35 {
36 name_ = name;
37 }
38
SetParam(const JSRef<JSVal> & param)39 void JSRouteInfo::SetParam(const JSRef<JSVal>& param)
40 {
41 param_ = param;
42 }
43
GetParam() const44 JSRef<JSVal> JSRouteInfo::GetParam() const
45 {
46 return param_;
47 }
48
SetDataSourceObj(const JSRef<JSObject> & dataSourceObj)49 void JSNavigationStack::SetDataSourceObj(const JSRef<JSObject>& dataSourceObj)
50 {
51 dataSourceObj_ = dataSourceObj;
52 }
53
GetDataSourceObj()54 const JSRef<JSObject>& JSNavigationStack::GetDataSourceObj()
55 {
56 return dataSourceObj_;
57 }
58
SetNavDestBuilderFunc(const JSRef<JSFunc> & navDestBuilderFunc)59 void JSNavigationStack::SetNavDestBuilderFunc(const JSRef<JSFunc>& navDestBuilderFunc)
60 {
61 navDestBuilderFunc_ = navDestBuilderFunc;
62 }
63
IsEmpty()64 bool JSNavigationStack::IsEmpty()
65 {
66 return dataSourceObj_->IsEmpty();
67 }
68
Pop()69 void JSNavigationStack::Pop()
70 {
71 if (dataSourceObj_->IsEmpty()) {
72 return;
73 }
74 auto popFunc = dataSourceObj_->GetProperty("pop");
75 if (!popFunc->IsFunction()) {
76 return;
77 }
78 auto func = JSRef<JSFunc>::Cast(popFunc);
79 JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
80 }
81
Push(const std::string & name,const RefPtr<NG::RouteInfo> & routeInfo)82 void JSNavigationStack::Push(const std::string& name, const RefPtr<NG::RouteInfo>& routeInfo)
83 {
84 // obtain param from NavPathStack
85 JSRef<JSVal> param;
86 if (routeInfo) {
87 auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
88 param = jsRouteInfo->GetParam();
89 } else {
90 auto getFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getParamByName"));
91 auto result = JSRef<JSArray>::Cast(getFunc->Call(dataSourceObj_));
92 param = result->GetValueAt(0);
93 }
94
95 auto pushFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("pushName"));
96 JSRef<JSVal> params[2];
97 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
98 params[1] = param;
99 pushFunc->Call(dataSourceObj_, 2, params);
100 }
101
PushName(const std::string & name,const JSRef<JSVal> & param)102 void JSNavigationStack::PushName(const std::string& name, const JSRef<JSVal>& param)
103 {
104 // obtain param from routeInfo
105 auto pushFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("pushName"));
106 JSRef<JSVal> params[2];
107 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
108 params[1] = param;
109 pushFunc->Call(dataSourceObj_, 2, params);
110 }
111
Push(const std::string & name,int32_t index)112 void JSNavigationStack::Push(const std::string& name, int32_t index)
113 {
114 auto getFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getParamByIndex"));
115 auto param = JSRef<JSVal>::Cast(getFunc->Call(dataSourceObj_));
116 auto pushFunc = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("pushName"));
117 JSRef<JSVal> params[2];
118 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
119 params[1] = param;
120 pushFunc->Call(dataSourceObj_, 2, params);
121 }
122
RemoveName(const std::string & name)123 void JSNavigationStack::RemoveName(const std::string& name)
124 {
125 if (dataSourceObj_->IsEmpty()) {
126 return;
127 }
128 auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("removeName"));
129 JSRef<JSVal> params[1];
130 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
131 func->Call(dataSourceObj_, 1, params);
132 }
133
RemoveIndex(int32_t index)134 void JSNavigationStack::RemoveIndex(int32_t index)
135 {
136 if (dataSourceObj_->IsEmpty()) {
137 return;
138 }
139 auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("removeIndex"));
140 JSRef<JSVal> params[1];
141 params[0] = JSRef<JSVal>::Make(ToJSValue(index));
142 func->Call(dataSourceObj_, 1, params);
143 }
144
Clear()145 void JSNavigationStack::Clear()
146 {
147 if (dataSourceObj_->IsEmpty()) {
148 return;
149 }
150 auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("clear"));
151 func->Call(dataSourceObj_);
152 }
153
GetAllPathName()154 std::vector<std::string> JSNavigationStack::GetAllPathName()
155 {
156 if (dataSourceObj_->IsEmpty()) {
157 return {};
158 }
159 auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getAllPathName"));
160 auto array = JSRef<JSArray>::Cast(func->Call(dataSourceObj_));
161 if (array->IsEmpty()) {
162 return {};
163 }
164 std::vector<std::string> pathNames;
165 for (size_t i = 0; i < array->Length(); i++) {
166 auto value = array->GetValueAt(i);
167 if (value->IsString()) {
168 pathNames.emplace_back(value->ToString());
169 }
170 }
171
172 return pathNames;
173 }
174
CreateNodeByIndex(int32_t index)175 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByIndex(int32_t index)
176 {
177 auto name = GetNameByIndex(index);
178 auto param = GetParamByIndex(index);
179 JSRef<JSVal> params[2];
180 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
181 params[1] = param;
182 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
183 NG::ScopedViewStackProcessor scopedViewStackProcessor;
184 navDestBuilderFunc_->Call(JSRef<JSObject>(), 2, params);
185 auto node = NG::ViewStackProcessor::GetInstance()->Finish();
186 if (CheckNavDestinationNodeInUINode(node)) {
187 return node;
188 }
189 return AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
190 }
191
CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo> & routeInfo)192 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo>& routeInfo)
193 {
194 auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
195 auto name = jsRouteInfo->GetName();
196 auto param = jsRouteInfo->GetParam();
197 JSRef<JSVal> params[2];
198 params[0] = JSRef<JSVal>::Make(ToJSValue(name));
199 params[1] = param;
200 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
201 NG::ScopedViewStackProcessor scopedViewStackProcessor;
202 navDestBuilderFunc_->Call(JSRef<JSObject>(), 2, params);
203 auto node = NG::ViewStackProcessor::GetInstance()->Finish();
204 if (CheckNavDestinationNodeInUINode(node)) {
205 return node;
206 }
207 return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
208 }
209
SetJSExecutionContext(const JSExecutionContext & context)210 void JSNavigationStack::SetJSExecutionContext(const JSExecutionContext& context)
211 {
212 executionContext_ = context;
213 }
214
GetNameByIndex(int32_t index)215 std::string JSNavigationStack::GetNameByIndex(int32_t index)
216 {
217 auto pathNames = GetAllPathName();
218 if (index < 0 || index >= static_cast<int32_t>(pathNames.size())) {
219 return "";
220 }
221
222 return pathNames[index];
223 }
224
GetParamByIndex(int32_t index) const225 JSRef<JSVal> JSNavigationStack::GetParamByIndex(int32_t index) const
226 {
227 if (dataSourceObj_->IsEmpty()) {
228 return JSRef<JSVal>::Make();
229 }
230 auto func = JSRef<JSFunc>::Cast(dataSourceObj_->GetProperty("getParamByIndex"));
231 JSRef<JSVal> params[1];
232 params[0] = JSRef<JSVal>::Make(ToJSValue(index));
233 return func->Call(dataSourceObj_, 1, params);
234 }
235
CheckNavDestinationNodeInUINode(RefPtr<NG::UINode> node)236 bool JSNavigationStack::CheckNavDestinationNodeInUINode(RefPtr<NG::UINode> node)
237 {
238 while (node) {
239 if (node->GetTag() == V2::JS_VIEW_ETS_TAG) {
240 auto customNode = AceType::DynamicCast<NG::CustomNode>(node);
241 // render, and find deep further
242 customNode->Render();
243 } else if (node->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
244 return true;
245 }
246 auto children = node->GetChildren();
247 node = children.front();
248 }
249 return false;
250 }
251 } // namespace OHOS::Ace::Framework
252