@saltcorn/server 0.7.2-beta.5 → 0.7.2-beta.8

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.
@@ -1,6 +1,372 @@
1
- function press_store_button(clicked) {
2
- const width = $(clicked).width();
3
- $(clicked).html('<i class="fas fa-spinner fa-spin"></i>').width(width);
1
+ //https://stackoverflow.com/a/698386
2
+ jQuery.fn.swapWith = function (to) {
3
+ return this.each(function () {
4
+ var copy_to = $(to).clone(true);
5
+ var copy_from = $(this).clone(true);
6
+ $(to).replaceWith(copy_from);
7
+ $(this).replaceWith(copy_to);
8
+ });
9
+ };
10
+
11
+ //avoids hiding in overflow:hidden
12
+ function init_bs5_dropdowns() {
13
+ $("body").on(
14
+ "show.bs.dropdown",
15
+ "table [data-bs-toggle=dropdown]",
16
+ function () {
17
+ let target;
18
+ if (!$("#page-inner-content").length) target = $("body");
19
+ else target = $("#page-inner-content");
20
+ let dropdown = bootstrap.Dropdown.getInstance(this);
21
+ $(dropdown._menu).insertAfter(target);
22
+ }
23
+ );
24
+ }
25
+ function add_repeater(nm) {
26
+ var es = $("div.form-repeat.repeat-" + nm);
27
+ var e = es.first();
28
+ var newix = es.length;
29
+ var newe = $(e).clone();
30
+ newe.find("[name]").each(function (ix, element) {
31
+ var newnm = (element.name || "").replace("_0", "_" + newix);
32
+ var newid = (element.id || "").replace("_0", "_" + newix);
33
+ $(element).attr("name", newnm).attr("id", newid);
34
+ });
35
+ newe.appendTo($("div.repeats-" + nm));
36
+ }
37
+ // "e.closest('.form-namespace').find('.coltype').val()==='Field';"
38
+ function apply_showif() {
39
+ $("[data-show-if]").each(function (ix, element) {
40
+ var e = $(element);
41
+ try {
42
+ var to_show = new Function(
43
+ "e",
44
+ "return " + decodeURIComponent(e.attr("data-show-if"))
45
+ );
46
+ if (to_show(e))
47
+ e.show()
48
+ .find("input, textarea, button, select")
49
+ .prop("disabled", e.attr("data-disabled") || false);
50
+ else
51
+ e.hide().find("input, textarea, button, select").prop("disabled", true);
52
+ } catch (e) {
53
+ console.error(e);
54
+ }
55
+ });
56
+ $("[data-calc-options]").each(function (ix, element) {
57
+ var e = $(element);
58
+ var data = JSON.parse(decodeURIComponent(e.attr("data-calc-options")));
59
+
60
+ var val = e
61
+ .closest(".form-namespace")
62
+ .find(`[data-fieldname=${data[0]}]`)
63
+ .val();
64
+
65
+ var options = data[1][val];
66
+ var current = e.attr("data-selected");
67
+ //console.log({ val, options, current, data });
68
+ e.empty();
69
+ (options || []).forEach((o) => {
70
+ if (
71
+ !(o && typeof o.label !== "undefined" && typeof o.value !== "undefined")
72
+ ) {
73
+ if (`${current}` === `${o}`)
74
+ e.append($("<option selected>" + o + "</option>"));
75
+ else e.append($("<option>" + o + "</option>"));
76
+ } else {
77
+ e.append(
78
+ $(
79
+ `<option ${
80
+ `${current}` === `${o.value}` ? "selected" : ""
81
+ } value="${o.value}">${o.label}</option>`
82
+ )
83
+ );
84
+ }
85
+ });
86
+ e.change(function (ec) {
87
+ e.attr("data-selected", ec.target.value);
88
+ });
89
+ });
90
+ $("[data-source-url]").each(function (ix, element) {
91
+ const e = $(element);
92
+ const rec = get_form_record(e);
93
+ ajax_post_json(e.attr("data-source-url"), rec, {
94
+ success: (data) => {
95
+ e.html(data);
96
+ },
97
+ error: (err) => {
98
+ console.error(err);
99
+ e.html("");
100
+ },
101
+ });
102
+ });
103
+ }
104
+ function get_form_record(e, select_labels) {
105
+ const rec = {};
106
+ e.closest("form")
107
+ .find("input[name],select[name]")
108
+ .each(function () {
109
+ if (select_labels && $(this).prop("tagName").toLowerCase() === "select")
110
+ rec[$(this).attr("name")] = $(this).find("option:selected").text();
111
+ else if ($(this).prop("type") === "checkbox")
112
+ rec[$(this).attr("name")] = $(this).prop("checked");
113
+ else rec[$(this).attr("name")] = $(this).val();
114
+ });
115
+ return rec;
116
+ }
117
+ function showIfFormulaInputs(e, fml) {
118
+ const rec = get_form_record(e);
119
+ return new Function(`{${Object.keys(rec).join(",")}}`, "return " + fml)(rec);
120
+ }
121
+
122
+ function rep_del(e) {
123
+ var myrep = $(e).closest(".form-repeat");
124
+ var ix = myrep.index();
125
+ var parent = myrep.parent();
126
+ parent.children().each(function (childix, element) {
127
+ if (childix > ix) {
128
+ reindex(element, childix, childix - 1);
129
+ }
130
+ });
131
+ myrep.remove();
132
+ }
133
+
134
+ function reindex(element, oldix, newix) {
135
+ $(element).html(
136
+ $(element)
137
+ .html()
138
+ .split("_" + oldix)
139
+ .join("_" + newix)
140
+ );
141
+ }
142
+
143
+ function get_form_subset_record(e) {
144
+ const rec = {};
145
+ e.find("input[name],select[name]").each(function () {
146
+ rec[$(this).attr("name")] = $(this).val();
147
+ });
148
+ return rec;
149
+ }
150
+
151
+ function apply_form_subset_record(e, vals) {
152
+ e.find("input[name],select[name]").each(function () {
153
+ var name = $(this).attr("name");
154
+ if (vals[name]) $(this).val(vals[name]);
155
+ });
156
+ }
157
+
158
+ function reindex_form_record(vals, oldix, newix) {
159
+ const rec = {};
160
+ Object.keys(vals).forEach((k) => {
161
+ const newkey = k.split("_" + oldix).join("_" + newix);
162
+ rec[newkey] = vals[k];
163
+ });
164
+ return rec;
165
+ }
166
+
167
+ function rep_up(e) {
168
+ var myrep = $(e).closest(".form-repeat");
169
+ var theform = $(e).closest("form");
170
+ var ix = myrep.index();
171
+ var parent = myrep.parent();
172
+ if (ix > 0) {
173
+ var swap_with = parent.children(".form-repeat").eq(ix - 1);
174
+ var vals1 = reindex_form_record(get_form_subset_record(myrep), ix, ix - 1);
175
+ var vals2 = reindex_form_record(
176
+ get_form_subset_record(swap_with),
177
+ ix - 1,
178
+ ix
179
+ );
180
+ reindex(myrep, ix, ix - 1);
181
+ reindex(swap_with, ix - 1, ix);
182
+ $(myrep).swapWith(swap_with);
183
+ apply_form_subset_record(theform, vals2);
184
+ apply_form_subset_record(theform, vals1);
185
+ }
186
+ }
187
+
188
+ function rep_down(e) {
189
+ var myrep = $(e).closest(".form-repeat");
190
+ var theform = $(e).closest("form");
191
+ var ix = myrep.index();
192
+ var parent = myrep.parent();
193
+ var nchildren = parent.children(".form-repeat").length;
194
+ if (ix < nchildren - 1) {
195
+ var swap_with = parent.children(".form-repeat").eq(ix + 1);
196
+ var vals1 = reindex_form_record(get_form_subset_record(myrep), ix, ix + 1);
197
+ var vals2 = reindex_form_record(
198
+ get_form_subset_record(swap_with),
199
+ ix + 1,
200
+ ix
201
+ );
202
+ reindex(myrep, ix, ix + 1);
203
+ reindex(swap_with, ix + 1, ix);
204
+ $(myrep).swapWith(swap_with);
205
+ apply_form_subset_record(theform, vals2);
206
+ apply_form_subset_record(theform, vals1);
207
+ }
208
+ }
209
+
210
+ function reload_on_init() {
211
+ localStorage.setItem("reload_on_init", true);
212
+ }
213
+ function initialize_page() {
214
+ //console.log("init page");
215
+ $(".blur-on-enter-keypress").bind("keyup", function (e) {
216
+ if (e.keyCode === 13) e.target.blur();
217
+ });
218
+ $("form").change(apply_showif);
219
+ apply_showif();
220
+ apply_showif();
221
+ $("[data-inline-edit-dest-url]").each(function () {
222
+ if ($(this).find(".editicon").length === 0) {
223
+ var current = $(this).html();
224
+ $(this).html(
225
+ `<span class="current">${current}</span><i class="editicon fas fa-edit ms-1"></i>`
226
+ );
227
+ }
228
+ });
229
+ $("[data-inline-edit-dest-url]").click(function () {
230
+ var url = $(this).attr("data-inline-edit-dest-url");
231
+ var current = $(this).children("span.current").html();
232
+ $(this).replaceWith(
233
+ `<form method="post" action="${url}" >
234
+ <input type="hidden" name="_csrf" value="${_sc_globalCsrf}">
235
+ <input type="text" name="value" value="${current}">
236
+ <button type="submit" class="btn btn-sm btn-primary">OK</button>
237
+ </form>`
238
+ );
239
+ });
240
+ function setExplainer(that) {
241
+ var id = $(that).attr("id") + "_explainer";
242
+
243
+ var explainers = JSON.parse(
244
+ decodeURIComponent($(that).attr("data-explainers"))
245
+ );
246
+ var currentVal = explainers[$(that).val()];
247
+ $("#" + id).html(`<strong>${$(that).val()}</strong>: ${currentVal}`);
248
+ if (currentVal) $("#" + id).show();
249
+ else $("#" + id).hide();
250
+ }
251
+ $("[data-explainers]").each(function () {
252
+ var id = $(this).attr("id") + "_explainer";
253
+ if ($("#" + id).length === 0) {
254
+ $(this).after(`<div class="alert alert-info my-2" id="${id}"></div>`);
255
+ setExplainer(this);
256
+ }
257
+ });
258
+ $("[data-explainers]").change(function () {
259
+ setExplainer(this);
260
+ });
261
+
262
+ const codes = [];
263
+ $("textarea.to-code").each(function () {
264
+ codes.push(this);
265
+ });
266
+ if (codes.length > 0)
267
+ enable_codemirror(() => {
268
+ setTimeout(() => {
269
+ codes.forEach((el) => {
270
+ //console.log($(el).attr("mode"), el);
271
+ CodeMirror.fromTextArea(el, {
272
+ lineNumbers: true,
273
+ mode: $(el).attr("mode"),
274
+ });
275
+ });
276
+ }, 100);
277
+ });
278
+ const locale =
279
+ navigator.userLanguage ||
280
+ (navigator.languages &&
281
+ navigator.languages.length &&
282
+ navigator.languages[0]) ||
283
+ navigator.language ||
284
+ navigator.browserLanguage ||
285
+ navigator.systemLanguage ||
286
+ "en";
287
+ window.detected_locale = locale;
288
+ const parse = (s) => JSON.parse(decodeURIComponent(s));
289
+ $("time[locale-time-options]").each(function () {
290
+ var el = $(this);
291
+ var date = new Date(el.attr("datetime"));
292
+ const options = parse(el.attr("locale-time-options"));
293
+ el.text(date.toLocaleTimeString(locale, options));
294
+ });
295
+ $("time[locale-options]").each(function () {
296
+ var el = $(this);
297
+ var date = new Date(el.attr("datetime"));
298
+ const options = parse(el.attr("locale-options"));
299
+ el.text(date.toLocaleString(locale, options));
300
+ });
301
+ $("time[locale-date-options]").each(function () {
302
+ var el = $(this);
303
+ var date = new Date(el.attr("datetime"));
304
+ const options = parse(el.attr("locale-date-options"));
305
+ el.text(date.toLocaleDateString(locale, options));
306
+ });
307
+ if ($.fn.historyTabs) $('a[data-bs-toggle="tab"].deeplink').historyTabs();
308
+ init_bs5_dropdowns();
309
+
310
+ // Initialize Sliders - https://stackoverflow.com/a/31083391
311
+ var sliderSections = document.getElementsByClassName("range-slider");
312
+ for (var x = 0; x < sliderSections.length; x++) {
313
+ var sliders = sliderSections[x].getElementsByTagName("input");
314
+ for (var y = 0; y < sliders.length; y++) {
315
+ if (sliders[y].type === "range") {
316
+ sliders[y].oninput = function () {
317
+ // Get slider values
318
+ var parent = this.parentNode;
319
+ var slides = parent.getElementsByTagName("input");
320
+ var slide1 = parseFloat(slides[0].value);
321
+ var slide2 = parseFloat(slides[1].value);
322
+ // Neither slider will clip the other, so make sure we determine which is larger
323
+ if (slide1 > slide2) {
324
+ var tmp = slide2;
325
+ slide2 = slide1;
326
+ slide1 = tmp;
327
+ }
328
+
329
+ var displayElement = parent.getElementsByClassName("rangeValues")[0];
330
+ displayElement.innerHTML = slide1 + " - " + slide2;
331
+ };
332
+ // Manually trigger event first time to display values
333
+ sliders[y].oninput();
334
+ }
335
+ }
336
+ }
337
+ }
338
+
339
+ $(initialize_page);
340
+
341
+ function enable_codemirror(f) {
342
+ $("<link/>", {
343
+ rel: "stylesheet",
344
+ type: "text/css",
345
+ href: `/static_assets/${_sc_version_tag}/codemirror.css`,
346
+ }).appendTo("head");
347
+ $.ajax({
348
+ url: `/static_assets/${_sc_version_tag}/codemirror.min.js`,
349
+ dataType: "script",
350
+ cache: true,
351
+ success: f,
352
+ });
353
+ }
354
+ function tristateClick(nm) {
355
+ var current = $(`button#trib${nm}`).html();
356
+ switch (current) {
357
+ case "?":
358
+ $(`button#trib${nm}`).html("T");
359
+ $(`input#input${nm}`).val("on");
360
+ break;
361
+ case "T":
362
+ $(`button#trib${nm}`).html("F");
363
+ $(`input#input${nm}`).val("off");
364
+ break;
365
+ default:
366
+ $(`button#trib${nm}`).html("?");
367
+ $(`input#input${nm}`).val("?");
368
+ break;
369
+ }
4
370
  }
5
371
 
6
372
  function notifyAlert(note, spin) {
@@ -31,6 +397,11 @@ function notifyAlert(note, spin) {
31
397
  </div>`);
32
398
  }
33
399
 
400
+ function press_store_button(clicked) {
401
+ const width = $(clicked).width();
402
+ $(clicked).html('<i class="fas fa-spinner fa-spin"></i>').width(width);
403
+ }
404
+
34
405
  function common_done(res, isWeb = true) {
35
406
  if (res.notify) notifyAlert(res.notify);
36
407
  if (res.error) notifyAlert({ type: "danger", text: res.error });
@@ -53,6 +424,7 @@ function common_done(res, isWeb = true) {
53
424
  });
54
425
  }
55
426
  if (res.goto && !isWeb)
427
+ // TODO ch
56
428
  notifyAlert({
57
429
  type: "danger",
58
430
  text: "Goto is not supported in a mobile deployment.",
@@ -63,6 +435,73 @@ function common_done(res, isWeb = true) {
63
435
  }
64
436
  }
65
437
 
438
+ const repeaterCopyValuesToForm = (form, editor) => {
439
+ const vs = JSON.parse(editor.getString());
440
+ const allNames = new Set([]);
441
+ const setVal = (k, ix, v) => {
442
+ const $e = form.find(`input[name="${k}_${ix}"]`);
443
+ if ($e.length) $e.val(v);
444
+ else
445
+ form.append(
446
+ `<input type="hidden" name="${k}_${ix}" value="${v}"></input>`
447
+ );
448
+ };
449
+ vs.forEach((v, ix) => {
450
+ Object.entries(v).forEach(([k, v]) => {
451
+ //console.log(ix, k, typeof v, v)
452
+ allNames.add(k);
453
+ if (typeof v === "boolean") setVal(k, ix, v ? "on" : "");
454
+ else setVal(k, ix, v);
455
+ });
456
+ });
457
+ //delete
458
+ [...allNames].forEach((k) => {
459
+ for (let ix = vs.length; ix < vs.length + 20; ix++) {
460
+ $(`input[name="${k}_${ix}"]`).remove();
461
+ }
462
+ });
463
+ };
464
+ function align_dropdown(id) {
465
+ setTimeout(() => {
466
+ if ($("#dm" + id).hasClass("show")) {
467
+ var inputWidth = $("#search-input-group-" + id).outerWidth();
468
+ $("#dm" + id).css("width", inputWidth);
469
+ var d0pos = $("#search-input-group-" + id).offset();
470
+ $("#dm" + id).offset({ left: d0pos.left });
471
+ $(document).on("click", "#dm" + id, function (e) {
472
+ e.stopPropagation();
473
+ });
474
+ }
475
+ }, 0);
476
+ }
477
+
478
+ function remove_outline(form) {
479
+ $(form)
480
+ .find("button[type=submit]")
481
+ .removeClass("btn-outline-primary")
482
+ .addClass("btn-primary");
483
+ }
484
+
485
+ const columnSummary = (col) => {
486
+ if (!col) return "Unknown";
487
+ switch (col.type) {
488
+ case "Field":
489
+ return `Field ${col.field_name} ${col.fieldview || ""}`;
490
+ case "Link":
491
+ return `Link ${col.link_text}`;
492
+ case "JoinField":
493
+ return `Join ${col.join_field}`;
494
+ case "ViewLink":
495
+ return `View link ${col.view_label || col.view.split(":")[1] || ""}`;
496
+ case "Action":
497
+ return `Action ${col.action_label || col.action_name}`;
498
+ case "Aggregation":
499
+ return `${col.stat} ${col.agg_field} ${col.agg_relation}`;
500
+ default:
501
+ return "Unknown";
502
+ }
503
+ };
504
+
66
505
  function submitWithEmptyAction(form) {
67
506
  var formAction = form.action;
68
507
  form.action = "javascript:void(0)";