@saltcorn/mobile-app 1.1.0-beta.2 → 1.1.0-beta.21

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.
Files changed (39) hide show
  1. package/.babelrc +3 -0
  2. package/build_scripts/modify_android_manifest.js +47 -0
  3. package/build_scripts/modify_gradle_cfg.js +34 -0
  4. package/package.json +20 -11
  5. package/src/.eslintrc +21 -0
  6. package/src/helpers/api.js +43 -0
  7. package/src/helpers/auth.js +191 -0
  8. package/src/helpers/common.js +175 -0
  9. package/{www/js/utils/table_utils.js → src/helpers/db_schema.js} +18 -40
  10. package/src/helpers/file_system.js +102 -0
  11. package/{www/js/utils/global_utils.js → src/helpers/navigation.js} +175 -335
  12. package/src/helpers/offline_mode.js +645 -0
  13. package/src/index.js +20 -0
  14. package/src/init.js +424 -0
  15. package/src/routing/index.js +98 -0
  16. package/{www/js → src/routing}/mocks/request.js +5 -5
  17. package/{www/js → src/routing}/mocks/response.js +1 -1
  18. package/{www/js → src/routing}/routes/api.js +10 -15
  19. package/{www/js → src/routing}/routes/auth.js +12 -6
  20. package/{www/js → src/routing}/routes/delete.js +9 -6
  21. package/{www/js → src/routing}/routes/edit.js +9 -6
  22. package/src/routing/routes/error.js +6 -0
  23. package/{www/js → src/routing}/routes/fields.js +7 -2
  24. package/{www/js → src/routing}/routes/page.js +14 -9
  25. package/{www/js → src/routing}/routes/sync.js +9 -5
  26. package/{www/js → src/routing}/routes/view.js +16 -11
  27. package/{www/js/routes/common.js → src/routing/utils.js} +15 -13
  28. package/webpack.config.js +31 -0
  29. package/www/data/encoded_site_logo.js +1 -0
  30. package/www/index.html +23 -493
  31. package/www/js/{utils/iframe_view_utils.js → iframe_view_utils.js} +187 -273
  32. package/config.xml +0 -27
  33. package/res/icon/android/icon.png +0 -0
  34. package/res/screen/android/splash-icon.png +0 -0
  35. package/res/screen/ios/Default@2x~universal~anyany.png +0 -0
  36. package/www/js/routes/error.js +0 -5
  37. package/www/js/routes/init.js +0 -76
  38. package/www/js/utils/file_helpers.js +0 -108
  39. 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 } = parent.splitPathQuery(url);
34
- await parent.handleRoute(`get${path}`, query);
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 } = parent.splitPathQuery(url);
43
- const page = await parent.router.resolve({
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
- // read and add file to submit
88
- const binary = await parent.readBinary(fileName, directory);
89
- files[entry[0]] = new File([binary], fileName);
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
- const loginResult = await loginRequest({
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
- const loginResult = await loginRequest({ isPublic: true });
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
- const page = await parent.router.resolve({
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 } = parent.splitPathQuery(url);
367
- await parent.handleRoute(
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, href) {
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
- let currentQuery = parent.currentQuery();
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
- await parent.handleRoute(href, queryParams.join("&"));
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(parent.currentQuery(), key, value);
459
- await parent.handleRoute(parent.currentLocation(), query);
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(parent.currentLocation(), key);
470
- await parent.handleRoute(href, query);
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
- parent.currentLocation()
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
- parent.currentLocation()
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 } = parent.splitPathQuery(url);
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.offlineHelper.startOfflineMode();
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) await parent.handleRoute(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) await parent.handleRoute(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(parent.currentLocation(), newQuery);
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(parent.currentQuery(), name, that.value)
643
+ ? updateQueryStringParameter(
644
+ parent.saltcorn.mobileApp.navigation.currentQuery(),
645
+ name,
646
+ that.value
647
+ )
707
648
  : removeQueryStringParameter(name);
708
- await parent.handleRoute(parent.currentLocation(), newQuery);
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(parent.currentLocation(), undefined);
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.offlineHelper.startOfflineMode();
787
- parent.clearHistory();
788
- parent.addRoute({ route: "/" });
789
- parent.addRoute({ route: "get/sync/sync_settings" });
790
- parent.showAlerts(
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.offlineHelper.getOfflineMsg(),
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.offlineHelper.endOfflineMode();
804
- parent.clearHistory();
805
- parent.addRoute({ route: "/" });
806
- parent.addRoute({ route: "get/sync/sync_settings" });
807
- parent.showAlerts([
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.offlineHelper.sync();
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({ route: "get/sync/sync_settings" });
859
- parent.showAlerts([
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 = await parent.offlineHelper.getLastOfflineSession();
878
- const { user_name } = parent.saltcorn.data.state.getState().mobileConfig;
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 !== user_name) {
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 getPictureWithPromise();
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