1 /*
2 * Copyright (c) 2021 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 "frameworks/bridge/declarative_frontend/engine/quickjs/modules/qjs_router_module.h"
17
18 #include "base/log/log.h"
19 #include "frameworks/bridge/declarative_frontend/engine/quickjs/qjs_declarative_engine.h"
20 #include "frameworks/bridge/js_frontend/engine/common/js_constants.h"
21 #include "frameworks/bridge/js_frontend/engine/quickjs/qjs_utils.h"
22
23 namespace OHOS::Ace::Framework {
24
JsParseRouteUrl(JSContext * ctx,JSValueConst valObject,const std::string & routerKey)25 std::string JsParseRouteUrl(JSContext* ctx, JSValueConst valObject, const std::string& routerKey)
26 {
27 std::string routeUrl;
28 JSPropertyEnum* pTab = nullptr;
29 uint32_t len = 0;
30 if (!CheckAndGetJsProperty(ctx, valObject, &pTab, &len)) {
31 return routeUrl;
32 }
33 for (uint32_t i = 0; i < len; ++i) {
34 const char* key = JS_AtomToCString(ctx, pTab[i].atom);
35 if (key == nullptr) {
36 JS_FreeAtom(ctx, pTab[i].atom);
37 LOGW("key is null. Ignoring!");
38 continue;
39 }
40 JSValue valItem = JS_GetProperty(ctx, valObject, pTab[i].atom);
41 if (JS_IsString(valItem)) {
42 ScopedString styleVal(ctx, valItem);
43 const char* valStr = styleVal.get();
44 if (strcmp(key, routerKey.c_str()) == 0) {
45 routeUrl = valStr;
46 LOGD("routeUrl : %{public}s ", routeUrl.c_str());
47 } else {
48 LOGE("routeUrl : %{public}s unsupported. Ignoring!", key);
49 }
50 } else {
51 LOGE("value of unsupported type. Ignoring!");
52 }
53 JS_FreeAtom(ctx, pTab[i].atom);
54 JS_FreeCString(ctx, key);
55 JS_FreeValue(ctx, valItem);
56 }
57 js_free(ctx, pTab);
58 return routeUrl;
59 }
60
JsParseRouteParams(JSContext * ctx,JSValueConst valObject,const std::string & paramsKey)61 std::string JsParseRouteParams(JSContext* ctx, JSValueConst valObject, const std::string& paramsKey)
62 {
63 std::string routeParams;
64 JSPropertyEnum* pTab = nullptr;
65 uint32_t len = 0;
66 if (!CheckAndGetJsProperty(ctx, valObject, &pTab, &len)) {
67 return routeParams;
68 }
69 for (uint32_t i = 0; i < len; ++i) {
70 const char* key = JS_AtomToCString(ctx, pTab[i].atom);
71 if (key == nullptr) {
72 JS_FreeAtom(ctx, pTab[i].atom);
73 LOGW("key is null. Ignoring!");
74 continue;
75 }
76 JSValue valItem = JS_GetProperty(ctx, valObject, pTab[i].atom);
77 if (JS_IsObject(valItem)) {
78 if (strcmp(key, paramsKey.c_str()) == 0) {
79 routeParams = ScopedString::Stringify(valItem);
80 LOGD("routeParams : %{public}s ", routeParams.c_str());
81 } else {
82 LOGE("routeParams : %{public}s unsupported. Ignoring!", key);
83 }
84 } else {
85 LOGE("value of unsupported type. Ignoring!");
86 }
87 JS_FreeAtom(ctx, pTab[i].atom);
88 JS_FreeCString(ctx, key);
89 JS_FreeValue(ctx, valItem);
90 }
91 js_free(ctx, pTab);
92 return routeParams;
93 }
94
PagePush(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)95 JSValue PagePush(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
96 {
97 if (argc != 1) {
98 LOGE("PagePush args count is invalid");
99 return JS_NULL;
100 }
101
102 std::string uri = JsParseRouteUrl(ctx, argv[0], ROUTE_KEY_URI);
103 std::string params = JsParseRouteParams(ctx, argv[0], ROUTE_KEY_PARAMS);
104 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
105 if (instance == nullptr) {
106 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
107 return JS_NULL;
108 }
109 instance->GetDelegate()->Push(uri, params);
110 return JS_NULL;
111 }
112
PageReplace(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)113 JSValue PageReplace(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
114 {
115 if (argc != 1) {
116 LOGE("PageReplace args count is invalid");
117 return JS_NULL;
118 }
119
120 std::string uri = JsParseRouteUrl(ctx, argv[0], ROUTE_KEY_URI);
121 std::string params = JsParseRouteParams(ctx, argv[0], ROUTE_KEY_PARAMS);
122 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
123 if (instance == nullptr) {
124 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
125 return JS_NULL;
126 }
127 instance->GetDelegate()->Replace(uri, params);
128 return JS_NULL;
129 }
130
PageBack(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)131 JSValue PageBack(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
132 {
133 if (argc != 1 && argc != 0) {
134 LOGE("PageBack args count is invalid");
135 return JS_NULL;
136 }
137
138 std::string uri = JsParseRouteUrl(ctx, argv[0], ROUTE_KEY_URI);
139 std::string params = JsParseRouteParams(ctx, argv[0], ROUTE_KEY_PARAMS);
140 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
141 if (instance == nullptr) {
142 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
143 return JS_NULL;
144 }
145 instance->GetDelegate()->Back(uri, params);
146 return JS_NULL;
147 }
148
PageClear(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)149 JSValue PageClear(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
150 {
151 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
152 if (instance == nullptr) {
153 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
154 return JS_NULL;
155 }
156 instance->GetDelegate()->Clear();
157 return JS_NULL;
158 }
159
PageGetLength(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)160 JSValue PageGetLength(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
161 {
162 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
163 if (instance == nullptr) {
164 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
165 return JS_NULL;
166 }
167 int32_t routeLength = instance->GetDelegate()->GetStackSize();
168 return JS_NewString(ctx, std::to_string(routeLength).c_str());
169 }
170
PageGetState(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)171 JSValue PageGetState(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
172 {
173 int32_t routeIndex = 0;
174 std::string routeName;
175 std::string routePath;
176 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
177 if (instance == nullptr) {
178 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
179 return JS_NULL;
180 }
181 instance->GetDelegate()->GetState(routeIndex, routeName, routePath);
182 JSValue jsState = JS_NewObject(ctx);
183 JS_SetPropertyStr(ctx, jsState, "index", JS_NewInt32(ctx, routeIndex));
184 JS_SetPropertyStr(ctx, jsState, "name", JS_NewString(ctx, routeName.c_str()));
185 JS_SetPropertyStr(ctx, jsState, "path", JS_NewString(ctx, routePath.c_str()));
186 return jsState;
187 }
188
PageGetParams(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)189 JSValue PageGetParams(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
190 {
191 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
192 if (instance == nullptr) {
193 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
194 return JS_NULL;
195 }
196 std::string paramsStr = instance->GetDelegate()->GetParams();
197 if (paramsStr.empty()) {
198 LOGI("PageGetParams params is null");
199 return JS_NULL;
200 }
201
202 JSValue paramsRes = JS_ParseJSON(ctx, paramsStr.c_str(), paramsStr.length(), nullptr);
203 return paramsRes;
204 }
205
PostponePageTransition(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)206 JSValue PostponePageTransition(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
207 {
208 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
209 if (instance == nullptr) {
210 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
211 return JS_NULL;
212 }
213 instance->GetDelegate()->PostponePageTransition();
214 return JS_NULL;
215 }
216
LaunchPageTransition(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)217 JSValue LaunchPageTransition(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
218 {
219 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(ctx));
220 if (instance == nullptr) {
221 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
222 return JS_NULL;
223 }
224 instance->GetDelegate()->LaunchPageTransition();
225 return JS_NULL;
226 }
227
InitRouterModule(JSContext * ctx,JSValue & moduleObj)228 void InitRouterModule(JSContext* ctx, JSValue& moduleObj)
229 {
230 JS_SetPropertyStr(ctx, moduleObj, ROUTE_PAGE_PUSH, JS_NewCFunction(ctx, PagePush, ROUTE_PAGE_PUSH, 1));
231 JS_SetPropertyStr(ctx, moduleObj, ROUTE_PAGE_REPLACE, JS_NewCFunction(ctx, PageReplace, ROUTE_PAGE_REPLACE, 1));
232 JS_SetPropertyStr(ctx, moduleObj, ROUTE_PAGE_BACK, JS_NewCFunction(ctx, PageBack, ROUTE_PAGE_BACK, 1));
233 JS_SetPropertyStr(ctx, moduleObj, ROUTE_PAGE_CLEAR, JS_NewCFunction(ctx, PageClear, ROUTE_PAGE_CLEAR, 0));
234 JS_SetPropertyStr(
235 ctx, moduleObj, ROUTE_PAGE_GET_LENGTH, JS_NewCFunction(ctx, PageGetLength, ROUTE_PAGE_GET_LENGTH, 0));
236 JS_SetPropertyStr(
237 ctx, moduleObj, ROUTE_PAGE_GET_STATE, JS_NewCFunction(ctx, PageGetState, ROUTE_PAGE_GET_STATE, 0));
238 JS_SetPropertyStr(
239 ctx, moduleObj, ROUTE_PAGE_GET_PARAMS, JS_NewCFunction(ctx, PageGetParams, ROUTE_PAGE_GET_PARAMS, 0));
240 JS_SetPropertyStr(
241 ctx, moduleObj, ROUTE_POSTPONE, JS_NewCFunction(ctx, PostponePageTransition, ROUTE_POSTPONE, 0));
242
243 JSValue globalObj = JS_GetGlobalObject(ctx);
244 JSValue requireNapiFunc = JS_GetPropertyStr(ctx, globalObj, "requireNapi");
245 if (!JS_IsFunction(ctx, requireNapiFunc)) {
246 JS_FreeValue(ctx, globalObj);
247 return;
248 }
249 JSValueConst argv[] = { JS_NewString(ctx, "router") };
250 JSValue retVal = JS_Call(ctx, requireNapiFunc, globalObj, countof(argv), argv);
251 JS_SetPropertyStr(ctx, moduleObj,
252 ROUTE_ENABLE_ALERT_BEFORE_BACK_PAGE, JS_GetPropertyStr(ctx, retVal, ROUTE_ENABLE_ALERT_BEFORE_BACK_PAGE));
253 JS_SetPropertyStr(ctx, moduleObj,
254 ROUTE_DISABLE_ALERT_BEFORE_BACK_PAGE, JS_GetPropertyStr(ctx, retVal, ROUTE_DISABLE_ALERT_BEFORE_BACK_PAGE));
255 JS_FreeValue(ctx, retVal);
256 JS_FreeValue(ctx, globalObj);
257 }
258 } // namespace OHOS::Ace::Framework
259