@saltcorn/markup 0.6.2-beta.4 → 0.6.2-beta.5

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 (60) hide show
  1. package/dist/builder.d.ts +18 -0
  2. package/dist/builder.d.ts.map +1 -0
  3. package/dist/builder.js +57 -0
  4. package/dist/builder.js.map +1 -0
  5. package/dist/emergency_layout.d.ts +6 -0
  6. package/dist/emergency_layout.d.ts.map +1 -0
  7. package/dist/emergency_layout.js +38 -0
  8. package/dist/emergency_layout.js.map +1 -0
  9. package/dist/form.d.ts +12 -0
  10. package/dist/form.d.ts.map +1 -0
  11. package/dist/form.js +372 -0
  12. package/dist/form.js.map +1 -0
  13. package/dist/helpers.d.ts +58 -0
  14. package/dist/helpers.d.ts.map +1 -0
  15. package/dist/helpers.js +169 -0
  16. package/dist/helpers.js.map +1 -0
  17. package/dist/index.d.ts +21 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +158 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/layout.d.ts +22 -0
  22. package/dist/layout.d.ts.map +1 -0
  23. package/dist/layout.js +338 -0
  24. package/dist/layout.js.map +1 -0
  25. package/dist/layout_utils.d.ts +21 -0
  26. package/dist/layout_utils.d.ts.map +1 -0
  27. package/dist/layout_utils.js +272 -0
  28. package/dist/layout_utils.js.map +1 -0
  29. package/dist/mktag.d.ts +12 -0
  30. package/dist/mktag.d.ts.map +1 -0
  31. package/dist/mktag.js +102 -0
  32. package/dist/mktag.js.map +1 -0
  33. package/dist/table.d.ts +22 -0
  34. package/dist/table.d.ts.map +1 -0
  35. package/dist/table.js +51 -0
  36. package/dist/table.js.map +1 -0
  37. package/dist/tabs.d.ts +7 -0
  38. package/dist/tabs.d.ts.map +1 -0
  39. package/dist/tabs.js +34 -0
  40. package/dist/tabs.js.map +1 -0
  41. package/dist/tags.d.ts +16 -0
  42. package/dist/tags.d.ts.map +1 -0
  43. package/dist/tags.js +71 -0
  44. package/dist/tags.js.map +1 -0
  45. package/dist/tsconfig.ref.tsbuildinfo +1 -0
  46. package/package.json +25 -6
  47. package/builder.js +0 -106
  48. package/emergency_layout.js +0 -54
  49. package/form.js +0 -603
  50. package/form.test.js +0 -98
  51. package/helpers.js +0 -268
  52. package/index.js +0 -226
  53. package/layout.js +0 -595
  54. package/layout.test.js +0 -39
  55. package/layout_utils.js +0 -430
  56. package/markup.test.js +0 -104
  57. package/mktag.js +0 -105
  58. package/table.js +0 -115
  59. package/tabs.js +0 -54
  60. package/tags.js +0 -56
