alchemy-form 0.1.8 → 0.1.11

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,21 @@
1
+ ## 0.1.11 (2022-07-23)
2
+
3
+ * Upgrade to `alchemy-media` v0.6.3
4
+ * Add `purpose` and `mode` attributes to AlchemyForm-based elements for improved field-template getting
5
+ * Add first few `edit_inline` and `view_inline` field templates
6
+
7
+ ## 0.1.10 (2022-07-14)
8
+
9
+ * Hide `code-input` contents until it's fully loaded
10
+ * Don't crash when failing to get a field definition in a table
11
+
12
+ ## 0.1.9 (2022-07-06)
13
+
14
+ * Allow supplying a custom `data-src` to `alchemy-field` elements
15
+ * Add `view` templates for File & Datetime fields
16
+ * Use the new `alchemy.getClientModel()` method in `alchemy-field` element
17
+ * Add `alchemy-password-input` element
18
+
1
19
  ## 0.1.8 (2022-06-29)
2
20
 
3
21
  * Move the `alchemy-select` pagination checker initializer to a static function
@@ -1,3 +1,36 @@
1
1
  alchemy-field {
2
2
  display: block;
3
+
4
+ &[field-type="boolean"] {
5
+
6
+ .field {
7
+ display: flex;
8
+ justify-content: center;
9
+ }
10
+
11
+ .boolean-wrapper {
12
+ &.boolean-true {
13
+ --boolean-color: green;
14
+ --text-color: white;
15
+ }
16
+
17
+ &.boolean-false {
18
+ --boolean-color: red;
19
+ --text-color: white;
20
+ }
21
+
22
+ &.boolean-null {
23
+ --boolean-color: #f3f3f3;
24
+ --text-color: #666;
25
+ font-style: italic;
26
+ }
27
+
28
+ background-color: var(--boolean-color);
29
+ border-radius: 5px;
30
+ padding: 4px 8px;
31
+ min-width: 1rem;
32
+ color: var(--text-color, white);
33
+ display: inline-flex;
34
+ }
35
+ }
3
36
  }
@@ -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
 
@@ -5,9 +5,7 @@
5
5
  * @since 0.1.0
6
6
  * @version 0.1.0
7
7
  */
8
- var Base = Function.inherits('Alchemy.Element', 'Alchemy.Element.Form', function Base() {
9
- Base.super.call(this);
10
- });
8
+ var Base = Function.inherits('Alchemy.Element', 'Alchemy.Element.Form', 'Base');
11
9
 
12
10
  /**
13
11
  * Set the custom element prefix
@@ -59,27 +57,67 @@ Base.setStatic(function addParentTypeGetter(name, type) {
59
57
  });
60
58
 
61
59
  /**
62
- * The view-type determines which type of wrapper/field to use,
63
- * e.g.: view, list, edit, ...
60
+ * The purpose determines what the goal of the field is.
61
+ * Is it for editing or viewing?
64
62
  *
65
63
  * @author Jelle De Loecker <jelle@elevenways.be>
66
- * @since 0.1.0
67
- * @version 0.1.0
64
+ * @since 0.1.11
65
+ * @version 0.1.11
68
66
  */
