@saltcorn/markup
Advanced tools
Comparing version 0.5.6-beta.2 to 0.5.6-beta.3
@@ -41,26 +41,28 @@ const { | ||
const radio_group = ({ name, options, value, form_name, ...rest }) => | ||
(options || []) | ||
.filter((o) => (typeof o === "string" ? o : o.value)) | ||
.map((o, ix) => { | ||
const myvalue = typeof o === "string" ? o : o.value; | ||
const id = `input${text_attr(name)}${ix}`; | ||
return div( | ||
{ class: "form-check" }, | ||
input({ | ||
class: ["form-check-input", rest.class], | ||
type: "radio", | ||
name, | ||
"data-fieldname": form_name, | ||
id, | ||
value: text_attr(myvalue), | ||
checked: myvalue === value, | ||
}), | ||
label( | ||
{ class: "form-check-label", for: id }, | ||
typeof o === "string" ? o : o.label | ||
) | ||
); | ||
}) | ||
.join(""); | ||
const radio_group = ({ name, options, value, inline, form_name, ...rest }) => | ||
div( | ||
(options || []) | ||
.filter((o) => (typeof o === "string" ? o : o.value)) | ||
.map((o, ix) => { | ||
const myvalue = typeof o === "string" ? o : o.value; | ||
const id = `input${text_attr(name)}${ix}`; | ||
return div( | ||
{ class: ["form-check", inline && "form-check-inline"] }, | ||
input({ | ||
class: ["form-check-input", rest.class], | ||
type: "radio", | ||
name, | ||
"data-fieldname": form_name, | ||
id, | ||
value: text_attr(myvalue), | ||
checked: myvalue === value, | ||
}), | ||
label( | ||
{ class: "form-check-label", for: id }, | ||
typeof o === "string" ? o : o.label | ||
) | ||
); | ||
}) | ||
.join("") | ||
); | ||
@@ -67,0 +69,0 @@ const pagination = ({ |
@@ -15,3 +15,6 @@ const { | ||
domReady, | ||
footer, | ||
i, | ||
small, | ||
br, | ||
} = require("./tags"); | ||
@@ -73,7 +76,11 @@ | ||
innerSections(sections).map((s) => | ||
s.subitems | ||
s.location === "Mobile Bottom" | ||
? "" | ||
: s.subitems | ||
? navSubitems(s) | ||
: s.link | ||
? li( | ||
{ class: ["nav-item", active(currentUrl, s) && "active"] }, | ||
{ | ||
class: ["nav-item", active(currentUrl, s) && "active"], | ||
}, | ||
a( | ||
@@ -93,2 +100,41 @@ { | ||
const hasMobileItems = (sections) => | ||
innerSections(sections).some((s) => s.location === "Mobile Bottom"); | ||
const mobileBottomNavBar = (currentUrl, sections, cls = "", clsLink = "") => | ||
hasMobileItems(sections) | ||
? footer( | ||
{ | ||
class: | ||
"bs-mobile-nav-footer d-flex justify-content-around d-sm-flex d-md-none " + | ||
cls, | ||
}, | ||
innerSections(sections).map((s) => | ||
s.location !== "Mobile Bottom" | ||
? "" | ||
: //: s.subitems | ||
//? navSubitems(s) | ||
s.link | ||
? div( | ||
{ | ||
class: [ | ||
"mt-2 text-center", | ||
active(currentUrl, s) ? "active" : "opacity-50", | ||
], | ||
}, | ||
a( | ||
{ | ||
class: [s.style || "", clsLink], | ||
href: text(s.link), | ||
}, | ||
s.icon ? i({ class: `fa-lg ${s.icon}` }) : "", | ||
br(), | ||
small(text(s.label)) | ||
) | ||
) | ||
: "" | ||
) | ||
) | ||
: ""; | ||
const leftNavBar = ({ name, logo }) => [ | ||
@@ -122,8 +168,3 @@ a( | ||
const navbar = ( | ||
brand, | ||
sections, | ||
currentUrl, | ||
opts = { fixedTop: true} | ||
) => | ||
const navbar = (brand, sections, currentUrl, opts = { fixedTop: true }) => | ||
nav( | ||
@@ -259,2 +300,3 @@ { | ||
cardHeaderTabs, | ||
mobileBottomNavBar, | ||
}; |
@@ -1,2 +0,2 @@ | ||
const { a, input, div, ul, text, text_attr } = require("./tags"); | ||
const { a, input, div, ul, text, text_attr, i, hr } = require("./tags"); | ||
@@ -15,2 +15,4 @@ describe("tags", () => { | ||
expect(div()).toBe("<div></div>"); | ||
expect(i()).toBe("<i></i>"); | ||
expect(hr()).toBe("<hr>"); | ||
expect(div(["hello ", "world"])).toBe("<div>hello world</div>"); | ||
@@ -25,2 +27,8 @@ expect(ul({ class: "foo" }, [false, "hello ", "world"])).toBe( | ||
expect(Array.isArray({})).toBe(false); | ||
expect(i({ class: "fas fa-plus-square" })).toBe( | ||
'<i class="fas fa-plus-square"></i>' | ||
); | ||
}); | ||
it("class", () => { | ||
expect(div({ class: "foo" }, 5)).toBe('<div class="foo">5</div>'); | ||
@@ -32,3 +40,2 @@ expect(div({ class: false }, 5)).toBe("<div>5</div>"); | ||
); | ||
expect(div({ class: ["foo", " "] }, 5)).toBe('<div class="foo ">5</div>'); | ||
@@ -41,5 +48,25 @@ expect(input({ class: ["foo", " "] })).toBe('<input class="foo ">'); | ||
expect(div({ class: [undefined, null, false] }, 5)).toBe("<div>5</div>"); | ||
expect(hr({ class: "foo" })).toBe('<hr class="foo">'); | ||
}); | ||
it("style", () => { | ||
expect(div({ style: "color:red;border:1px solid black" }, 5)).toBe( | ||
'<div style="color:red;border:1px solid black">5</div>' | ||
); | ||
expect(div({ style: ["color:red", "border:1px solid black"] }, 5)).toBe( | ||
'<div style="color:red;border:1px solid black">5</div>' | ||
); | ||
expect( | ||
div({ class: [undefined, null, false] }, 5) | ||
).toBe('<div>5</div>'); | ||
div( | ||
{ style: ["color:red", false, undefined, "border:1px solid black"] }, | ||
5 | ||
) | ||
).toBe('<div style="color:red;border:1px solid black">5</div>'); | ||
expect(div({ style: { color: "red", border: "1px solid black" } }, 5)).toBe( | ||
'<div style="color:red;border:1px solid black">5</div>' | ||
); | ||
expect(hr({ style: { color: "red" } }, 5)).toBe('<hr style="color:red">'); | ||
}); | ||
it("escaping", () => { | ||
expect(text("foo")).toBe("foo"); | ||
@@ -51,3 +78,5 @@ expect(text_attr('" onMouseOver="alert(1);')).toBe( | ||
expect(text(0)).toBe("0"); | ||
expect(text("<script>alert(1);<script>")).toBe("<script>alert(1);<script>"); | ||
expect(text("<script>alert(1);<script>")).toBe( | ||
"<script>alert(1);<script>" | ||
); | ||
expect(text("<p>alert<p>")).toBe("<p>alert<p>"); | ||
@@ -54,0 +83,0 @@ expect(text("<kbd>ctrl<kbd>")).toBe("<kbd>ctrl<kbd>"); |
{ | ||
"name": "@saltcorn/markup", | ||
"version": "0.5.6-beta.2", | ||
"version": "0.5.6-beta.3", | ||
"description": "Markup for Saltcorn, open-source no-code platform", | ||
@@ -15,2 +15,3 @@ "homepage": "https://saltcorn.com", | ||
"escape-html": "^1.0.3", | ||
"html-tags": "3.1.0", | ||
"xss": "^1.0.8" | ||
@@ -17,0 +18,0 @@ }, |
82
tags.js
const xss = require("xss"); | ||
const escape = require("escape-html"); | ||
const htmlTags = require("html-tags"); | ||
const voidHtmlTags = new Set(require("html-tags/void")); | ||
@@ -10,2 +12,18 @@ const ppClasses = (cs) => | ||
}; | ||
const ppStyles = (cs) => | ||
typeof cs === "string" | ||
? cs | ||
: !cs | ||
? "" | ||
: Array.isArray(cs) | ||
? cs.filter((c) => c).join(";") | ||
: typeof cs === "object" | ||
? Object.entries(cs) | ||
.map(([k, v]) => `${k}:${v}`) | ||
.join(";") | ||
: ""; | ||
const ppStyle = (c) => { | ||
const clss = ppStyles(c); | ||
return clss ? `style="${clss}"` : ""; | ||
}; | ||
const ppAttrib = ([k, v]) => | ||
@@ -20,4 +38,6 @@ typeof v === "boolean" | ||
? ppClass(v) | ||
: k === "style" | ||
? ppStyle(v) | ||
: `${k}="${v}"`; | ||
const mkTag = (tnm, forceStandAloneClosingTag) => (...args) => { | ||
const mkTag = (tnm, voidTag) => (...args) => { | ||
var body = ""; | ||
@@ -41,10 +61,4 @@ var attribs = " "; | ||
if (attribs === " ") attribs = ""; | ||
return body.length > 0 || forceStandAloneClosingTag | ||
? `<${tnm}${attribs}>${body}</${tnm}>` | ||
: `<${tnm}${attribs} />`; | ||
return voidTag ? `<${tnm}${attribs}>` : `<${tnm}${attribs}>${body}</${tnm}>`; | ||
}; | ||
const input = (kvs) => { | ||
const attribs = Object.entries(kvs).map(ppAttrib).join(" "); | ||
return `<input ${attribs}>`; | ||
}; | ||
@@ -60,53 +74,13 @@ //https://stackoverflow.com/a/59220393 | ||
const nbsp = " "; | ||
const allTags = Object.fromEntries( | ||
htmlTags.map((tag) => [tag, mkTag(tag, voidHtmlTags.has(tag))]) | ||
); | ||
module.exports = { | ||
a: mkTag("a"), | ||
div: mkTag("div", true), | ||
span: mkTag("span"), | ||
label: mkTag("label"), | ||
option: mkTag("option"), | ||
select: mkTag("select"), | ||
button: mkTag("button"), | ||
textarea: mkTag("textarea", true), | ||
form: mkTag("form"), | ||
script: mkTag("script", true), | ||
style: mkTag("style"), | ||
p: mkTag("p"), | ||
colgroup: mkTag("colgroup"), | ||
col: mkTag("col", true), | ||
table: mkTag("table"), | ||
img: mkTag("img"), | ||
thead: mkTag("thead"), | ||
tbody: mkTag("tbody"), | ||
small: mkTag("small", true), | ||
pre: mkTag("pre"), | ||
code: mkTag("code"), | ||
time: mkTag("time"), | ||
header: mkTag("header"), | ||
footer: mkTag("footer"), | ||
section: mkTag("section"), | ||
strong: mkTag("strong"), | ||
tr: mkTag("tr"), | ||
th: mkTag("th"), | ||
td: mkTag("td"), | ||
ul: mkTag("ul"), | ||
ol: mkTag("ol"), | ||
li: mkTag("li"), | ||
h1: mkTag("h1"), | ||
h2: mkTag("h2"), | ||
h3: mkTag("h3"), | ||
h4: mkTag("h4"), | ||
h5: mkTag("h5"), | ||
h6: mkTag("h6"), | ||
b: mkTag("b"), | ||
nav: mkTag("nav"), | ||
i: mkTag("i", true), | ||
hr: mkTag("hr"), | ||
link: mkTag("link"), | ||
...allTags, | ||
domReady, | ||
input, | ||
text, | ||
text_attr, | ||
nbsp, | ||
nbsp: " ", | ||
mkTag, | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
60574
2035
4
+ Addedhtml-tags@3.1.0
+ Addedhtml-tags@3.1.0(transitive)