alchemy-form 0.2.10 → 0.3.0-alpha.1
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/CHANGELOG.md +8 -0
- package/assets/stylesheets/form/elements/_code_input.scss +0 -1
- package/assets/stylesheets/form/elements/_field.scss +15 -0
- package/assets/stylesheets/form/elements/_settings_editor.scss +62 -0
- package/assets/stylesheets/form/elements/_table.scss +0 -1
- package/assets/stylesheets/form/elements/index.scss +2 -1
- package/config/routes.js +3 -3
- package/controller/form_api_controller.js +2 -4
- package/element/00_form_base.js +21 -0
- package/element/al_code_input.js +51 -13
- package/element/al_field.js +25 -24
- package/element/al_form.js +9 -2
- package/element/al_select.js +2 -1
- package/element/al_settings_editor.js +367 -0
- package/element/al_table.js +9 -5
- package/package.json +3 -3
- package/view/form/elements/al_settings_editor.hwk +36 -0
- package/view/form/inputs/edit/object.hwk +9 -0
- package/view/form/inputs/edit/settings.hwk +5 -0
- package/view/form/inputs/view/string.hwk +14 -1
- package/view/form/wrappers/default/default.hwk +18 -2
- /package/element/{al_string_input.js → 50-al_string_input.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.3.0-alpha.1 (2024-02-15)
|
|
2
|
+
|
|
3
|
+
* Upgrade to Alchemy v1.4.0
|
|
4
|
+
* Add edit template for the `Object` field type
|
|
5
|
+
* Add settings editor element
|
|
6
|
+
* Make `readonly` attribute work on `al-field` and `al-form` elements
|
|
7
|
+
* Use "alchemy-field-title" and "alchemy-field-description" microcopy in `al-field` labels
|
|
8
|
+
|
|
1
9
|
## 0.2.10 (2024-01-15)
|
|
2
10
|
|
|
3
11
|
* Fix `al-table` throwing an error when receiving null data
|
|
@@ -33,4 +33,19 @@ al-field {
|
|
|
33
33
|
display: inline-flex;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
.alchemy-field-empty-value {
|
|
38
|
+
color: #666;
|
|
39
|
+
font-style: italic;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
al-form[readonly] al-field,
|
|
44
|
+
al-field[readonly] {
|
|
45
|
+
pointer-events: none;
|
|
46
|
+
|
|
47
|
+
.alchemy-field-value {
|
|
48
|
+
opacity: 0.8;
|
|
49
|
+
filter: brightness(0.95);
|
|
50
|
+
}
|
|
36
51
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
al-settings-editor {
|
|
2
|
+
display: grid;
|
|
3
|
+
grid-template-columns: minmax(200px, 1.5fr) minmax(25vw, 9fr);
|
|
4
|
+
|
|
5
|
+
.al-settings-group {
|
|
6
|
+
padding-top: 0.5rem;
|
|
7
|
+
margin-bottom: 0.5rem;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.al-settings-setting-header {
|
|
11
|
+
margin-bottom: 0.5rem;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.al-settings-group-title {
|
|
15
|
+
font-weight: bold;
|
|
16
|
+
font-size: 1.6rem;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.al-settings-group-header {
|
|
20
|
+
padding: 0.2rem 1rem 0.5rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.al-settings-actions,
|
|
24
|
+
.al-settings-setting {
|
|
25
|
+
padding: 0.2rem 1rem 1.5rem;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.al-settings-actions {
|
|
29
|
+
margin-top: 2rem;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.al-settings-setting-title {
|
|
33
|
+
font-weight: bold;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.al-settings-setting-description micro-copy:not(:empty) {
|
|
37
|
+
display: block;
|
|
38
|
+
margin-top: 0.3rem;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.al-settings-sidebar {
|
|
42
|
+
border-right: 1px solid #ebebeb;
|
|
43
|
+
margin-right: 1.5rem;
|
|
44
|
+
|
|
45
|
+
a {
|
|
46
|
+
text-decoration: none;
|
|
47
|
+
color: inherit;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
al-field {
|
|
52
|
+
.field,
|
|
53
|
+
.field input {
|
|
54
|
+
width: 100%;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
al-toc {
|
|
59
|
+
position: sticky;
|
|
60
|
+
top: 1rem;
|
|
61
|
+
}
|
|
62
|
+
}
|
package/config/routes.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
Plugin.addRoute({
|
|
2
2
|
name : 'FormApi#related',
|
|
3
3
|
methods : 'post',
|
|
4
4
|
paths : '/api/form/data/related',
|
|
@@ -7,7 +7,7 @@ Router.add({
|
|
|
7
7
|
is_system_route : true,
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Plugin.addRoute({
|
|
11
11
|
name : 'FormApi#queryBuilderData',
|
|
12
12
|
methods : 'post',
|
|
13
13
|
paths : '/api/form/data/qbdata',
|
|
@@ -16,7 +16,7 @@ Router.add({
|
|
|
16
16
|
is_system_route : true,
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Plugin.addRoute({
|
|
20
20
|
name : 'FormApi#recompute',
|
|
21
21
|
methods : 'post',
|
|
22
22
|
paths : '/api/form/data/recompute/{model_name}/{field}',
|
|
@@ -17,7 +17,7 @@ const FormApi = Function.inherits('Alchemy.Controller', 'FormApi');
|
|
|
17
17
|
*
|
|
18
18
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
19
19
|
* @since 0.1.0
|
|
20
|
-
* @version 0.
|
|
20
|
+
* @version 0.3.0
|
|
21
21
|
*
|
|
22
22
|
* @param {Conduit} conduit
|
|
23
23
|
*/
|
|
@@ -32,9 +32,7 @@ FormApi.setAction(async function related(conduit) {
|
|
|
32
32
|
crit.setOption('scenario', 'related_data');
|
|
33
33
|
|
|
34
34
|
if (body.constraints) {
|
|
35
|
-
|
|
36
|
-
crit.where(key).equals(body.constraints[key]);
|
|
37
|
-
}
|
|
35
|
+
crit.applyConditions(body.constraints);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
if (config.value) {
|
package/element/00_form_base.js
CHANGED
|
@@ -102,6 +102,27 @@ Base.setAttribute('purpose', function getPurpose(value) {
|
|
|
102
102
|
*/
|
|
103
103
|
Base.setAttribute('mode');
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* The zone determines where the form/field is being used.
|
|
107
|
+
* For example: admin, frontend, chimera, invoice, ...
|
|
108
|
+
*
|
|
109
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
110
|
+
* @since 0.3.0
|
|
111
|
+
* @version 0.3.0
|
|
112
|
+
*/
|
|
113
|
+
Base.setAttribute('zone', function getZone(value) {
|
|
114
|
+
|
|
115
|
+
if (value) {
|
|
116
|
+
return value;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!value && this.alchemy_form) {
|
|
120
|
+
value = this.alchemy_form.zone;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return value;
|
|
124
|
+
});
|
|
125
|
+
|
|
105
126
|
/**
|
|
106
127
|
* The view-type determines which type of wrapper/field to use,
|
|
107
128
|
* e.g.: view, list, edit, ...
|
package/element/al_code_input.js
CHANGED
|
@@ -43,6 +43,15 @@ CodeInput.setAttribute('language-mode');
|
|
|
43
43
|
*/
|
|
44
44
|
CodeInput.setAttribute('color-theme');
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Is the value an object?
|
|
48
|
+
*
|
|
49
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
50
|
+
* @since 0.3.0
|
|
51
|
+
* @version 0.3.0
|
|
52
|
+
*/
|
|
53
|
+
CodeInput.setAttribute('value-is-object', {type: 'boolean'});
|
|
54
|
+
|
|
46
55
|
/**
|
|
47
56
|
* The minimum number of lines to show (height)
|
|
48
57
|
*
|
|
@@ -66,25 +75,43 @@ CodeInput.setAttribute('max-lines', {type: 'number'});
|
|
|
66
75
|
*
|
|
67
76
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
68
77
|
* @since 0.1.0
|
|
69
|
-
* @version 0.
|
|
78
|
+
* @version 0.3.0
|
|
70
79
|
*/
|
|
71
|
-
CodeInput.setProperty(function value(
|
|
80
|
+
CodeInput.setProperty(function value() {
|
|
81
|
+
|
|
82
|
+
let result;
|
|
72
83
|
|
|
73
84
|
if (this._editor) {
|
|
74
|
-
|
|
85
|
+
result = this._editor.getValue();
|
|
86
|
+
} else {
|
|
87
|
+
let editor_el = this.querySelector('.code-editor');
|
|
88
|
+
|
|
89
|
+
if (editor_el) {
|
|
90
|
+
result = editor_el.textContent;
|
|
91
|
+
} else {
|
|
92
|
+
if (this.assigned_data.value) {
|
|
93
|
+
return this.assigned_data.value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
75
98
|
}
|
|
76
99
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (editor_el) {
|
|
80
|
-
return editor_el.textContent;
|
|
100
|
+
if (result && this.value_is_object) {
|
|
101
|
+
result = JSON.safeParse(result);
|
|
81
102
|
}
|
|
82
103
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
104
|
+
return result;
|
|
105
|
+
|
|
106
|
+
}, function setValue(original_value) {
|
|
86
107
|
|
|
87
|
-
|
|
108
|
+
let value;
|
|
109
|
+
|
|
110
|
+
if (this.value_is_object) {
|
|
111
|
+
value = JSON.stringify(value, null, '\t');
|
|
112
|
+
} else {
|
|
113
|
+
value = original_value;
|
|
114
|
+
}
|
|
88
115
|
|
|
89
116
|
if (this._editor) {
|
|
90
117
|
this._editor.setValue(value);
|
|
@@ -101,7 +128,9 @@ CodeInput.setProperty(function value(value) {
|
|
|
101
128
|
return editor_el.textContent = value;
|
|
102
129
|
}
|
|
103
130
|
|
|
104
|
-
this.assigned_data.value =
|
|
131
|
+
this.assigned_data.value = original_value;
|
|
132
|
+
|
|
133
|
+
this.hawkejs_renderer.registerElementInstance(this);
|
|
105
134
|
});
|
|
106
135
|
|
|
107
136
|
/**
|
|
@@ -153,7 +182,14 @@ CodeInput.setMethod(async function introduced() {
|
|
|
153
182
|
}
|
|
154
183
|
|
|
155
184
|
if (this.assigned_data.value) {
|
|
156
|
-
|
|
185
|
+
|
|
186
|
+
let value = this.assigned_data.value;
|
|
187
|
+
|
|
188
|
+
if (this.value_is_object) {
|
|
189
|
+
value = JSON.stringify(value, null, '\t');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
editor.setValue(value, -1);
|
|
157
193
|
}
|
|
158
194
|
|
|
159
195
|
if (this.language_mode) {
|
|
@@ -164,5 +200,7 @@ CodeInput.setMethod(async function introduced() {
|
|
|
164
200
|
}
|
|
165
201
|
}
|
|
166
202
|
|
|
203
|
+
this.style.height = null;
|
|
204
|
+
|
|
167
205
|
this._editor = editor;
|
|
168
206
|
});
|
package/element/al_field.js
CHANGED
|
@@ -77,9 +77,17 @@ Field.setAttribute('wrapper-view');
|
|
|
77
77
|
*
|
|
78
78
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
79
79
|
* @since 0.1.2
|
|
80
|
-
* @version 0.
|
|
80
|
+
* @version 0.3.0
|
|
81
81
|
*/
|
|
82
|
-
Field.setAttribute('readonly',
|
|
82
|
+
Field.setAttribute('readonly', function getReadonlyValue(current_value) {
|
|
83
|
+
|
|
84
|
+
if (current_value == null) {
|
|
85
|
+
current_value = this.alchemy_form?.readonly;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return current_value;
|
|
89
|
+
|
|
90
|
+
}, {boolean: true});
|
|
83
91
|
|
|
84
92
|
/**
|
|
85
93
|
* Widget settings for use in the views
|
|
@@ -585,14 +593,20 @@ Field.setProperty(function value_element() {
|
|
|
585
593
|
*
|
|
586
594
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
587
595
|
* @since 0.1.0
|
|
588
|
-
* @version 0.
|
|
596
|
+
* @version 0.3.0
|
|
589
597
|
*/
|
|
590
598
|
Field.setProperty(function value() {
|
|
591
599
|
|
|
592
600
|
let element = this.value_element;
|
|
593
601
|
|
|
594
602
|
if (element) {
|
|
595
|
-
|
|
603
|
+
let value = element.value;
|
|
604
|
+
|
|
605
|
+
if (this.config) {
|
|
606
|
+
value = this.config.castContainedValues(value);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return value;
|
|
596
610
|
}
|
|
597
611
|
|
|
598
612
|
return this.value_to_render;
|
|
@@ -1043,32 +1057,19 @@ Field.setMethod(async function loadData(config, element) {
|
|
|
1043
1057
|
*
|
|
1044
1058
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1045
1059
|
* @since 0.2.9
|
|
1046
|
-
* @version 0.
|
|
1060
|
+
* @version 0.3.0
|
|
1047
1061
|
*
|
|
1048
|
-
* @param {Object} constraints
|
|
1062
|
+
* @param {Criteria|Object} constraints
|
|
1063
|
+
*
|
|
1064
|
+
* @param {Object}
|
|
1049
1065
|
*/
|
|
1050
1066
|
Field.setMethod(function resolveConstraintInstruction(constraints) {
|
|
1051
1067
|
|
|
1052
|
-
let context
|
|
1053
|
-
result = {},
|
|
1054
|
-
value,
|
|
1055
|
-
key;
|
|
1056
|
-
|
|
1057
|
-
for (key in constraints) {
|
|
1058
|
-
value = constraints[key];
|
|
1068
|
+
let context = {$0: this.alchemy_form.getValueAsDocument()};
|
|
1059
1069
|
|
|
1060
|
-
|
|
1061
|
-
if (value instanceof Classes.Alchemy.PathEvaluator) {
|
|
1062
|
-
if (!context && this.alchemy_form) {
|
|
1063
|
-
context = this.alchemy_form.getValueAsDocument();
|
|
1064
|
-
}
|
|
1070
|
+
constraints = Classes.Alchemy.Criteria.Criteria.cast(constraints);
|
|
1065
1071
|
|
|
1066
|
-
|
|
1067
|
-
}
|
|
1068
|
-
} else {
|
|
1069
|
-
result[key] = value;
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
+
let result = constraints.compileToConditions(context);
|
|
1072
1073
|
|
|
1073
1074
|
return result;
|
|
1074
1075
|
});
|
package/element/al_form.js
CHANGED
|
@@ -34,6 +34,15 @@ Form.setAttribute('method');
|
|
|
34
34
|
*/
|
|
35
35
|
Form.setAttribute('model');
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Is this a read only form?
|
|
39
|
+
*
|
|
40
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
41
|
+
* @since 0.3.0
|
|
42
|
+
* @version 0.3.0
|
|
43
|
+
*/
|
|
44
|
+
Form.setAttribute('readonly', {boolean: true});
|
|
45
|
+
|
|
37
46
|
/**
|
|
38
47
|
* Should the entire document be submitted?
|
|
39
48
|
*
|
|
@@ -249,8 +258,6 @@ Form.setMethod(function setDocument(document) {
|
|
|
249
258
|
// Set the current document
|
|
250
259
|
this.document = document;
|
|
251
260
|
|
|
252
|
-
console.log('Setting document', document);
|
|
253
|
-
|
|
254
261
|
for (let key in current_value) {
|
|
255
262
|
let original_value = current_value[key],
|
|
256
263
|
new_value = document[key];
|
package/element/al_select.js
CHANGED
|
@@ -951,12 +951,13 @@ AlchemySelect.setMethod(function getRemoteFetchConfig() {
|
|
|
951
951
|
*
|
|
952
952
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
953
953
|
* @since 0.2.0
|
|
954
|
-
* @version 0.
|
|
954
|
+
* @version 0.3.0
|
|
955
955
|
*/
|
|
956
956
|
AlchemySelect.setMethod(function applyFetchedData(err, result, config) {
|
|
957
957
|
|
|
958
958
|
if (err) {
|
|
959
959
|
this.loading_dropdown = false;
|
|
960
|
+
alchemy.handleError(err);
|
|
960
961
|
return;
|
|
961
962
|
}
|
|
962
963
|
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The settings editor
|
|
3
|
+
*
|
|
4
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
5
|
+
* @since 0.3.0
|
|
6
|
+
* @version 0.3.0
|
|
7
|
+
*/
|
|
8
|
+
const SettingsEditor = Function.inherits('Alchemy.Element.Form.Base', 'SettingsEditor');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The template to use for the content of this element
|
|
12
|
+
*
|
|
13
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
14
|
+
* @since 0.3.0
|
|
15
|
+
* @version 0.3.0
|
|
16
|
+
*/
|
|
17
|
+
SettingsEditor.setTemplateFile('form/elements/al_settings_editor');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The actual settings and their values
|
|
21
|
+
*
|
|
22
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
23
|
+
* @since 0.3.0
|
|
24
|
+
* @version 0.3.0
|
|
25
|
+
*/
|
|
26
|
+
SettingsEditor.setAssignedProperty('settings_config');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Address to send updates t
|
|
30
|
+
*
|
|
31
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
32
|
+
* @since 0.3.0
|
|
33
|
+
* @version 0.3.0
|
|
34
|
+
*/
|
|
35
|
+
SettingsEditor.setAttribute('src');
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get the current value
|
|
39
|
+
*
|
|
40
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
41
|
+
* @since 1.3.0
|
|
42
|
+
* @version 1.3.0
|
|
43
|
+
*/
|
|
44
|
+
SettingsEditor.setProperty(function value() {
|
|
45
|
+
|
|
46
|
+
let result = {};
|
|
47
|
+
|
|
48
|
+
let root_key,
|
|
49
|
+
elements = this.querySelectorAll('.al-settings-setting'),
|
|
50
|
+
element,
|
|
51
|
+
field,
|
|
52
|
+
i;
|
|
53
|
+
|
|
54
|
+
for (i = 0; i < elements.length; i++) {
|
|
55
|
+
element = elements[i];
|
|
56
|
+
|
|
57
|
+
field = element.querySelector('al-field');
|
|
58
|
+
|
|
59
|
+
if (!field) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!root_key) {
|
|
64
|
+
root_key = element.dataset.id.split('.')[0];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Object.setPath(result, element.dataset.id, field.value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result[root_key];
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Populate the settings container
|
|
75
|
+
*
|
|
76
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
77
|
+
* @since 1.3.0
|
|
78
|
+
* @version 1.3.0
|
|
79
|
+
*/
|
|
80
|
+
SettingsEditor.setMethod(function populateSettingsContainer(container) {
|
|
81
|
+
|
|
82
|
+
if (!container) {
|
|
83
|
+
container = this.querySelector('.al-settings-container');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Hawkejs.removeChildren(container);
|
|
87
|
+
|
|
88
|
+
this._addGroupToContainer(container, this.settings_config);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Create an id
|
|
93
|
+
*
|
|
94
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
95
|
+
* @since 1.3.0
|
|
96
|
+
* @version 1.3.0
|
|
97
|
+
*
|
|
98
|
+
* @param {string} suffix
|
|
99
|
+
*
|
|
100
|
+
* @return {string}
|
|
101
|
+
*/
|
|
102
|
+
SettingsEditor.setMethod(function createId(suffix) {
|
|
103
|
+
|
|
104
|
+
let id = this.id;
|
|
105
|
+
|
|
106
|
+
if (!id) {
|
|
107
|
+
id = 'settings-editor';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
id += '-' + suffix.slug().underscore();
|
|
111
|
+
|
|
112
|
+
return id;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Add the given group to the container
|
|
117
|
+
*
|
|
118
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
119
|
+
* @since 1.3.0
|
|
120
|
+
* @version 1.3.0
|
|
121
|
+
*
|
|
122
|
+
* @param {HTMLElement} container
|
|
123
|
+
* @param {Object} group
|
|
124
|
+
*/
|
|
125
|
+
SettingsEditor.setMethod(function _addGroupToContainer(container, group) {
|
|
126
|
+
|
|
127
|
+
if (!group) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!container) {
|
|
132
|
+
throw new Error('No container given');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let add_group = false;
|
|
136
|
+
|
|
137
|
+
if (group.settings?.length) {
|
|
138
|
+
add_group = true;
|
|
139
|
+
} else if (group.children?.length) {
|
|
140
|
+
// If the root group has no settings, don't add it
|
|
141
|
+
if (!group.is_root) {
|
|
142
|
+
add_group = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (add_group) {
|
|
147
|
+
let group_element = this.createElement('div');
|
|
148
|
+
group_element.classList.add('al-settings-group');
|
|
149
|
+
group_element.dataset.id = group.group_id;
|
|
150
|
+
group_element.id = this.createId(group.group_id);
|
|
151
|
+
|
|
152
|
+
let header_element = this.createElement('header');
|
|
153
|
+
header_element.classList.add('al-settings-group-header');
|
|
154
|
+
|
|
155
|
+
let title_element = this.createElement('div');
|
|
156
|
+
title_element.classList.add('al-settings-group-title');
|
|
157
|
+
title_element.dataset.toc_level = group.group_id.count('.');
|
|
158
|
+
|
|
159
|
+
let group_title_microcopy = this.createElement('micro-copy');
|
|
160
|
+
group_title_microcopy.key = 'settings.title.group:' + group.group_id;
|
|
161
|
+
group_title_microcopy.fallback = group.name.titleize();
|
|
162
|
+
|
|
163
|
+
title_element.append(group_title_microcopy);
|
|
164
|
+
header_element.append(title_element);
|
|
165
|
+
group_element.append(header_element);
|
|
166
|
+
|
|
167
|
+
let settings_container = this.createElement('div');
|
|
168
|
+
settings_container.classList.add('al-settings-settings-container');
|
|
169
|
+
|
|
170
|
+
for (let setting of group.settings) {
|
|
171
|
+
this._addSettingToGroupElement(settings_container, setting);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
group_element.append(settings_container);
|
|
175
|
+
container.append(group_element);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
for (let child_group of group.children) {
|
|
179
|
+
this._addGroupToContainer(container, child_group);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Add the given setting to the container
|
|
185
|
+
*
|
|
186
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
187
|
+
* @since 1.3.0
|
|
188
|
+
* @version 1.3.0
|
|
189
|
+
*
|
|
190
|
+
* @param {HTMLElement} settings_container_element
|
|
191
|
+
* @param {Object} setting
|
|
192
|
+
*/
|
|
193
|
+
SettingsEditor.setMethod(function _addSettingToGroupElement(settings_container_element, setting) {
|
|
194
|
+
|
|
195
|
+
if (!setting?.schema) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
let value_field = setting.schema.get('value');
|
|
200
|
+
|
|
201
|
+
if (!value_field) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let settings_element = this.createElement('div');
|
|
206
|
+
|
|
207
|
+
let id = this.createId(setting.setting_id);
|
|
208
|
+
|
|
209
|
+
// Set the IDs
|
|
210
|
+
settings_element.dataset.id = setting.setting_id;
|
|
211
|
+
settings_element.id = id;
|
|
212
|
+
|
|
213
|
+
// Add the CSS class
|
|
214
|
+
settings_element.classList.add('al-settings-setting');
|
|
215
|
+
|
|
216
|
+
// Create the title element
|
|
217
|
+
let header_element = this.createElement('header');
|
|
218
|
+
header_element.classList.add('al-settings-setting-header');
|
|
219
|
+
|
|
220
|
+
let title_element = this.createElement('div');
|
|
221
|
+
title_element.classList.add('al-settings-setting-title');
|
|
222
|
+
|
|
223
|
+
let title_microcopy = this.createElement('micro-copy');
|
|
224
|
+
title_microcopy.key = 'settings.title:' + setting.setting_id;
|
|
225
|
+
title_microcopy.fallback = setting.name.titleize();
|
|
226
|
+
|
|
227
|
+
header_element.append(title_element);
|
|
228
|
+
title_element.append(title_microcopy);
|
|
229
|
+
|
|
230
|
+
if (setting.show_description !== false) {
|
|
231
|
+
let description_element = this.createElement('div');
|
|
232
|
+
description_element.classList.add('al-settings-setting-description');
|
|
233
|
+
|
|
234
|
+
let description_microcopy = this.createElement('micro-copy');
|
|
235
|
+
description_microcopy.key = 'settings.description:' + setting.setting_id;
|
|
236
|
+
description_microcopy.fallback = setting.description || '';
|
|
237
|
+
|
|
238
|
+
header_element.append(description_element);
|
|
239
|
+
description_element.append(description_microcopy);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
settings_element.append(header_element);
|
|
243
|
+
|
|
244
|
+
let input_wrapper = this.createElement('div');
|
|
245
|
+
|
|
246
|
+
let al_field = this.createElement('al-field');
|
|
247
|
+
al_field.id = 'af-' + id;
|
|
248
|
+
al_field.config = value_field;
|
|
249
|
+
al_field.value = setting.current_value;
|
|
250
|
+
al_field.mode = 'inline';
|
|
251
|
+
|
|
252
|
+
this.hawkejs_view.registerElementInstance(al_field);
|
|
253
|
+
|
|
254
|
+
if (setting.locked) {
|
|
255
|
+
al_field.readonly = true;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
input_wrapper.append(al_field);
|
|
259
|
+
|
|
260
|
+
settings_element.append(input_wrapper);
|
|
261
|
+
|
|
262
|
+
settings_container_element.append(settings_element);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* This element has been added to the DOM for the first time
|
|
267
|
+
*
|
|
268
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
269
|
+
* @since 1.3.0
|
|
270
|
+
* @version 1.3.0
|
|
271
|
+
*/
|
|
272
|
+
SettingsEditor.setMethod(function introduced() {
|
|
273
|
+
|
|
274
|
+
let save_button = this.querySelector('.save-changes');
|
|
275
|
+
|
|
276
|
+
save_button.addEventListener('activate', async e => {
|
|
277
|
+
|
|
278
|
+
let old_state = save_button.state;
|
|
279
|
+
|
|
280
|
+
save_button.setState('saving');
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
await this.save();
|
|
284
|
+
} catch (err) {
|
|
285
|
+
save_button.setState('error', 2500, old_state);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
save_button.setState('saved', 1000, old_state);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
save_button.hidden = !this.src;
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Get the changes
|
|
297
|
+
*
|
|
298
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
299
|
+
* @since 1.3.0
|
|
300
|
+
* @version 1.3.0
|
|
301
|
+
*/
|
|
302
|
+
SettingsEditor.setMethod(function getChanges() {
|
|
303
|
+
|
|
304
|
+
let result = {};
|
|
305
|
+
|
|
306
|
+
let new_value,
|
|
307
|
+
original_value,
|
|
308
|
+
elements = this.querySelectorAll('.al-settings-setting'),
|
|
309
|
+
element,
|
|
310
|
+
field,
|
|
311
|
+
i;
|
|
312
|
+
|
|
313
|
+
for (i = 0; i < elements.length; i++) {
|
|
314
|
+
element = elements[i];
|
|
315
|
+
|
|
316
|
+
field = element.querySelector('al-field');
|
|
317
|
+
|
|
318
|
+
if (!field) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
new_value = field.value;
|
|
323
|
+
original_value = field.original_value;
|
|
324
|
+
|
|
325
|
+
if (Object.alike(new_value, original_value) || new_value == original_value) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Ignore empty values that were not set before
|
|
330
|
+
if (new_value === '' && original_value == null) {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Ignore empty values that were not set before
|
|
335
|
+
if (new_value === false && original_value == null) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
result[element.dataset.id] = new_value;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return result;
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Save the changes
|
|
347
|
+
*
|
|
348
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
349
|
+
* @since 1.3.0
|
|
350
|
+
* @version 1.3.0
|
|
351
|
+
*/
|
|
352
|
+
SettingsEditor.setMethod(async function save() {
|
|
353
|
+
|
|
354
|
+
if (!this.src) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
let changes = this.getChanges();
|
|
359
|
+
|
|
360
|
+
let result;
|
|
361
|
+
|
|
362
|
+
try {
|
|
363
|
+
result = await alchemy.fetch(this.src, {post: changes});
|
|
364
|
+
} catch (err) {
|
|
365
|
+
throw err;
|
|
366
|
+
}
|
|
367
|
+
});
|
package/element/al_table.js
CHANGED
|
@@ -677,7 +677,7 @@ Table.setMethod(function addDataRow(entry) {
|
|
|
677
677
|
*
|
|
678
678
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
679
679
|
* @since 0.1.0
|
|
680
|
-
* @version 0.
|
|
680
|
+
* @version 0.3.0
|
|
681
681
|
*
|
|
682
682
|
* @param {Object} entry
|
|
683
683
|
*
|
|
@@ -705,6 +705,10 @@ Table.setMethod(function createDataRow(entry) {
|
|
|
705
705
|
tr.dataset.pk = id;
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
+
if (!this.fieldset) {
|
|
709
|
+
throw new Error('No fieldset has been defined for this table yet');
|
|
710
|
+
}
|
|
711
|
+
|
|
708
712
|
for (field_set_config of this.fieldset) {
|
|
709
713
|
|
|
710
714
|
let create_new_contents = true,
|
|
@@ -907,7 +911,7 @@ Table.setMethod(function attachContextMenus() {
|
|
|
907
911
|
*
|
|
908
912
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
909
913
|
* @since 0.1.0
|
|
910
|
-
* @version 0.
|
|
914
|
+
* @version 0.3.0
|
|
911
915
|
*/
|
|
912
916
|
Table.setMethod(function onFieldsetAssignment(value, old_value) {
|
|
913
917
|
|
|
@@ -935,7 +939,7 @@ Table.setMethod(function onFieldsetAssignment(value, old_value) {
|
|
|
935
939
|
}
|
|
936
940
|
|
|
937
941
|
for (field of value) {
|
|
938
|
-
col = this.createElement('
|
|
942
|
+
col = this.createElement('th');
|
|
939
943
|
span = this.createElement('span');
|
|
940
944
|
span.textContent = field.title;
|
|
941
945
|
|
|
@@ -980,10 +984,10 @@ Table.setMethod(function onFieldsetAssignment(value, old_value) {
|
|
|
980
984
|
}
|
|
981
985
|
|
|
982
986
|
if (this.has_actions) {
|
|
983
|
-
col = this.createElement('
|
|
987
|
+
col = this.createElement('th');
|
|
984
988
|
names_row.append(col);
|
|
985
989
|
|
|
986
|
-
col = this.createElement('
|
|
990
|
+
col = this.createElement('th');
|
|
987
991
|
filter_row.append(col);
|
|
988
992
|
}
|
|
989
993
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alchemy-form",
|
|
3
3
|
"description": "Form plugin for Alchemy",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0-alpha.1",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type" : "git",
|
|
7
7
|
"url" : "https://github.com/11ways/alchemy-form.git"
|
|
8
8
|
},
|
|
9
9
|
"peerDependencies": {
|
|
10
|
-
"alchemymvc" : ">=1.
|
|
11
|
-
"alchemy-media" : ">=0.
|
|
10
|
+
"alchemymvc" : ">=1.4.0||>=1.4.0-alpha",
|
|
11
|
+
"alchemy-media" : ">=0.9.0||>=0.9.0-alpha"
|
|
12
12
|
},
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"engines": {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<div class="al-settings-sidebar">
|
|
2
|
+
<al-toc
|
|
3
|
+
container-element="ul"
|
|
4
|
+
entry-element="li"
|
|
5
|
+
parent-selector="al-settings-editor"
|
|
6
|
+
children-selector=".al-settings-container"
|
|
7
|
+
elements-selector=".al-settings-group"
|
|
8
|
+
title-selector=".al-settings-group-title"
|
|
9
|
+
></al-toc>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="al-settings-main">
|
|
12
|
+
<div class="al-settings-container"><% self.populateSettingsContainer($0) %></div>
|
|
13
|
+
<div class="al-settings-actions">
|
|
14
|
+
<al-button class="save-changes" state="ready" hidden>
|
|
15
|
+
<al-state state-name="saving">
|
|
16
|
+
<al-icon icon-style="duotone" icon-name="spinner" icon-flags="spin"></al-icon>
|
|
17
|
+
{%t "saving" %}
|
|
18
|
+
</al-state>
|
|
19
|
+
|
|
20
|
+
<al-state state-name="saved">
|
|
21
|
+
<al-icon icon-style="duotone" icon-name="badge-check" icon-flags="beat"></al-icon>
|
|
22
|
+
{%t "saved" %}
|
|
23
|
+
</al-state>
|
|
24
|
+
|
|
25
|
+
<al-state state-name="error">
|
|
26
|
+
<al-icon icon-style="duotone" icon-name="skull" icon-flags="shake"></al-icon>
|
|
27
|
+
{%t "error" action="save" %}
|
|
28
|
+
</al-state>
|
|
29
|
+
|
|
30
|
+
<al-state state-name="ready">
|
|
31
|
+
<al-icon icon-style="duotone" icon-name="floppy-disk-circle-arrow-right"></al-icon>
|
|
32
|
+
{%t "save" %}
|
|
33
|
+
</al-state>
|
|
34
|
+
</al-button>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
<div>
|
|
2
|
-
<span class="alchemy-field-value">
|
|
2
|
+
<span class="alchemy-field-value">
|
|
3
|
+
<% if (value || value === false) { %>
|
|
4
|
+
{{ value }}
|
|
5
|
+
<% } else { %>
|
|
6
|
+
<span class="alchemy-field-empty-value">
|
|
7
|
+
{%t
|
|
8
|
+
"empty-value"
|
|
9
|
+
field=field_context.config.name
|
|
10
|
+
path=field_context.config.path_in_document
|
|
11
|
+
zone=self.zone
|
|
12
|
+
%}
|
|
13
|
+
</span>
|
|
14
|
+
<% } %>
|
|
15
|
+
</span>
|
|
3
16
|
{% if alchemy_field.config.options.suffix %}
|
|
4
17
|
<span class="alchemy-field-suffix">{{ alchemy_field.config.options.suffix }}</span>
|
|
5
18
|
{% /if %}
|
|
@@ -3,11 +3,27 @@
|
|
|
3
3
|
<span
|
|
4
4
|
data-he-name="field-title"
|
|
5
5
|
data-he-slot="field-title"
|
|
6
|
-
>
|
|
6
|
+
>
|
|
7
|
+
{%t
|
|
8
|
+
"alchemy-field-title"
|
|
9
|
+
field=field_context.config.name
|
|
10
|
+
path=field_context.config.path_in_document
|
|
11
|
+
zone=self.zone
|
|
12
|
+
fallback=alchemy_field.field_title
|
|
13
|
+
%}
|
|
14
|
+
</span>
|
|
7
15
|
<small
|
|
8
16
|
data-he-name="field-description"
|
|
9
17
|
data-he-slot="field-description"
|
|
10
|
-
>
|
|
18
|
+
>
|
|
19
|
+
{%t
|
|
20
|
+
"alchemy-field-description"
|
|
21
|
+
field=field_context.config.name
|
|
22
|
+
path=field_context.config.path_in_document
|
|
23
|
+
zone=self.zone
|
|
24
|
+
fallback=alchemy_field.field_description
|
|
25
|
+
%}
|
|
26
|
+
</small>
|
|
11
27
|
</al-label>
|
|
12
28
|
</div>
|
|
13
29
|
<div data-he-name="field"></div>
|
|
File without changes
|