@saltcorn/builder 0.9.4-beta.2 → 0.9.4-beta.20
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.
- package/dist/builder_bundle.js +23 -11
- package/package.json +3 -1
- package/src/components/Builder.js +92 -66
- package/src/components/Library.js +46 -22
- package/src/components/RenderNode.js +5 -0
- package/src/components/Toolbox.js +173 -165
- package/src/components/elements/Action.js +12 -0
- package/src/components/elements/Aggregation.js +193 -104
- package/src/components/elements/BoxModelEditor.js +8 -8
- package/src/components/elements/Column.js +16 -2
- package/src/components/elements/Columns.js +4 -4
- package/src/components/elements/Container.js +26 -2
- package/src/components/elements/DropMenu.js +31 -2
- package/src/components/elements/Field.js +22 -20
- package/src/components/elements/HTMLCode.js +1 -1
- package/src/components/elements/JoinField.js +25 -1
- package/src/components/elements/Link.js +1 -0
- package/src/components/elements/ListColumn.js +177 -0
- package/src/components/elements/ListColumns.js +62 -0
- package/src/components/elements/RelationBadges.js +53 -44
- package/src/components/elements/Tabs.js +118 -40
- package/src/components/elements/Text.js +4 -2
- package/src/components/elements/View.js +125 -68
- package/src/components/elements/ViewLink.js +100 -48
- package/src/components/elements/utils.js +198 -98
- package/src/components/storage.js +67 -5
- package/tests/relations_finder.test.js +58 -92
- package/tests/test_data.js +0 -163
|
@@ -376,6 +376,7 @@ const JoinFieldSettings = () => {
|
|
|
376
376
|
textStyle,
|
|
377
377
|
configuration,
|
|
378
378
|
fieldview,
|
|
379
|
+
click_to_edit,
|
|
379
380
|
node_id,
|
|
380
381
|
} = useNode((node) => ({
|
|
381
382
|
name: node.data.props.name,
|
|
@@ -383,7 +384,7 @@ const JoinFieldSettings = () => {
|
|
|
383
384
|
textStyle: node.data.props.textStyle,
|
|
384
385
|
fieldview: node.data.props.fieldview,
|
|
385
386
|
configuration: node.data.props.configuration,
|
|
386
|
-
|
|
387
|
+
click_to_edit: node.data.props.click_to_edit,
|
|
387
388
|
node_id: node.id,
|
|
388
389
|
}));
|
|
389
390
|
const options = useContext(optionsCtx);
|
|
@@ -493,6 +494,28 @@ const JoinFieldSettings = () => {
|
|
|
493
494
|
</td>
|
|
494
495
|
</tr>
|
|
495
496
|
)}
|
|
497
|
+
{options.mode === "show" || options.mode === "list" ? (
|
|
498
|
+
<tr>
|
|
499
|
+
<td></td>
|
|
500
|
+
<td>
|
|
501
|
+
<div className="form-check">
|
|
502
|
+
<input
|
|
503
|
+
className="form-check-input"
|
|
504
|
+
name="inline"
|
|
505
|
+
type="checkbox"
|
|
506
|
+
checked={click_to_edit}
|
|
507
|
+
onChange={(e) => {
|
|
508
|
+
if (e && e.target) {
|
|
509
|
+
const target_value = e.target.checked;
|
|
510
|
+
setProp((prop) => (prop.click_to_edit = target_value));
|
|
511
|
+
}
|
|
512
|
+
}}
|
|
513
|
+
/>
|
|
514
|
+
<label className="form-check-label">Click to edit?</label>
|
|
515
|
+
</div>
|
|
516
|
+
</td>
|
|
517
|
+
</tr>
|
|
518
|
+
) : null}
|
|
496
519
|
<tr>
|
|
497
520
|
<td></td>
|
|
498
521
|
<td>
|
|
@@ -527,6 +550,7 @@ JoinField.craft = {
|
|
|
527
550
|
{ name: "name", segment_name: "join_field", column_name: "join_field" },
|
|
528
551
|
"fieldview",
|
|
529
552
|
"textStyle",
|
|
553
|
+
"click_to_edit",
|
|
530
554
|
"block",
|
|
531
555
|
{ name: "configuration", default: {} },
|
|
532
556
|
],
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-builder
|
|
3
|
+
* @module components/elements/Column
|
|
4
|
+
* @subcategory components / elements
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, {
|
|
8
|
+
useContext,
|
|
9
|
+
Fragment,
|
|
10
|
+
useRef,
|
|
11
|
+
useEffect,
|
|
12
|
+
useState,
|
|
13
|
+
} from "react";
|
|
14
|
+
|
|
15
|
+
import { Element, useNode, useEditor } from "@craftjs/core";
|
|
16
|
+
import { setAPropGen, SettingsFromFields } from "./utils";
|
|
17
|
+
import { Column } from "./Column";
|
|
18
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
19
|
+
import { faArrowUp, faArrowDown } from "@fortawesome/free-solid-svg-icons";
|
|
20
|
+
import optionsCtx from "../context";
|
|
21
|
+
|
|
22
|
+
export /**
|
|
23
|
+
*
|
|
24
|
+
* @param {object} props
|
|
25
|
+
* @param {string} props.children
|
|
26
|
+
* @param {*} props.align
|
|
27
|
+
* @returns {div}
|
|
28
|
+
* @category saltcorn-builder
|
|
29
|
+
* @subcategory components
|
|
30
|
+
* @namespace
|
|
31
|
+
*/
|
|
32
|
+
const ListColumn = ({
|
|
33
|
+
alignment,
|
|
34
|
+
colIndex,
|
|
35
|
+
contents,
|
|
36
|
+
header_label,
|
|
37
|
+
showif,
|
|
38
|
+
col_width,
|
|
39
|
+
col_width_units,
|
|
40
|
+
}) => {
|
|
41
|
+
const {
|
|
42
|
+
selected,
|
|
43
|
+
id,
|
|
44
|
+
connectors: { connect, drag },
|
|
45
|
+
} = useNode((node) => ({ selected: node.events.selected }));
|
|
46
|
+
const { actions, query, isActve } = useEditor((state) => ({}));
|
|
47
|
+
const options = useContext(optionsCtx);
|
|
48
|
+
|
|
49
|
+
const {
|
|
50
|
+
data: { parent },
|
|
51
|
+
} = query.node(id).get();
|
|
52
|
+
const siblings = query.node(parent).childNodes();
|
|
53
|
+
const nChildren = siblings.length;
|
|
54
|
+
const childIx = siblings.findIndex((sib) => sib === id);
|
|
55
|
+
|
|
56
|
+
const moveDown = () => {
|
|
57
|
+
const {
|
|
58
|
+
data: { parent },
|
|
59
|
+
} = query.node(id).get();
|
|
60
|
+
actions.move(id, parent, childIx + 2);
|
|
61
|
+
};
|
|
62
|
+
const moveUp = () => {
|
|
63
|
+
const {
|
|
64
|
+
data: { parent },
|
|
65
|
+
} = query.node(id).get();
|
|
66
|
+
actions.move(id, parent, childIx - 1);
|
|
67
|
+
};
|
|
68
|
+
return (
|
|
69
|
+
<div
|
|
70
|
+
className={`${
|
|
71
|
+
selected ? "selected-node" : ""
|
|
72
|
+
} d-flex w-100 list-column-outer`}
|
|
73
|
+
ref={(dom) => connect(drag(dom))}
|
|
74
|
+
>
|
|
75
|
+
<div className={`list-column flex-50 p-2`}>
|
|
76
|
+
<div className="d-flex justify-content-between h-100">
|
|
77
|
+
<div className="">
|
|
78
|
+
Column {childIx}
|
|
79
|
+
{header_label ? `: ${header_label}` : ""}
|
|
80
|
+
<br />
|
|
81
|
+
{showif ? (
|
|
82
|
+
<span className="badge bg-secondary me-2">showif</span>
|
|
83
|
+
) : (
|
|
84
|
+
""
|
|
85
|
+
)}
|
|
86
|
+
{alignment && alignment !== "Default" ? (
|
|
87
|
+
<span className="badge bg-secondary me-2">Align {alignment}</span>
|
|
88
|
+
) : (
|
|
89
|
+
""
|
|
90
|
+
)}
|
|
91
|
+
{col_width ? (
|
|
92
|
+
<span className="badge bg-secondary me-2">
|
|
93
|
+
{col_width}
|
|
94
|
+
{col_width_units}
|
|
95
|
+
</span>
|
|
96
|
+
) : (
|
|
97
|
+
""
|
|
98
|
+
)}
|
|
99
|
+
</div>
|
|
100
|
+
<div className="d-flex flex-column h-100 justify-content-between">
|
|
101
|
+
{childIx !== null && childIx > 0 ? (
|
|
102
|
+
<FontAwesomeIcon icon={faArrowUp} onClick={moveUp} />
|
|
103
|
+
) : (
|
|
104
|
+
<span></span>
|
|
105
|
+
)}
|
|
106
|
+
{childIx !== null && childIx < nChildren - 1 ? (
|
|
107
|
+
<FontAwesomeIcon icon={faArrowDown} onClick={moveDown} />
|
|
108
|
+
) : (
|
|
109
|
+
<span></span>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
<Element
|
|
115
|
+
canvas
|
|
116
|
+
id={`listcol`}
|
|
117
|
+
is={Column}
|
|
118
|
+
singleOccupancy={!options.allowMultipleElementsPerColumn}
|
|
119
|
+
>
|
|
120
|
+
{contents}
|
|
121
|
+
</Element>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const fields = [
|
|
127
|
+
{
|
|
128
|
+
name: "header_label",
|
|
129
|
+
label: "Header label",
|
|
130
|
+
type: "String",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "showif",
|
|
134
|
+
label: "Show if true",
|
|
135
|
+
sublabel: "Formula. Leave blank to always show",
|
|
136
|
+
class: "validate-expression",
|
|
137
|
+
type: "String",
|
|
138
|
+
required: false,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: "col_width",
|
|
142
|
+
label: "Column width",
|
|
143
|
+
type: "Integer",
|
|
144
|
+
attributes: { asideNext: true },
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "col_width_units",
|
|
148
|
+
label: "Units",
|
|
149
|
+
type: "String",
|
|
150
|
+
required: true,
|
|
151
|
+
attributes: {
|
|
152
|
+
inline: true,
|
|
153
|
+
options: ["px", "%", "vw", "em", "rem"],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "alignment",
|
|
158
|
+
label: "Alignment",
|
|
159
|
+
input_type: "select",
|
|
160
|
+
options: ["Default", "Left", "Center", "Right"],
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
ListColumn.craft = {
|
|
164
|
+
displayName: "ListColumn",
|
|
165
|
+
props: {},
|
|
166
|
+
rules: {
|
|
167
|
+
canDrag: () => true,
|
|
168
|
+
},
|
|
169
|
+
related: {
|
|
170
|
+
settings: SettingsFromFields(fields, {
|
|
171
|
+
additionalFieldsOptionKey: "additionalColumnFields",
|
|
172
|
+
}),
|
|
173
|
+
segment_type: "list_column",
|
|
174
|
+
hasContents: true,
|
|
175
|
+
colFields: fields,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-builder
|
|
3
|
+
* @module components/elements/ListColumns
|
|
4
|
+
* @subcategory components / elements
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useContext, Fragment } from "react";
|
|
8
|
+
|
|
9
|
+
import { Element, useNode } from "@craftjs/core";
|
|
10
|
+
import optionsCtx from "../context";
|
|
11
|
+
|
|
12
|
+
export /**
|
|
13
|
+
*
|
|
14
|
+
* @param {object} props
|
|
15
|
+
* @param {string} props.children
|
|
16
|
+
* @param {*} props.align
|
|
17
|
+
* @returns {div}
|
|
18
|
+
* @category saltcorn-builder
|
|
19
|
+
* @subcategory components
|
|
20
|
+
* @namespace
|
|
21
|
+
*/
|
|
22
|
+
const ListColumns = ({ children, align }) => {
|
|
23
|
+
const {
|
|
24
|
+
selected,
|
|
25
|
+
id,
|
|
26
|
+
connectors: { connect, drag },
|
|
27
|
+
} = useNode((node) => ({ selected: node.events.selected }));
|
|
28
|
+
return (
|
|
29
|
+
<div className={selected ? "selected-node" : ""}>
|
|
30
|
+
<div className={` ${id === "ROOT" ? "root-canvas" : ""}`}>{children}</div>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export /**
|
|
36
|
+
* @returns {div}
|
|
37
|
+
* @category saltcorn-builder
|
|
38
|
+
* @subcategory components
|
|
39
|
+
* @namespace
|
|
40
|
+
*/
|
|
41
|
+
const ListColumnsSettings = () => {
|
|
42
|
+
useNode((node) => ({}));
|
|
43
|
+
return <div></div>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @type {object}
|
|
48
|
+
*/
|
|
49
|
+
ListColumns.craft = {
|
|
50
|
+
displayName: "ListColumns",
|
|
51
|
+
props: {},
|
|
52
|
+
rules: {
|
|
53
|
+
canDrag: () => false,
|
|
54
|
+
canDrop: () => false,
|
|
55
|
+
canMoveIn: (incoming) => {
|
|
56
|
+
return incoming?.data?.displayName === "ListColumn";
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
related: {
|
|
60
|
+
settings: ListColumnsSettings,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -1,33 +1,49 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { removeWhitespaces } from "./utils";
|
|
3
|
+
import { parseLegacyRelation, RelationType } from "@saltcorn/common-code";
|
|
3
4
|
|
|
4
|
-
const buildBadgeCfgs = (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
const buildBadgeCfgs = (sourceTblName, type, path, caches) => {
|
|
6
|
+
if (type === RelationType.OWN)
|
|
7
|
+
return [{ table: `${sourceTblName} (same table)` }];
|
|
8
|
+
else if (type === RelationType.INDEPENDENT)
|
|
9
|
+
return [{ table: "None (no relation)" }];
|
|
10
|
+
else if (path.length === 0) return [{ table: "invalid relation" }];
|
|
11
|
+
else {
|
|
12
|
+
const result = [];
|
|
13
|
+
let currentCfg = null;
|
|
14
|
+
let currentTbl = sourceTblName;
|
|
15
|
+
for (const pathElement of path) {
|
|
16
|
+
if (pathElement.inboundKey) {
|
|
17
|
+
if (currentCfg) result.push(currentCfg);
|
|
18
|
+
currentTbl = pathElement.table;
|
|
19
|
+
currentCfg = { up: pathElement.inboundKey, table: currentTbl };
|
|
20
|
+
} else if (pathElement.fkey) {
|
|
21
|
+
if (!currentCfg)
|
|
22
|
+
result.push({ down: pathElement.fkey, table: currentTbl });
|
|
23
|
+
else {
|
|
24
|
+
currentCfg.down = pathElement.fkey;
|
|
25
|
+
result.push(currentCfg);
|
|
26
|
+
}
|
|
27
|
+
const tblObj = caches.tableNameCache[currentTbl];
|
|
28
|
+
const fkey = tblObj.foreign_keys.find(
|
|
29
|
+
(key) => key.name === pathElement.fkey
|
|
30
|
+
);
|
|
31
|
+
currentTbl = fkey.reftable_name;
|
|
32
|
+
currentCfg = { table: currentTbl };
|
|
16
33
|
}
|
|
17
|
-
currentCfg = { table };
|
|
18
34
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
if (
|
|
36
|
+
currentCfg &&
|
|
37
|
+
!result.find(
|
|
38
|
+
({ down, table, up }) =>
|
|
39
|
+
down === currentCfg.down &&
|
|
40
|
+
table === currentCfg.table &&
|
|
41
|
+
up === currentCfg.up
|
|
42
|
+
)
|
|
27
43
|
)
|
|
28
|
-
|
|
29
|
-
result
|
|
30
|
-
|
|
44
|
+
result.push(currentCfg);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
31
47
|
};
|
|
32
48
|
|
|
33
49
|
const buildBadge = ({ up, table, down }, index) => {
|
|
@@ -59,41 +75,34 @@ const buildBadge = ({ up, table, down }, index) => {
|
|
|
59
75
|
);
|
|
60
76
|
};
|
|
61
77
|
|
|
62
|
-
export const RelationBadges = ({
|
|
63
|
-
view,
|
|
64
|
-
relation,
|
|
65
|
-
parentTbl,
|
|
66
|
-
tableNameCache,
|
|
67
|
-
}) => {
|
|
78
|
+
export const RelationBadges = ({ view, relation, parentTbl, caches }) => {
|
|
68
79
|
if (relation) {
|
|
69
|
-
const parsed = relationHelpers.parseRelationPath(relation, tableNameCache);
|
|
70
|
-
|
|
71
80
|
return (
|
|
72
81
|
<div className="overflow-scroll">
|
|
73
|
-
{
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
{buildBadgeCfgs(
|
|
83
|
+
relation.sourceTblName,
|
|
84
|
+
relation.type,
|
|
85
|
+
relation.path,
|
|
86
|
+
caches
|
|
87
|
+
).map(buildBadge)}
|
|
76
88
|
</div>
|
|
77
89
|
);
|
|
78
90
|
} else {
|
|
79
91
|
if (!view) return buildBadge({ table: "invalid relation" }, 0);
|
|
80
92
|
const [prefix, rest] = view.split(":");
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
else if (
|
|
85
|
-
parsed.length === 1 &&
|
|
86
|
-
(parsed[0].type === "Independent" || parsed[0].type === "Own")
|
|
87
|
-
)
|
|
93
|
+
if (!rest) return buildBadge({ table: "invalid relation" }, 0);
|
|
94
|
+
const { type, path } = parseLegacyRelation(prefix, rest, parentTbl);
|
|
95
|
+
if (path.length === 0) return buildBadge({ table: "invalid relation" }, 0);
|
|
96
|
+
else if (path.length === 1 && (type === "Independent" || type === "Own"))
|
|
88
97
|
return (
|
|
89
98
|
<div className="overflow-scroll">
|
|
90
|
-
{buildBadge({ table:
|
|
99
|
+
{buildBadge({ table: path[0].table }, 0)}
|
|
91
100
|
</div>
|
|
92
101
|
);
|
|
93
102
|
else
|
|
94
103
|
return (
|
|
95
104
|
<div className="overflow-scroll">
|
|
96
|
-
{buildBadgeCfgs(
|
|
105
|
+
{buildBadgeCfgs(parentTbl, type, path, caches).map(buildBadge)}
|
|
97
106
|
</div>
|
|
98
107
|
);
|
|
99
108
|
}
|
|
@@ -8,7 +8,7 @@ import React, { Fragment, useState, useContext, useEffect } from "react";
|
|
|
8
8
|
import { ntimes } from "./Columns";
|
|
9
9
|
import { Column } from "./Column";
|
|
10
10
|
import optionsCtx from "../context";
|
|
11
|
-
import { setAPropGen, buildOptions } from "./utils";
|
|
11
|
+
import { setAPropGen, buildOptions, ConfigField } from "./utils";
|
|
12
12
|
|
|
13
13
|
import { Element, useNode } from "@craftjs/core";
|
|
14
14
|
|
|
@@ -31,14 +31,16 @@ const Tabs = ({
|
|
|
31
31
|
independent,
|
|
32
32
|
startClosed,
|
|
33
33
|
field,
|
|
34
|
+
setting_tab_n,
|
|
34
35
|
}) => {
|
|
35
36
|
const {
|
|
36
37
|
selected,
|
|
37
38
|
connectors: { connect, drag },
|
|
39
|
+
actions: { setProp },
|
|
38
40
|
} = useNode((node) => ({ selected: node.events.selected }));
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
41
|
+
|
|
42
|
+
const showTab = setting_tab_n;
|
|
43
|
+
const setShowTab = (n) => setProp((prop) => (prop.setting_tab_n = n));
|
|
42
44
|
const [showTabs, setShowTabs] = useState(
|
|
43
45
|
tabsStyle === "Accordion" && startClosed ? [] : [true]
|
|
44
46
|
);
|
|
@@ -178,9 +180,12 @@ const TabsSettings = () => {
|
|
|
178
180
|
deeplink: node.data.props.deeplink,
|
|
179
181
|
disable_inactive: node.data.props.disable_inactive,
|
|
180
182
|
serverRendered: node.data.props.serverRendered,
|
|
183
|
+
setting_tab_n: node.data.props.setting_tab_n,
|
|
181
184
|
tabId: node.data.props.tabId,
|
|
182
185
|
titles: node.data.props.titles,
|
|
186
|
+
showif: node.data.props.showif,
|
|
183
187
|
field: node.data.props.field,
|
|
188
|
+
acc_init_opens: node.data.props.acc_init_opens,
|
|
184
189
|
}));
|
|
185
190
|
const {
|
|
186
191
|
actions: { setProp },
|
|
@@ -194,7 +199,11 @@ const TabsSettings = () => {
|
|
|
194
199
|
field,
|
|
195
200
|
serverRendered,
|
|
196
201
|
tabId,
|
|
202
|
+
showif,
|
|
203
|
+
setting_tab_n,
|
|
204
|
+
acc_init_opens,
|
|
197
205
|
} = node;
|
|
206
|
+
const use_setting_tab_n = setting_tab_n || 0;
|
|
198
207
|
const options = useContext(optionsCtx);
|
|
199
208
|
useEffect(() => {
|
|
200
209
|
if (field)
|
|
@@ -263,42 +272,6 @@ const TabsSettings = () => {
|
|
|
263
272
|
</Fragment>
|
|
264
273
|
) : (
|
|
265
274
|
<Fragment>
|
|
266
|
-
<tr>
|
|
267
|
-
<th>
|
|
268
|
-
<label>Number of sections</label>
|
|
269
|
-
</th>
|
|
270
|
-
<td>
|
|
271
|
-
<input
|
|
272
|
-
type="number"
|
|
273
|
-
className="form-control"
|
|
274
|
-
value={ntabs}
|
|
275
|
-
step="1"
|
|
276
|
-
min="0"
|
|
277
|
-
max="20"
|
|
278
|
-
onChange={setAProp("ntabs")}
|
|
279
|
-
/>
|
|
280
|
-
</td>
|
|
281
|
-
</tr>
|
|
282
|
-
<tr>
|
|
283
|
-
<th colSpan="2">Titles</th>
|
|
284
|
-
</tr>
|
|
285
|
-
{ntimes(ntabs, (ix) => (
|
|
286
|
-
<tr key={ix}>
|
|
287
|
-
<th>{ix + 1}</th>
|
|
288
|
-
<td>
|
|
289
|
-
<input
|
|
290
|
-
type="text"
|
|
291
|
-
className="form-control text-to-display"
|
|
292
|
-
value={titles[ix]}
|
|
293
|
-
onChange={(e) => {
|
|
294
|
-
if (!e.target) return;
|
|
295
|
-
const value = e.target.value;
|
|
296
|
-
setProp((prop) => (prop.titles[ix] = value));
|
|
297
|
-
}}
|
|
298
|
-
/>
|
|
299
|
-
</td>
|
|
300
|
-
</tr>
|
|
301
|
-
))}
|
|
302
275
|
{tabsStyle === "Accordion" ? (
|
|
303
276
|
<tr>
|
|
304
277
|
<td colSpan="2">
|
|
@@ -401,6 +374,107 @@ const TabsSettings = () => {
|
|
|
401
374
|
</td>
|
|
402
375
|
</tr>
|
|
403
376
|
) : null}
|
|
377
|
+
<tr>
|
|
378
|
+
<th>
|
|
379
|
+
<label>Number of sections</label>
|
|
380
|
+
</th>
|
|
381
|
+
<td>
|
|
382
|
+
<input
|
|
383
|
+
type="number"
|
|
384
|
+
className="form-control"
|
|
385
|
+
value={ntabs}
|
|
386
|
+
step="1"
|
|
387
|
+
min="1"
|
|
388
|
+
max="20"
|
|
389
|
+
onChange={setAProp("ntabs")}
|
|
390
|
+
/>
|
|
391
|
+
</td>
|
|
392
|
+
</tr>
|
|
393
|
+
<tr>
|
|
394
|
+
<td colSpan={2}>
|
|
395
|
+
<ConfigField
|
|
396
|
+
field={{
|
|
397
|
+
name: "setting_tab_n",
|
|
398
|
+
label: "Tab number",
|
|
399
|
+
type: "btn_select",
|
|
400
|
+
options: ntimes(ntabs, (i) => ({
|
|
401
|
+
value: i,
|
|
402
|
+
title: `${i + 1}`,
|
|
403
|
+
label: `${i + 1}`,
|
|
404
|
+
})),
|
|
405
|
+
}}
|
|
406
|
+
node={node}
|
|
407
|
+
setProp={setProp}
|
|
408
|
+
props={node}
|
|
409
|
+
></ConfigField>
|
|
410
|
+
</td>
|
|
411
|
+
</tr>
|
|
412
|
+
<tr>
|
|
413
|
+
<th colSpan="2">Title</th>
|
|
414
|
+
</tr>
|
|
415
|
+
<tr>
|
|
416
|
+
<td colSpan={2}>
|
|
417
|
+
<input
|
|
418
|
+
type="text"
|
|
419
|
+
className="form-control text-to-display"
|
|
420
|
+
value={titles[use_setting_tab_n] || ""}
|
|
421
|
+
onChange={(e) => {
|
|
422
|
+
if (!e.target) return;
|
|
423
|
+
const value = e.target.value;
|
|
424
|
+
setProp((prop) => (prop.titles[use_setting_tab_n] = value));
|
|
425
|
+
}}
|
|
426
|
+
/>
|
|
427
|
+
</td>
|
|
428
|
+
</tr>
|
|
429
|
+
{options.mode === "show" ||
|
|
430
|
+
options.mode === "edit" ||
|
|
431
|
+
options.mode === "filter" ? (
|
|
432
|
+
<Fragment>
|
|
433
|
+
<tr>
|
|
434
|
+
<th colSpan="2">Show if formula</th>
|
|
435
|
+
</tr>
|
|
436
|
+
<tr>
|
|
437
|
+
<td colSpan={2}>
|
|
438
|
+
<input
|
|
439
|
+
type="text"
|
|
440
|
+
className="form-control text-to-display"
|
|
441
|
+
value={showif?.[use_setting_tab_n] || ""}
|
|
442
|
+
onChange={(e) => {
|
|
443
|
+
if (!e.target) return;
|
|
444
|
+
const value = e.target.value;
|
|
445
|
+
setProp((prop) => {
|
|
446
|
+
if (!prop.showif) prop.showif = [];
|
|
447
|
+
prop.showif[use_setting_tab_n] = value;
|
|
448
|
+
});
|
|
449
|
+
}}
|
|
450
|
+
/>
|
|
451
|
+
</td>
|
|
452
|
+
</tr>
|
|
453
|
+
</Fragment>
|
|
454
|
+
) : null}
|
|
455
|
+
{tabsStyle === "Accordion" ? (
|
|
456
|
+
<tr>
|
|
457
|
+
<td colSpan="2">
|
|
458
|
+
<div className="form-check">
|
|
459
|
+
<input
|
|
460
|
+
className="form-check-input"
|
|
461
|
+
name="block"
|
|
462
|
+
type="checkbox"
|
|
463
|
+
checked={acc_init_opens?.[use_setting_tab_n] || false}
|
|
464
|
+
onChange={(e) => {
|
|
465
|
+
if (!e.target) return;
|
|
466
|
+
const value = e.target.checked;
|
|
467
|
+
setProp((prop) => {
|
|
468
|
+
if (!prop.acc_init_opens) prop.acc_init_opens = [];
|
|
469
|
+
prop.acc_init_opens[use_setting_tab_n] = value;
|
|
470
|
+
});
|
|
471
|
+
}}
|
|
472
|
+
/>
|
|
473
|
+
<label className="form-check-label">Initially open</label>
|
|
474
|
+
</div>
|
|
475
|
+
</td>
|
|
476
|
+
</tr>
|
|
477
|
+
) : null}
|
|
404
478
|
</Fragment>
|
|
405
479
|
)}
|
|
406
480
|
</tbody>
|
|
@@ -414,6 +488,8 @@ const TabsSettings = () => {
|
|
|
414
488
|
Tabs.craft = {
|
|
415
489
|
props: {
|
|
416
490
|
titles: ["Tab1", "Tab2"],
|
|
491
|
+
showif: [],
|
|
492
|
+
acc_init_opens: [],
|
|
417
493
|
ntabs: 2,
|
|
418
494
|
tabsStyle: "Tabs",
|
|
419
495
|
independent: false,
|
|
@@ -421,8 +497,10 @@ Tabs.craft = {
|
|
|
421
497
|
deeplink: true,
|
|
422
498
|
disable_inactive: false,
|
|
423
499
|
serverRendered: false,
|
|
500
|
+
setting_tab_n: 0,
|
|
424
501
|
tabId: "",
|
|
425
502
|
},
|
|
503
|
+
defaultProps: { setting_tab_n: 0, ntabs: 2 },
|
|
426
504
|
displayName: "Tabs",
|
|
427
505
|
related: {
|
|
428
506
|
settings: TabsSettings,
|
|
@@ -179,9 +179,11 @@ const TextSettings = () => {
|
|
|
179
179
|
} = node;
|
|
180
180
|
const { mode, fields } = useContext(optionsCtx);
|
|
181
181
|
const setAProp = setAPropGen(setProp);
|
|
182
|
+
const allowFormula = mode === "show" || mode === "list";
|
|
183
|
+
|
|
182
184
|
return (
|
|
183
185
|
<div>
|
|
184
|
-
{
|
|
186
|
+
{allowFormula && (
|
|
185
187
|
<div className="form-check">
|
|
186
188
|
<input
|
|
187
189
|
type="checkbox"
|
|
@@ -197,7 +199,7 @@ const TextSettings = () => {
|
|
|
197
199
|
</div>
|
|
198
200
|
)}
|
|
199
201
|
<label>Text to display</label>
|
|
200
|
-
{
|
|
202
|
+
{allowFormula && isFormula.text ? (
|
|
201
203
|
<input
|
|
202
204
|
type="text"
|
|
203
205
|
className="text-to-display form-control"
|