alchemy-form 0.2.9 → 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 CHANGED
@@ -1,3 +1,18 @@
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
+
9
+ ## 0.2.10 (2024-01-15)
10
+
11
+ * Fix `al-table` throwing an error when receiving null data
12
+ * Add `al-virtual-scroll` element
13
+ * Make field `constraints` work by using the `Document` instance instead of plain data object
14
+ * Clear old errors when validating a form
15
+
1
16
  ## 0.2.9 (2023-11-27)
2
17
 
3
18
  * Add support for new local Date/Time fields & Decimal fields
@@ -1,6 +1,5 @@
1
1
  al-code-input {
2
2
  display: inline-block;
3
- height: 30rem;
4
3
  width: 100%;
5
4
  position: relative;
6
5
 
@@ -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
+ }
@@ -4,7 +4,6 @@ al-table {
4
4
  border: 1px solid #dadee0;
5
5
  font-family: sans-serif;
6
6
  background-color: white;
7
- color: #313131;
8
7
 
9
8
  table {
10
9
  border-collapse: collapse;
@@ -0,0 +1,19 @@
1
+ al-virtual-scroll {
2
+ display: block;
3
+ min-height: 20rem;
4
+ min-width: 2rem;
5
+ overflow: auto;
6
+ border: 1px solid red;
7
+
8
+ .top-trigger,
9
+ .bottom-trigger {
10
+ width: 1px;
11
+ height: 1px;
12
+ }
13
+
14
+ [data-loaded-entry-index] {
15
+ border: 1px solid orange;
16
+ min-height: 2rem;
17
+ padding: 1rem;
18
+ }
19
+ }
@@ -13,4 +13,6 @@
13
13
  @import "_toggle.scss";
14
14
  @import "_tabs.scss";
15
15
  @import "_pathway.scss";
16
- @import "_apex_charts.scss";
16
+ @import "_apex_charts.scss";
17
+ @import "_virtual_scroll.scss";
18
+ @import "_settings_editor.scss";
package/config/routes.js CHANGED
@@ -1,4 +1,4 @@
1
- Router.add({
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
- Router.add({
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
- Router.add({
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.2.9
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
- for (let key in body.constraints) {
36
- crit.where(key).equals(body.constraints[key]);
37
- }
35
+ crit.applyConditions(body.constraints);
38
36
  }
39
37
 
40
38
  if (config.value) {
@@ -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, ...
@@ -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.2.5
78
+ * @version 0.3.0
70
79
  */
71
- CodeInput.setProperty(function value(value) {
80
+ CodeInput.setProperty(function value() {
81
+
82
+ let result;
72
83
 
73
84
  if (this._editor) {
74
- return this._editor.getValue();
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
- let editor_el = this.querySelector('.code-editor');
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
- if (this.assigned_data.value) {
84
- return this.assigned_data.value;
85
- }
104
+ return result;
105
+
106
+ }, function setValue(original_value) {
86
107
 
87
- }, function setValue(value) {
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 = 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
- editor.setValue(this.assigned_data.value, -1);
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
  });
@@ -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.1.2
80
+ * @version 0.3.0
81
81
  */
82
- Field.setAttribute('readonly', {boolean: true});
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.2.9
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
- return element.value;
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.2.9
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
- if (value && typeof value == 'object') {
1061
- if (value instanceof Classes.Alchemy.PathEvaluator) {
1062
- if (!context && this.alchemy_form) {
1063
- context = this.alchemy_form.getMainValue();
1064
- }
1070
+ constraints = Classes.Alchemy.Criteria.Criteria.cast(constraints);
1065
1071
 
1066
- result[key] = value.getValue({$0: context}) ?? null;
1067
- }
1068
- } else {
1069
- result[key] = value;
1070
- }
1071
- }
1072
+ let result = constraints.compileToConditions(context);
1072
1073
 
1073
1074
  return result;
1074
1075
  });
@@ -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];
@@ -271,7 +278,7 @@ Form.setMethod(function setDocument(document) {
271
278
  *
272
279
  * @author Jelle De Loecker <jelle@elevenways.be>
273
280
  * @since 0.2.2
274
- * @version 0.2.9
281
+ * @version 0.2.10
275
282
  */
276
283
  Form.setMethod(async function validate() {
277
284
 
@@ -279,11 +286,12 @@ Form.setMethod(async function validate() {
279
286
 
280
287
  let violations = await doc.getViolations();
281
288
 
289
+ this.clearErrors();
290
+
282
291
  if (violations) {
283
292
  this.showError(violations);
284
293
  throw violations;
285
294
  }
286
-
287
295
  });
288
296
 
289
297
  /**
@@ -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.2.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