@saltcorn/server 0.7.1-beta.3 → 0.7.2-beta.10

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,332 +1,14 @@
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
1
  function sortby(k, desc) {
26
2
  set_state_fields({ _sortby: k, _sortdesc: desc ? "on" : { unset: true } });
27
3
  }
28
4
  function gopage(n, pagesize, extra = {}) {
29
5
  set_state_fields({ ...extra, _page: n, _pagesize: pagesize });
30
6
  }
31
- function add_repeater(nm) {
32
- var es = $("div.form-repeat.repeat-" + nm);
33
- var e = es.first();
34
- var newix = es.length;
35
- var newe = $(e).clone();
36
- newe.find("[name]").each(function (ix, element) {
37
- var newnm = (element.name || "").replace("_0", "_" + newix);
38
- var newid = (element.id || "").replace("_0", "_" + newix);
39
- $(element).attr("name", newnm).attr("id", newid);
40
- });
41
- newe.appendTo($("div.repeats-" + nm));
42
- }
43
- // "e.closest('.form-namespace').find('.coltype').val()==='Field';"
44
- function apply_showif() {
45
- $("[data-show-if]").each(function (ix, element) {
46
- var e = $(element);
47
- try {
48
- var to_show = new Function(
49
- "e",
50
- "return " + decodeURIComponent(e.attr("data-show-if"))
51
- );
52
- if (to_show(e))
53
- e.show()
54
- .find("input, textarea, button, select")
55
- .prop("disabled", e.attr("data-disabled") || false);
56
- else
57
- e.hide().find("input, textarea, button, select").prop("disabled", true);
58
- } catch (e) {
59
- console.error(e);
60
- }
61
- });
62
- $("[data-calc-options]").each(function (ix, element) {
63
- var e = $(element);
64
- var data = JSON.parse(decodeURIComponent(e.attr("data-calc-options")));
65
-
66
- var val = e
67
- .closest(".form-namespace")
68
- .find(`[data-fieldname=${data[0]}]`)
69
- .val();
70
-
71
- var options = data[1][val];
72
- var current = e.attr("data-selected");
73
- //console.log(val, options, current,data)
74
- e.empty();
75
- (options || []).forEach((o) => {
76
- if (!(o && o.label && o.value)) {
77
- if (`${current}` === `${o}`)
78
- e.append($("<option selected>" + o + "</option>"));
79
- else e.append($("<option>" + o + "</option>"));
80
- } else {
81
- e.append(
82
- $(
83
- `<option ${
84
- `${current}` === `${o.value}` ? "selected" : ""
85
- } value="${o.value}">${o.label}</option>`
86
- )
87
- );
88
- }
89
- });
90
- e.change(function (ec) {
91
- e.attr("data-selected", ec.target.value);
92
- });
93
- });
94
- $("[data-source-url]").each(function (ix, element) {
95
- const e = $(element);
96
- const rec = get_form_record(e);
97
- ajax_post_json(e.attr("data-source-url"), rec, {
98
- success: (data) => {
99
- e.html(data);
100
- },
101
- error: (err) => {
102
- console.error(err);
103
- e.html("");
104
- },
105
- });
106
- });
107
- }
108
- function get_form_record(e, select_labels) {
109
- const rec = {};
110
- e.closest("form")
111
- .find("input[name],select[name]")
112
- .each(function () {
113
- if (select_labels && $(this).prop("tagName").toLowerCase() === "select")
114
- rec[$(this).attr("name")] = $(this).find("option:selected").text();
115
- else if ($(this).prop("type") === "checkbox")
116
- rec[$(this).attr("name")] = $(this).prop("checked");
117
- else rec[$(this).attr("name")] = $(this).val();
118
- });
119
- return rec;
120
- }
121
- function showIfFormulaInputs(e, fml) {
122
- const rec = get_form_record(e);
123
- return new Function(`{${Object.keys(rec).join(",")}}`, "return " + fml)(rec);
124
- }
125
-
126
- function rep_del(e) {
127
- var myrep = $(e).closest(".form-repeat");
128
- var ix = myrep.index();
129
- var parent = myrep.parent();
130
- parent.children().each(function (childix, element) {
131
- if (childix > ix) {
132
- reindex(element, childix, childix - 1);
133
- }
134
- });
135
- myrep.remove();
136
- }
137
-
138
- function reindex(element, oldix, newix) {
139
- $(element).html(
140
- $(element)
141
- .html()
142
- .split("_" + oldix)
143
- .join("_" + newix)
144
- );
145
- }
146
-
147
- function get_form_subset_record(e) {
148
- const rec = {};
149
- e.find("input[name],select[name]").each(function () {
150
- rec[$(this).attr("name")] = $(this).val();
151
- });
152
- return rec;
153
- }
154
7
 
