alchemy-form 0.1.6 → 0.1.9

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,30 @@
1
+ ## 0.1.9 (2022-07-06)
2
+
3
+ * Allow supplying a custom `data-src` to `alchemy-field` elements
4
+ * Add `view` templates for File & Datetime fields
5
+ * Use the new `alchemy.getClientModel()` method in `alchemy-field` element
6
+ * Add `alchemy-password-input` element
7
+
8
+ ## 0.1.8 (2022-06-29)
9
+
10
+ * Move the `alchemy-select` pagination checker initializer to a static function
11
+ * Prevent `alchemy-select` from keeping on loading remote data when last few results were empty
12
+ * Fix pagination breaking re-opening of `alchemy-select` dropdown
13
+ * Fix initial value of a `BelongsTo` `alchemy-select` element not loading
14
+ * Fix `alchemy-select` downward-arrow-icon being rendered over value content
15
+ * Use `alchemy-code-input` for HTML fields
16
+ * Allow manually setting a value on `alchemy-field` elements
17
+ * Try to let `Field` instances decide the representation of values in `alchemy-table` elements
18
+ * Don't open the `alchemy-table` contextmenu when clicking on anchors
19
+
20
+ ## 0.1.7 (2022-06-12)
21
+
22
+ * Fix `<alchemy-table>` code typo
23
+ * Fix QueryBuilderGroup value being set incorrectly
24
+ * Add `<alchemy-query-builder-value>` element
25
+ * Add `<alchemy-query-builder-variable>` element
26
+ * Add List variable definition, which can contain other variables
27
+
1
28
  ## 0.1.6 (2022-05-31)
2
29
 
3
30
  * Fix `FormApi#related` action searching through multiple fields in an `and` group
@@ -39,7 +39,7 @@ alchemy-select {
39
39
  align-items: center;
40
40
 
41
41
  input.type-area {
42
- height: 1.5rem;
42
+ height: 1.5rem !important;
43
43
  }
44
44
  }
45
45
 
