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 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
@@ -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;
@@ -14,4 +14,5 @@
14
14
  @import "_tabs.scss";
15
15
  @import "_pathway.scss";
16
16
  @import "_apex_charts.scss";
17
- @import "_virtual_scroll.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.10
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.getValueAsDocument();
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];
@@ -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
 
@@ -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
+ });
@@ -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.2.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.1.12
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('td');
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('td');
987
+ col = this.createElement('th');
984
988
  names_row.append(col);
985
989
 
986
- col = this.createElement('td');
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.2.10",
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.3.0",
11
- "alchemy-media" : ">=0.7.6"
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>
@@ -0,0 +1,9 @@
1
+ <al-code-input
2
+ class="alchemy-field-value"
3
+ form=<% form_id %>
4
+ name=<% path %>
5
+ placeholder={% alchemy_field.placeholder %}
6
+ language-mode="json"
7
+ value-is-object
8
+ #value={% value %}
9
+ ></al-code-input>
@@ -0,0 +1,5 @@
1
+ <% config = value.getEditorConfiguration() %>
2
+ <al-settings-editor
3
+ class="alchemy-field-value"
4
+ #settings_config={% config %}
5
+ ></al-settings-editor>
@@ -1,5 +1,18 @@
1
1
  <div>
2
- <span class="alchemy-field-value">{{ value }}</span>
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
- >{{ alchemy_field.field_title }}</span>
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
- >{{ alchemy_field.field_description }}</small>
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>