155
- function apply_form_subset_record(e, vals) {
156
- e.find("input[name],select[name]").each(function () {
157
- var name = $(this).attr("name");
158
- if (vals[name]) $(this).val(vals[name]);
159
- });
160
- }
161
-
162
- function reindex_form_record(vals, oldix, newix) {
163
- const rec = {};
164
- Object.keys(vals).forEach((k) => {
165
- const newkey = k.split("_" + oldix).join("_" + newix);
166
- rec[newkey] = vals[k];
167
- });
168
- return rec;
169
- }
170
-
171
- function rep_up(e) {
172
- var myrep = $(e).closest(".form-repeat");
173
- var theform = $(e).closest("form");
174
- var ix = myrep.index();
175
- var parent = myrep.parent();
176
- if (ix > 0) {
177
- var swap_with = parent.children(".form-repeat").eq(ix - 1);
178
- var vals1 = reindex_form_record(get_form_subset_record(myrep), ix, ix - 1);
179
- var vals2 = reindex_form_record(
180
- get_form_subset_record(swap_with),
181
- ix - 1,
182
- ix
183
- );
184
- reindex(myrep, ix, ix - 1);
185
- reindex(swap_with, ix - 1, ix);
186
- $(myrep).swapWith(swap_with);
187
- apply_form_subset_record(theform, vals2);
188
- apply_form_subset_record(theform, vals1);
189
- }
190
- }
191
-
192
- function rep_down(e) {
193
- var myrep = $(e).closest(".form-repeat");
194
- var theform = $(e).closest("form");
195
- var ix = myrep.index();
196
- var parent = myrep.parent();
197
- var nchildren = parent.children(".form-repeat").length;
198
- if (ix < nchildren - 1) {
199
- var swap_with = parent.children(".form-repeat").eq(ix + 1);
200
- var vals1 = reindex_form_record(get_form_subset_record(myrep), ix, ix + 1);
201
- var vals2 = reindex_form_record(
202
- get_form_subset_record(swap_with),
203
- ix + 1,
204
- ix
205
- );
206
- reindex(myrep, ix, ix + 1);
207
- reindex(swap_with, ix + 1, ix);
208
- $(myrep).swapWith(swap_with);
209
- apply_form_subset_record(theform, vals2);
210
- apply_form_subset_record(theform, vals1);
211
- }
212
- }
213
-
214
- function reload_on_init() {
215
- localStorage.setItem("reload_on_init", true);
216
- }
217
8
  if (localStorage.getItem("reload_on_init")) {
218
9
  localStorage.removeItem("reload_on_init");
219
10
  location.reload();
220
11
  }