package/layout_utils.js DELETED
@@ -1,430 +0,0 @@
1
- /**
2
- * @category saltcorn-markup
3
- * @module layout_utils
4
- */
5
-
6
- const {
7
- ul,
8
- li,
9
- ol,
10
- a,
11
- span,
12
- hr,
13
- div,
14
- text,
15
- img,
16
- button,
17
- nav,
18
- script,
19
- domReady,
20
- footer,
21
- i,
22
- small,
23
- br,
24
- form,
25
- input,
26
- } = require("./tags");
27
-
28
- /**
29
- * @param {string} item
30
- * @returns {string}
31
- */
32
- const labelToId = (item) => text(item.replace(" ", ""));
33
-
34
- /**
35
- * @param {string} currentUrl
36
- * @param {object} item
37
- * @returns {boolean}
38
- */
39
- const active = (currentUrl, item) =>
40
- (item.link && currentUrl.startsWith(item.link)) ||
41
- (item.subitems &&
42
- item.subitems.some((si) => si.link && currentUrl.startsWith(si.link)));
43
-
44
- /**
45
- * @param {object[]} sections
46
- * @returns {object[]}
47
- */
48
- const innerSections = (sections) => {
49
- var items = [];
50
- (sections || []).forEach((section) => {
51
- (section.items || []).forEach((item) => {
52
- items.push(item);
53
- });
54
- });
55
- return items;
56
- };
57
-
58
- /**
59
- * @param {object} opts
60
- * @param {string} opts.label
61
- * @param {object[]} opts.subitems
62
- * @param {string} [opts.icon]
63
- * @param {boolean} opts.isUser
64
- * @returns {li}
65
- */
66
- const navSubitems = ({ label, subitems, icon, isUser }) =>
67
- li(
68
- { class: "nav-item dropdown" },
69
- a(
70
- {
71
- class: "nav-link dropdown-toggle",
72
- href: "#",
73
- id: `dropdown${labelToId(label)}`,
74
- role: "button",
75
- "data-toggle": "dropdown",
76
- "aria-haspopup": "true",
77
- "aria-expanded": "false",
78
- },
79
- icon ? i({ class: `fa-fw mr-05 ${icon}` }) : "",
80
- label
81
- ),
82
- div(
83
- {
84
- class: ["dropdown-menu", isUser && "dropdown-menu-right"],
85
- "aria-labelledby": `dropdown${labelToId(label)}`,
86
- },
87
- subitems.map((si) =>
88
- a(
89
- { class: ["dropdown-item", si.style || ""], href: si.link },
90
- si.icon ? i({ class: `fa-fw mr-05 ${si.icon}` }) : "",
91
- si.label
92
- )
93
- )
94
- )
95
- );
96
-
97
- /**
98
- * @param {string} currentUrl
99
- * @param {object[]} sections
100
- * @returns {div}
101
- */
102
- const rightNavBar = (currentUrl, sections) =>
103
- div(
104
- { class: "collapse navbar-collapse", id: "navbarResponsive" },
105
- ul(
106
- { class: "navbar-nav ml-auto my-2 my-lg-0" },
107
-
108
- innerSections(sections).map((s) =>
109
- s.location === "Mobile Bottom"
110
- ? ""
111
- : s.subitems
112
- ? navSubitems(s)
113
- : s.link
114
- ? li(
115
- {
116
- class: ["nav-item", active(currentUrl, s) && "active"],
117
- },
118
- a(
119
- {
120
- class: ["nav-link js-scroll-trigger", s.style || ""],
121
- href: text(s.link),
122
- },
123
- s.icon ? i({ class: `fa-fw mr-05 ${s.icon}` }) : "",
124
- text(s.label)
125
- )
126
- )
127
- : s.type === "Search"
128
- ? li(
129
- form(
130
- {
131
- action: "/search",
132
- class: "menusearch",
133
- method: "get",
134
- },
135
- div(
136
- { class: "input-group search-bar" },
137
-
138
- input({
139
- type: "search",
140
- class: "form-control search-bar pl-2 hasbl",
141
- placeholder: s.label,
142
- id: "inputq",
143
- name: "q",
144
- "aria-label": "Search",
145
- "aria-describedby": "button-search-submit",
146
- }),
147
- div(
148
- { class: "input-group-append" },
149
- button(
150
- {
151
- class: "btn btn-outline-secondary search-bar",
152
- type: "submit",
153
- },
154
- i({ class: "fas fa-search" })
155
- )
156
- )
157
- )
158
- )
159
- )
160
- : ""
161
- )
162
- )
163
- );
164
-
165
- /**
166
- * @param {object[]} sections
167
- * @returns {boolean}
168
- */
169
- const hasMobileItems = (sections) =>
170
- innerSections(sections).some((s) => s.location === "Mobile Bottom");
171
-
172
- /**
173
- * @param {string} currentUrl
174
- * @param {object[]} sections
175
- * @param {string} [cls = ""]
176
- * @param {string} [clsLink = ""]
177
- * @returns {footer|string}
178
- */
179
- const mobileBottomNavBar = (currentUrl, sections, cls = "", clsLink = "") =>
180
- hasMobileItems(sections)
181
- ? footer(
182
- {
183
- class:
184
- "bs-mobile-nav-footer d-flex justify-content-around d-sm-flex d-md-none " +
185
- cls,
186
- },
187
- innerSections(sections).map((s) =>
188
- s.location !== "Mobile Bottom"
189
- ? ""
190
- : //: s.subitems
191
- //? navSubitems(s)
192
- s.link
193
- ? div(
194
- {
195
- class: [
196
- "mt-2 text-center",
197
- active(currentUrl, s) ? "active" : "opacity-50",
198
- ],
199
- },
200
- a(
201
- {
202
- class: [s.style || "", clsLink],
203
- href: text(s.link),
204
- },
205
- s.icon ? i({ class: `fa-lg ${s.icon}` }) : "",
206
- br(),
207
- small(text(s.label))
208
- )
209
- )
210
- : ""
211
- )
212
- )
213
- : "";
214
-
215
- /**
216
- * @param {object} opts
217
- * @param {string} opts.name
218
- * @param {string} opts.logo
219
- * @returns {string[]}
220
- */
221
- const leftNavBar = ({ name, logo }) => [
222
- a(
223
- { class: "navbar-brand js-scroll-trigger", href: "/" },
224
- logo &&
225
- img({
226
- src: logo,
227
- width: "30",
228
- height: "30",
229
- class: "mx-1 d-inline-block align-top",
230
- alt: "Logo",
231
- loading: "lazy",
232
- }),
233
- name
234
- ),
235
- button(
236
- {
237
- class: "navbar-toggler navbar-toggler-right",
238
- type: "button",
239
- "data-toggle": "collapse",
240
- "data-target": "#navbarResponsive",
241
- "aria-controls": "navbarResponsive",
242
- "aria-expanded": "false",
243
- "aria-label": "Toggle navigation",
244
- },
245
- span({ class: "navbar-toggler-icon" })
246
- ),
247
- ];
248
-
249
- /**
250
- * @param {object} brand
251
- * @param {object[]} sections
252
- * @param {string} currentUrl
253
- * @param {object} opts
254
- * @param {boolean} [opts.fixedTop = true]
255
- * @returns {string}
256
- */
257
- const navbar = (brand, sections, currentUrl, opts = { fixedTop: true }) =>
258
- nav(
259
- {
260
- class: `navbar navbar-expand-md ${opts.class || ""} ${
261
- opts.colorscheme ? opts.colorscheme.toLowerCase() : "navbar-light"
262
- } ${opts.fixedTop ? "fixed-top" : ""}`,
263
- id: "mainNav",
264
- },
265
- div(
266
- { class: opts.fluid ? "container-fluid" : "container" },
267
- leftNavBar(brand),
268
- rightNavBar(currentUrl, sections)
269
- )
270
- );
271
-
272
- /**
273
- * @param {string} type
274
- * @param {string} s
275
- * @returns {string}
276
- */
277
- const alert = (type, s) => {
278
- //console.log("alert", type, s,s.length)
279
- const realtype = type === "error" ? "danger" : type;
280
- return s && s.length > 0
281
- ? `<div class="alert alert-${realtype} alert-dismissible fade show" role="alert">
282
- ${text(s)}
283
- <button type="button" class="close" data-dismiss="alert" aria-label="Close">
284
- <span aria-hidden="true">&times;</span>
285
- </button>
286
- </div>`
287
- : "";
288
- };
289
-
290
- /**
291
- * @returns {string}
292
- */
293
- const navbarSolidOnScroll = script(
294
- domReady(`$(window).scroll(function () {
295
- if ($(window).scrollTop() >= 10) {
296
- $('.navbar').css('background','white');
297
- } else {
298
- $('.navbar').css('background','transparent');
299
- }
300
- });`)
301
- );
302
-
303
- /**
304
- * @param {object} x
305
- * @param {object} s
306
- * @returns {object}
307
- */
308
- const logit = (x, s) => {
309
- if (s) console.log(s, x);
310
- else console.log(x);
311
- return x;
312
- };
313
-
314
- /**
315
- * @param {number} len
316
- * @returns {function}
317
- */
318
- const standardBreadcrumbItem = (len) => ({ href, text }, ix) =>
319
- li(
320
- {
321
- class: ["breadcrumb-item", ix == len - 1 && "active"],
322
- "aria-current": ix == len - 1 && "page",
323
- },
324
- href ? a({ href }, text) : text
325
- );
326
-
327
- /**
328
- * @param {object} opts
329
- * @param {Workflow} opts.workflow
330
- * @param {object} opts.step
331
- * @returns {string}
332
- */
333
- const workflowBreadcrumbItem = ({ workflow, step }) =>
334
- workflow.steps
335
- .map((wfstep, ix) =>
336
- li(
337
- {
338
- class: [
339
- "breadcrumb-item breadcrumb-workflow",
340
- step.currentStep - 1 === ix && "active-step font-weight-bold",
341
- ],
342
- },
343
- span(wfstep.name)
344
- )
345
- )
346
- .join("");
347
-
348
- /**
349
- * @param {object[]} crumbs
350
- * @returns {string}
351
- */
352
- const breadcrumbs = (crumbs, right) =>
353
- nav(
354
- { "aria-label": "breadcrumb" },
355
- ol(
356
- { class: "breadcrumb" },
357
- crumbs.map((c) =>
358
- c.workflow
359
- ? workflowBreadcrumbItem(c)
360
- : standardBreadcrumbItem(crumbs.length)(c)
361
- ),
362
- right ? li({ class: "ml-auto" }, right) : ""
363
- )
364
- );
365
-
366
- /**
367
- * @param {object[]} headers
368
- * @returns {string}
369
- */
370
- const headersInHead = (headers) =>
371
- headers
372
- .filter((h) => h.css)
373
- .map((h) => `<link href="${h.css}" rel="stylesheet">`)
374
- .join("") +
375
- headers
376
- .filter((h) => h.style)
377
- .map((h) => `<style>${h.style}</style>`)
378
- .join("") +
379
- headers
380
- .filter((h) => h.headerTag)
381
- .map((h) => h.headerTag)
382
- .join("");
383
-
384
- /**
385
- * @param {object[]} headers
386
- * @returns {string}
387
- */
388
- const headersInBody = (headers) =>
389
- headers
390
- .filter((h) => h.script)
391
- .map(
392
- (h) =>
393
- `<script src="${h.script}" ${
394
- h.integrity
395
- ? `integrity="${h.integrity}" crossorigin="anonymous"`
396
- : ""
397
- }></script>`
398
- )
399
- .join("") +
400
- headers
401
- .filter((h) => h.scriptBody)
402
- .map((h) => `<script>${h.scriptBody}</script>`)
403
- .join("");
404
-
405
- /**
406
- * @param {object[]} tabList
407
- * @returns {ul}
408
- */
409
- const cardHeaderTabs = (tabList) =>
410
- ul(
411
- { class: "nav nav-tabs card-header-tabs" },
412
- tabList.map(({ href, label, active }) =>
413
- li(
414
- { class: "nav-item" },
415
- a({ class: ["nav-link", active && "active"], href }, label)
416
- )
417
- )
418
- );
419
-
420
- module.exports = {
421
- navbar,
422
- alert,
423
- logit,
424
- navbarSolidOnScroll,
425
- breadcrumbs,
426
- headersInHead,
427
- headersInBody,
428
- cardHeaderTabs,
429
- mobileBottomNavBar,
430
- };
package/markup.test.js DELETED
@@ -1,104 +0,0 @@
1
- const {
2
- a,
3
- input,
4
- div,
5
- ul,
6
- text,
7
- text_attr,
8
- i,
9
- hr,
10
- genericElement,
11
- } = require("./tags");
12
-
13
- describe("tags", () => {
14
- it("renders", () => {
15
- expect(a({ href: "/" }, "Home")).toBe('<a href="/">Home</a>');
16
- expect(a({ href: "/" }, ["Home", " Sweet", " Home"])).toBe(
17
- '<a href="/">Home Sweet Home</a>'
18
- );
19
- expect(a({ href: "/", class: "centre" }, "Home")).toBe(
20
- '<a href="/" class="centre">Home</a>'
21
- );
22
- expect(input({ type: "text" })).toBe('<input type="text">');
23
- expect(div(5)).toBe("<div>5</div>");
24
- expect(div()).toBe("<div></div>");
25
- expect(i()).toBe("<i></i>");
26
- expect(hr()).toBe("<hr>");
27
- expect(div(["hello ", "world"])).toBe("<div>hello world</div>");
28
- expect(ul({ class: "foo" }, [false, "hello ", "world"])).toBe(
29
- `<ul class="foo">hello world</ul>`
30
- );
31
- expect(ul({ class: "foo" }, [["hello ", "world"]])).toBe(
32
- `<ul class="foo">hello world</ul>`
33
- );
34
- expect(Array.isArray(["hello ", "world"])).toBe(true);
35
- expect(Array.isArray({})).toBe(false);
36
- expect(i({ class: "fas fa-plus-square" })).toBe(
37
- '<i class="fas fa-plus-square"></i>'
38
- );
39
- expect(genericElement("div", { class: "foo" }, "Hello")).toBe(
40
- '<div class="foo">Hello</div>'
41
- );
42
- });
43
-
44
- it("class", () => {
45
- expect(div({ class: "foo" }, 5)).toBe('<div class="foo">5</div>');
46
- expect(div({ class: false }, 5)).toBe("<div>5</div>");
47
- expect(div({ class: "foo bar" }, 5)).toBe('<div class="foo bar">5</div>');
48
- expect(div({ class: ["foo", "bar"] }, 5)).toBe(
49
- '<div class="foo bar">5</div>'
50
- );
51
- expect(div({ class: ["foo", " "] }, 5)).toBe('<div class="foo ">5</div>');
52
- expect(input({ class: ["foo", " "] })).toBe('<input class="foo ">');
53
-
54
- expect(
55
- div({ class: ["foo bar", "", undefined, null, false, "baz"] }, 5)
56
- ).toBe('<div class="foo bar baz">5</div>');
57
-
58
- expect(div({ class: [undefined, null, false] }, 5)).toBe("<div>5</div>");
59
- expect(hr({ class: "foo" })).toBe('<hr class="foo">');
60
- });
61
- it("style", () => {
62
- expect(div({ style: "color:red;border:1px solid black" }, 5)).toBe(
63
- '<div style="color:red;border:1px solid black">5</div>'
64
- );
65
- expect(div({ style: ["color:red", "border:1px solid black"] }, 5)).toBe(
66
- '<div style="color:red;border:1px solid black">5</div>'
67
- );
68
- expect(
69
- div(
70
- { style: ["color:red", false, undefined, "border:1px solid black"] },
71
- 5
72
- )
73
- ).toBe('<div style="color:red;border:1px solid black">5</div>');
74
- expect(div({ style: { color: "red", border: "1px solid black" } }, 5)).toBe(
75
- '<div style="color:red;border:1px solid black">5</div>'
76
- );
77
-
78
- expect(
79
- div({ style: { marginRight: "1px", border: "1px solid black" } }, 5)
80
- ).toBe('<div style="margin-right:1px;border:1px solid black">5</div>');
81
- //border-top-left-radius
82
- expect(
83
- div({ style: { marginRight: "1px", borderTopLeftRadius: "3px" } }, 5)
84
- ).toBe('<div style="margin-right:1px;border-top-left-radius:3px">5</div>');
85
- expect(hr({ style: { color: "red" } }, 5)).toBe('<hr style="color:red">');
86
- expect(hr({ style: {} })).toBe("<hr>");
87
- expect(hr({ style: null })).toBe("<hr>");
88
- expect(div({ class: "foo", style: null })).toBe('<div class="foo"></div>');
89
- });
90
-
91
- it("escaping", () => {
92
- expect(text("foo")).toBe("foo");
93
- expect(text_attr('" onMouseOver="alert(1);')).toBe(
94
- "&quot; onMouseOver=&quot;alert(1);"
95
- );
96
- expect(text(1)).toBe("1");
97
- expect(text(0)).toBe("0");
98
- expect(text("<script>alert(1);<script>")).toBe(
99
- "&lt;script&gt;alert(1);&lt;script&gt;"
100
- );
101
- expect(text("<p>alert<p>")).toBe("<p>alert<p>");
102
- expect(text("<kbd>ctrl<kbd>")).toBe("<kbd>ctrl<kbd>");
103
- });
104
- });
package/mktag.js DELETED
@@ -1,105 +0,0 @@
1
- /**
2
- * @category saltcorn-markup
3
- * @module mktag
4
- */
5
-
6
- //https://stackoverflow.com/a/54246501
7
- /**
8
- * @param {string} str
9
- * @returns {string}
10
- */
11
- const camelToCssCase = (str) =>
12
- str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
13
-
14
- /**
15
- * @param {string|object} cs
16
- * @returns {string}
17
- */
18
- const ppClasses = (cs) =>
19
- typeof cs === "string" ? cs : !cs ? "" : cs.filter((c) => c).join(" ");
20
-
21
- /**
22
- * @param {string|object} c
23
- * @returns {string}
24
- */
25
- const ppClass = (c) => {
26
- const clss = ppClasses(c);
27
- return clss ? `class="${clss}"` : "";
28
- };
29
-
30
- /**
31
- * @param {string|string[]|object} [cs]
32
- * @returns {string}
33
- */
34
- const ppStyles = (cs) =>
35
- typeof cs === "string"
36
- ? cs
37
- : !cs
38
- ? ""
39
- : Array.isArray(cs)
40
- ? cs.filter((c) => c).join(";")
41
- : typeof cs === "object"
42
- ? Object.entries(cs)
43
- .map(([k, v]) => `${camelToCssCase(k)}:${v}`)
44
- .join(";")
45
- : "";
46
-
47
- /**
48
- * @param {string|string[]|object} [cs]
49
- * @returns {string}
50
- */
51
- const ppStyle = (c) => {
52
- const clss = ppStyles(c);
53
- return clss ? `style="${clss}"` : "";
54
- };
55
-
56
- /**
57
- * @param {object[]} opts
58
- * @param {string} opts.k
59
- * @param {boolean} [opts.v]
60
- * @returns {string}
61
- */
62
- const ppAttrib = ([k, v]) =>
63
- typeof v === "boolean"
64
- ? v
65
- ? k
66
- : ""
67
- : typeof v === "undefined"
68
- ? ""
69
- : k === "class"
70
- ? ppClass(v)
71
- : k === "style"
72
- ? ppStyle(v)
73
- : `${k}="${v}"`;
74
-
75
- /**
76
- * @param {string} tnm
77
- * @param {boolean} voidTag
78
- * @returns {function}
79
- */
80
- const mkTag = (tnm, voidTag) => (...args) => {
81
- var body = "";
82
- var attribs = " ";
83
-
84
- const argIter = (arg) => {
85
- if (typeof arg === "undefined" || arg === null || arg === false) {
86
- //do nothing
87
- } else if (typeof arg === "string") {
88
- body += arg;
89
- } else if (typeof arg === "object") {
90
- if (Array.isArray(arg)) {
91
- arg.forEach(argIter);
92
- } else {
93
- attribs += Object.entries(arg)
94
- .map(ppAttrib)
95
- .filter((s) => s)
96
- .join(" ");
97
- }
98
- } else body += arg;
99
- };
100
- args.forEach(argIter);
101
- if (attribs === " ") attribs = "";
102
- return voidTag ? `<${tnm}${attribs}>` : `<${tnm}${attribs}>${body}</${tnm}>`;
103
- };
104
-
105
- module.exports = mkTag;