🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

@saltcorn/markup

Package Overview
Dependencies
Maintainers
1
Versions
593
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@saltcorn/markup - npm Package Compare versions

Comparing version
0.0.8
to
0.0.9
+70
form.test.js
const { a, input, div, ul, text, text_attr } = require("./tags");
const { renderForm } = require(".");
class Form {
constructor(o) {
Object.entries(o).forEach(([k, v]) => {
this[k] = v;
});
}
}
const nolines = s => s.split("\n").join("");
describe("form render", () => {
it("renders a simple form", () => {
const form = new Form({
action: "/",
fields: [
{
name: "name",
label: "Name",
input_type: "text"
}
]
});
const want = `<form action="/" class="form-namespace undefined" method="post" >
<input type="hidden" name="_csrf" value=""><div class="form-group">
<label for="inputname" >Name</label>
<div><input type="text" class="form-control undefined" name="name" id="inputname" >
</div></div><div class="form-group row">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</form>`;
expect(nolines(renderForm(form, ""))).toBe(nolines(want));
});
it("renders a form with layout", () => {
const form = new Form({
action: "/",
fields: [
{
name: "name",
label: "Name",
input_type: "text"
}
],
values: {},
errors: {},
layout: {
above: [
{
type: "field",
block: false,
fieldview: "edit",
textStyle: "h2",
field_name: "name"
},
{ type: "line_break" }
]
}
});
const want = `<form action="/" class="form-namespace undefined" method="post" >
<input type="hidden" name="_csrf" value="">
<span class="h2">
<input type="text" class="form-control undefined" name="name" id="inputname" >
</span><br /></form>`;
expect(nolines(renderForm(form, ""))).toBe(nolines(want));
});
});
const { contract, is } = require("contractis");
const { div, span, h6, text } = require("./tags");
const { alert } = require("./layout_utils");
const makeSegments = (body, alerts) => {
const alertsSegments =
alerts && alerts.length > 0
? [{ type: "blank", contents: alerts.map(a => alert(a.type, a.msg)) }]
: [];
if (typeof body === "string")
return {
above: [...alertsSegments, { type: "blank", contents: body }]
};
else if (body.above) {
if (alerts && alerts.length > 0) body.above.unshift(alertsSegments[0]);
return body;
} else {
if (alerts && alerts.length > 0)
return { above: [...alertsSegments, body] };
else return body;
}
};
const render = ({ blockDispatch, layout, role, alerts }) => {
//console.log(JSON.stringify(layout, null, 2));
function wrap(segment, isTop, ix, inner) {
if (isTop && blockDispatch && blockDispatch.wrapTop)
return blockDispatch.wrapTop(segment, ix, inner);
else
return segment.block
? div({ class: segment.textStyle || "" }, inner)
: segment.textStyle
? span({ class: segment.textStyle || "" }, inner)
: inner;
}
function go(segment, isTop, ix) {
if (!segment) return "";
if (typeof segment === "string") return wrap(segment, isTop, ix, segment);
if (Array.isArray(segment))
return wrap(
segment,
isTop,
ix,
segment.map((s, jx) => go(s, isTop, jx + ix)).join("")
);
if (segment.minRole && role > segment.minRole) return "";
if (segment.type && blockDispatch && blockDispatch[segment.type]) {
return wrap(segment, isTop, ix, blockDispatch[segment.type](segment, go));
}
if (segment.type === "blank") {
return wrap(segment, isTop, ix, segment.contents);
}
if (segment.type === "card")
return wrap(
segment,
isTop,
ix,
div(
{ class: "card shadow mt-4" },
segment.title &&
div(
{ class: "card-header py-3" },
h6(
{ class: "m-0 font-weight-bold text-primary" },
text(segment.title)
)
),
div({ class: "card-body" }, go(segment.contents))
)
);
if (segment.type === "line_break") {
return "<br />";
}
if (segment.above) {
return segment.above.map((s, ix) => go(s, isTop, ix)).join("");
} else if (segment.besides) {
const defwidth = Math.round(12 / segment.besides.length);
const markup = div(
{ class: "row" },
segment.besides.map((t, ixb) =>
div(
{
class: `col-sm-${
segment.widths ? segment.widths[ixb] : defwidth
} text-${segment.aligns ? segment.aligns[ixb] : ""}`
},
go(t, false, ixb)
)
)
);
return isTop ? wrap(segment, isTop, ix, markup) : markup;
} else throw new Error("unknown layout segment" + JSON.stringify(segment));
}
return go(makeSegments(layout, alerts), true, 0);
};
const is_segment = is.obj({ type: is.maybe(is.str) });
module.exports = contract(
is.fun(
is.obj({
blockDispatch: is.maybe(is.objVals(is.fun(is_segment, is.str))),
layout: is.or(is_segment, is.str),
role: is.maybe(is.posint),
alerts: is.maybe(is.array(is.obj({ type: is.str, msg: is.or(is.str, is.array(is.str)) })))
}),
is.str
),
render
);
const render = require("./layout");
const { p } = require("./tags");
describe("layout", () => {
it("renders a simple layout", () => {
const blockDispatch = {
wrapTop(segment, ix, s) {
return p(s);
},
reverseIt({ theString }) {
return theString
.split("")
.reverse()
.join("");
}
};
const markup = { above: [{ type: "reverseIt", theString: "foobar" }] };
expect(render({ blockDispatch, layout: markup })).toBe("<p>raboof</p>");
});
});
+6
-2