221
- function initialize_page() {
222
- $("form").change(apply_showif);
223
- apply_showif();
224
- apply_showif();
225
- $("[data-inline-edit-dest-url]").each(function () {
226
- if ($(this).find(".editicon").length === 0) {
227
- var current = $(this).html();
228
- $(this).html(
229
- `<span class="current">${current}</span><i class="editicon fas fa-edit ms-1"></i>`
230
- );
231
- }
232
- });
233
- $("[data-inline-edit-dest-url]").click(function () {
234
- var url = $(this).attr("data-inline-edit-dest-url");
235
- var current = $(this).children("span.current").html();
236
- $(this).replaceWith(
237
- `<form method="post" action="${url}" >
238
- <input type="hidden" name="_csrf" value="${_sc_globalCsrf}">
239
- <input type="text" name="value" value="${current}">
240
- <button type="submit" class="btn btn-sm btn-primary">OK</button>
241
- </form>`
242
- );
243
- });
244
- function setExplainer(that) {
245
- var id = $(that).attr("id") + "_explainer";
246
-
247
- var explainers = JSON.parse(
248
- decodeURIComponent($(that).attr("data-explainers"))
249
- );
250
- var currentVal = explainers[$(that).val()];
251
- $("#" + id).html(`<strong>${$(that).val()}</strong>: ${currentVal}`);
252
- if (currentVal) $("#" + id).show();
253
- else $("#" + id).hide();
254
- }
255
- $("[data-explainers]").each(function () {
256
- var id = $(this).attr("id") + "_explainer";
257
- if ($("#" + id).length === 0) {
258
- $(this).after(`<div class="alert alert-info my-2" id="${id}"></div>`);
259
- setExplainer(this);
260
- }
261
- });
262
- $("[data-explainers]").change(function () {
263
- setExplainer(this);
264
- });
265
-
266
- const codes = [];
267
- $("textarea.to-code").each(function () {
268
- codes.push(this);
269
- });
270
- if (codes.length > 0)
271
- enable_codemirror(() => {
272
- setTimeout(() => {
273
- codes.forEach((el) => {
274
- //console.log($(el).attr("mode"), el);
275
- CodeMirror.fromTextArea(el, {
276
- lineNumbers: true,
277
- mode: $(el).attr("mode"),
278
- });
279
- });
280
- }, 100);
281
- });
282
- const locale =
283
- navigator.userLanguage ||
284
- (navigator.languages &&
285
- navigator.languages.length &&
286
- navigator.languages[0]) ||
287
- navigator.language ||
288
- navigator.browserLanguage ||
289
- navigator.systemLanguage ||
290
- "en";
291
- window.detected_locale = locale;
292
- const parse = (s) => JSON.parse(decodeURIComponent(s));
293
- $("time[locale-time-options]").each(function () {
294
- var el = $(this);
295
- var date = new Date(el.attr("datetime"));
296
- const options = parse(el.attr("locale-time-options"));
297
- el.text(date.toLocaleTimeString(locale, options));
298
- });
299
- $("time[locale-options]").each(function () {
300
- var el = $(this);
301
- var date = new Date(el.attr("datetime"));
302
- const options = parse(el.attr("locale-options"));
303
- el.text(date.toLocaleString(locale, options));
304
- });
305
- $("time[locale-date-options]").each(function () {
306
- var el = $(this);
307
- var date = new Date(el.attr("datetime"));
308
- const options = parse(el.attr("locale-date-options"));
309
- el.text(date.toLocaleDateString(locale, options));
310
- });
311
- $('a[data-bs-toggle="tab"].deeplink').historyTabs();
312
- init_bs5_dropdowns();
313
- }
314
-
315
- $(initialize_page);
316
-
317
- function enable_codemirror(f) {
318
- $("<link/>", {
319
- rel: "stylesheet",
320
- type: "text/css",
321
- href: `/static_assets/${_sc_version_tag}/codemirror.css`,
322
- }).appendTo("head");
323
- $.ajax({
324
- url: `/static_assets/${_sc_version_tag}/codemirror.min.js`,
325
- dataType: "script",
326
- cache: true,
327
- success: f,
328
- });
329
- }
330
12
 
331
13
  //https://stackoverflow.com/a/6021027
