alchemy-form 0.1.1 → 0.1.4

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.
@@ -18,15 +18,6 @@ var FieldArrayEntry = Function.inherits('Alchemy.Element.Form.FieldEntry', funct
18
18
  */
19
19
  FieldArrayEntry.setTemplateFile('form/elements/alchemy_field_array_entry');
20
20
 
21
- /**
22
- * The prefix of this translation
23
- *
24
- * @author Jelle De Loecker <jelle@elevenways.be>
25
- * @since 0.1.0
26
- * @version 0.1.0
27
- */
28
- FieldArrayEntry.setAttribute('index');
29
-
30
21
  /**
31
22
  * Get a reference to the alchemy-field-array parent
32
23
  *
@@ -43,6 +34,46 @@ FieldArrayEntry.enforceProperty(function alchemy_field_array(new_value, old_valu
43
34
  return new_value;
44
35
  });
45
36
 
37
+ /**
38
+ * Get the index of this entry
39
+ *
40
+ * @author Jelle De Loecker <jelle@elevenways.be>
41
+ * @since 0.1.3
42
+ * @version 0.1.3
43
+ */
44
+ FieldArrayEntry.setProperty(function index() {
45
+
46
+ let defined_index = this.getAttribute('index'),
47
+ index;
48
+
49
+ let container = this.alchemy_field_array;
50
+
51
+ if (!container || !container.entries_element) {
52
+ if (defined_index) {
53
+ index = +defined_index;
54
+ }
55
+ } else {
56
+ let counter = -1,
57
+ child;
58
+
59
+ for (let i = 0; i < container.entries_element.children.length; i++) {
60
+ child = container.entries_element.children[i];
61
+
62
+ if (child.tagName == 'ALCHEMY-FIELD-ARRAY-ENTRY') {
63
+ counter++;
64
+ }
65
+
66
+ if (child == this) {
67
+ break;
68
+ }
69
+ }
70
+
71
+ index = counter;
72
+ }
73
+
74
+ return index;
75
+ });
76
+
46
77
  /**
47
78
  * Get the original value
48
79
  *
@@ -58,3 +89,16 @@ FieldArrayEntry.setProperty(function original_value() {
58
89
  return context_value[this.index];
59
90
  }
60
91
  });
92
+
93
+ /**
94
+ * Get the name of this entry for use in a record path
95
+ *
96
+ * @author Jelle De Loecker <jelle@elevenways.be>
97
+ * @since 0.1.3
98
+ * @version 0.1.3
99
+ *
100
+ * @return {String}
101
+ */
102
+ FieldArrayEntry.setMethod(function getPathEntryName() {
103
+ return '' + this.index;
104
+ });
@@ -23,12 +23,36 @@ FieldSchema.setTemplateFile('form/elements/alchemy_field_schema');
23
23
  *
24
24
  * @author Jelle De Loecker <jelle@elevenways.be>
25
25
  * @since 0.1.0
26
- * @version 0.1.0
26
+ * @version 0.1.4
27
27
  */
28
28
  FieldSchema.setProperty(function schema() {
29
29
 
30
30
  if (this.alchemy_field && this.alchemy_field.config.options) {
31
- return this.alchemy_field.config.options.schema;
31
+ let schema = this.alchemy_field.config.options.schema;
32
+
33
+ if (typeof schema == 'string') {
34
+ let other_field = this.getSchemaSupplierField();
35
+ schema = null;
36
+
37
+ if (other_field && other_field.value && other_field.config && other_field.config.options) {
38
+ let values = other_field.config.options.values;
39
+
40
+ if (values) {
41
+
42
+ if (values instanceof Classes.Alchemy.Map.Backed) {
43
+ schema = values.get(other_field.value);
44
+ } else {
45
+ schema = values[other_field.value];
46
+ }
47
+
48
+ if (schema && schema.schema) {
49
+ schema = schema.schema;
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ return schema;
32
56
  }
33
57
  });
34
58
 
@@ -37,12 +61,21 @@ FieldSchema.setProperty(function schema() {
37
61
  *
38
62
  * @author Jelle De Loecker <jelle@elevenways.be>
39
63
  * @since 0.1.0
40
- * @version 0.1.0
64
+ * @version 0.1.3
41
65
  */
42
66
  FieldSchema.setProperty(function sub_fields() {
43
67
 
44
- if (this.schema) {
45
- return this.schema.getSorted();
68
+ let schema = this.schema;
69
+
70
+ if (schema) {
71
+
72
+ if (typeof schema != 'object') {
73
+ throw new Error('Expected a schema object, but found "' + typeof schema + '" instead');
74
+ }
75
+
76
+ if (schema) {
77
+ return schema.getSorted();
78
+ }
46
79
  }
47
80
 
48
81
  return [];
@@ -73,56 +106,87 @@ FieldSchema.setProperty(function value() {
73
106
  throw new Error('Unable to set value of schema field');
74
107
  });
75
108
 
76
- return;
109
+ /**
110
+ * Get the optional field that is supplying the schema
111
+ *
112
+ * @author Jelle De Loecker <jelle@elevenways.be>
113
+ * @since 0.1.3
114
+ * @version 0.1.3
115
+ */
116
+ FieldSchema.setMethod(function getSchemaSupplierField() {
77
117
 
118
+ if (!this.alchemy_field || !this.alchemy_field.config || !this.alchemy_field.config.options) {
119
+ return;
120
+ }
78
121
 
122
+ let schema = this.alchemy_field.config.options.schema;
79
123
 
124
+ if (typeof schema == 'string') {
125
+ let other_field_path = this.resolvePath(schema);
80
126
 
127
+ schema = null;
128
+
129
+ let form = this.alchemy_field.alchemy_form;
81
130
 
131
+ if (form) {
132
+ return form.findFieldByPath(other_field_path);
133
+ }
134
+ }
135
+ });
82
136
 
83
137
  /**
84
138
  * Added to the DOM for the first time
85
139
  *
86
140
  * @author Jelle De Loecker <jelle@elevenways.be>
87
- * @since 0.1.0
88
- * @version 0.1.0
141
+ * @since 0.1.3
142
+ * @version 0.1.3
89
143
  */
90
- FieldArray.setMethod(function introduced() {
91
-
92
- const that = this;
93
-
94
- this.onEventSelector('click', '.remove', function onClick(e) {
95
-
96
- e.preventDefault();
144
+ FieldSchema.setMethod(function introduced() {
97
145
 
98
- let entry = e.target.queryUp('alchemy-field-array-entry');
146
+ let supplier_field = this.getSchemaSupplierField();
99
147
 
100
- entry.remove();
101
- });
148
+ if (supplier_field) {
149
+ supplier_field.addEventListener('change', e => {
150
+ this.rerender();
151
+ });
102
152
 
103
- let add_entry = this.querySelector('.add-entry');
153
+ this.rerender();
154
+ }
155
+ });
104
156
 
105
- if (add_entry) {
106
- add_entry.addEventListener('click', function onClick(e) {
157
+ /**
158
+ * Get the original value
159
+ *
160
+ * @author Jelle De Loecker <jelle@elevenways.be>
161
+ * @since 0.1.4
162
+ * @version 0.1.4
163
+ */
164
+ FieldSchema.setProperty(function original_value() {
107
165
 
108
- let field_context = that.field_context,
109
- alchemy_field = that.alchemy_field;
166
+ let field = this.alchemy_field,
167
+ path = this.field_path_in_record;
110
168
 
111
- e.preventDefault();
169
+ if (field && path) {
170
+ let form = field.alchemy_form || this.alchemy_form || this.field_context.alchemy_form;
112
171
 
113
- let view_files = alchemy_field.view_files;
172
+ if (form) {
173
+ return Object.path(form.document, path);
174
+ }
175
+ }
114
176
 
115
- if (!view_files || !view_files.length) {
116
- throw new Error('Unable to add new entry for ' + alchemy_field.field_title);
117
- }
177
+ let context = this.field_context.alchemy_field_schema,
178
+ data;
118
179
 
119
- let new_entry = that.createElement('alchemy-field-array-entry');
180
+ if (context) {
181
+ data = context.original_value;
182
+ } else {
183
+ context = this.field_context.alchemy_form || this.alchemy_field.alchemy_form;
184
+ data = context.document;
185
+ }
120
186
 
121
- new_entry.alchemy_field_array = that;
187
+ path = this.field_path_in_current_schema;
122
188
 
123
- that.entries_element.append(new_entry);
124
- });
125
- }
189
+ let result = Object.path(data, path);
126
190
 
191
+ return result;
127
192
  });
128
-
@@ -5,18 +5,7 @@
5
5
  * @since 0.1.0
6
6
  * @version 0.1.0
7
7
  */
8
- var Form = Function.inherits('Alchemy.Element.Form.Base', function Form() {
9
- Form.super.call(this);
10
- });
11
-
12
- /**
13
- * The stylesheet to load for this element
14
- *
15
- * @author Jelle De Loecker <jelle@develry.be>
16
- * @since 0.1.0
17
- * @version 0.1.0
18
- */
19
- Form.setStylesheetFile('form/form');
8
+ var Form = Function.inherits('Alchemy.Element.Form.Base', 'Form');
20
9
 
21
10
  /**
22
11
  * The stylesheet to load for this element
@@ -108,7 +97,7 @@ Form.setProperty(function main_error_area() {
108
97
  *
109
98
  * @author Jelle De Loecker <jelle@elevenways.be>
110
99
  * @since 0.1.0
111
- * @version 0.1.0
100
+ * @version 0.1.2
112
101
  */
113
102
  Form.setProperty(function value() {
114
103
 
@@ -125,6 +114,10 @@ Form.setProperty(function value() {
125
114
  for (i = 0; i < fields.length; i++) {
126
115
  field = fields[i];
127
116
 
117
+ if (field && field.readonly) {
118
+ continue;
119
+ }
120
+
128
121
  result[field.field_name] = field.value;
129
122
  }
130
123
 
@@ -30,7 +30,7 @@ AlchemyLabel.setAttribute('for');
30
30
  *
31
31
  * @author Jelle De Loecker <jelle@elevenways.be>
32
32
  * @since 0.1.0
33
- * @version 0.1.0
33
+ * @version 0.1.3
34
34
  */
35
35
  AlchemyLabel.setMethod(function introduced() {
36
36
 
@@ -46,8 +46,14 @@ AlchemyLabel.setMethod(function introduced() {
46
46
  return;
47
47
  }
48
48
 
49
- element.click();
49
+ try {
50
+ // Trigger a click (for buttons & checkboxes)
51
+ element.click();
50
52
 
53
+ // Focus on the element (for inputs)
54
+ element.focus();
55
+ } catch (err) {
56
+ console.error('Failed to focus element:', err);
57
+ }
51
58
  });
52
-
53
59
  });
@@ -244,12 +244,16 @@ AlchemySelect.setProperty(function loaded_items() {
244
244
  *
245
245
  * @author Jelle De Loecker <jelle@develry.be>
246
246
  * @since 0.1.0
247
- * @version 0.1.0
247
+ * @version 0.1.4
248
248
  *
249
249
  * @type {Number}
250
250
  */
251
251
  AlchemySelect.setProperty(function loaded_item_count() {
252
- return Object.size(this.options.values);
252
+ if (this.options.values) {
253
+ return this.options.values.size;
254
+ } else {
255
+ return 0;
256
+ }
253
257
  });
254
258
 
255
259
  /**
@@ -403,6 +407,7 @@ AlchemySelect.setMethod(function introduced() {
403
407
  const that = this;
404
408
 
405
409
  this._initAttributes();
410
+ this.enableFocusWithinEvent();
406
411
 
407
412
  if (this.sortable) {
408
413
  this.makeSortable();
@@ -417,6 +422,13 @@ AlchemySelect.setMethod(function introduced() {
417
422
  });
418
423
  }
419
424
 
425
+ this.addEventListener('focus-without', function onFocusOut(e) {
426
+ that.type_area.value = '';
427
+ that.refitTypeArea(e);
428
+ that.applyLocalFilter();
429
+ that.close();
430
+ });
431
+
420
432
  // Give the type area focus when clicking on the wrapper
421
433
  this.wrapper.addEventListener('click', function onClick(e) {
422
434
  that.open();
@@ -430,24 +442,26 @@ AlchemySelect.setMethod(function introduced() {
430
442
 
431
443
  this.addEventListener('keydown', function onKeydown(e) {
432
444
 
445
+ console.log('keydown:', e);
446
+
433
447
  // Only listen for keydowns on the alchemy-select itself
434
448
  if (e.target != that) {
435
449
  return;
436
450
  }
437
451
 
438
- if (e.key == 'Space' || e.key == 'Enter') {
452
+ if (e.code == 'Space' || e.code == 'Enter') {
439
453
  that.open(e);
440
- } else if (e.key == 'Escape') {
454
+ } else if (e.code == 'Escape') {
441
455
  that.close(e);
442
456
  }
443
457
  });
444
458
 
445
459
  this.dropdown_content.addEventListener('keydown', function onKeydown(e) {
446
- if (e.key == 'ArrowUp' || e.key == 'ArrowDown') {
460
+ if (e.code == 'ArrowUp' || e.code == 'ArrowDown') {
447
461
  that.handleArrowKey(e);
448
- } else if (e.key == 'Escape') {
462
+ } else if (e.code == 'Escape') {
449
463
  that.close(e);
450
- } else if (e.key == 'Enter') {
464
+ } else if (e.code == 'Enter') {
451
465
  that.selectFocusedElement(e);
452
466
  }
453
467
  });
@@ -756,7 +770,7 @@ AlchemySelect.setMethod(function _ensureValueData(value) {
756
770
  *
757
771
  * @author Jelle De Loecker <jelle@develry.be>
758
772
  * @since 0.1.0
759
- * @version 0.1.0
773
+ * @version 0.1.4
760
774
  */
761
775
  AlchemySelect.setMethod(function _processPreloadedValues() {
762
776
 
@@ -774,9 +788,14 @@ AlchemySelect.setMethod(function _processPreloadedValues() {
774
788
  let item,
775
789
  key;
776
790
 
777
- for (key in values) {
791
+ let enum_values = new Classes.Alchemy.Map.Enum(values),
792
+ value;
793
+
794
+ for (let key of enum_values.keys()) {
795
+ value = enum_values.get(key);
796
+
778
797
  response.available++;
779
- item = Object.assign({}, values[key]);
798
+ item = Object.assign({}, value);
780
799
  item.id = key;
781
800
 
782
801
  response.items.push(item);
@@ -905,7 +924,7 @@ AlchemySelect.setMethod(function _loadRemote(config) {
905
924
  *
906
925
  * @author Jelle De Loecker <jelle@develry.be>
907
926
  * @since 0.1.0
908
- * @version 0.1.0
927
+ * @version 0.1.4
909
928
  */
910
929
  AlchemySelect.setMethod(function recreateDropdownElements() {
911
930
 
@@ -915,8 +934,8 @@ AlchemySelect.setMethod(function recreateDropdownElements() {
915
934
 
916
935
  Hawkejs.removeChildren(this.dropdown_content);
917
936
 
918
- for (key in items) {
919
- item = items[key];
937
+ for (let key of items.keys()) {
938
+ item = items.get(key);
920
939
  item = this._makeOption(item.id, item);
921
940
  this.addToDropdown(item);
922
941
  }
@@ -1123,6 +1142,7 @@ AlchemySelect.setMethod(function open(event) {
1123
1142
  * @param {Event} event The optional event
1124
1143
  */
1125
1144
  AlchemySelect.setMethod(function close(event) {
1145
+ this.removeAttribute('aria-activedescendant');
1126
1146
  this.setAttribute('aria-expanded', 'false');
1127
1147
  this.type_area.setAttribute('aria-expanded', 'false');
1128
1148
  this.type_area.setAttribute('tabindex', '-1');
@@ -1130,7 +1150,7 @@ AlchemySelect.setMethod(function close(event) {
1130
1150
  this.classList.remove('open');
1131
1151
  this.emit('close');
1132
1152
 
1133
- if (event === true || (event && event.key == 'Escape')) {
1153
+ if (event === true || (event && event.code == 'Escape')) {
1134
1154
  this.focus();
1135
1155
  this.result_info.textContent = 'Gesloten';
1136
1156
  }
@@ -1146,7 +1166,7 @@ AlchemySelect.setMethod(function close(event) {
1146
1166
  *
1147
1167
  * @author Jelle De Loecker <jelle@develry.be>
1148
1168
  * @since 0.1.0
1149
- * @version 0.1.0
1169
+ * @version 0.1.4
1150
1170
  *
1151
1171
  * @param {String} type "value" or "option"
1152
1172
  * @param {Mixed} value The actual value of this item
@@ -1177,7 +1197,11 @@ AlchemySelect.setMethod(function _makeValueItem(type, value, data) {
1177
1197
  this.options.values = {};
1178
1198
  }
1179
1199
 
1180
- this.options.values[value] = data;
1200
+ if (this.options.values instanceof Classes.Alchemy.Map.Enum) {
1201
+ this.options.values.set(value, data);
1202
+ } else {
1203
+ this.options.values[value] = data;
1204
+ }
1181
1205
  }
1182
1206
 
1183
1207
  // And the associated data
@@ -1196,8 +1220,12 @@ AlchemySelect.setMethod(function _makeValueItem(type, value, data) {
1196
1220
  return
1197
1221
  }
1198
1222
 
1199
- if (that.options.values && that.options.values[value]) {
1200
- data = that.options.values[value];
1223
+ if (that.options.values) {
1224
+ if (that.options.values instanceof Classes.Alchemy.Map.Enum) {
1225
+ data = that.options.values.get(value);
1226
+ } else if (that.options.values[value]) {
1227
+ data = that.options.values[value];
1228
+ }
1201
1229
  }
1202
1230
 
1203
1231
  this.data = data;
@@ -1303,7 +1331,7 @@ AlchemySelect.setMethod(function handleArrowKey(event) {
1303
1331
  this.open();
1304
1332
  }
1305
1333
 
1306
- if (event.key == 'ArrowUp') {
1334
+ if (event.code == 'ArrowUp') {
1307
1335
  direction = -1;
1308
1336
  } else {
1309
1337
  // Down
@@ -1391,18 +1419,27 @@ AlchemySelect.setMethod(function _focusOnOption(option_element) {
1391
1419
  option_element = this.dropdown_content.children[option_element];
1392
1420
  }
1393
1421
 
1422
+ this.setAttribute('aria-activedescendant', null);
1423
+
1394
1424
  for (i = 0; i < this.dropdown_content.children.length; i++) {
1395
1425
  element = this.dropdown_content.children[i];
1396
1426
 
1397
1427
  if (element == option_element) {
1398
1428
  element.classList.add('focused');
1399
- element.setAttribute('tabindex', 0);
1429
+ //element.setAttribute('tabindex', 0);
1400
1430
  this._selected_entry = element._entry;
1401
1431
  selected_index = i;
1402
- element.focus();
1432
+
1433
+ //element.focus();
1434
+
1435
+ if (!element.id) {
1436
+ element.id = this.hawkejs_view.getId();
1437
+ }
1438
+
1439
+ this.setAttribute('aria-activedescendant', element.id);
1403
1440
  } else {
1404
1441
  element.classList.remove('focused');
1405
- element.setAttribute('tabindex', '-1');
1442
+ //element.setAttribute('tabindex', '-1');
1406
1443
  }
1407
1444
  }
1408
1445
 
@@ -1507,7 +1544,7 @@ AlchemySelect.setMethod(function advanceCaret(direction) {
1507
1544
  */
1508
1545
  AlchemySelect.setMethod(function onTypeAreaKeydown(e, is_input) {
1509
1546
 
1510
- switch (e.key) {
1547
+ switch (e.code) {
1511
1548
  case 'ArrowUp':
1512
1549
  case 'ArrowDown':
1513
1550
  this.handleArrowKey(e);
@@ -1529,6 +1566,10 @@ AlchemySelect.setMethod(function onTypeAreaKeydown(e, is_input) {
1529
1566
  this.removeItem(this.type_area.previousSibling);
1530
1567
  break;
1531
1568
 
1569
+ case 'Enter':
1570
+ this.selectFocusedElement(e);
1571
+ break;
1572
+
1532
1573
  case 'Delete':
1533
1574
  if (this.type_area.value.length) {
1534
1575
  return;
@@ -1549,7 +1590,7 @@ AlchemySelect.setMethod(function onTypeAreaKeydown(e, is_input) {
1549
1590
  */
1550
1591
  AlchemySelect.setMethod(function onTypeAreaKeyup(e, is_input) {
1551
1592
 
1552
- switch (e.key) {
1593
+ switch (e.code) {
1553
1594
  case 'ArrowUp':
1554
1595
  case 'ArrowDown':
1555
1596
  case 'ArrowLeft':
@@ -1818,13 +1859,13 @@ AlchemySelect.setMethod(function measureString(str, element, event) {
1818
1859
  code === 32 // space
1819
1860
  );
1820
1861
 
1821
- if (event.key == 'Delete' || event.key == 'Backspace') {
1862
+ if (event.code == 'Delete' || event.code == 'Backspace') {
1822
1863
  selection = this._getSelection(this.type_area);
1823
1864
  if (selection.length) {
1824
1865
  str = str.substring(0, selection.start) + str.substring(selection.start + selection.length);
1825
- } else if (event.key == 'Backspace' && selection.start) {
1866
+ } else if (event.code == 'Backspace' && selection.start) {
1826
1867
  str = str.substring(0, selection.start - 1) + str.substring(selection.start);
1827
- } else if (event.key == 'Delete' && typeof selection.start !== 'undefined') {
1868
+ } else if (event.code == 'Delete' && typeof selection.start !== 'undefined') {
1828
1869
  str = str.substring(0, selection.start) + str.substring(selection.start + 1);
1829
1870
  }
1830
1871
  } else if (printable) {
@@ -126,6 +126,15 @@ Table.setAttribute('page-size', {number: true});
126
126
  */
127
127
  Table.setAttribute('show-filters', {boolean: true});
128
128
 
129
+ /**
130
+ * Keep track of the loadRemote calls
131
+ *
132
+ * @author Jelle De Loecker <jelle@elevenways.be>
133
+ * @since 0.1.3
134
+ * @version 0.1.3
135
+ */
136
+ Table.setProperty('load_remote_counter', 0);
137
+
129
138
  /**
130
139
  * Look for changes to the show-filters attribute
131
140
  *
@@ -834,7 +843,7 @@ Table.setMethod(function selectRow(row) {
834
843
  *
835
844
  * @author Jelle De Loecker <jelle@elevenways.be>
836
845
  * @since 0.1.0
837
- * @version 0.1.0
846
+ * @version 0.1.3
838
847
  */
839
848
  Table.setMethod(function loadRemoteData() {
840
849
 
@@ -859,14 +868,24 @@ Table.setMethod(function loadRemoteData() {
859
868
  body : body
860
869
  };
861
870
 
871
+ let load_remote_id = ++this.load_remote_counter;
872
+
862
873
  this.delayAssemble(async function() {
863
874
 
875
+ if (load_remote_id != that.load_remote_counter) {
876
+ return;
877
+ }
878
+
864
879
  let result = await that.getResource(options);
865
880
 
866
881
  if (!result) {
867
882
  return;
868
883
  }
869
884
 
885
+ if (load_remote_id != that.load_remote_counter) {
886
+ return;
887
+ }
888
+
870
889
  let records = result.records;
871
890
 
872
891
  that.records = records;
@@ -80,5 +80,20 @@ CodeInput.setMethod(async function introduced() {
80
80
  editor.session.setUseWrapMode(true);
81
81
  editor.setFontSize(16);
82
82
 
83
+ let parent_field = this.queryParents('alchemy-field');
84
+
85
+ if (parent_field && parent_field.widget_settings && parent_field.widget_settings.language_mode) {
86
+
87
+ let mode = parent_field.widget_settings.language_mode;
88
+
89
+ // Even though it correctly downloads the language mode file without it,
90
+ // it still requires the `ace/mode/` prefix
91
+ if (mode.indexOf('/') == -1) {
92
+ mode = 'ace/mode/' + mode;
93
+ }
94
+
95
+ editor.session.setMode(mode);
96
+ }
97
+
83
98
  this._editor = editor;
84
99
  });