@@ -102,7 +102,6 @@ alchemy-select {
102
102
  font-family: inherit;
103
103
  font-size: 13px;
104
104
  line-height: 18px;
105
- -webkit-font-smoothing: inherit;
106
105
  display: inline-block !important;
107
106
  padding: 0 !important;
108
107
  min-height: 0 !important;
@@ -113,11 +112,10 @@ alchemy-select {
113
112
  border: 0 none !important;
114
113
  background: none !important;
115
114
  line-height: inherit !important;
116
- -webkit-user-select: auto !important;
117
- -webkit-box-shadow: none !important;
118
115
  box-shadow: none !important;
119
116
  outline: none !important;
120
117
  flex: 0 1 auto;
118
+ margin-right: 20px !important;
121
119
  }
122
120
 
123
121
  .dropdown {
@@ -17,20 +17,23 @@ 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.1.6
20
+ * @version 0.1.8
21
21
  *
22
22
  * @param {Conduit} conduit
23
23
  */
24
24
  FormApi.setAction(async function related(conduit) {
25
25
 
26
- const body = conduit.body;
26
+ const body = conduit.body || {},
27
+ config = body.config || {};
27
28
 
28
29
  const model = this.getModel(body.assoc_model);
29
30
  let crit = model.find();
30
31
  crit.limit(50);
31
32
  crit.setOption('scenario', 'related_data');
32
33
 
33
- if (body.config && body.config.search) {
34
+ if (config.value) {
35
+ crit.where(model.primary_key).equals(config.value);
36
+ } else if (config.search) {
34
37
  let display_fields = Array.cast(model.displayField);
35
38
 
36
39
  let or = crit.or();
@@ -45,6 +48,10 @@ FormApi.setAction(async function related(conduit) {
45
48
  }
46
49
  }
47
50
 
51
+ if (config.page) {
52
+ crit.page(config.page);
53
+ }
54
+
48
55
  let records = await model.find('all', crit);
49
56
 
50
57
  let result = {
@@ -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
+ });
@@ -34,6 +34,15 @@ Field.setStylesheetFile('form/alchemy_field');
34
34
  */
35
35
  Field.setStatic('use_new_renderer_scope', true);
36
36
 
37
+ /**
38
+ * The data source url/route to use
39
+ *
40
+ * @author Jelle De Loecker <jelle@elevenways.be>
41
+ * @since 0.1.9
42
+ * @version 0.1.9
43
+ */
44
+ Field.setAttribute('data-src');
45
+
37
46
  /**
38
47
  * The name of the field
39
48
  *
@@ -133,7 +142,7 @@ Field.enforceProperty(function alchemy_field_schema(new_value, old_value) {
133
142
  *
134
143
  * @author Jelle De Loecker <jelle@elevenways.be>
135
144
  * @since 0.1.0
136
- * @version 0.1.4
145
+ * @version 0.1.8
137
146
  */
138
147
  Field.enforceProperty(function config(new_value, old_value) {
139
148
 
@@ -148,7 +157,7 @@ Field.enforceProperty(function config(new_value, old_value) {
148
157
 
149
158
  if (new_value && new_value.constructor && new_value.constructor.type_name) {
150
159
  this.field_type = new_value.constructor.type_name;
151
- } else {
160
+ } else if (new_value) {
152
161
  this.field_type = null;
153
162
  }
154
163
 
@@ -160,7 +169,7 @@ Field.enforceProperty(function config(new_value, old_value) {
160
169
  *
161
170
  * @author Jelle De Loecker <jelle@elevenways.be>
162
171
  * @since 0.1.0
163
- * @version 0.1.0
172
+ * @version 0.1.9
164
173
  */
165
174
  Field.enforceProperty(function schema(new_value, old_value) {
166
175
 
@@ -181,15 +190,10 @@ Field.enforceProperty(function schema(new_value, old_value) {
181
190
  let model_name = this.model;
182
191
 
183
192
  if (model_name) {
184
- // @TODO: Always get the Client-side model here
185
- let model = alchemy.getModel(model_name);
193
+ let model = alchemy.getClientModel(model_name);
186
194
 
187
195
  if (model) {
188
196
  new_value = model.schema;
189
-
190
- if (Blast.isNode) {
191
- new_value = JSON.clone(new_value, 'toHawkejs');
192
- }
193
197
  }
194
198
  }
195
199
  }
@@ -493,10 +497,14 @@ Field.setProperty(function wrapper_files() {
493
497
  *
494
498
  * @author Jelle De Loecker <jelle@elevenways.be>
495
499
  * @since 0.1.0
496
- * @version 0.1.4
500
+ * @version 0.1.8
497
501
  */
498
502
  Field.setProperty(function original_value() {
499
503
 
504
+ if (this.assigned_data.original_value != null) {
505
+ return this.assigned_data.original_value;
506
+ }
507
+
500
508
  let alchemy_field_schema = this.alchemy_field_schema,
501
509
  path = this.field_path_in_current_schema;
502
510
 
@@ -517,6 +525,8 @@ Field.setProperty(function original_value() {
517
525
  if (form && form.document) {
518
526
  return Object.path(form.document, path);
519
527
  }
528
+ }, function setOriginalValue(value) {
529
+ return this.assigned_data.original_value = value;
520
530
  });
521
531
 
522
532
  /**
@@ -551,7 +561,7 @@ Field.setProperty(function value_element() {
551
561
  *
552
562
  * @author Jelle De Loecker <jelle@elevenways.be>
553
563
  * @since 0.1.0
554
- * @version 0.1.3
564
+ * @version 0.1.8
555
565
  */
556
566
  Field.setProperty(function value() {
557
567
 
@@ -569,8 +579,9 @@ Field.setProperty(function value() {
569
579
 
570
580
  if (element) {
571
581
  element.value = value;
582
+ } else if (this.original_value == null) {
583
+ this.original_value = value;
572
584
  }
573
-
574
585
  });
575
586
 
576
587
  /**
@@ -708,7 +719,7 @@ Field.setMethod(function retained() {
708
719
  *
709
720
  * @author Jelle De Loecker <jelle@elevenways.be>
710
721
  * @since 0.1.0
711
- * @version 0.1.6
722
+ * @version 0.1.9
712
723
  *
713
724
  * @param {Object} config
714
725
  * @param {HTMLElement} element
@@ -735,7 +746,7 @@ Field.setMethod(async function loadData(config, element) {
735
746
  }
736
747
  }
737
748
 
738
- return this.hawkejs_helpers.Alchemy.getResource({
749
+ let resource_options = {
739
750
  name : 'FormApi#related',
740
751
  post : true,
741
752
  body : {
@@ -744,7 +755,13 @@ Field.setMethod(async function loadData(config, element) {
744
755
  assoc_model : field.options.modelName,
745
756
  config : config,
746
757
  }
747
- });
758
+ };
759
+
760
+ if (this.data_src) {
761
+ resource_options.name = this.data_src;
762
+ }
763
+
764
+ return this.hawkejs_helpers.Alchemy.getResource(resource_options);
748
765
  }
749
766
 
750
767
  });
@@ -0,0 +1,141 @@
1
+ /**
2
+ * The number-input custom element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.1.9
6
+ * @version 0.1.9
7
+ */
8
+ const PasswordInput = Function.inherits('Alchemy.Element.Form.StringInput', 'PasswordInput');
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.9
15
+ * @version 0.1.9
16
+ */
17
+ PasswordInput.setTemplateFile('form/elements/password_input');
18
+
19
+ /**
20
+ * Reference to the repeat input element
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 0.1.9
24
+ * @version 0.1.9
25
+ */
26
+ PasswordInput.addElementGetter('repeat_el', '.repeat-input');
27
+
28
+ /**
29
+ * Reference to the repeat label element
30
+ *
31
+ * @author Jelle De Loecker <jelle@elevenways.be>
32
+ * @since 0.1.9
33
+ * @version 0.1.9
34
+ */
35
+ PasswordInput.addElementGetter('repeat_label', '.repeat-input-label');
36
+
37
+ /**
38
+ * The value property
39
+ *
40
+ * @author Jelle De Loecker <jelle@elevenways.be>
41
+ * @since 0.1.9
42
+ * @version 0.1.9
43
+ */
44
+ PasswordInput.setProperty(function value() {
45
+
46
+ let val;
47
+
48
+ if (this.input_el) {
49
+ val = this.input_el.value;
50
+ }
51
+
52
+ if (!val) {
53
+ return undefined;
54
+ }
55
+
56
+ if (!this.valuesAreEqual()) {
57
+ return undefined;
58
+ }
59
+
60
+ return val;
61
+ });
62
+
63
+ /**
64
+ * Are both inputs the same?
65
+ *
66
+ * @author Jelle De Loecker <jelle@elevenways.be>
67
+ * @since 0.1.9
68
+ * @version 0.1.9
69
+ */
70
+ PasswordInput.setMethod(function valuesAreEqual() {
71
+
72
+ let first_value = this.input_el?.value,
73
+ repeat_value = this.repeat_el?.value;
74
+
75
+ return first_value == repeat_value;
76
+ });
77
+
78
+ /**
79
+ * Revalidate the value
80
+ *
81
+ * @author Jelle De Loecker <jelle@elevenways.be>
82
+ * @since 0.1.9
83
+ * @version 0.1.9
84
+ */
85
+ PasswordInput.setMethod(async function revalidate() {
86
+
87
+ let first_value = this.input_el?.value,
88
+ repeat_value = this.repeat_el.value;
89
+
90
+ if (first_value) {
91
+ this.repeat_label.hidden = false;
92
+ } else {
93
+ this.repeat_el.value = '';
94
+ this.repeat_label.hidden = true;
95
+ }
96
+
97
+ this.removeErrors();
98
+
99
+ if (!first_value && !repeat_value) {
100
+ return;
101
+ }
102
+
103
+ if (first_value != repeat_value) {
104
+ return this.addError(this.__('does-not-match'), true);
105
+ }
106
+
107
+ return revalidate.super.call(this);
108
+ });
109
+
110
+ /**
111
+ * Actions to perform when this element
112
+ * has been added to the DOM for the first time
113
+ *
114
+ * @author Jelle De Loecker <jelle@elevenways.be>
115
+ * @since 0.1.9
116
+ * @version 0.1.9
117
+ */
118
+ PasswordInput.setMethod(function introduced() {
119
+
120
+ const that = this;
121
+
122
+ introduced.super.call(this);
123
+
124
+ this.repeat_el.addEventListener('focus', function onFocus(e) {
125
+ that.inputbox_el.classList.add('focus');
126
+ });
127
+
128
+ this.repeat_el.addEventListener('blur', function onBlur(e) {
129
+ that.inputbox_el.classList.remove('focus');
130
+ });
131
+
132
+ this.repeat_el.addEventListener('keyup', Fn.throttle(function onKeyup(e) {
133
+ that.revalidate();
134
+ that.emit('changing');
135
+ }, {
136
+ minimum_wait : 350,
137
+ immediate : false,
138
+ reset_on_call : true
139
+ }));
140
+
141
+ });