alchemy-form 0.1.6 → 0.1.7

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.1.7 (2022-06-12)
2
+
3
+ * Fix `<alchemy-table>` code typo
4
+ * Fix QueryBuilderGroup value being set incorrectly
5
+ * Add `<alchemy-query-builder-value>` element
6
+ * Add `<alchemy-query-builder-variable>` element
7
+ * Add List variable definition, which can contain other variables
8
+
1
9
  ## 0.1.6 (2022-05-31)
2
10
 
3
11
  * Fix `FormApi#related` action searching through multiple fields in an `and` group
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The base abstract query builder custom element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.1.7
6
+ * @version 0.1.7
7
+ */
8
+ const QueryBuilderData = Function.inherits('Alchemy.Element.Form.QueryBuilderBase', 'QueryBuilderData');
9
+
10
+ /**
11
+ * Don't register this as a custom element,
12
+ * but don't let child classes inherit this
13
+ *
14
+ * @author Jelle De Loecker <jelle@elevenways.be>
15
+ * @since 0.1.7
16
+ * @version 0.1.7
17
+ */
18
+ QueryBuilderData.setStatic('is_abstract_class', true, false);
19
+
20
+ /**
21
+ * Check a filter
22
+ *
23
+ * @author Jelle De Loecker <jelle@elevenways.be>
24
+ * @since 0.1.6
25
+ * @version 0.1.7
26
+ */
27
+ QueryBuilderData.setMethod(function checkFilterType(filter_type, entry) {
28
+
29
+ if (!entry) {
30
+ return false;
31
+ }
32
+
33
+ let whitelist = this[filter_type];
34
+
35
+ if (!whitelist) {
36
+ return true;
37
+ }
38
+
39
+ let type = entry.type_name || entry.type || entry.id || entry.name;
40
+
41
+ if (!type) {
42
+ return false;
43
+ }
44
+
45
+ let entries = whitelist.split(',');
46
+
47
+ return entries.indexOf(type) > -1;
48
+ });
49
+
50
+ /**
51
+ * Load data for a specific element
52
+ *
53
+ * @author Jelle De Loecker <jelle@elevenways.be>
54
+ * @since 0.1.6
55
+ * @version 0.1.6
56
+ */
57
+ QueryBuilderData.setMethod(async function loadData(config, element) {
58
+
59
+ if (!element) {
60
+ return;
61
+ }
62
+
63
+ if (!config) {
64
+ config = {};
65
+ }
66
+
67
+ let filter_type,
68
+ result = [],
69
+ items;
70
+
71
+ if (element.classList.contains('qb-source-type')) {
72
+ items = await this.loadSourceTypeData(config);
73
+ filter_type = 'source-types';
74
+ } else if (element.classList.contains('qb-value-variable') || element.classList.contains('qb-variable')) {
75
+ items = await this.loadVariableData(config);
76
+ filter_type = 'variable-types';
77
+ }
78
+
79
+ if (items && items.length) {
80
+
81
+ let entry;
82
+
83
+ for (entry of items) {
84
+ if (!entry) {
85
+ continue;
86
+ }
87
+
88
+ if (filter_type && !this.checkFilterType(filter_type, entry)) {
89
+ continue;
90
+ }
91
+
92
+ result.push(entry);
93
+ }
94
+ }
95
+
96
+ return {
97
+ items: result,
98
+ };
99
+ });
100
+
101
+ /**
102
+ * Load variable data
103
+ *
104
+ * @author Jelle De Loecker <jelle@elevenways.be>
105
+ * @since 0.1.6
106
+ * @version 0.1.7
107
+ */
108
+ QueryBuilderData.setMethod(async function loadVariableData(config) {
109
+
110
+ let dataprovider = this.dataprovider;
111
+
112
+ if (!config) {
113
+ config = {};
114
+ }
115
+
116
+ config.source_type = 'variable';
117
+
118
+ let variables = [];
119
+
120
+ if (dataprovider) {
121
+ variables = await dataprovider.loadData(config, this);
122
+ }
123
+
124
+ let result = [];
125
+
126
+ if (variables && variables.length) {
127
+ let entry;
128
+
129
+ for (entry of variables) {
130
+ if (entry) {
131
+ result.push(entry);
132
+ }
133
+ }
134
+ }
135
+
136
+ console.log('Got loadvariable data:', result);
137
+
138
+ return result;
139
+ });
@@ -709,7 +709,7 @@ Table.setMethod(function getEntryActions(record, filter) {
709
709
  *
710
710
  * @author Jelle De Loecker <jelle@elevenways.be>
711
711
  * @since 0.1.6
712
- * @version 0.1.6
712
+ * @version 0.1.7
713
713
  *
714
714
  * @param {Object} entry
715
715
  */
@@ -728,7 +728,7 @@ Table.setMethod(function attachContextMenus() {
728
728
  let context_actions = this.getEntryActions(record, 'context');
729
729
 
730
730
  if (!context_actions || !context_actions.length) {
731
- contintue;
731
+ continue;
732
732
  }
733
733
 
734
734
  let pk = record.$pk || record._id || record.id;
@@ -73,7 +73,7 @@ QueryBuilder.setMethod(function applyValue(value) {
73
73
  return;
74
74
  }
75
75
 
76
- this.root_group.applyValue(value);
76
+ this.root_group.value = value;
77
77
  });
78
78
 
79
79
  /**
@@ -104,7 +104,7 @@ QueryBuilderGroup.setProperty(function group_type() {
104
104
  *
105
105
  * @author Jelle De Loecker <jelle@elevenways.be>
106
106
  * @since 0.1.6
107
- * @version 0.1.6
107
+ * @version 0.1.7
108
108
  */
109
109
  QueryBuilderGroup.setProperty(function inverted() {
110
110
 
@@ -116,8 +116,17 @@ QueryBuilderGroup.setProperty(function inverted() {
116
116
 
117
117
  return false;
118
118
  }, function setInverted(value) {
119
- let input = this.header.querySelector('.qb-group-invert input');
120
- input.checked = value;
119
+
120
+ if (!this.assigned_data.value) {
121
+ this.assigned_data.value = {};
122
+ }
123
+
124
+ this.assigned_data.value.inverted = value;
125
+
126
+ if (this.header) {
127
+ let input = this.header.querySelector('.qb-group-invert input');
128
+ input.checked = value;
129
+ }
121
130
  });
122
131
 
123
132
  /**
@@ -125,7 +134,7 @@ QueryBuilderGroup.setProperty(function inverted() {
125
134
  *
126
135
  * @author Jelle De Loecker <jelle@elevenways.be>
127
136
  * @since 0.1.6
128
- * @version 0.1.6
137
+ * @version 0.1.7
129
138
  */
130
139
  QueryBuilderGroup.setProperty(function value() {
131
140
 
@@ -148,6 +157,13 @@ QueryBuilderGroup.setProperty(function value() {
148
157
  }
149
158
 
150
159
  return result;
160
+ }, function setValue(value) {
161
+
162
+ this.assigned_data.value = value;
163
+
164
+ if (this.has_rendered) {
165
+ this.applyValue(value);
166
+ }
151
167
  });
152
168
 
153
169
  /**
@@ -155,7 +171,7 @@ QueryBuilderGroup.setProperty(function value() {
155
171
  *
156
172
  * @author Jelle De Loecker <jelle@elevenways.be>
157
173
  * @since 0.1.6
158
- * @version 0.1.6
174
+ * @version 0.1.7
159
175
  */
160
176
  QueryBuilderGroup.setMethod(function applyValue(value) {
161
177
 
@@ -163,15 +179,25 @@ QueryBuilderGroup.setMethod(function applyValue(value) {
163
179
  return;
164
180
  }
165
181
 
182
+ // Keep track of how many time a value has been applied
183
+ // (needed for the initial value setter)
184
+ if (!this.applied_value_counter) {
185
+ this.applied_value_counter = 0;
186
+ }
187
+
188
+ this.applied_value_counter++;
189
+
166
190
  this.inverted = value.inverted;
167
191
  this.group_type = value.condition;
168
192
 
193
+ Hawkejs.removeChildren(this.rules_list);
194
+
169
195
  if (value.rules && value.rules.length) {
170
196
  let element,
171
197
  rule;
172
198
 
173
199
  for (rule of value.rules) {
174
- if (rule.type == 'field') {
200
+ if (rule.type == 'qb_entry') {
175
201
  element = this.createElement('alchemy-query-builder-entry');
176
202
  } else {
177
203
  element = this.createElement('alchemy-query-builder-group');
@@ -188,7 +214,7 @@ QueryBuilderGroup.setMethod(function applyValue(value) {
188
214
  *
189
215
  * @author Jelle De Loecker <jelle@elevenways.be>
190
216
  * @since 0.1.6
191
- * @version 0.1.6
217
+ * @version 0.1.7
192
218
  */
193
219
  QueryBuilderGroup.setMethod(function introduced() {
194
220
 
@@ -215,7 +241,8 @@ QueryBuilderGroup.setMethod(function introduced() {
215
241
  this.remove();
216
242
  });
217
243
 
218
- if (this.assigned_data.value) {
244
+ // Apply the value if it hasn't been done already
245
+ if (this.assigned_data.value && !this.applied_value_counter) {
219
246
  this.applyValue(this.assigned_data.value);
220
247
  }
221
248
  });
@@ -5,7 +5,7 @@
5
5
  * @since 0.1.6
6
6
  * @version 0.1.6
7
7
  */
8
- const QueryBuilderValue = Function.inherits('Alchemy.Element.Form.QueryBuilderBase', 'QueryBuilderValue');
8
+ const QueryBuilderValue = Function.inherits('Alchemy.Element.Form.QueryBuilderData', 'QueryBuilderValue');
9
9
 
10
10
  /**
11
11
  * The template to use for the content of this element
@@ -124,125 +124,6 @@ QueryBuilderValue.setProperty(function value() {
124
124
  this.assigned_data.value = value;
125
125
  });
126
126
 
127
- /**
128
- * Check a filter
129
- *
130
- * @author Jelle De Loecker <jelle@elevenways.be>
131
- * @since 0.1.6
132
- * @version 0.1.6
133
- */
134
- QueryBuilderValue.setMethod(function checkFilterType(filter_type, entry) {
135
-
136
- if (!entry) {
137
- return false;
138
- }
139
-
140
- let whitelist = this[filter_type];
141
-
142
- if (!whitelist) {
143
- return true;
144
- }
145
-
146
- let type = entry.type_name || entry.type || entry.id || entry.name;
147
-
148
- if (!type) {
149
- return false;
150
- }
151
-
152
- let entries = whitelist.split(',');
153
-
154
- return entries.indexOf(type) > -1;
155
- });
156
-
157
- /**
158
- * Load data for a specific element
159
- *
160
- * @author Jelle De Loecker <jelle@elevenways.be>
161
- * @since 0.1.6
162
- * @version 0.1.6
163
- */
164
- QueryBuilderValue.setMethod(async function loadData(config, element) {
165
-
166
- if (!element) {
167
- return;
168
- }
169
-
170
- if (!config) {
171
- config = {};
172
- }
173
-
174
- let filter_type,
175
- result = [],
176
- items;
177
-
178
- if (element.classList.contains('qb-source-type')) {
179
- items = await this.loadSourceTypeData(config);
180
- filter_type = 'source-types';
181
- } else if (element.classList.contains('qb-value-variable')) {
182
- items = await this.loadVariableData(config);
183
- filter_type = 'variable-types';
184
- }
185
-
186
- if (items && items.length) {
187
-
188
- let entry;
189
-
190
- for (entry of items) {
191
- if (!entry) {
192
- continue;
193
- }
194
-
195
- if (filter_type && !this.checkFilterType(filter_type, entry)) {
196
- continue;
197
- }
198
-
199
- result.push(entry);
200
- }
201
- }
202
-
203
- return {
204
- items: result,
205
- };
206
- });
207
-
208
- /**
209
- * Load variable data
210
- *
211
- * @author Jelle De Loecker <jelle@elevenways.be>
212
- * @since 0.1.6
213
- * @version 0.1.6
214
- */
215
- QueryBuilderValue.setMethod(async function loadVariableData(config) {
216
-
217
- let dataprovider = this.dataprovider;
218
-
219
- if (!config) {
220
- config = {};
221
- }
222
-
223
- config.source_type = 'variable';
224
-
225
- let variables = [];
226
-
227
- if (dataprovider) {
228
- variables = await dataprovider.loadData(config, this);
229
- }
230
-
231
- let result = [];
232
-
233
- if (variables && variables.length) {
234
- let entry;
235
-
236
- for (entry of variables) {
237
- if (entry) {
238
- result.push(entry);
239
- }
240
- }
241
- }
242
-
243
- return result;
244
- });
245
-
246
127
  /**
247
128
  * Load value type data
248
129
  *
@@ -0,0 +1,103 @@
1
+ /**
2
+ * The alchemy-query-builder-value custom element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.1.7
6
+ * @version 0.1.7
7
+ */
8
+ const QueryBuilderVariable = Function.inherits('Alchemy.Element.Form.QueryBuilderData', 'QueryBuilderVariable');
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.1.7
15
+ * @version 0.1.7
16
+ */
17
+ QueryBuilderVariable.setTemplateFile('form/elements/query_builder_variable');
18
+
19
+ /**
20
+ * A filter of variable definition types
21
+ * (number, string, ...)
22
+ *
23
+ * @author Jelle De Loecker <jelle@elevenways.be>
24
+ * @since 0.1.7
25
+ * @version 0.1.7
26
+ */
27
+ QueryBuilderVariable.setAttribute('variable-types');
28
+
29
+ /**
30
+ * Getter for the value input wrapper
31
+ *
32
+ * @author Jelle De Loecker <jelle@elevenways.be>
33
+ * @since 0.1.7
34
+ * @version 0.1.7
35
+ */
36
+ QueryBuilderVariable.addElementGetter('variable_select', '.qb-variable');
37
+
38
+ /**
39
+ * Get/set the value
40
+ *
41
+ * @author Jelle De Loecker <jelle@elevenways.be>
42
+ * @since 0.1.7
43
+ * @version 0.1.7
44
+ */
45
+ QueryBuilderVariable.setProperty(function value() {
46
+
47
+ let result = {
48
+ type : 'qb_variable',
49
+ variable_type : null,
50
+ };
51
+
52
+ let select = this.variable_select;
53
+
54
+ if (select) {
55
+ result.variable = select.value;
56
+
57
+ if (select.values) {
58
+ let value_def = select.values[result.variable];
59
+
60
+ if (value_def) {
61
+ result.variable_type = value_def.type_name;
62
+ }
63
+ }
64
+ }
65
+
66
+ return result;
67
+ }, function setValue(value) {
68
+ this.assigned_data.value = value;
69
+ });
70
+
71
+ /**
72
+ * Apply the given value
73
+ *
74
+ * @author Jelle De Loecker <jelle@elevenways.be>
75
+ * @since 0.1.7
76
+ * @version 0.1.7
77
+ */
78
+ QueryBuilderVariable.setMethod(async function applyValue(value) {
79
+
80
+ if (!value) {
81
+ return;
82
+ }
83
+
84
+ let select = this.variable_select;
85
+
86
+ if (select) {
87
+ select.value = value.variable;
88
+ }
89
+ });
90
+
91
+ /**
92
+ * Added to the dom
93
+ *
94
+ * @author Jelle De Loecker <jelle@elevenways.be>
95
+ * @since 0.1.7
96
+ * @version 0.1.7
97
+ */
98
+ QueryBuilderVariable.setMethod(async function introduced() {
99
+
100
+ if (this.assigned_data.value) {
101
+ await this.applyValue(this.assigned_data.value);
102
+ }
103
+ });
@@ -154,10 +154,20 @@ VariableDefinition.setStatic(function addLogicalOperator(name, config) {
154
154
  config = {};
155
155
  }
156
156
 
157
- if(!config.title) {
157
+ if (!config.title) {
158
158
  config.title = name.titleize();
159
159
  }
160
160
 
161
+ // By default logical operators have a binary arity:
162
+ // they take 2 operands. The value of the variable + another value.
163
+ if (!config.arity) {
164
+ config.arity = 'binary';
165
+ }
166
+
167
+ if (config.arity != 'unary' && config.arity != 'binary' && config.arity != 'ternary') {
168
+ throw new Error('Unable to add Logical operator "' + name + '" to ' + this.name + ', unknown arity: "' + config.arity);
169
+ }
170
+
161
171
  config.id = name;
162
172
 
163
173
  this.constitute(function _addOperator() {
@@ -185,10 +195,20 @@ VariableDefinition.setStatic(function addAssignmentOperator(name, config) {
185
195
  config = {};
186
196
  }
187
197
 
188
- if(!config.title) {
198
+ if (!config.title) {
189
199
  config.title = name.titleize();
190
200
  }
191
201
 
202
+ // By default assignment operators have a binary arity:
203
+ // they take 2 operands. The value of the variable + another value
204
+ if (!config.arity) {
205
+ config.arity = 'binary';
206
+ }
207
+
208
+ if (config.arity != 'unary' && config.arity != 'binary' && config.arity != 'ternary') {
209
+ throw new Error('Unable to add Assignment operator "' + name + '" to ' + this.name + ', unknown arity: "' + config.arity);
210
+ }
211
+
192
212
  config.id = name;
193
213
 
194
214
  this.constitute(function _addOperator() {
@@ -330,7 +350,7 @@ VariableDefinition.addLogicalOperator('not_equals');
330
350
  * @since 0.1.6
331
351
  * @version 0.1.6
332
352
  */
333
- VariableDefinition.addLogicalOperator('is_empty');
353
+ VariableDefinition.addLogicalOperator('is_empty', {arity: 'unary'});
334
354
 
335
355
  /**
336
356
  * The `is_null` operator
@@ -339,7 +359,7 @@ VariableDefinition.addLogicalOperator('is_empty');
339
359
  * @since 0.1.6
340
360
  * @version 0.1.6
341
361
  */
342
- VariableDefinition.addLogicalOperator('is_null');
362
+ VariableDefinition.addLogicalOperator('is_null', {arity: 'unary'});
343
363
 
344
364
  /**
345
365
  * The `set` operator sets a value
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The List Value Type:
3
+ * Can contain other value types.
4
+ *
5
+ * @constructor
6
+ *
7
+ * @author Jelle De Loecker <jelle@elevenways.be>
8
+ * @since 0.1.7
9
+ * @version 0.1.7
10
+ */
11
+ const ListDefinition = Function.inherits('Alchemy.QueryBuilder.VariableDefinition', 'List');
12
+
13
+ /**
14
+ * The optional type this list holds
15
+ *
16
+ * @author Jelle De Loecker <jelle@elevenways.be>
17
+ * @since 0.1.7
18
+ * @version 0.1.7
19
+ */
20
+ ListDefinition.setProperty('content_type');
21
+
22
+ /**
23
+ * The `contains` operator
24
+ *
25
+ * @author Jelle De Loecker <jelle@elevenways.be>
26
+ * @since 0.1.7
27
+ * @version 0.1.7
28
+ */
29
+ ListDefinition.addLogicalOperator('contains');
30
+
31
+ /**
32
+ * The `add` assignment operator adds an entry
33
+ *
34
+ * @author Jelle De Loecker <jelle@elevenways.be>
35
+ * @since 0.1.7
36
+ * @version 0.1.7
37
+ */
38
+ ListDefinition.addAssignmentOperator('add');
@@ -0,0 +1,56 @@
1
+ /**
2
+ * A QueryBuilderVariable field lets you select a specific variable
3
+ * using the QueryBuilder logic
4
+ *
5
+ * @constructor
6
+ *
7
+ * @author Jelle De Loecker <jelle@elevenways.be>
8
+ * @since 0.1.6
9
+ * @version 0.1.6
10
+ */
11
+ const QueryBuilderVariable = Function.inherits('Alchemy.Field.QueryBuilder', 'QueryBuilderVariable');
12
+
13
+ /**
14
+ * Load remote data
15
+ *
16
+ * @author Jelle De Loecker <jelle@elevenways.be>
17
+ * @since 0.1.6
18
+ * @version 0.1.6
19
+ *
20
+ * @param {Object} config
21
+ * @param {HTMLElement} element
22
+ */
23
+ QueryBuilderVariable.setMethod(function loadData(config, element) {
24
+
25
+ if (element) {
26
+ let form = element.queryParents('alchemy-form');
27
+
28
+ if (form) {
29
+ let doc = form.document;
30
+
31
+ if (doc && doc.root_document) {
32
+ doc = doc.root_document;
33
+ }
34
+
35
+ let model_name,
36
+ $pk;
37
+
38
+ if (doc) {
39
+ model_name = doc.$model_name;
40
+ $pk = doc.$pk;
41
+ }
42
+
43
+ return element.hawkejs_helpers.Alchemy.getResource({
44
+ name : 'FormApi#queryBuilderData',
45
+ post : true,
46
+ body : {
47
+ model : model_name,
48
+ $pk : $pk,
49
+ config : config,
50
+ }
51
+ });
52
+ }
53
+ }
54
+
55
+ return [];
56
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemy-form",
3
3
  "description": "Form plugin for Alchemy",
4
- "version": "0.1.6",
4
+ "version": "0.1.7",
5
5
  "repository": {
6
6
  "type" : "git",
7
7
  "url" : "https://github.com/11ways/alchemy-form.git"
@@ -0,0 +1,6 @@
1
+ <alchemy-select
2
+ class="qb-variable"
3
+ #dataprovider={% self %}
4
+ value-item-template="form/select/qb_item"
5
+ option-item-template="form/select/qb_item"
6
+ ></alchemy-select>
@@ -0,0 +1,10 @@
1
+ <%
2
+ options = alchemy_field.config.options || {};
3
+ %>
4
+
5
+ <alchemy-query-builder-variable
6
+ class="alchemy-field-value"
7
+ #value={% value %}
8
+ #dataprovider={% alchemy_field %}
9
+ variable-types={% options.variable_types %}
10
+ ></alchemy-query-builder-variable>