@saltcorn/mobile-app 0.8.7 → 0.8.8-beta.1
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/package.json
CHANGED
package/www/js/mocks/request.js
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
/*global i18next, saltcorn*/
|
|
1
|
+
/*global i18next, saltcorn, currentLocation*/
|
|
2
2
|
|
|
3
3
|
function MobileRequest({
|
|
4
4
|
xhr = false,
|
|
5
5
|
files = undefined,
|
|
6
6
|
query = undefined,
|
|
7
|
+
refererRoute = undefined,
|
|
7
8
|
} = {}) {
|
|
8
9
|
const cfg = saltcorn.data.state.getState().mobileConfig;
|
|
9
10
|
const roleId = cfg.role_id ? cfg.role_id : 100;
|
|
10
11
|
const userId = cfg.user_id ? cfg.user_id : undefined;
|
|
11
12
|
const flashMessages = [];
|
|
12
|
-
|
|
13
|
+
const refererPath = refererRoute ? refererRoute.route : undefined;
|
|
14
|
+
const referQuery =
|
|
15
|
+
refererPath && refererRoute.query
|
|
16
|
+
? refererRoute.query.startsWith("?")
|
|
17
|
+
? refererRoute.query
|
|
18
|
+
: `?${refererRoute.query}`
|
|
19
|
+
: "";
|
|
20
|
+
const referer = refererPath ? `${refererPath}${referQuery}` : undefined;
|
|
13
21
|
return {
|
|
14
22
|
__: (s, ...params) =>
|
|
15
23
|
i18next.t(s, {
|
|
@@ -41,5 +49,8 @@ function MobileRequest({
|
|
|
41
49
|
xhr,
|
|
42
50
|
files,
|
|
43
51
|
query,
|
|
52
|
+
headers: {
|
|
53
|
+
referer: referer,
|
|
54
|
+
},
|
|
44
55
|
};
|
|
45
56
|
}
|
package/www/js/routes/common.js
CHANGED
|
@@ -6,6 +6,7 @@ const getHeaders = () => {
|
|
|
6
6
|
const stdHeaders = [
|
|
7
7
|
{ css: `static_assets/${versionTag}/saltcorn.css` },
|
|
8
8
|
{ script: `static_assets/${versionTag}/saltcorn-common.js` },
|
|
9
|
+
{ script: `static_assets/${versionTag}/dayjs.min.js` },
|
|
9
10
|
{ script: "js/utils/iframe_view_utils.js" },
|
|
10
11
|
];
|
|
11
12
|
return [...stdHeaders, ...config.pluginHeaders];
|
package/www/js/routes/edit.js
CHANGED
|
@@ -10,7 +10,7 @@ const postToggleField = async (context) => {
|
|
|
10
10
|
if (isOfflineMode || localTableIds.indexOf(table.id) >= 0) {
|
|
11
11
|
if (role_id > table.min_role_write)
|
|
12
12
|
throw new saltcorn.data.utils.NotAuthorized(i18next.t("Not authorized"));
|
|
13
|
-
await table.toggleBool(+id, field_name);
|
|
13
|
+
await table.toggleBool(+id, field_name); //TODO call with user
|
|
14
14
|
if (isOfflineMode && !(await offlineHelper.getLastOfflineSession()))
|
|
15
15
|
await offlineHelper.setOfflineSession({ offlineUser: user_name });
|
|
16
16
|
} else {
|
package/www/js/routes/view.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*global MobileRequest, MobileResponse, parseQuery, wrapContents, saltcorn, offlineHelper*/
|
|
1
|
+
/*global MobileRequest, MobileResponse, parseQuery, wrapContents, saltcorn, offlineHelper, routingHistory*/
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
*
|
|
@@ -76,7 +76,11 @@ const getView = async (context) => {
|
|
|
76
76
|
const query = parseQuery(context.query);
|
|
77
77
|
const { viewname } = context.params;
|
|
78
78
|
const view = saltcorn.data.models.View.findOne({ name: viewname });
|
|
79
|
-
const
|
|
79
|
+
const refererRoute =
|
|
80
|
+
routingHistory?.length > 1
|
|
81
|
+
? routingHistory[routingHistory.length - 2]
|
|
82
|
+
: undefined;
|
|
83
|
+
const req = new MobileRequest({ xhr: context.xhr, query, refererRoute });
|
|
80
84
|
if (
|
|
81
85
|
state.mobileConfig.role_id > view.min_role &&
|
|
82
86
|
!(await view.authorise_get({ query, req, ...view }))
|
|
@@ -189,6 +189,15 @@ async function gotoEntryView() {
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
function handleOpenModal() {
|
|
193
|
+
const iframe = document.getElementById("content-iframe");
|
|
194
|
+
if (!iframe) return false;
|
|
195
|
+
const openModal = iframe.contentWindow.$("#scmodal.modal.show");
|
|
196
|
+
if (openModal.length === 0) return;
|
|
197
|
+
iframe.contentWindow.bootstrap.Modal.getInstance(openModal[0]).hide();
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
192
201
|
async function handleRoute(route, query, files) {
|
|
193
202
|
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
194
203
|
try {
|
|
@@ -201,7 +210,8 @@ async function handleRoute(route, query, files) {
|
|
|
201
210
|
clearHistory();
|
|
202
211
|
await gotoEntryView();
|
|
203
212
|
} else {
|
|
204
|
-
if (route === "/" || route === "get"
|
|
213
|
+
if (route === "/" || route === "get" || route === "get/")
|
|
214
|
+
return await gotoEntryView();
|
|
205
215
|
const safeRoute = route ? route : currentLocation();
|
|
206
216
|
addRoute({ route: safeRoute, query });
|
|
207
217
|
const page = await router.resolve({
|
|
@@ -218,6 +228,7 @@ async function handleRoute(route, query, files) {
|
|
|
218
228
|
: [],
|
|
219
229
|
});
|
|
220
230
|
if (page.redirect) {
|
|
231
|
+
if (handleOpenModal()) return;
|
|
221
232
|
if (
|
|
222
233
|
page.redirect.startsWith("http://localhost") ||
|
|
223
234
|
page.redirect === "undefined"
|
|
@@ -20,8 +20,13 @@ function combineFormAndQuery(form, query) {
|
|
|
20
20
|
* @param {*} url
|
|
21
21
|
*/
|
|
22
22
|
async function execLink(url) {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
try {
|
|
24
|
+
showLoadSpinner();
|
|
25
|
+
const { path, query } = parent.splitPathQuery(url);
|
|
26
|
+
await parent.handleRoute(`get${path}`, query);
|
|
27
|
+
} finally {
|
|
28
|
+
removeLoadSpinner();
|
|
29
|
+
}
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
async function execNavbarLink(url) {
|
|
@@ -36,33 +41,39 @@ async function execNavbarLink(url) {
|
|
|
36
41
|
* @returns
|
|
37
42
|
*/
|
|
38
43
|
async function formSubmit(e, urlSuffix, viewname, noSubmitCb) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
try {
|
|
45
|
+
showLoadSpinner();
|
|
46
|
+
if (!noSubmitCb) e.submit();
|
|
47
|
+
const files = {};
|
|
48
|
+
const urlParams = new URLSearchParams();
|
|
49
|
+
for (const entry of new FormData(e).entries()) {
|
|
50
|
+
if (entry[1] instanceof File) files[entry[0]] = entry[1];
|
|
51
|
+
else {
|
|
52
|
+
// is there a hidden input with a filename?
|
|
53
|
+
const domEl = $(e).find(
|
|
54
|
+
`[name='${entry[0]}'][mobile-camera-input='true']`
|
|
55
|
+
);
|
|
56
|
+
if (domEl.length > 0) {
|
|
57
|
+
const tokens = entry[1].split("/");
|
|
58
|
+
const fileName = tokens[tokens.length - 1];
|
|
59
|
+
const directory = tokens.splice(0, tokens.length - 1).join("/");
|
|
60
|
+
// read and add file to submit
|
|
61
|
+
const binary = await parent.readBinary(fileName, directory);
|
|
62
|
+
files[entry[0]] = new File([binary], fileName);
|
|
63
|
+
} else urlParams.append(entry[0], entry[1]);
|
|
64
|
+
}
|
|
57
65
|
}
|
|
66
|
+
const queryStr = urlParams.toString();
|
|
67
|
+
await parent.handleRoute(`post${urlSuffix}${viewname}`, queryStr, files);
|
|
68
|
+
} finally {
|
|
69
|
+
removeLoadSpinner();
|
|
58
70
|
}
|
|
59
|
-
const queryStr = urlParams.toString();
|
|
60
|
-
await parent.handleRoute(`post${urlSuffix}${viewname}`, queryStr, files);
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
async function inline_local_submit(e, opts1) {
|
|
64
74
|
try {
|
|
65
75
|
e.preventDefault();
|
|
76
|
+
showLoadSpinner();
|
|
66
77
|
const opts = JSON.parse(decodeURIComponent(opts1 || "") || "{}");
|
|
67
78
|
const form = $(e.target).closest("form");
|
|
68
79
|
const urlParams = new URLSearchParams();
|
|
@@ -82,25 +93,32 @@ async function inline_local_submit(e, opts1) {
|
|
|
82
93
|
msg: error.message ? error.message : "An error occured.",
|
|
83
94
|
},
|
|
84
95
|
]);
|
|
96
|
+
} finally {
|
|
97
|
+
removeLoadSpinner();
|
|
85
98
|
}
|
|
86
99
|
}
|
|
87
100
|
|
|
88
101
|
async function saveAndContinue(e, action, k) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
try {
|
|
103
|
+
showLoadSpinner();
|
|
104
|
+
const form = $(e).closest("form");
|
|
105
|
+
submitWithEmptyAction(form[0]);
|
|
106
|
+
const queryStr = new URLSearchParams(new FormData(form[0])).toString();
|
|
107
|
+
const res = await parent.router.resolve({
|
|
108
|
+
pathname: `post${action}`,
|
|
109
|
+
query: queryStr,
|
|
110
|
+
xhr: true,
|
|
111
|
+
});
|
|
112
|
+
if (res.id && form.find("input[name=id")) {
|
|
113
|
+
form.append(
|
|
114
|
+
`<input type="hidden" class="form-control " name="id" value="${res.id}">`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (k) await k();
|
|
118
|
+
// TODO ch error (request.responseText?)
|
|
119
|
+
} finally {
|
|
120
|
+
removeLoadSpinner();
|
|
101
121
|
}
|
|
102
|
-
if (k) await k();
|
|
103
|
-
// TODO ch error (request.responseText?)
|
|
104
122
|
}
|
|
105
123
|
|
|
106
124
|
async function loginRequest({ email, password, isSignup, isPublic }) {
|
|
@@ -131,78 +149,84 @@ async function loginRequest({ email, password, isSignup, isPublic }) {
|
|
|
131
149
|
}
|
|
132
150
|
|
|
133
151
|
async function login(e, entryPoint, isSignup) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// use it as a token
|
|
142
|
-
const decodedJwt = parent.jwt_decode(loginResult);
|
|
143
|
-
const state = parent.saltcorn.data.state.getState();
|
|
144
|
-
const config = state.mobileConfig;
|
|
145
|
-
config.role_id = decodedJwt.user.role_id ? decodedJwt.user.role_id : 100;
|
|
146
|
-
config.user_name = decodedJwt.user.email;
|
|
147
|
-
config.user_id = decodedJwt.user.id;
|
|
148
|
-
config.language = decodedJwt.user.language;
|
|
149
|
-
config.isPublicUser = false;
|
|
150
|
-
config.isOfflineMode = false;
|
|
151
|
-
await parent.insertUser({
|
|
152
|
-
id: config.user_id,
|
|
153
|
-
email: config.user_name,
|
|
154
|
-
role_id: config.role_id,
|
|
155
|
-
language: config.language,
|
|
152
|
+
try {
|
|
153
|
+
showLoadSpinner();
|
|
154
|
+
const formData = new FormData(e);
|
|
155
|
+
const loginResult = await loginRequest({
|
|
156
|
+
email: formData.get("email"),
|
|
157
|
+
password: formData.get("password"),
|
|
158
|
+
isSignup,
|
|
156
159
|
});
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
160
|
+
if (typeof loginResult === "string") {
|
|
161
|
+
// use it as a token
|
|
162
|
+
const decodedJwt = parent.jwt_decode(loginResult);
|
|
163
|
+
const state = parent.saltcorn.data.state.getState();
|
|
164
|
+
const config = state.mobileConfig;
|
|
165
|
+
config.role_id = decodedJwt.user.role_id ? decodedJwt.user.role_id : 100;
|
|
166
|
+
config.user_name = decodedJwt.user.email;
|
|
167
|
+
config.user_id = decodedJwt.user.id;
|
|
168
|
+
config.language = decodedJwt.user.language;
|
|
169
|
+
config.isPublicUser = false;
|
|
170
|
+
config.isOfflineMode = false;
|
|
171
|
+
await parent.insertUser({
|
|
172
|
+
id: config.user_id,
|
|
173
|
+
email: config.user_name,
|
|
174
|
+
role_id: config.role_id,
|
|
175
|
+
language: config.language,
|
|
176
|
+
});
|
|
177
|
+
await parent.setJwt(loginResult);
|
|
178
|
+
config.jwt = loginResult;
|
|
179
|
+
await parent.i18next.changeLanguage(config.language);
|
|
180
|
+
const alerts = [];
|
|
181
|
+
if (config.allowOfflineMode) {
|
|
182
|
+
const { offlineUser, upload_started_at, upload_ended_at } =
|
|
183
|
+
(await parent.offlineHelper.getLastOfflineSession()) || {};
|
|
184
|
+
if (offlineUser === config.user_name) {
|
|
185
|
+
if (upload_started_at && !upload_ended_at) {
|
|
186
|
+
alerts.push({
|
|
187
|
+
type: "warning",
|
|
188
|
+
msg: "Please check if your offline data is already online. An upload was started but did not finish.",
|
|
189
|
+
});
|
|
190
|
+
} else {
|
|
191
|
+
alerts.push({
|
|
192
|
+
type: "info",
|
|
193
|
+
msg: "You have offline data, to handle it open the Network menu.",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
} else if (offlineUser) {
|
|
166
197
|
alerts.push({
|
|
167
198
|
type: "warning",
|
|
168
|
-
msg:
|
|
169
|
-
});
|
|
170
|
-
} else {
|
|
171
|
-
alerts.push({
|
|
172
|
-
type: "info",
|
|
173
|
-
msg: "You have offline data, to handle it open the Network menu.",
|
|
199
|
+
msg: `'${offlineUser}' has not yet uploaded offline data.`,
|
|
174
200
|
});
|
|
175
201
|
}
|
|
176
|
-
} else if (offlineUser) {
|
|
177
|
-
alerts.push({
|
|
178
|
-
type: "warning",
|
|
179
|
-
msg: `'${offlineUser}' has not yet uploaded offline data.`,
|
|
180
|
-
});
|
|
181
202
|
}
|
|
203
|
+
alerts.push({
|
|
204
|
+
type: "success",
|
|
205
|
+
msg: parent.i18next.t("Welcome, %s!", {
|
|
206
|
+
postProcess: "sprintf",
|
|
207
|
+
sprintf: [config.user_name],
|
|
208
|
+
}),
|
|
209
|
+
});
|
|
210
|
+
parent.addRoute({ route: entryPoint, query: undefined });
|
|
211
|
+
const page = await parent.router.resolve({
|
|
212
|
+
pathname: entryPoint,
|
|
213
|
+
fullWrap: true,
|
|
214
|
+
alerts,
|
|
215
|
+
});
|
|
216
|
+
await parent.replaceIframe(page.content);
|
|
217
|
+
} else if (loginResult?.alerts) {
|
|
218
|
+
parent.showAlerts(loginResult?.alerts);
|
|
219
|
+
} else {
|
|
220
|
+
throw new Error("The login failed.");
|
|
182
221
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
msg: parent.i18next.t("Welcome, %s!", {
|
|
186
|
-
postProcess: "sprintf",
|
|
187
|
-
sprintf: [config.user_name],
|
|
188
|
-
}),
|
|
189
|
-
});
|
|
190
|
-
parent.addRoute({ route: entryPoint, query: undefined });
|
|
191
|
-
const page = await parent.router.resolve({
|
|
192
|
-
pathname: entryPoint,
|
|
193
|
-
fullWrap: true,
|
|
194
|
-
alerts,
|
|
195
|
-
});
|
|
196
|
-
await parent.replaceIframe(page.content);
|
|
197
|
-
} else if (loginResult?.alerts) {
|
|
198
|
-
parent.showAlerts(loginResult?.alerts);
|
|
199
|
-
} else {
|
|
200
|
-
throw new Error("The login failed.");
|
|
222
|
+
} finally {
|
|
223
|
+
removeLoadSpinner();
|
|
201
224
|
}
|
|
202
225
|
}
|
|
203
226
|
|
|
204
227
|
async function publicLogin(entryPoint) {
|
|
205
228
|
try {
|
|
229
|
+
showLoadSpinner();
|
|
206
230
|
const loginResult = await loginRequest({ isPublic: true });
|
|
207
231
|
if (typeof loginResult === "string") {
|
|
208
232
|
const config = parent.saltcorn.data.state.getState().mobileConfig;
|
|
@@ -237,12 +261,15 @@ async function publicLogin(entryPoint) {
|
|
|
237
261
|
msg: error.message ? error.message : "An error occured.",
|
|
238
262
|
},
|
|
239
263
|
]);
|
|
264
|
+
} finally {
|
|
265
|
+
removeLoadSpinner();
|
|
240
266
|
}
|
|
241
267
|
}
|
|
242
268
|
|
|
243
269
|
async function logout() {
|
|
244
270
|
const config = parent.saltcorn.data.state.getState().mobileConfig;
|
|
245
271
|
try {
|
|
272
|
+
showLoadSpinner();
|
|
246
273
|
const page = await parent.router.resolve({
|
|
247
274
|
pathname: "get/auth/logout",
|
|
248
275
|
entryView: config.entry_point,
|
|
@@ -256,6 +283,8 @@ async function logout() {
|
|
|
256
283
|
msg: error.message ? error.message : "An error occured.",
|
|
257
284
|
},
|
|
258
285
|
]);
|
|
286
|
+
} finally {
|
|
287
|
+
removeLoadSpinner();
|
|
259
288
|
}
|
|
260
289
|
}
|
|
261
290
|
|
|
@@ -276,14 +305,19 @@ async function loginFormSubmit(e, entryView) {
|
|
|
276
305
|
}
|
|
277
306
|
|
|
278
307
|
async function local_post_btn(e) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
308
|
+
try {
|
|
309
|
+
showLoadSpinner();
|
|
310
|
+
const form = $(e).closest("form");
|
|
311
|
+
const url = form.attr("action");
|
|
312
|
+
const method = form.attr("method");
|
|
313
|
+
const { path, query } = parent.splitPathQuery(url);
|
|
314
|
+
await parent.handleRoute(
|
|
315
|
+
`${method}${path}`,
|
|
316
|
+
combineFormAndQuery(form, query)
|
|
317
|
+
);
|
|
318
|
+
} finally {
|
|
319
|
+
removeLoadSpinner();
|
|
320
|
+
}
|
|
287
321
|
}
|
|
288
322
|
|
|
289
323
|
/**
|
|
@@ -292,8 +326,13 @@ async function local_post_btn(e) {
|
|
|
292
326
|
* @param {*} path
|
|
293
327
|
*/
|
|
294
328
|
async function stateFormSubmit(e, path) {
|
|
295
|
-
|
|
296
|
-
|
|
329
|
+
try {
|
|
330
|
+
showLoadSpinner();
|
|
331
|
+
const formQuery = new URLSearchParams(new FormData(e)).toString();
|
|
332
|
+
await parent.handleRoute(path, formQuery);
|
|
333
|
+
} finally {
|
|
334
|
+
removeLoadSpinner();
|
|
335
|
+
}
|
|
297
336
|
}
|
|
298
337
|
|
|
299
338
|
function removeQueryStringParameter(queryStr, key) {
|
|
@@ -337,33 +376,48 @@ function invalidate_pagings(currentQuery) {
|
|
|
337
376
|
}
|
|
338
377
|
|
|
339
378
|
async function set_state_fields(kvs, href) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
currentQuery =
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (kv[1].unset && kv[1].unset === true) {
|
|
347
|
-
currentQuery = removeQueryStringParameter(currentQuery, kv[0]);
|
|
348
|
-
} else {
|
|
349
|
-
currentQuery = updateQueryStringParameter(currentQuery, kv[0], kv[1]);
|
|
379
|
+
try {
|
|
380
|
+
showLoadSpinner();
|
|
381
|
+
let queryParams = [];
|
|
382
|
+
let currentQuery = parent.currentQuery();
|
|
383
|
+
if (Object.keys(kvs).some((k) => !is_paging_param(k))) {
|
|
384
|
+
currentQuery = invalidate_pagings(currentQuery);
|
|
350
385
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
386
|
+
Object.entries(kvs).forEach((kv) => {
|
|
387
|
+
if (kv[1].unset && kv[1].unset === true) {
|
|
388
|
+
currentQuery = removeQueryStringParameter(currentQuery, kv[0]);
|
|
389
|
+
} else {
|
|
390
|
+
currentQuery = updateQueryStringParameter(currentQuery, kv[0], kv[1]);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
for (const [k, v] of new URLSearchParams(currentQuery).entries()) {
|
|
394
|
+
queryParams.push(`${k}=${v}`);
|
|
395
|
+
}
|
|
396
|
+
await parent.handleRoute(href, queryParams.join("&"));
|
|
397
|
+
} finally {
|
|
398
|
+
removeLoadSpinner();
|
|
354
399
|
}
|
|
355
|
-
await parent.handleRoute(href, queryParams.join("&"));
|
|
356
400
|
}
|
|
357
401
|
|
|
358
402
|
async function set_state_field(key, value) {
|
|
359
|
-
|
|
360
|
-
|
|
403
|
+
try {
|
|
404
|
+
showLoadSpinner();
|
|
405
|
+
const query = updateQueryStringParameter(parent.currentQuery(), key, value);
|
|
406
|
+
await parent.handleRoute(parent.currentLocation(), query);
|
|
407
|
+
} finally {
|
|
408
|
+
removeLoadSpinner();
|
|
409
|
+
}
|
|
361
410
|
}
|
|
362
411
|
|
|
363
412
|
async function unset_state_field(key) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
413
|
+
try {
|
|
414
|
+
showLoadSpinner();
|
|
415
|
+
const href = parent.currentLocation();
|
|
416
|
+
const query = removeQueryStringParameter(parent.currentLocation(), key);
|
|
417
|
+
await parent.handleRoute(href, query);
|
|
418
|
+
} finally {
|
|
419
|
+
removeLoadSpinner();
|
|
420
|
+
}
|
|
367
421
|
}
|
|
368
422
|
|
|
369
423
|
async function sortby(k, desc, viewIdentifier) {
|
|
@@ -456,6 +510,7 @@ function closeModal() {
|
|
|
456
510
|
|
|
457
511
|
async function local_post(url, args) {
|
|
458
512
|
try {
|
|
513
|
+
showLoadSpinner();
|
|
459
514
|
const result = await parent.router.resolve({
|
|
460
515
|
pathname: `post${url}`,
|
|
461
516
|
data: args,
|
|
@@ -464,11 +519,14 @@ async function local_post(url, args) {
|
|
|
464
519
|
else common_done(result);
|
|
465
520
|
} catch (error) {
|
|
466
521
|
parent.errorAlert(error);
|
|
522
|
+
} finally {
|
|
523
|
+
removeLoadSpinner();
|
|
467
524
|
}
|
|
468
525
|
}
|
|
469
526
|
|
|
470
527
|
async function local_post_json(url) {
|
|
471
528
|
try {
|
|
529
|
+
showLoadSpinner();
|
|
472
530
|
const result = await parent.router.resolve({
|
|
473
531
|
pathname: `post${url}`,
|
|
474
532
|
});
|
|
@@ -477,6 +535,8 @@ async function local_post_json(url) {
|
|
|
477
535
|
else common_done(result);
|
|
478
536
|
} catch (error) {
|
|
479
537
|
parent.errorAlert(error);
|
|
538
|
+
} finally {
|
|
539
|
+
removeLoadSpinner();
|
|
480
540
|
}
|
|
481
541
|
}
|
|
482
542
|
|
|
@@ -545,26 +605,46 @@ function openFile(fileId) {
|
|
|
545
605
|
}
|
|
546
606
|
|
|
547
607
|
async function select_id(id) {
|
|
548
|
-
|
|
549
|
-
|
|
608
|
+
try {
|
|
609
|
+
showLoadSpinner();
|
|
610
|
+
const newQuery = updateQueryStringParameter(
|
|
611
|
+
parent.currentQuery(),
|
|
612
|
+
"id",
|
|
613
|
+
id
|
|
614
|
+
);
|
|
615
|
+
await parent.handleRoute(parent.currentLocation(), newQuery);
|
|
616
|
+
} finally {
|
|
617
|
+
removeLoadSpinner();
|
|
618
|
+
}
|
|
550
619
|
}
|
|
551
620
|
|
|
552
621
|
async function check_state_field(that) {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
622
|
+
try {
|
|
623
|
+
showLoadSpinner();
|
|
624
|
+
const name = that.name;
|
|
625
|
+
const newQuery = that.checked
|
|
626
|
+
? updateQueryStringParameter(parent.currentQuery(), name, that.value)
|
|
627
|
+
: removeQueryStringParameter(name);
|
|
628
|
+
await parent.handleRoute(parent.currentLocation(), newQuery);
|
|
629
|
+
} finally {
|
|
630
|
+
removeLoadSpinner();
|
|
631
|
+
}
|
|
558
632
|
}
|
|
559
633
|
|
|
560
634
|
async function clear_state() {
|
|
561
|
-
|
|
635
|
+
try {
|
|
636
|
+
showLoadSpinner();
|
|
637
|
+
await parent.handleRoute(parent.currentLocation(), undefined);
|
|
638
|
+
} finally {
|
|
639
|
+
removeLoadSpinner();
|
|
640
|
+
}
|
|
562
641
|
}
|
|
563
642
|
|
|
564
643
|
async function view_post(viewname, route, data, onDone) {
|
|
565
644
|
const mobileConfig = parent.saltcorn.data.state.getState().mobileConfig;
|
|
566
645
|
const view = parent.saltcorn.data.models.View.findOne({ name: viewname });
|
|
567
646
|
try {
|
|
647
|
+
showLoadSpinner();
|
|
568
648
|
let respData = undefined;
|
|
569
649
|
if (
|
|
570
650
|
mobileConfig.isOfflineMode ||
|
|
@@ -589,6 +669,8 @@ async function view_post(viewname, route, data, onDone) {
|
|
|
589
669
|
common_done(respData);
|
|
590
670
|
} catch (error) {
|
|
591
671
|
parent.errorAlert(error);
|
|
672
|
+
} finally {
|
|
673
|
+
removeLoadSpinner();
|
|
592
674
|
}
|
|
593
675
|
}
|
|
594
676
|
|