@saltcorn/mobile-app 1.1.0-beta.2 → 1.1.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +3 -0
- package/build_scripts/modify_android_manifest.js +47 -0
- package/build_scripts/modify_gradle_cfg.js +34 -0
- package/package.json +20 -11
- package/src/.eslintrc +21 -0
- package/src/helpers/api.js +43 -0
- package/src/helpers/auth.js +191 -0
- package/src/helpers/common.js +175 -0
- package/{www/js/utils/table_utils.js → src/helpers/db_schema.js} +18 -40
- package/src/helpers/file_system.js +102 -0
- package/{www/js/utils/global_utils.js → src/helpers/navigation.js} +175 -335
- package/src/helpers/offline_mode.js +645 -0
- package/src/index.js +20 -0
- package/src/init.js +424 -0
- package/src/routing/index.js +98 -0
- package/{www/js → src/routing}/mocks/request.js +5 -5
- package/{www/js → src/routing}/mocks/response.js +1 -1
- package/{www/js → src/routing}/routes/api.js +10 -15
- package/{www/js → src/routing}/routes/auth.js +12 -6
- package/{www/js → src/routing}/routes/delete.js +9 -6
- package/{www/js → src/routing}/routes/edit.js +9 -6
- package/src/routing/routes/error.js +6 -0
- package/{www/js → src/routing}/routes/fields.js +7 -2
- package/{www/js → src/routing}/routes/page.js +14 -9
- package/{www/js → src/routing}/routes/sync.js +9 -5
- package/{www/js → src/routing}/routes/view.js +16 -11
- package/{www/js/routes/common.js → src/routing/utils.js} +15 -13
- package/webpack.config.js +31 -0
- package/www/data/encoded_site_logo.js +1 -0
- package/www/index.html +23 -493
- package/www/js/{utils/iframe_view_utils.js → iframe_view_utils.js} +187 -273
- package/config.xml +0 -27
- package/res/icon/android/icon.png +0 -0
- package/res/screen/android/splash-icon.png +0 -0
- package/res/screen/ios/Default@2x~universal~anyany.png +0 -0
- package/www/js/routes/error.js +0 -5
- package/www/js/routes/init.js +0 -76
- package/www/js/utils/file_helpers.js +0 -108
- package/www/js/utils/offline_mode_helper.js +0 -625
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*eslint-env browser*/
|
|
2
|
-
/*global $, KTDrawer, submitWithEmptyAction, is_paging_param, bootstrap, common_done, unique_field_from_rows, inline_submit_success*/
|
|
2
|
+
/*global $, KTDrawer, submitWithEmptyAction, is_paging_param, bootstrap, common_done, unique_field_from_rows, inline_submit_success, get_current_state_url, initialize_page */
|
|
3
3
|
|
|
4
4
|
function combineFormAndQuery(form, query) {
|
|
5
5
|
let paramsList = [];
|
|
@@ -30,8 +30,15 @@ async function execLink(url, linkSrc) {
|
|
|
30
30
|
showLoadSpinner();
|
|
31
31
|
if (url.startsWith("javascript:")) eval(url.substring(11));
|
|
32
32
|
else {
|
|
33
|
-
const { path, query } =
|
|
34
|
-
|
|
33
|
+
const { path, query } =
|
|
34
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(url);
|
|
35
|
+
const safePath = path.startsWith("http")
|
|
36
|
+
? new URL(path).pathname
|
|
37
|
+
: path;
|
|
38
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(
|
|
39
|
+
`get${safePath}`,
|
|
40
|
+
query
|
|
41
|
+
);
|
|
35
42
|
}
|
|
36
43
|
} finally {
|
|
37
44
|
removeLoadSpinner();
|
|
@@ -39,8 +46,9 @@ async function execLink(url, linkSrc) {
|
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
async function runUrl(url, method = "get") {
|
|
42
|
-
const { path, query } =
|
|
43
|
-
|
|
49
|
+
const { path, query } =
|
|
50
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(url);
|
|
51
|
+
const page = await parent.saltcorn.mobileApp.navigation.router.resolve({
|
|
44
52
|
pathname: `${method}${path}`,
|
|
45
53
|
query: query,
|
|
46
54
|
});
|
|
@@ -84,17 +92,23 @@ async function formSubmit(e, urlSuffix, viewname, noSubmitCb, matchingState) {
|
|
|
84
92
|
const tokens = entry[1].split("/");
|
|
85
93
|
const fileName = tokens[tokens.length - 1];
|
|
86
94
|
const directory = tokens.splice(0, tokens.length - 1).join("/");
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
const { buffer, file } =
|
|
96
|
+
await parent.saltcorn.mobileApp.fileSystem.readBinaryCordova(
|
|
97
|
+
fileName,
|
|
98
|
+
directory
|
|
99
|
+
);
|
|
100
|
+
files[entry[0]] = {
|
|
101
|
+
blob: new Blob([buffer], { type: file.type }),
|
|
102
|
+
fileObj: file,
|
|
103
|
+
};
|
|
90
104
|
} else if (!matchingState) urlParams.append(entry[0], entry[1]);
|
|
91
105
|
else data[entry[0]] = entry[1];
|
|
92
106
|
}
|
|
93
107
|
}
|
|
94
108
|
const queryStr = !matchingState
|
|
95
109
|
? urlParams.toString()
|
|
96
|
-
: parent.currentQuery() || "";
|
|
97
|
-
await parent.handleRoute(
|
|
110
|
+
: parent.saltcorn.mobileApp.navigation.currentQuery() || "";
|
|
111
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(
|
|
98
112
|
`post${urlSuffix}${viewname}`,
|
|
99
113
|
queryStr,
|
|
100
114
|
files,
|
|
@@ -116,13 +130,13 @@ async function inline_local_submit(e, opts1) {
|
|
|
116
130
|
urlParams.append(entry[0], entry[1]);
|
|
117
131
|
}
|
|
118
132
|
const url = form.attr("action");
|
|
119
|
-
await parent.router.resolve({
|
|
133
|
+
await parent.saltcorn.mobileApp.navigation.router.resolve({
|
|
120
134
|
pathname: `post${url}`,
|
|
121
135
|
query: urlParams.toString(),
|
|
122
136
|
});
|
|
123
137
|
inline_submit_success(e, form, opts);
|
|
124
138
|
} catch (error) {
|
|
125
|
-
parent.showAlerts([
|
|
139
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
126
140
|
{
|
|
127
141
|
type: "error",
|
|
128
142
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -145,7 +159,7 @@ async function saveAndContinue(e, action, k) {
|
|
|
145
159
|
const form = $(e).closest("form");
|
|
146
160
|
submitWithEmptyAction(form[0]);
|
|
147
161
|
const queryStr = new URLSearchParams(new FormData(form[0])).toString();
|
|
148
|
-
const res = await parent.router.resolve({
|
|
162
|
+
const res = await parent.saltcorn.mobileApp.navigation.router.resolve({
|
|
149
163
|
pathname: `post${action}`,
|
|
150
164
|
query: queryStr,
|
|
151
165
|
xhr: true,
|
|
@@ -162,95 +176,16 @@ async function saveAndContinue(e, action, k) {
|
|
|
162
176
|
}
|
|
163
177
|
}
|
|
164
178
|
|
|
165
|
-
async function loginRequest({ email, password, isSignup, isPublic }) {
|
|
166
|
-
const opts = isPublic
|
|
167
|
-
? {
|
|
168
|
-
method: "GET",
|
|
169
|
-
path: "/auth/login-with/jwt",
|
|
170
|
-
}
|
|
171
|
-
: isSignup
|
|
172
|
-
? {
|
|
173
|
-
method: "POST",
|
|
174
|
-
path: "/auth/signup",
|
|
175
|
-
body: {
|
|
176
|
-
email,
|
|
177
|
-
password,
|
|
178
|
-
},
|
|
179
|
-
}
|
|
180
|
-
: {
|
|
181
|
-
method: "GET",
|
|
182
|
-
path: "/auth/login-with/jwt",
|
|
183
|
-
params: {
|
|
184
|
-
email,
|
|
185
|
-
password,
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
const response = await parent.apiCall(opts);
|
|
189
|
-
return response.data;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
179
|
async function login(e, entryPoint, isSignup) {
|
|
193
180
|
try {
|
|
194
181
|
showLoadSpinner();
|
|
195
182
|
const formData = new FormData(e);
|
|
196
|
-
|
|
183
|
+
await parent.saltcorn.mobileApp.auth.login({
|
|
197
184
|
email: formData.get("email"),
|
|
198
185
|
password: formData.get("password"),
|
|
199
186
|
isSignup,
|
|
187
|
+
entryPoint,
|
|
200
188
|
});
|
|
201
|
-
if (typeof loginResult === "string") {
|
|
202
|
-
// use it as a token
|
|
203
|
-
const decodedJwt = parent.jwt_decode(loginResult);
|
|
204
|
-
const state = parent.saltcorn.data.state.getState();
|
|
205
|
-
const config = state.mobileConfig;
|
|
206
|
-
config.role_id = decodedJwt.user.role_id ? decodedJwt.user.role_id : 100;
|
|
207
|
-
config.user_name = decodedJwt.user.email;
|
|
208
|
-
config.user_id = decodedJwt.user.id;
|
|
209
|
-
config.language = decodedJwt.user.language;
|
|
210
|
-
config.user = decodedJwt.user;
|
|
211
|
-
config.isPublicUser = false;
|
|
212
|
-
config.isOfflineMode = false;
|
|
213
|
-
await parent.insertUser(config.user);
|
|
214
|
-
await parent.setJwt(loginResult);
|
|
215
|
-
config.jwt = loginResult;
|
|
216
|
-
await parent.i18next.changeLanguage(config.language);
|
|
217
|
-
const alerts = [];
|
|
218
|
-
if (config.allowOfflineMode) {
|
|
219
|
-
const { offlineUser, hasOfflineData } =
|
|
220
|
-
(await parent.offlineHelper.getLastOfflineSession()) || {};
|
|
221
|
-
if (!offlineUser || offlineUser === config.user_name) {
|
|
222
|
-
await parent.offlineHelper.sync();
|
|
223
|
-
} else {
|
|
224
|
-
if (hasOfflineData)
|
|
225
|
-
alerts.push({
|
|
226
|
-
type: "warning",
|
|
227
|
-
msg: `'${offlineUser}' has not yet uploaded offline data.`,
|
|
228
|
-
});
|
|
229
|
-
else {
|
|
230
|
-
await deleteOfflineData(true);
|
|
231
|
-
await parent.offlineHelper.sync();
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
alerts.push({
|
|
236
|
-
type: "success",
|
|
237
|
-
msg: parent.i18next.t("Welcome, %s!", {
|
|
238
|
-
postProcess: "sprintf",
|
|
239
|
-
sprintf: [config.user_name],
|
|
240
|
-
}),
|
|
241
|
-
});
|
|
242
|
-
parent.addRoute({ route: entryPoint, query: undefined });
|
|
243
|
-
const page = await parent.router.resolve({
|
|
244
|
-
pathname: entryPoint,
|
|
245
|
-
fullWrap: true,
|
|
246
|
-
alerts,
|
|
247
|
-
});
|
|
248
|
-
if (page.content) await parent.replaceIframe(page.content, page.isFile);
|
|
249
|
-
} else if (loginResult?.alerts) {
|
|
250
|
-
parent.showAlerts(loginResult?.alerts);
|
|
251
|
-
} else {
|
|
252
|
-
throw new Error("The login failed.");
|
|
253
|
-
}
|
|
254
189
|
} finally {
|
|
255
190
|
removeLoadSpinner();
|
|
256
191
|
}
|
|
@@ -259,77 +194,16 @@ async function login(e, entryPoint, isSignup) {
|
|
|
259
194
|
async function publicLogin(entryPoint) {
|
|
260
195
|
try {
|
|
261
196
|
showLoadSpinner();
|
|
262
|
-
|
|
263
|
-
if (typeof loginResult === "string") {
|
|
264
|
-
const config = parent.saltcorn.data.state.getState().mobileConfig;
|
|
265
|
-
config.user = {
|
|
266
|
-
role_id: 100,
|
|
267
|
-
user_name: "public",
|
|
268
|
-
language: "en",
|
|
269
|
-
};
|
|
270
|
-
// TODO remove these, use 'user' everywhere
|
|
271
|
-
config.role_id = 100;
|
|
272
|
-
config.user_name = "public";
|
|
273
|
-
config.language = "en";
|
|
274
|
-
|
|
275
|
-
config.isPublicUser = true;
|
|
276
|
-
await parent.setJwt(loginResult);
|
|
277
|
-
config.jwt = loginResult;
|
|
278
|
-
parent.i18next.changeLanguage(config.language);
|
|
279
|
-
parent.addRoute({ route: entryPoint, query: undefined });
|
|
280
|
-
const page = await parent.router.resolve({
|
|
281
|
-
pathname: entryPoint,
|
|
282
|
-
fullWrap: true,
|
|
283
|
-
alerts: [
|
|
284
|
-
{
|
|
285
|
-
type: "success",
|
|
286
|
-
msg: parent.i18next.t("Welcome to %s!", {
|
|
287
|
-
postProcess: "sprintf",
|
|
288
|
-
sprintf: [
|
|
289
|
-
parent.saltcorn.data.state.getState().getConfig("site_name") ||
|
|
290
|
-
"Saltcorn",
|
|
291
|
-
],
|
|
292
|
-
}),
|
|
293
|
-
},
|
|
294
|
-
],
|
|
295
|
-
});
|
|
296
|
-
if (page.content) await parent.replaceIframe(page.content, page.isFile);
|
|
297
|
-
} else if (loginResult?.alerts) {
|
|
298
|
-
parent.showAlerts(loginResult?.alerts);
|
|
299
|
-
} else {
|
|
300
|
-
throw new Error("The login failed.");
|
|
301
|
-
}
|
|
302
|
-
} catch (error) {
|
|
303
|
-
console.log(error);
|
|
304
|
-
parent.showAlerts([
|
|
305
|
-
{
|
|
306
|
-
type: "error",
|
|
307
|
-
msg: error.message ? error.message : "An error occured.",
|
|
308
|
-
},
|
|
309
|
-
]);
|
|
310
|
-
throw error;
|
|
197
|
+
await parent.saltcorn.mobileApp.auth.publicLogin(entryPoint);
|
|
311
198
|
} finally {
|
|
312
199
|
removeLoadSpinner();
|
|
313
200
|
}
|
|
314
201
|
}
|
|
315
202
|
|
|
316
203
|
async function logout() {
|
|
317
|
-
const config = parent.saltcorn.data.state.getState().mobileConfig;
|
|
318
204
|
try {
|
|
319
205
|
showLoadSpinner();
|
|
320
|
-
|
|
321
|
-
pathname: "get/auth/logout",
|
|
322
|
-
entryView: config.entry_point,
|
|
323
|
-
versionTag: config.version_tag,
|
|
324
|
-
});
|
|
325
|
-
await parent.replaceIframe(page.content);
|
|
326
|
-
} catch (error) {
|
|
327
|
-
parent.showAlerts([
|
|
328
|
-
{
|
|
329
|
-
type: "error",
|
|
330
|
-
msg: error.message ? error.message : "An error occured.",
|
|
331
|
-
},
|
|
332
|
-
]);
|
|
206
|
+
await parent.saltcorn.mobileApp.auth.logout();
|
|
333
207
|
} finally {
|
|
334
208
|
removeLoadSpinner();
|
|
335
209
|
}
|
|
@@ -339,7 +213,7 @@ async function signupFormSubmit(e, entryView) {
|
|
|
339
213
|
try {
|
|
340
214
|
await login(e, entryView, true);
|
|
341
215
|
} catch (error) {
|
|
342
|
-
parent.errorAlert(error);
|
|
216
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
343
217
|
}
|
|
344
218
|
}
|
|
345
219
|
|
|
@@ -353,7 +227,7 @@ async function loginFormSubmit(e, entryView) {
|
|
|
353
227
|
}
|
|
354
228
|
await login(e, safeEntryView, false);
|
|
355
229
|
} catch (error) {
|
|
356
|
-
parent.errorAlert(error);
|
|
230
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
357
231
|
}
|
|
358
232
|
}
|
|
359
233
|
|
|
@@ -363,8 +237,9 @@ async function local_post_btn(e) {
|
|
|
363
237
|
const form = $(e).closest("form");
|
|
364
238
|
const url = form.attr("action");
|
|
365
239
|
const method = form.attr("method");
|
|
366
|
-
const { path, query } =
|
|
367
|
-
|
|
240
|
+
const { path, query } =
|
|
241
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(url);
|
|
242
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(
|
|
368
243
|
`${method}${path}`,
|
|
369
244
|
combineFormAndQuery(form, query)
|
|
370
245
|
);
|
|
@@ -382,7 +257,7 @@ async function stateFormSubmit(e, path) {
|
|
|
382
257
|
try {
|
|
383
258
|
showLoadSpinner();
|
|
384
259
|
const formQuery = new URLSearchParams(new FormData(e)).toString();
|
|
385
|
-
await parent.handleRoute(path, formQuery);
|
|
260
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(path, formQuery);
|
|
386
261
|
} finally {
|
|
387
262
|
removeLoadSpinner();
|
|
388
263
|
}
|
|
@@ -428,11 +303,14 @@ function invalidate_pagings(currentQuery) {
|
|
|
428
303
|
return newQuery;
|
|
429
304
|
}
|
|
430
305
|
|
|
431
|
-
async function set_state_fields(kvs,
|
|
306
|
+
async function set_state_fields(kvs, disablePjax, e) {
|
|
432
307
|
try {
|
|
433
308
|
showLoadSpinner();
|
|
309
|
+
let newhref = get_current_state_url(e);
|
|
434
310
|
let queryParams = [];
|
|
435
|
-
|
|
311
|
+
const { path, query } =
|
|
312
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(newhref);
|
|
313
|
+
let currentQuery = query || {};
|
|
436
314
|
if (Object.keys(kvs).some((k) => !is_paging_param(k))) {
|
|
437
315
|
currentQuery = invalidate_pagings(currentQuery);
|
|
438
316
|
}
|
|
@@ -446,17 +324,65 @@ async function set_state_fields(kvs, href) {
|
|
|
446
324
|
for (const [k, v] of new URLSearchParams(currentQuery).entries()) {
|
|
447
325
|
queryParams.push(`${k}=${v}`);
|
|
448
326
|
}
|
|
449
|
-
|
|
327
|
+
const queryStr = queryParams.join("&");
|
|
328
|
+
if (disablePjax)
|
|
329
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(path, queryStr);
|
|
330
|
+
else await pjax_to(path, queryStr, e);
|
|
450
331
|
} finally {
|
|
451
332
|
removeLoadSpinner();
|
|
452
333
|
}
|
|
453
334
|
}
|
|
454
335
|
|
|
336
|
+
async function pjax_to(href, query, e) {
|
|
337
|
+
const safeHref = href.startsWith("get") ? href.substring(3) : href;
|
|
338
|
+
const path = `${safeHref}?${query}`;
|
|
339
|
+
let $modal = $("#scmodal");
|
|
340
|
+
const inModal = $modal.length && $modal.hasClass("show");
|
|
341
|
+
const localizer = e ? $(e).closest("[data-sc-local-state]") : [];
|
|
342
|
+
let $dest = localizer.length
|
|
343
|
+
? localizer
|
|
344
|
+
: inModal
|
|
345
|
+
? $("#scmodal .modal-body")
|
|
346
|
+
: $("#page-inner-content");
|
|
347
|
+
if (!$dest.length)
|
|
348
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(safeHref, query);
|
|
349
|
+
else
|
|
350
|
+
try {
|
|
351
|
+
const headers = {
|
|
352
|
+
pjaxpageload: "true",
|
|
353
|
+
};
|
|
354
|
+
if (localizer.length) headers.localizedstate = "true";
|
|
355
|
+
const result = await parent.saltcorn.mobileApp.api.apiCall({
|
|
356
|
+
path: path,
|
|
357
|
+
method: "GET",
|
|
358
|
+
additionalHeaders: headers,
|
|
359
|
+
});
|
|
360
|
+
if (!inModal && !localizer.length) {
|
|
361
|
+
// not sure for mobile
|
|
362
|
+
// window.history.pushState({ url: href }, "", href);
|
|
363
|
+
}
|
|
364
|
+
if (inModal && !localizer.length)
|
|
365
|
+
$(".sc-modal-linkout").attr("href", path);
|
|
366
|
+
$dest.html(result.data);
|
|
367
|
+
if (localizer.length) localizer.attr("data-sc-local-state", path);
|
|
368
|
+
initialize_page();
|
|
369
|
+
} catch (error) {
|
|
370
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
455
374
|
async function set_state_field(key, value) {
|
|
456
375
|
try {
|
|
457
376
|
showLoadSpinner();
|
|
458
|
-
const query = updateQueryStringParameter(
|
|
459
|
-
|
|
377
|
+
const query = updateQueryStringParameter(
|
|
378
|
+
parent.saltcorn.mobileApp.navigation.currentQuery(),
|
|
379
|
+
key,
|
|
380
|
+
value
|
|
381
|
+
);
|
|
382
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(
|
|
383
|
+
parent.saltcorn.mobileApp.navigation.currentLocation(),
|
|
384
|
+
query
|
|
385
|
+
);
|
|
460
386
|
} finally {
|
|
461
387
|
removeLoadSpinner();
|
|
462
388
|
}
|
|
@@ -465,32 +391,37 @@ async function set_state_field(key, value) {
|
|
|
465
391
|
async function unset_state_field(key) {
|
|
466
392
|
try {
|
|
467
393
|
showLoadSpinner();
|
|
468
|
-
const href = parent.currentLocation();
|
|
469
|
-
const query = removeQueryStringParameter(
|
|
470
|
-
|
|
394
|
+
const href = parent.saltcorn.mobileApp.navigation.currentLocation();
|
|
395
|
+
const query = removeQueryStringParameter(
|
|
396
|
+
parent.saltcorn.mobileApp.navigation.currentLocation(),
|
|
397
|
+
key
|
|
398
|
+
);
|
|
399
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(href, query);
|
|
471
400
|
} finally {
|
|
472
401
|
removeLoadSpinner();
|
|
473
402
|
}
|
|
474
403
|
}
|
|
475
404
|
|
|
476
|
-
async function sortby(k, desc, viewIdentifier) {
|
|
405
|
+
async function sortby(k, desc, viewIdentifier, e) {
|
|
477
406
|
await set_state_fields(
|
|
478
407
|
{
|
|
479
408
|
[`_${viewIdentifier}_sortby`]: k,
|
|
480
409
|
[`_${viewIdentifier}_sortdesc`]: desc ? "on" : { unset: true },
|
|
481
410
|
},
|
|
482
|
-
|
|
411
|
+
false,
|
|
412
|
+
e
|
|
483
413
|
);
|
|
484
414
|
}
|
|
485
415
|
|
|
486
|
-
async function gopage(n, pagesize, viewIdentifier, extra) {
|
|
416
|
+
async function gopage(n, pagesize, viewIdentifier, extra, e) {
|
|
487
417
|
await set_state_fields(
|
|
488
418
|
{
|
|
489
419
|
...extra,
|
|
490
420
|
[`_${viewIdentifier}_page`]: n,
|
|
491
421
|
[`_${viewIdentifier}_pagesize`]: pagesize,
|
|
492
422
|
},
|
|
493
|
-
|
|
423
|
+
false,
|
|
424
|
+
e
|
|
494
425
|
);
|
|
495
426
|
}
|
|
496
427
|
|
|
@@ -529,18 +460,19 @@ async function mobile_modal(url, opts = {}) {
|
|
|
529
460
|
if (opts.submitReload === false) $("#scmodal").addClass("no-submit-reload");
|
|
530
461
|
else $("#scmodal").removeClass("no-submit-reload");
|
|
531
462
|
try {
|
|
532
|
-
const { path, query } =
|
|
463
|
+
const { path, query } =
|
|
464
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(url);
|
|
533
465
|
const mobileConfig = parent.saltcorn.data.state.getState().mobileConfig;
|
|
534
466
|
if (
|
|
535
467
|
mobileConfig.networkState === "none" &&
|
|
536
468
|
mobileConfig.allowOfflineMode &&
|
|
537
469
|
!mobileConfig.isOfflineMode
|
|
538
470
|
) {
|
|
539
|
-
await parent.
|
|
540
|
-
parent.clearHistory();
|
|
541
|
-
await parent.gotoEntryView();
|
|
471
|
+
await parent.saltcorn.mobileApp.offlineMode.startOfflineMode();
|
|
472
|
+
parent.saltcorn.mobileApp.navigation.clearHistory();
|
|
473
|
+
await parent.saltcorn.mobileApp.navigation.gotoEntryView();
|
|
542
474
|
} else {
|
|
543
|
-
const page = await parent.router.resolve({
|
|
475
|
+
const page = await parent.saltcorn.mobileApp.navigation.router.resolve({
|
|
544
476
|
pathname: `get${path}`,
|
|
545
477
|
query: query,
|
|
546
478
|
alerts: [],
|
|
@@ -553,7 +485,7 @@ async function mobile_modal(url, opts = {}) {
|
|
|
553
485
|
// onOpen onClose initialize_page?
|
|
554
486
|
}
|
|
555
487
|
} catch (error) {
|
|
556
|
-
parent.showAlerts([
|
|
488
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
557
489
|
{
|
|
558
490
|
type: "error",
|
|
559
491
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -569,14 +501,15 @@ function closeModal() {
|
|
|
569
501
|
async function local_post(url, args) {
|
|
570
502
|
try {
|
|
571
503
|
showLoadSpinner();
|
|
572
|
-
const result = await parent.router.resolve({
|
|
504
|
+
const result = await parent.saltcorn.mobileApp.navigation.router.resolve({
|
|
573
505
|
pathname: `post${url}`,
|
|
574
506
|
data: args,
|
|
575
507
|
});
|
|
576
|
-
if (result.redirect)
|
|
508
|
+
if (result.redirect)
|
|
509
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(result.redirect);
|
|
577
510
|
else await common_done(result, "", false);
|
|
578
511
|
} catch (error) {
|
|
579
|
-
parent.errorAlert(error);
|
|
512
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
580
513
|
} finally {
|
|
581
514
|
removeLoadSpinner();
|
|
582
515
|
}
|
|
@@ -585,17 +518,18 @@ async function local_post(url, args) {
|
|
|
585
518
|
async function local_post_json(url, data, cb) {
|
|
586
519
|
try {
|
|
587
520
|
showLoadSpinner();
|
|
588
|
-
const result = await parent.router.resolve({
|
|
521
|
+
const result = await parent.saltcorn.mobileApp.navigation.router.resolve({
|
|
589
522
|
pathname: `post${url}`,
|
|
590
523
|
data: data,
|
|
591
|
-
query: parent.currentQuery(),
|
|
524
|
+
query: parent.saltcorn.mobileApp.navigation.currentQuery(),
|
|
592
525
|
});
|
|
593
526
|
if (result.server_eval) await evalServerCode(url);
|
|
594
|
-
if (result.redirect)
|
|
527
|
+
if (result.redirect)
|
|
528
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(result.redirect);
|
|
595
529
|
else await common_done(result, "", false);
|
|
596
530
|
if (cb?.success) cb.success(result);
|
|
597
531
|
} catch (error) {
|
|
598
|
-
parent.errorAlert(error);
|
|
532
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
599
533
|
if (cb?.error) cb.error(error);
|
|
600
534
|
} finally {
|
|
601
535
|
removeLoadSpinner();
|
|
@@ -603,7 +537,7 @@ async function local_post_json(url, data, cb) {
|
|
|
603
537
|
}
|
|
604
538
|
|
|
605
539
|
async function evalServerCode(url) {
|
|
606
|
-
await parent.apiCall({
|
|
540
|
+
await parent.saltcorn.mobileApp.api.apiCall({
|
|
607
541
|
method: "POST",
|
|
608
542
|
path: url,
|
|
609
543
|
});
|
|
@@ -626,7 +560,7 @@ async function make_unique_field(
|
|
|
626
560
|
)}=${encodeURIComponent(value)}&fields=${encodeURIComponent(field_name)}`;
|
|
627
561
|
try {
|
|
628
562
|
// TODO ch support local tables
|
|
629
|
-
const response = await parent.apiCall({
|
|
563
|
+
const response = await parent.saltcorn.mobileApp.api.apiCall({
|
|
630
564
|
method: "GET",
|
|
631
565
|
path,
|
|
632
566
|
});
|
|
@@ -643,7 +577,7 @@ async function make_unique_field(
|
|
|
643
577
|
);
|
|
644
578
|
}
|
|
645
579
|
} catch (error) {
|
|
646
|
-
parent.showAlerts([
|
|
580
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
647
581
|
{
|
|
648
582
|
type: "error",
|
|
649
583
|
msg: "unable to 'make_unique_field'",
|
|
@@ -688,11 +622,14 @@ async function select_id(id) {
|
|
|
688
622
|
try {
|
|
689
623
|
showLoadSpinner();
|
|
690
624
|
const newQuery = updateQueryStringParameter(
|
|
691
|
-
parent.currentQuery(),
|
|
625
|
+
parent.saltcorn.mobileApp.navigation.currentQuery(),
|
|
692
626
|
"id",
|
|
693
627
|
id
|
|
694
628
|
);
|
|
695
|
-
await parent.handleRoute(
|
|
629
|
+
await parent.handleRoute(
|
|
630
|
+
parent.saltcorn.mobileApp.navigation.currentLocation(),
|
|
631
|
+
newQuery
|
|
632
|
+
);
|
|
696
633
|
} finally {
|
|
697
634
|
removeLoadSpinner();
|
|
698
635
|
}
|
|
@@ -703,9 +640,16 @@ async function check_state_field(that) {
|
|
|
703
640
|
showLoadSpinner();
|
|
704
641
|
const name = that.name;
|
|
705
642
|
const newQuery = that.checked
|
|
706
|
-
? updateQueryStringParameter(
|
|
643
|
+
? updateQueryStringParameter(
|
|
644
|
+
parent.saltcorn.mobileApp.navigation.currentQuery(),
|
|
645
|
+
name,
|
|
646
|
+
that.value
|
|
647
|
+
)
|
|
707
648
|
: removeQueryStringParameter(name);
|
|
708
|
-
await parent.handleRoute(
|
|
649
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(
|
|
650
|
+
parent.saltcorn.mobileApp.navigation.currentLocation(),
|
|
651
|
+
newQuery
|
|
652
|
+
);
|
|
709
653
|
} finally {
|
|
710
654
|
removeLoadSpinner();
|
|
711
655
|
}
|
|
@@ -714,7 +658,10 @@ async function check_state_field(that) {
|
|
|
714
658
|
async function clear_state() {
|
|
715
659
|
try {
|
|
716
660
|
showLoadSpinner();
|
|
717
|
-
await parent.handleRoute(
|
|
661
|
+
await parent.saltcorn.mobileApp.navigation.handleRoute(
|
|
662
|
+
parent.saltcorn.mobileApp.navigation.currentLocation(),
|
|
663
|
+
undefined
|
|
664
|
+
);
|
|
718
665
|
} finally {
|
|
719
666
|
removeLoadSpinner();
|
|
720
667
|
}
|
|
@@ -728,7 +675,7 @@ async function view_post(viewnameOrElem, route, data, onDone, sendState) {
|
|
|
728
675
|
.closest("[data-sc-embed-viewname]")
|
|
729
676
|
.attr("data-sc-embed-viewname");
|
|
730
677
|
const buildQuery = () => {
|
|
731
|
-
const query = parent.currentQuery();
|
|
678
|
+
const query = parent.saltcorn.mobileApp.navigation.currentQuery();
|
|
732
679
|
return query ? `?${query}` : "";
|
|
733
680
|
};
|
|
734
681
|
const mobileConfig = parent.saltcorn.data.state.getState().mobileConfig;
|
|
@@ -741,13 +688,13 @@ async function view_post(viewnameOrElem, route, data, onDone, sendState) {
|
|
|
741
688
|
mobileConfig.isOfflineMode ||
|
|
742
689
|
(view?.table_id && mobileConfig.localTableIds.indexOf(view.table_id) >= 0)
|
|
743
690
|
) {
|
|
744
|
-
respData = await parent.router.resolve({
|
|
691
|
+
respData = await parent.saltcorn.mobileApp.navigation.router.resolve({
|
|
745
692
|
pathname: `post/view/${viewname}/${route}`,
|
|
746
693
|
data,
|
|
747
694
|
query,
|
|
748
695
|
});
|
|
749
696
|
} else {
|
|
750
|
-
const response = await parent.apiCall({
|
|
697
|
+
const response = await parent.saltcorn.mobileApp.api.apiCall({
|
|
751
698
|
method: "POST",
|
|
752
699
|
path: "/view/" + viewname + "/" + route + query,
|
|
753
700
|
body: data,
|
|
@@ -760,7 +707,7 @@ async function view_post(viewnameOrElem, route, data, onDone, sendState) {
|
|
|
760
707
|
if (onDone) await onDone(respData);
|
|
761
708
|
await common_done(respData, viewname, false);
|
|
762
709
|
} catch (error) {
|
|
763
|
-
parent.errorAlert(error);
|
|
710
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
764
711
|
} finally {
|
|
765
712
|
removeLoadSpinner();
|
|
766
713
|
}
|
|
@@ -783,37 +730,41 @@ async function switchNetworkMode() {
|
|
|
783
730
|
const state = parent.saltcorn.data.state.getState();
|
|
784
731
|
const { isOfflineMode, networkState } = state.mobileConfig;
|
|
785
732
|
if (!isOfflineMode) {
|
|
786
|
-
await parent.
|
|
787
|
-
parent.clearHistory();
|
|
788
|
-
parent.addRoute({ route: "/" });
|
|
789
|
-
parent.addRoute({
|
|
790
|
-
|
|
733
|
+
await parent.saltcorn.mobileApp.offlineMode.startOfflineMode();
|
|
734
|
+
parent.saltcorn.mobileApp.navigation.clearHistory();
|
|
735
|
+
parent.saltcorn.mobileApp.navigation.addRoute({ route: "/" });
|
|
736
|
+
parent.saltcorn.mobileApp.navigation.addRoute({
|
|
737
|
+
route: "get/sync/sync_settings",
|
|
738
|
+
});
|
|
739
|
+
parent.saltcorn.mobileApp.common.showAlerts(
|
|
791
740
|
[
|
|
792
741
|
{
|
|
793
742
|
type: "info",
|
|
794
|
-
msg: parent.
|
|
743
|
+
msg: parent.saltcorn.mobileApp.offlineMode.getOfflineMsg(),
|
|
795
744
|
},
|
|
796
745
|
],
|
|
797
746
|
false
|
|
798
747
|
);
|
|
799
|
-
parent.clearAlerts();
|
|
748
|
+
parent.saltcorn.mobileApp.common.clearAlerts();
|
|
800
749
|
} else {
|
|
801
750
|
if (networkState === "none")
|
|
802
751
|
throw new Error("No internet connection is available.");
|
|
803
|
-
await parent.
|
|
804
|
-
parent.clearHistory();
|
|
805
|
-
parent.addRoute({ route: "/" });
|
|
806
|
-
parent.addRoute({
|
|
807
|
-
|
|
752
|
+
await parent.saltcorn.mobileApp.offlineMode.endOfflineMode();
|
|
753
|
+
parent.saltcorn.mobileApp.navigation.clearHistory();
|
|
754
|
+
parent.saltcorn.mobileApp.navigation.addRoute({ route: "/" });
|
|
755
|
+
parent.saltcorn.mobileApp.navigation.addRoute({
|
|
756
|
+
route: "get/sync/sync_settings",
|
|
757
|
+
});
|
|
758
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
808
759
|
{
|
|
809
760
|
type: "info",
|
|
810
761
|
msg: "You are online again.",
|
|
811
762
|
},
|
|
812
763
|
]);
|
|
813
|
-
parent.clearTopAlerts();
|
|
764
|
+
parent.saltcorn.mobileApp.common.clearTopAlerts();
|
|
814
765
|
}
|
|
815
766
|
} catch (error) {
|
|
816
|
-
parent.showAlerts([
|
|
767
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
817
768
|
{
|
|
818
769
|
type: "error",
|
|
819
770
|
msg: `Unable to change the network mode: ${
|
|
@@ -833,7 +784,7 @@ async function callSync() {
|
|
|
833
784
|
try {
|
|
834
785
|
const mobileConfig = parent.saltcorn.data.state.getState().mobileConfig;
|
|
835
786
|
if (mobileConfig.networkState === "none") {
|
|
836
|
-
parent.showAlerts([
|
|
787
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
837
788
|
{
|
|
838
789
|
type: "error",
|
|
839
790
|
msg: "You don't have an internet connection.",
|
|
@@ -842,10 +793,10 @@ async function callSync() {
|
|
|
842
793
|
} else {
|
|
843
794
|
const wasOffline = mobileConfig.isOfflineMode;
|
|
844
795
|
showLoadSpinner();
|
|
845
|
-
await parent.
|
|
846
|
-
parent.clearAlerts();
|
|
796
|
+
await parent.saltcorn.mobileApp.offlineMode.sync();
|
|
797
|
+
parent.saltcorn.mobileApp.common.clearAlerts();
|
|
847
798
|
if (!wasOffline) {
|
|
848
|
-
parent.showAlerts([
|
|
799
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
849
800
|
{
|
|
850
801
|
type: "info",
|
|
851
802
|
msg: "Synchronized your offline data.",
|
|
@@ -853,38 +804,41 @@ async function callSync() {
|
|
|
853
804
|
]);
|
|
854
805
|
} else {
|
|
855
806
|
setNetworSwitcherOn();
|
|
856
|
-
parent.clearHistory();
|
|
857
|
-
parent.addRoute({ route: "/" });
|
|
858
|
-
parent.addRoute({
|
|
859
|
-
|
|
807
|
+
parent.saltcorn.mobileApp.navigation.clearHistory();
|
|
808
|
+
parent.saltcorn.mobileApp.navigation.addRoute({ route: "/" });
|
|
809
|
+
parent.saltcorn.mobileApp.navigation.addRoute({
|
|
810
|
+
route: "get/sync/sync_settings",
|
|
811
|
+
});
|
|
812
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
860
813
|
{
|
|
861
814
|
type: "info",
|
|
862
815
|
msg: "Synchronized your offline data, you are online again.",
|
|
863
816
|
},
|
|
864
817
|
]);
|
|
865
|
-
parent.clearTopAlerts();
|
|
818
|
+
parent.saltcorn.mobileApp.common.clearTopAlerts();
|
|
866
819
|
}
|
|
867
820
|
}
|
|
868
821
|
} catch (error) {
|
|
869
822
|
console.log(error);
|
|
870
|
-
parent.errorAlert(error);
|
|
823
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
871
824
|
} finally {
|
|
872
825
|
removeLoadSpinner();
|
|
873
826
|
}
|
|
874
827
|
}
|
|
875
828
|
|
|
876
829
|
async function deleteOfflineDataClicked() {
|
|
877
|
-
const lastOfflineSession =
|
|
878
|
-
|
|
830
|
+
const lastOfflineSession =
|
|
831
|
+
await parent.saltcorn.mobileApp.offlineMode.getLastOfflineSession();
|
|
832
|
+
const { user } = parent.saltcorn.data.state.getState().mobileConfig;
|
|
879
833
|
if (!lastOfflineSession?.offlineUser) {
|
|
880
|
-
parent.showAlerts([
|
|
834
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
881
835
|
{
|
|
882
836
|
type: "error",
|
|
883
837
|
msg: "You don't have any offline data.",
|
|
884
838
|
},
|
|
885
839
|
]);
|
|
886
|
-
} else if (lastOfflineSession.offlineUser !==
|
|
887
|
-
parent.showAlerts([
|
|
840
|
+
} else if (lastOfflineSession.offlineUser !== user.email) {
|
|
841
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
888
842
|
{
|
|
889
843
|
type: "error",
|
|
890
844
|
msg: `The offline data is owned by '${lastOfflineSession.offlineUser}'.`,
|
|
@@ -895,30 +849,8 @@ async function deleteOfflineDataClicked() {
|
|
|
895
849
|
}
|
|
896
850
|
}
|
|
897
851
|
|
|
898
|
-
async function deleteOfflineData(noFeedback) {
|
|
899
|
-
const mobileConfig = parent.saltcorn.data.state.getState().mobileConfig;
|
|
900
|
-
try {
|
|
901
|
-
mobileConfig.inLoadState = true;
|
|
902
|
-
if (!noFeedback) showLoadSpinner();
|
|
903
|
-
await parent.offlineHelper.clearLocalData(false);
|
|
904
|
-
await parent.offlineHelper.setHasOfflineData(false);
|
|
905
|
-
if (!noFeedback)
|
|
906
|
-
parent.showAlerts([
|
|
907
|
-
{
|
|
908
|
-
type: "info",
|
|
909
|
-
msg: "Deleted your offline data.",
|
|
910
|
-
},
|
|
911
|
-
]);
|
|
912
|
-
} catch (error) {
|
|
913
|
-
parent.errorAlert(error);
|
|
914
|
-
} finally {
|
|
915
|
-
mobileConfig.inLoadState = false;
|
|
916
|
-
if (!noFeedback) removeLoadSpinner();
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
|
|
920
852
|
function showLoadSpinner() {
|
|
921
|
-
if (!parent.isHtmlFile()) {
|
|
853
|
+
if (!parent.saltcorn.mobileApp.navigation.isHtmlFile()) {
|
|
922
854
|
const spinner = $("#scspinner");
|
|
923
855
|
if (spinner.length === 0) {
|
|
924
856
|
$("body").append(`
|
|
@@ -961,7 +893,7 @@ function showLoadSpinner() {
|
|
|
961
893
|
}
|
|
962
894
|
|
|
963
895
|
function removeLoadSpinner() {
|
|
964
|
-
if (!parent.isHtmlFile()) {
|
|
896
|
+
if (!parent.saltcorn.mobileApp.navigation.isHtmlFile()) {
|
|
965
897
|
const spinner = $("#scspinner");
|
|
966
898
|
if (spinner.length > 0) {
|
|
967
899
|
const count = parseInt(spinner.attr("spinner-count")) - 1;
|
|
@@ -977,29 +909,11 @@ function removeLoadSpinner() {
|
|
|
977
909
|
* @param {*} fieldName
|
|
978
910
|
*/
|
|
979
911
|
async function getPicture(fieldName) {
|
|
980
|
-
const cameraOptions = {
|
|
981
|
-
quality: 50,
|
|
982
|
-
encodingType: parent.Camera.EncodingType.JPEG,
|
|
983
|
-
destinationType: parent.Camera.DestinationType.FILE_URI,
|
|
984
|
-
};
|
|
985
|
-
const getPictureWithPromise = () => {
|
|
986
|
-
return new Promise((resolve, reject) => {
|
|
987
|
-
parent.navigator.camera.getPicture(
|
|
988
|
-
(imageDate) => {
|
|
989
|
-
return resolve(imageDate);
|
|
990
|
-
},
|
|
991
|
-
(message) => {
|
|
992
|
-
return reject(message);
|
|
993
|
-
},
|
|
994
|
-
cameraOptions
|
|
995
|
-
);
|
|
996
|
-
});
|
|
997
|
-
};
|
|
998
912
|
try {
|
|
999
913
|
const form = $(`#cptbtn${fieldName}`).closest("form");
|
|
1000
914
|
const onsubmit = form.attr("onsubmit");
|
|
1001
915
|
form.attr("onsubmit", "javascript:void(0)");
|
|
1002
|
-
const fileURI = await
|
|
916
|
+
const fileURI = await parent.saltcorn.mobileApp.common.takePhoto("uri");
|
|
1003
917
|
form.attr("onsubmit", onsubmit);
|
|
1004
918
|
const inputId = `input${fieldName}`;
|
|
1005
919
|
form.find(`#${inputId}`).remove();
|
|
@@ -1009,7 +923,7 @@ async function getPicture(fieldName) {
|
|
|
1009
923
|
const tokens = fileURI.split("/");
|
|
1010
924
|
$(`#cpt-file-name-${fieldName}`).text(tokens[tokens.length - 1]);
|
|
1011
925
|
} catch (error) {
|
|
1012
|
-
parent.errorAlert(error);
|
|
926
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
1013
927
|
}
|
|
1014
928
|
}
|
|
1015
929
|
|
|
@@ -1024,7 +938,7 @@ async function updateMatchingRows(e, viewname) {
|
|
|
1024
938
|
true
|
|
1025
939
|
);
|
|
1026
940
|
} catch (error) {
|
|
1027
|
-
parent.errorAlert(error);
|
|
941
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
1028
942
|
}
|
|
1029
943
|
}
|
|
1030
944
|
|