@@ -17,3 +17,6 @@ const {

module.exports = ({ options, context, action, stepName, layout }, csrfToken) =>
module.exports = (
{ options, context, action, stepName, layout, mode = "show" },
csrfToken
) =>
div(

@@ -37,4 +40,5 @@ script({ src: "/builder_bundle.js" }),

${JSON.stringify(options)},
${JSON.stringify(layout || {})}
${JSON.stringify(layout || {})},
${JSON.stringify(mode)}
)`)
);
+83
-57

@@ -13,2 +13,3 @@ const {

const { contract, is } = require("contractis");
const renderLayout = require("./layout");

@@ -172,27 +173,12 @@ const mkShowIf = sIf =>

const mkFormRowForField = (
v,
errors,
formStyle,
labelCols,
nameAdd = ""
) => hdr => {
const innerField = (v, errors, nameAdd = "") => hdr => {
const name = hdr.name + nameAdd;
const validClass = errors[name] ? "is-invalid" : "";
const errorFeedback = errors[name]
? `<div class="invalid-feedback">${text(errors[name])}</div>`
: "";
switch (hdr.input_type) {
case "fromtype":
return formRowWrap(
return displayEdit(
hdr,
displayEdit(
hdr,
name,
v && isdef(v[hdr.name]) ? v[hdr.name] : hdr.default,
validClass
),
errorFeedback,
formStyle,
labelCols
name,
v && isdef(v[hdr.name]) ? v[hdr.name] : hdr.default,
validClass
);

@@ -207,40 +193,23 @@ case "hidden":

const opts = select_options(v, hdr);
return formRowWrap(
hdr,
`<select class="form-control ${validClass} ${
hdr.class
}" name="${text_attr(name)}" id="input${text_attr(
name
)}">${opts}</select>`,
errorFeedback,
formStyle,
labelCols
);
return `<select class="form-control ${validClass} ${
hdr.class
}" name="${text_attr(name)}" id="input${text_attr(
name
)}">${opts}</select>`;
case "file":
return formRowWrap(
hdr,
`${
v[hdr.name] ? text(v[hdr.name]) : ""
}<input type="file" class="form-control-file ${validClass} ${
hdr.class
}" name="${text_attr(name)}" id="input${text_attr(name)}">`,
errorFeedback,
formStyle,
labelCols
);
return `${
v[hdr.name] ? text(v[hdr.name]) : ""
}<input type="file" class="form-control-file ${validClass} ${
hdr.class
}" name="${text_attr(name)}" id="input${text_attr(name)}">`;
case "ordered_multi_select":
const mopts = select_options(v, hdr);
return formRowWrap(
hdr,
`<select class="form-control ${validClass} ${
hdr.class
}" class="chosen-select" multiple name="${text_attr(
name
)}" id="input${text_attr(
name
)}">${mopts}</select><script>$(function(){$("#input${name}").chosen()})</script>`,
errorFeedback,
formStyle,
labelCols
);
return `<select class="form-control ${validClass} ${
hdr.class
}" class="chosen-select" multiple name="${text_attr(
name
)}" id="input${text_attr(
name
)}">${mopts}</select><script>$(function(){$("#input${name}").chosen()})</script>`;