69
- Base.setProperty(function view_type() {
67
+ Base.setAttribute('purpose', function getPurpose(value) {
68
+
69
+ if (value) {
70
+ return value;
71
+ }
70
72
 
71
- var value = this.getAttribute('view-type');
73
+ value = this.getAttribute('view-type');
72
74
 
73
75
  if (!value && this.alchemy_form) {
74
76
  value = this.alchemy_form.view_type;
75
77
  }
76
78
 
79
+ // Fallback to the "edit" type
77
80
  if (!value) {
78
81
  value = 'edit';
79
82
  }
80
83
 
81
84
  return value;
85
+ });
86
+
87
+ /**
88
+ * The mode is used as a hint to how this element should be rendered.
89
+ * Could be "inline", "standalone", ...
90
+ *
91
+ * @author Jelle De Loecker <jelle@elevenways.be>
92
+ * @since 0.1.11
93
+ * @version 0.1.11
94
+ */
95
+ Base.setAttribute('mode');
82
96
 
97
+ /**
98
+ * The view-type determines which type of wrapper/field to use,
99
+ * e.g.: view, list, edit, ...
100
+ *
101
+ * @deprecated You should use `purpose` for this
102
+ *
103
+ * @author Jelle De Loecker <jelle@elevenways.be>
104
+ * @since 0.1.0
105
+ * @version 0.1.11
106
+ */
107
+ Base.setProperty(function view_type() {
108
+
109
+ if (this.hasAttribute('view-type')) {
110
+ return this.getAttribute('view-type');
111
+ }
112
+
113
+ let purpose = this.purpose,
114
+ mode = this.mode;
115
+
116
+ if (mode) {
117
+ purpose += '_' + mode;
118
+ }
119
+
120
+ return purpose;
83
121
  }, function setViewType(value) {
84
122
 
85
123
  if (value == null) {
@@ -88,6 +126,7 @@ Base.setProperty(function view_type() {
88
126
  this.setAttribute('view-type', value);
89
127
  }
90
128
 
129
+ return value;
91
130
  });
92
131
 
93
132
  /**
@@ -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
  *
@@ -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
  }
@@ -345,60 +349,55 @@ Field.setProperty(function model() {
345
349
  });
346
350
 
347
351
  /**
348
- * Get the view to use for this field
352
+ * Get the preferred view file to use for this field
349
353
  *
350
354
  * @author Jelle De Loecker <jelle@elevenways.be>
351
355
  * @since 0.1.0
352
- * @version 0.1.0
356
+ * @version 0.1.11
353
357
  */
354
358
  Field.enforceProperty(function view_file(new_value, old_value) {
355
359
 
356
360
  if (!new_value) {
357
361
 
358
- let config = this.config,
359
- view_type = this.view_type;
362
+ let view_type = this.view_type,
363
+ field_view = this.field_view || this.field_type;
364
+
365
+ if (!field_view) {
366
+ let config = this.config;
360
367
 
361
- if (config) {
362
-
363
- let field_view;
364
-
365
- if (this.field_view) {
366
- field_view = this.field_view;
367
- } else {
368
+ if (config) {
368
369
  field_view = config.constructor.type_name;
369
370
  }
370
-
371
- new_value = 'form/inputs/' + view_type + '/' + field_view;
372
371
  }
372
+
373
+ new_value = this.generateTemplatePath('inputs', view_type, field_view);
373
374
  }
374
375
 
375
376
  return new_value;
376
377
  });
377
378
 
378
-
379
379
  /**
380
- * Get the wrapper to use for this field
380
+ * Get the preferred wrapper to use for this field
381
381
  *
382
382
  * @author Jelle De Loecker <jelle@elevenways.be>
383
383
  * @since 0.1.0
384
- * @version 0.1.0
384
+ * @version 0.1.11
385
385
  */
386
386
  Field.enforceProperty(function wrapper_file(new_value, old_value) {
387
387
 
388
388
  if (!new_value) {
389
389
 
390
- let config = this.config,
391
- view_type = this.view_type;
392
-
393
390
  let wrapper_type = this.wrapper_type;
394
391
 
395
392
  if (wrapper_type === false) {
396
393
  return false;
397
394
  }
398
395
 
399
- if (config) {
400
- let field_type = config.constructor.type_name;
401
- return 'form/wrappers/' + view_type + '/' + field_type;
396
+ let field_type = this.getFieldType(),
397
+ view_type = this.view_type;
398
+
399
+ if (field_type) {
400
+ return this.generateTemplatePath('wrappers', view_type, field_type);
402
401
  }
403
402
  }
404
403
 
@@ -410,7 +409,7 @@ Field.enforceProperty(function wrapper_file(new_value, old_value) {
410
409
  *
411
410
  * @author Jelle De Loecker <jelle@elevenways.be>
412
411
  * @since 0.1.0
413
- * @version 0.1.0
412
+ * @version 0.1.11
414
413
  */
415
414
  Field.setProperty(function view_files() {
416
415
 
@@ -421,14 +420,20 @@ Field.setProperty(function view_files() {
421
420
  result.push(view_file);
422
421
  }
423
422
 
424
- let config = this.config,
423
+ let field_type = this.getFieldType(),
425
424
  view_type = this.view_type;
426
425
 
427
- if (config) {
428
- let field_type = config.constructor.type_name,
429
- view = 'form/inputs/' + view_type + '/' + field_type;
430
-
426
+ if (field_type) {
427
+ let view = this.generateTemplatePath('inputs', view_type, field_type);
428
+
431
429
  result.push(view);
430
+
431
+ let purpose = this.purpose;
432
+
433
+ if (purpose) {
434
+ view = this.generateTemplatePath('inputs', purpose, field_type);
435
+ result.push(view);
436
+ }
432
437
  }
433
438
 
434
439
  if (result.length == 0) {
@@ -436,7 +441,7 @@ Field.setProperty(function view_files() {
436
441
  }
437
442
 
438
443
  // Fallback to a simple string input
439
- result.push('form/inputs/' + view_type + '/string');
444
+ result.push(this.generateTemplatePath('inputs', view_type, 'string'));
440
445
 
441
446
  return result;
442
447
  });
@@ -446,7 +451,7 @@ Field.setProperty(function view_files() {
446
451
  *
447
452
  * @author Jelle De Loecker <jelle@elevenways.be>
448
453
  * @since 0.1.0
449
- * @version 0.1.0
454
+ * @version 0.1.11
450
455
  */
451
456
  Field.setProperty(function wrapper_files() {
452
457
 
@@ -462,22 +467,21 @@ Field.setProperty(function wrapper_files() {
462
467
  result.push(wrapper_file);
463
468
  }
464
469
 
465
- let config = this.config,
470
+ let field_type = this.getFieldType(),
466
471
  view_type = this.view_type;
467
472
 
468
- if (config) {
469
- let field_type = config.constructor.type_name,
470
- view = 'form/wrappers/' + view_type + '/' + field_type;
473
+ if (field_type) {
474
+ let view = this.generateTemplatePath('wrappers', view_type, field_type);
471
475
 
472
476
  result.push(view);
473
477
 
474
- view = 'form/wrappers/' + view_type + '/default';
478
+ view = this.generateTemplatePath('wrappers', view_type, 'default');
475
479
  result.push(view);
476
480
 
477
- view = 'form/wrappers/default/' + field_type;
481
+ view = this.generateTemplatePath('wrappers', 'default', field_type);
478
482
  result.push(view);
479
483
 
480
- view = 'form/wrappers/default/default';
484
+ view = this.generateTemplatePath('wrappers', 'default', 'default');
481
485
  result.push(view);
482
486
  }
483
487
 
@@ -580,6 +584,48 @@ Field.setProperty(function value() {
580
584
  }
581
585
  });
582
586
 
587
+ /**
588
+ * Get the field type
589
+ *
590
+ * @author Jelle De Loecker <jelle@elevenways.be>
591
+ * @since 0.1.11
592
+ * @version 0.1.11
593
+ *
594
+ * @return {String}
595
+ */
596
+ Field.setMethod(function getFieldType() {
597
+
598
+ let result = this.field_type;
599
+
600
+ if (!result) {
601
+ let config = this.config;
602
+
603
+ if (config) {
604
+ result = config.constructor.type_name;
605
+ }
606
+ }
607
+
608
+ return result;
609
+ });
610
+
611
+ /**
612
+ * Generate a template path
613
+ *
614
+ * @author Jelle De Loecker <jelle@elevenways.be>
615
+ * @since 0.1.11
616
+ * @version 0.1.11
617
+ *
618
+ * @param {String} container_type The container (inputs/wrappers)
619
+ * @param {String} view_type The view (edit/view/edit_inline/...)
620
+ * @param {String} field_type The name of the field (and thus the view)
621
+ *
622
+ * @return {String}
623
+ */
624
+ Field.setMethod(function generateTemplatePath(container_type, view_type, field_type) {
625
+ let result = 'form/' + container_type + '/' + view_type + '/' + field_type;
626
+ return result;
627
+ });
628
+
583
629
  /**
584
630
  * Get the rule violations for this field
585
631
  *
@@ -715,7 +761,7 @@ Field.setMethod(function retained() {
715
761
  *
716
762
  * @author Jelle De Loecker <jelle@elevenways.be>
717
763
  * @since 0.1.0
718
- * @version 0.1.6
764
+ * @version 0.1.9
719
765
  *
720
766
  * @param {Object} config
721
767
  * @param {HTMLElement} element
@@ -742,7 +788,7 @@ Field.setMethod(async function loadData(config, element) {
742
788
  }
743
789
  }
744
790
 
745
- return this.hawkejs_helpers.Alchemy.getResource({
791
+ let resource_options = {
746
792
  name : 'FormApi#related',
747
793
  post : true,
748
794
  body : {
@@ -751,7 +797,13 @@ Field.setMethod(async function loadData(config, element) {
751
797
  assoc_model : field.options.modelName,
752
798
  config : config,
753
799
  }
754
- });
800
+ };
801
+
802
+ if (this.data_src) {
803
+ resource_options.name = this.data_src;
804
+ }
805
+
806
+ return this.hawkejs_helpers.Alchemy.getResource(resource_options);
755
807
  }
756
808
 
757
809
  });
@@ -86,7 +86,7 @@ FieldArray.setMethod(function introduced() {
86
86
  let view_files = alchemy_field.view_files;
87
87
 
88
88
  if (!view_files || !view_files.length) {
89
- throw new Error('Unable to add new entry for ' + alchemy_field.field_title);
89
+ throw new Error('Unable to add new entry for field "' + alchemy_field.field_title + '", no view files found');
90
90
  }
91
91
 
92
92
  let new_entry = that.createElement('alchemy-field-array-entry');
@@ -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
+ });
@@ -25,7 +25,7 @@ Table.setTemplate(`<header class="aft-header"></header>
25
25
  <tfoot></tfoot>
26
26
  </table>
27
27
  </div>
28
- <footer class="aft-footer"></footer>`, {plain_html: true, render_immediate: true});
28
+ <footer data-he-slot="footer" class="aft-footer"></footer>`, {plain_html: true, render_immediate: true});
29
29
 
30
30
  /**
31
31
  * The stylesheet to load for this element
@@ -126,6 +126,15 @@ Table.setAttribute('page-size', {number: true});
126
126
  */
127
127
  Table.setAttribute('show-filters', {boolean: true});
128
128
 
129
+ /**
130
+ * Which optional view-type to use for field values
131
+ *
132
+ * @author Jelle De Loecker <jelle@elevenways.be>
133
+ * @since 0.1.11
134
+ * @version 0.1.11
135
+ */
136
+ Table.setAttribute('view-type');
137
+
129
138
  /**
130
139
  * Keep track of the loadRemote calls
131
140
  *
@@ -287,7 +296,7 @@ Table.addObservedAttribute('src', function onSource(src) {
287
296
  *
288
297
  * @author Jelle De Loecker <jelle@elevenways.be>
289
298
  * @since 0.1.0
290
- * @version 0.1.0
299
+ * @version 0.1.11
291
300
  *
292
301
  * @param {*} config
293
302
  */
@@ -302,7 +311,11 @@ Table.setMethod(function setRecordsource(config) {
302
311
  }
303
312
 
304
313
  if (url == '#') {
305
- url = ''+this.getCurrentUrl();
314
+ let current_url = this.getCurrentUrl();
315
+
316
+ if (current_url) {
317
+ url = ''+current_url;
318
+ }
306
319
  }
307
320
 
308
321
  this.src = url;
@@ -350,7 +363,7 @@ Table.setMethod(function clearBody() {
350
363
  *
351
364
  * @author Jelle De Loecker <jelle@elevenways.be>
352
365
  * @since 0.1.0
353
- * @version 0.1.0
366
+ * @version 0.1.11
354
367
  *
355
368
  * @return {Number}
356
369
  */
@@ -365,14 +378,17 @@ Table.setMethod(function getWantedPage() {
365
378
  if (this.id) {
366
379
  let url = this.getCurrentUrl();
367
380
 
368
- let data = url.param('aft');
381
+ if (url) {
369
382
 
370
- if (data && data[this.id]) {
371
- page = parseInt(data[this.id].page);
372
- }
383
+ let data = url.param('aft');
384
+
385
+ if (data && data[this.id]) {
386
+ page = parseInt(data[this.id].page);
387
+ }
373
388
 
374
- if (isFinite(page) && page > 0) {
375
- return page;
389
+ if (isFinite(page) && page > 0) {
390
+ return page;
391
+ }
376
392
  }
377
393
  }
378
394
 
@@ -384,7 +400,7 @@ Table.setMethod(function getWantedPage() {
384
400
  *
385
401
  * @author Jelle De Loecker <jelle@elevenways.be>
386
402
  * @since 0.1.0
387
- * @version 0.1.0
403
+ * @version 0.1.11
388
404
  *
389
405
  * @return {Number}
390
406
  */
@@ -405,11 +421,11 @@ Table.setMethod(function getWantedSort() {
405
421
  let url_param = this.getBaseUrlParam() + '[sort]',
406
422
  url = this.getCurrentUrl();
407
423
 
408
- if (!result.field) {
424
+ if (!result.field && url) {
409
425
  result.field = url.param(url_param + '[field]');
410
426
  }
411
427
 
412
- if (!result.dir) {
428
+ if (!result.dir && url) {
413
429
  result.dir = url.param(url_param + '[dir]');
414
430
  }
415
431
 
@@ -424,7 +440,7 @@ Table.setMethod(function getWantedSort() {
424
440
  *
425
441
  * @author Jelle De Loecker <jelle@elevenways.be>
426
442
  * @since 0.1.0
427
- * @version 0.1.0
443
+ * @version 0.1.11
428
444
  *
429
445
  * @return {Object}
430
446
  */
@@ -433,6 +449,11 @@ Table.setMethod(function getWantedFilters() {
433
449
  if (!this.filters) {
434
450
 
435
451
  let url = this.getCurrentUrl();
452
+
453
+ if (!url) {
454
+ return null;
455
+ }
456
+
436
457
  let data = url.param('aft');
437
458
  let filters;
438
459
 
@@ -486,15 +507,20 @@ Table.setMethod(function getBaseUrlParam() {
486
507
  *
487
508
  * @author Jelle De Loecker <jelle@elevenways.be>
488
509
  * @since 0.1.0
489
- * @version 0.1.0
510
+ * @version 0.1.11
490
511
  *
491
512
  * @return {RURL}
492
513
  */
493
514
  Table.setMethod(function getCurrentStateUrl() {
494
515
 
516
+ let url = this.getCurrentUrl();
517
+
518
+ if (!url) {
519
+ return null;
520
+ }
521
+
495
522
  let url_param = this.getBaseUrlParam(),
496
- page = this.getWantedPage(),
497
- url = this.getCurrentUrl();
523
+ page = this.getWantedPage();
498
524
 
499
525
  url.param(url_param + '[page]', page);
500
526
 
@@ -513,7 +539,7 @@ Table.setMethod(function getCurrentStateUrl() {
513
539
  *
514
540
  * @author Jelle De Loecker <jelle@elevenways.be>
515
541
  * @since 0.1.0
516
- * @version 0.1.6
542
+ * @version 0.1.11
517
543
  *
518
544
  * @param {Array} records
519
545
  */
@@ -526,7 +552,7 @@ Table.setMethod(function setRecords(records) {
526
552
  let record;
527
553
 
528
554
  for (record of records) {
529
- this.table_body.append(this.createDataRow(record));
555
+ this.addDataRow(record);
530
556
  }
531
557
 
532
558
  this.showPagination();
@@ -565,7 +591,7 @@ Table.setMethod(function setFilter(field, value) {
565
591
  *
566
592
  * @author Jelle De Loecker <jelle@elevenways.be>
567
593
  * @since 0.1.0
568
- * @version 0.1.0
594
+ * @version 0.1.11
569
595
  */
570
596
  Table.setMethod(function showPagination() {
571
597
 
@@ -575,6 +601,12 @@ Table.setMethod(function showPagination() {
575
601
  return;
576
602
  }
577
603
 
604
+ let url = this.getCurrentUrl();
605
+
606
+ if (!url) {
607
+ return;
608
+ }
609
+
578
610
  let pager = this.querySelector('alchemy-pager');
579
611
 
580
612
  if (!pager) {
@@ -582,7 +614,7 @@ Table.setMethod(function showPagination() {
582
614
  this.footer.append(pager);
583
615
  }
584
616
 
585
- pager.src = this.getCurrentUrl();
617
+ pager.src = url;
586
618
  pager.url_param = this.getBaseUrlParam();
587
619
  pager.page_size = records.page_size;
588
620
 
@@ -594,7 +626,7 @@ Table.setMethod(function showPagination() {
594
626
  *
595
627
  * @author Jelle De Loecker <jelle@elevenways.be>
596
628
  * @since 0.1.8
597
- * @version 0.1.8
629
+ * @version 0.1.11
598
630
  *
599
631
  * @param {FieldConfig} field_config The config on how to display the field
600
632
  * @param {Object} container The container where the field should be in
@@ -603,8 +635,18 @@ Table.setMethod(function showPagination() {
603
635
  */
604
636
  Table.setMethod(function getFieldConfigView(field_config, container) {
605
637
 
638
+ if (typeof field_config == 'string') {
639
+ field_config = this.fieldset.get(field_config);
640
+ }
641
+
606
642
  let value = field_config.getValueIn(container),
607
- field = field_config.getFieldDefinition();
643
+ field;
644
+
645
+ try {
646
+ field = field_config.getFieldDefinition();
647
+ } catch (err) {
648
+ console.error('Failed to get field definition:', err);
649
+ }
608
650
 
609
651
  if (value == null && !field) {
610
652
  return null;
@@ -618,7 +660,10 @@ Table.setMethod(function getFieldConfigView(field_config, container) {
618
660
  }
619
661
 
620
662
  let alchemy_field = this.createElement('alchemy-field');
621
- alchemy_field.view_type = 'view_inline';
663
+ alchemy_field.purpose = this.purpose || 'view';
664
+ alchemy_field.mode = this.mode || 'inline';
665
+
666
+ //alchemy_field.view_type = this.view_type || 'view_inline';
622
667
  alchemy_field.field_name = field.name;
623
668
  alchemy_field.config = field;
624
669
  alchemy_field.original_value = value;
@@ -626,6 +671,34 @@ Table.setMethod(function getFieldConfigView(field_config, container) {
626
671
  return alchemy_field;
627
672
  });
628
673
 
674
+ /**
675
+ * Create and add a datarow
676
+ *
677
+ * @author Jelle De Loecker <jelle@elevenways.be>
678
+ * @since 0.1.11
679
+ * @version 0.1.11
680
+ *
681
+ * @param {Object} entry
682
+ *
683
+ * @return <TR>
684
+ */
685
+ Table.setMethod(function addDataRow(entry) {
686
+
687
+ if (!entry) {
688
+ entry = {};
689
+ }
690
+
691
+ let tr = this.createDataRow(entry);
692
+
693
+ if (!tr) {
694
+ return;
695
+ }
696
+
697
+ this.table_body.append(tr);
698
+
699
+ return tr;
700
+ });
701
+
629
702
  /**
630
703
  * Create a datarow
631
704
  *
@@ -639,13 +712,19 @@ Table.setMethod(function getFieldConfigView(field_config, container) {
639
712
  */
640
713
  Table.setMethod(function createDataRow(entry) {
641
714
 
715
+ if (!entry) {
716
+ throw new Error('Unable to create datarow without data');
717
+ }
718
+
642
719
  let field_set_config,
643
720
  value,
644
721
  tr = this.createElement('tr'),
645
722
  td,
646
723
  id = entry.$pk || entry._id || entry.id;
647
724
 
648
- tr.dataset.pk = id;
725
+ if (id) {
726
+ tr.dataset.pk = id;
727
+ }
649
728
 
650
729
  for (field_set_config of this.fieldset) {
651
730
  td = this.createElement('td');
@@ -893,7 +972,7 @@ Table.setMethod(function onFieldsetAssignment(value, old_value) {
893
972
  *
894
973
  * @author Jelle De Loecker <jelle@elevenways.be>
895
974
  * @since 0.1.0
896
- * @version 0.1.0
975
+ * @version 0.1.11
897
976
  *
898
977
  * @param {String|RURL} base_url
899
978
  */
@@ -905,6 +984,10 @@ Table.setMethod(function updateAnchors(base_url) {
905
984
  base_url = RURL.parse(base_url);
906
985
  }
907
986
 
987
+ if (!base_url) {
988
+ return;
989
+ }
990
+
908
991
  let anchors = this.querySelectorAll('a.sorting-anchor'),
909
992
  anchor,
910
993
  url,
@@ -963,7 +1046,7 @@ Table.setMethod(function onRecordsAssignment(value, old_value) {
963
1046
  *
964
1047
  * @author Jelle De Loecker <jelle@elevenways.be>
965
1048
  * @since 0.1.0
966
- * @version 0.1.0
1049
+ * @version 0.1.11
967
1050
  *
968
1051
  * @param <TR>
969
1052
  */
@@ -979,7 +1062,9 @@ Table.setMethod(function selectRow(row) {
979
1062
  child.classList.remove('aft-selected');
980
1063
  }
981
1064
 
982
- row.classList.add('aft-selected');
1065
+ if (row) {
1066
+ row.classList.add('aft-selected');
1067
+ }
983
1068
  });
984
1069
 
985
1070
  /**
@@ -67,7 +67,7 @@ CodeInput.setProperty(function value(value) {
67
67
  *
68
68
  * @author Jelle De Loecker <jelle@elevenways.be>
69
69
  * @since 0.1.0
70
- * @version 0.1.0
70
+ * @version 0.1.10
71
71
  */
72
72
  CodeInput.setMethod(async function introduced() {
73
73
 
@@ -75,6 +75,8 @@ CodeInput.setMethod(async function introduced() {
75
75
 
76
76
  let editor_el = this.querySelector('.code-editor');
77
77
 
78
+ editor_el.hidden = false;
79
+
78
80
  let editor = ace.edit(editor_el);
79
81
 
80
82
  editor.session.setUseWrapMode(true);
@@ -121,7 +121,7 @@ QueryBuilderValue.setProperty(function value() {
121
121
 
122
122
  return result;
123
123
  }, function setValue(value) {
124
- this.assigned_data.value = value;
124
+ this.assignData('value', value);
125
125
  });
126
126
 
127
127
  /**
@@ -23,7 +23,7 @@ UrlAction.addConfigProperty('url');
23
23
  *
24
24
  * @author Jelle De Loecker <jelle@elevenways.be>
25
25
  * @since 0.1.6
26
- * @version 0.1.6
26
+ * @version 0.1.11
27
27
  *
28
28
  * @return {HTMLElement}
29
29
  */
@@ -35,7 +35,7 @@ UrlAction.setMethod(function _constructElement(renderer) {
35
35
 
36
36
  if (this.icon) {
37
37
  let alico = renderer.createElement('al-ico');
38
- alico.setAttribute('type', this.icon);
38
+ alico.setIcon(this.icon);
39
39
  anchor.append(alico);
40
40
  } else {
41
41
  anchor.textContent = this.title || this.name;
@@ -73,7 +73,7 @@ AlchemyField.enforceProperty(function alchemy_form(new_value) {
73
73
  *
74
74
  * @author Jelle De Loecker <jelle@elevenways.be>
75
75
  * @since 0.1.0
76
- * @version 0.1.4
76
+ * @version 0.1.11
77
77
  */
78
78
  AlchemyField.setMethod(function populateWidget() {
79
79
 
@@ -89,6 +89,14 @@ AlchemyField.setMethod(function populateWidget() {
89
89
 
90
90
  field_el.field_name = config.field;
91
91
 
92
+ if (config.purpose) {
93
+ field_el.purpose = config.purpose;
94
+ }
95
+
96
+ if (config.mode) {
97
+ field_el.mode = config.mode;
98
+ }
99
+
92
100
  if (config.view) {
93
101
  field_el.field_view = config.view;
94
102
  }
@@ -101,6 +109,10 @@ AlchemyField.setMethod(function populateWidget() {
101
109
  field_el.widget_settings = config.widget_settings;
102
110
  }
103
111
 
112
+ if (config.data_src) {
113
+ field_el.data_src = config.data_src;
114
+ }
115
+
104
116
  this.element.append(field_el);
105
117
  });
106
118
 
@@ -16,7 +16,7 @@ const AlchemyForm = Function.inherits('Alchemy.Widget', 'AlchemyForm');
16
16
  *
17
17
  * @author Jelle De Loecker <jelle@elevenways.be>
18
18
  * @since 0.1.0
19
- * @version 0.1.4
19
+ * @version 0.1.11
20
20
  */
21
21
  AlchemyForm.setMethod(function populateWidget() {
22
22
 
@@ -30,6 +30,14 @@ AlchemyForm.setMethod(function populateWidget() {
30
30
 
31
31
  form.classList.add('alchemy-widgets-container');
32
32
 
33
+ if (config.purpose) {
34
+ form.purpose = config.purpose;
35
+ }
36
+
37
+ if (config.mode) {
38
+ form.mode = config.mode;
39
+ }
40
+
33
41
  if (this.config && this.config.widgets) {
34
42
  let widgets = this.config.widgets.slice(0),
35
43
  widget,
@@ -59,7 +67,9 @@ AlchemyForm.setMethod(function populateWidget() {
59
67
  form.model = config.model;
60
68
  }
61
69
 
62
- form.view_type = config.view_type || 'edit';
70
+ if (config.view_type) {
71
+ form.view_type = config.view_type;
72
+ }
63
73
 
64
74
  form.append(col.widget);
65
75
 
@@ -16,7 +16,7 @@ const AlchemyTable = Function.inherits('Alchemy.Widget', 'AlchemyTable');
16
16
  *
17
17
  * @author Jelle De Loecker <jelle@elevenways.be>
18
18
  * @since 0.1.0
19
- * @version 0.1.0
19
+ * @version 0.1.8
20
20
  */
21
21
  AlchemyTable.setMethod(function populateWidget() {
22
22
 
@@ -46,5 +46,8 @@ AlchemyTable.setMethod(function populateWidget() {
46
46
  table.recordsource = config.recordsource;
47
47
  }
48
48
 
49
+ table.purpose = config.purpose || 'view';
50
+ table.mode = config.mode || 'inline';
51
+
49
52
  this.element.append(table);
50
53
  });
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "alchemy-form",
3
3
  "description": "Form plugin for Alchemy",
4
- "version": "0.1.8",
4
+ "version": "0.1.11",
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.2.0"
10
+ "alchemymvc" : ">=1.2.0",
11
+ "alchemy-media" : "~0.6.3"
11
12
  },
12
13
  "license": "MIT",
13
14
  "engines": {
14
- "node" : ">=12.0.0"
15
+ "node" : ">=14.0.0"
15
16
  }
16
17
  }
@@ -1 +1 @@
1
- <div class="code-editor"><% Blast.Classes.Hawkejs.replaceChildren($0, child_nodes) %></div>
1
+ <div class="code-editor" hidden><% Blast.Classes.Hawkejs.replaceChildren($0, child_nodes) %></div>
@@ -0,0 +1,36 @@
1
+ <label>
2
+ <div class="inputlabel">
3
+ <span class="label" data-he-slot="label"></span>
4
+ <span class="description" data-he-slot="description"></span>
5
+ <hr class="spacer">
6
+ </div>
7
+ <div class="inputbox">
8
+ <input
9
+ name=<% self.getAttribute('input-name') || 'name' %>
10
+ placeholder=<% self.getAttribute('placeholder') %>
11
+ minlength=<% self.getAttribute('min-length') %>
12
+ maxlength=<% self.getAttribute('max-length') %>
13
+ class="input"
14
+ value="<% self.getAttribute('value') || '' %>"
15
+ type="password"
16
+ >
17
+ <i class="icon cross"></i>
18
+ <i class="icon checkmark"></i>
19
+ </div>
20
+ </label>
21
+ <label class="repeat-input-label" hidden>
22
+ <div class="inputbox">
23
+ <input
24
+ placeholder=<% self.getAttribute('repeat-placeholder') %>
25
+ class="input repeat-input"
26
+ value="<% self.getAttribute('value') || '' %>"
27
+ minlength=<% self.getAttribute('min-length') %>
28
+ maxlength=<% self.getAttribute('max-length') %>
29
+ type="password"
30
+ >
31
+ <i class="icon cross"></i>
32
+ <i class="icon checkmark"></i>
33
+ </div>
34
+ <div class="errors"></div>
35
+ <div class="success"></div>
36
+ </label>
@@ -0,0 +1,4 @@
1
+ <alchemy-toggle
2
+ class="alchemy-field-value"
3
+ #value=<% value %>
4
+ ></alchemy-toggle>
@@ -0,0 +1 @@
1
+ <% include('form/inputs/view_inline/datetime') %>
@@ -0,0 +1,19 @@
1
+ <span
2
+ class="alchemy-field-value boolean-wrapper"
3
+ >
4
+ <%
5
+ new_class = '';
6
+
7
+ if (value) {
8
+ new_class = 'boolean-true';
9
+ } else if (value === false) {
10
+ new_class = 'boolean-false';
11
+ } else {
12
+ new_class = 'boolean-null';
13
+ value = 'empty';
14
+ }
15
+
16
+ $0.classList.add(new_class);
17
+ %>
18
+ {{ value }}
19
+ </span>
@@ -0,0 +1,4 @@
1
+ <time
2
+ class="alchemy-field-value"
3
+ datetime={% value.toISOString() %}
4
+ >{{ value.format('Y‑m‑d') }}</time>
@@ -0,0 +1,4 @@
1
+ <time
2
+ class="alchemy-field-value"
3
+ datetime={% value.toISOString() %}
4
+ >{{ value.format('Y‑m‑d H:i') }}</time>
@@ -0,0 +1,6 @@
1
+ {% if value %}
2
+ <img
3
+ !Media={% value %}
4
+ +media-route="Media::thumb"
5
+ >
6
+ {% /if %}
@@ -0,0 +1 @@
1
+ <code class="alchemy-field-value">{{ value }}</code>
@@ -0,0 +1 @@
1
+ <div class="wrapped-inline" data-he-name="field"></div>
@@ -1 +1 @@
1
- <div data-he-name="field"></div>
1
+ <div class="wrapped-inline" data-he-name="field"></div>