332
14
  function updateQueryStringParameter(uri1, key, value) {
@@ -441,75 +123,9 @@ function href_to(href) {
441
123
  function clear_state() {
442
124
  pjax_to(window.location.href.split("?")[0]);
443
125
  }
444
- function tristateClick(nm) {
445
- var current = $(`button#trib${nm}`).html();
446
- switch (current) {
447
- case "?":
448
- $(`button#trib${nm}`).html("T");
449
- $(`input#input${nm}`).val("on");
450
- break;
451
- case "T":
452
- $(`button#trib${nm}`).html("F");
453
- $(`input#input${nm}`).val("off");
454
- break;
455
- default:
456
- $(`button#trib${nm}`).html("?");
457
- $(`input#input${nm}`).val("?");
458
- break;
459
- }
460
- }
461
-
462
- function notifyAlert(note, spin) {
463
- if (Array.isArray(note)) {
464
- note.forEach(notifyAlert);
465
- return;
466
- }
467
- var txt, type;
468
- if (typeof note == "string") {
469
- txt = note;
470
- type = "info";
471
- } else {
472
- txt = note.text;
473
- type = note.type;
474
- }
475
-
476
- $("#alerts-area")
477
- .append(`<div class="alert alert-${type} alert-dismissible fade show ${
478
- spin ? "d-flex align-items-center" : ""
479
- }" role="alert">
480
- ${txt}
481
- ${
482
- spin
483
- ? `<div class="spinner-border ms-auto" role="status" aria-hidden="true"></div>`
484
- : `<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
485
- </button>`
486
- }
487
- </div>`);
488
- }
489
126
 
490
127
  function ajax_done(res) {
491
- if (res.notify) notifyAlert(res.notify);
492
- if (res.error) notifyAlert({ type: "danger", text: res.error });
493
- if (res.eval_js) eval(res.eval_js);
494
- if (res.reload_page) location.reload(); //TODO notify to cookie if reload or goto
495
- if (res.download) {
496
- const dataurl = `data:${
497
- res.download.mimetype || "application/octet-stream"
498
- };base64,${res.download.blob}`;
499
- fetch(dataurl)
500
- .then((res) => res.blob())
501
- .then((blob) => {
502
- const link = document.createElement("a");
503
- link.href = window.URL.createObjectURL(blob);
504
- if (res.download.filename) link.download = res.download.filename;
505
- else link.target = "_blank";
506
- link.click();
507
- });
508
- }
509
- if (res.goto) {
510
- if (res.target === "_blank") window.open(res.goto, "_blank").focus();
511
- else window.location.href = res.goto;
512
- }
128
+ common_done(res);
513
129
  }
514
130
 
515
131
  function view_post(viewname, route, data, onDone) {
@@ -546,11 +162,6 @@ function globalErrorCatcher(message, source, lineno, colno, error) {
546
162
  });
547
163
  }
548
164
 
549
- function press_store_button(clicked) {
550
- const width = $(clicked).width();
551
- $(clicked).html('<i class="fas fa-spinner fa-spin"></i>').width(width);
552
- }
553
-
554
165
  function ajax_modal(url, opts = {}) {
555
166
  if ($("#scmodal").length === 0) {
556
167
  $("body").append(`<div id="scmodal", class="modal">
@@ -567,6 +178,10 @@ function ajax_modal(url, opts = {}) {
567
178
  </div>
568
179
  </div>
569
180
  </div>`);
181
+ } else if ($("#scmodal").hasClass("show")) {
182
+ var myModalEl = document.getElementById("scmodal");
183
+ var modal = bootstrap.Modal.getInstance(myModalEl);
184
+ modal.dispose();
570
185
  }
571
186
  if (opts.submitReload === false) $("#scmodal").addClass("no-submit-reload");
572
187
  else $("#scmodal").removeClass("no-submit-reload");
@@ -587,6 +202,7 @@ function ajax_modal(url, opts = {}) {
587
202
 
588
203
  function saveAndContinue(e, k) {
589
204
  var form = $(e).closest("form");
205
+ submitWithEmptyAction(form[0]);
590
206
  var url = form.attr("action");
591
207
  var form_data = form.serialize();
592
208
  $.ajax(url, {
@@ -614,16 +230,38 @@ function saveAndContinue(e, k) {
614
230
  return false;
615
231
  }
616
232
 
233
+ function applyViewConfig(e, url) {
234
+ var form = $(e).closest("form");
235
+ var form_data = form.serializeArray();
236
+ const cfg = {};
237
+ form_data.forEach((item) => {
238
+ cfg[item.name] = item.value;
239
+ });
240
+ $.ajax(url, {
241
+ type: "POST",
242
+ dataType: "json",
243
+ contentType: "application/json",
244
+ headers: {
245
+ "CSRF-Token": _sc_globalCsrf,
246
+ },
247
+ data: JSON.stringify(cfg),
248
+ error: function (request) {},
249
+ });
250
+
251
+ return false;
252
+ }
253
+
617
254
  function ajaxSubmitForm(e) {
618
255
  var form = $(e).closest("form");
619
256
  var url = form.attr("action");
620
- var form_data = form.serialize();
621
257
  $.ajax(url, {
622
258
  type: "POST",
623
259
  headers: {
624
260
  "CSRF-Token": _sc_globalCsrf,
625
261
  },
626
- data: form_data,
262
+ data: new FormData(form[0]),
263
+ processData: false,
264
+ contentType: false,
627
265
  success: function () {
628
266
  var no_reload = $("#scmodal").hasClass("no-submit-reload");
629
267
  $("#scmodal").modal("hide");
@@ -698,31 +336,16 @@ function make_unique_field(
698
336
  type: "GET",
699
337
  success: function (res) {
700
338
  if (res.success) {
701
- const gen_char = (i) => {
702
- switch (char_type) {
703
- case "Lowercase Letters":
704
- return String.fromCharCode("a".charCodeAt(0) + i);
705
- break;
706
- case "Uppercase Letters":
707
- return String.fromCharCode("A".charCodeAt(0) + i);
708
- break;
709
- default:
710
- return i;
711
- break;
712
- }
713
- };
714
- const vals = res.success
715
- .map((o) => o[field_name])
716
- .filter((s) => s.startsWith(value));
717
- if (vals.includes(value) || always_append) {
718
- for (let i = start || 0; i < vals.length + (start || 0) + 2; i++) {
719
- const newname = `${value}${space ? " " : ""}${gen_char(i)}`;
720
- if (!vals.includes(newname)) {
721
- $("#" + id).val(newname);
722
- return;
723
- }
724
- }
725
- }
339
+ unique_field_from_rows(
340
+ res.success,
341
+ id,
342
+ field_name,
343
+ space,
344
+ start,
345
+ always_append,
346
+ char_type,
347
+ value
348
+ );
726
349
  }
727
350
  },
728
351
  }
@@ -737,26 +360,6 @@ function test_formula(tablename, stored) {
737
360
  },
738
361
  });
739
362
  }
740
- function align_dropdown(id) {
741
- setTimeout(() => {
742
- if ($("#dm" + id).hasClass("show")) {
743
- var inputWidth = $("#search-input-group-" + id).outerWidth();
744
- $("#dm" + id).css("width", inputWidth);
745
- var d0pos = $("#search-input-group-" + id).offset();
746
- $("#dm" + id).offset({ left: d0pos.left });
747
- $(document).on("click", "#dm" + id, function (e) {
748
- e.stopPropagation();
749
- });
750
- }
751
- }, 0);
752
- }
753
-
754
- function remove_outline(form) {
755
- $(form)
756
- .find("button[type=submit]")
757
- .removeClass("btn-outline-primary")
758
- .addClass("btn-primary");
759
- }
760
363
 
761
364
  function init_room(viewname, room_id) {
762
365
  const socket = io({ transports: ["websocket"] });
@@ -826,25 +429,6 @@ async function fill_formula_btn_click(btn, k) {
826
429
  if (k) k();
827
430
  }
828
431
 
829
- const columnSummary = (col) => {
830
- if (!col) return "Unknown";
831
- switch (col.type) {
832
- case "Field":
833
- return `Field ${col.field_name} ${col.fieldview}`;
834
- case "Link":
835
- return `Link ${col.link_text}`;
836
- case "JoinField":
837
- return `Join ${col.join_field}`;
838
- case "ViewLink":
839
- return `View ${col.view_label || col.view.split(":")[1] || ""}`;
840
- case "Action":
841
- return `Action ${col.action_label || col.action_name}`;
842
- case "Aggregation":
843
- return `${col.stat} ${col.agg_field} ${col.agg_relation}`;
844
- default:
845
- return "Unknown";
846
- }
847
- };
848
432
 
849
433
  /*
850
434
  https://github.com/jeffdavidgreen/bootstrap-html5-history-tabs/blob/master/bootstrap-history-tabs.js
@@ -17,6 +17,7 @@ const relevantPackages = [
17
17
  "db-common",
18
18
  "postgres",
19
19
  "saltcorn-data",
20
+ "saltcorn-admin-models",
20
21
  "saltcorn-markup",
21
22
  "saltcorn-sbadmin2",
22
23
  "server",
@@ -28,7 +29,6 @@ const relevantPackages = [
28
29
  */
29
30
  const excludePatterns = [
30
31
  /\/node_modules/,
31
- /\/public/,
32
32
  /\.git/,
33
33
  /\.docs/,
34
34
  /\.docs/,