@@ -266,6 +235,44 @@ default:

: the_input;
return formRowWrap(hdr, inner, errorFeedback, formStyle, labelCols);
return inner;
}
};
const mkFormRowForField = (
v,
errors,
formStyle,
labelCols,
nameAdd = ""
) => hdr => {
const name = hdr.name + nameAdd;
const errorFeedback = errors[name]
? `<div class="invalid-feedback">${text(errors[name])}</div>`
: "";
if (hdr.input_type === "hidden") {
return innerField(v, errors, nameAdd)(hdr);
} else
return formRowWrap(
hdr,
innerField(v, errors, nameAdd)(hdr),
errorFeedback,
formStyle,
labelCols
);
};
const renderFormLayout = form => {
const blockDispatch = {
field(segment) {
const field = form.fields.find(f => f.name === segment.field_name);
return innerField(form.values, form.errors)(field);
},
action({ action_name }) {
return `<button type="submit" class="btn btn-primary">${text(
form.submitLabel || "Save"
)}</button>`;
}
};
return renderLayout({ blockDispatch, layout: form.layout });
};
const renderForm = (form, csrfToken) => {

@@ -298,5 +305,24 @@ if (form.isStateForm) {

);
} else return mkForm(form, csrfToken, form.errors);
} else if (form.layout) return mkFormWithLayout(form, csrfToken);
else return mkForm(form, csrfToken, form.errors);
};
const mkFormWithLayout = (form, csrfToken) => {
const hasFile = form.fields.some(f => f.input_type === "file");
const csrfField = `<input type="hidden" name="_csrf" value="${csrfToken}">`;
const top = `<form action="${form.action}" class="form-namespace ${
form.class
}" method="${form.methodGET ? "get" : "post"}" ${
hasFile ? 'encType="multipart/form-data"' : ""
}>`;
const blurbp = form.blurb ? p(text(form.blurb)) : "";
const hiddens = form.fields
.filter(f => f.input_type === "hidden")
.map(f => innerField(form.values, form.errors)(f))
.join("");
return (
blurbp + top + csrfField + hiddens + renderFormLayout(form) + "</form>"
);
};
const mkForm = (form, csrfToken, errors = {}) => {

@@ -303,0 +329,0 @@ const hasFile = form.fields.some(f => f.input_type === "file");

@@ -121,3 +121,3 @@ const {

domReady(`$(window).scroll(function () {
if ($(window).scrollTop() >= 50) {
if ($(window).scrollTop() >= 10) {
$('.navbar').css('background','white');

@@ -124,0 +124,0 @@ } else {

{
"name": "@saltcorn/markup",
"version": "0.0.8",
"version": "0.0.9",
"description": "Markup for Saltcorn, open-source no-code platform",

@@ -13,3 +13,3 @@ "homepage": "https://saltcorn.com",

"dependencies": {
"contractis": "^0.0.8",
"contractis": "^0.0.9",
"escape-html": "^1.0.3",

@@ -28,3 +28,3 @@ "xss": "^1.0.6"

},
"gitHead": "d4a0f3070191b628424af5325c229a0c82681de7"
"gitHead": "2a088e28b3df98fb79b91d891ae0c2bff9811300"
}