alchemy-form 0.1.4 → 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.
Files changed (42) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/assets/stylesheets/form/alchemy_field_array.scss +4 -0
  3. package/assets/stylesheets/form/alchemy_toggle.scss +2 -0
  4. package/assets/stylesheets/form/query_builder.scss +185 -0
  5. package/config/routes.js +8 -0
  6. package/controller/form_api_controller.js +51 -2
  7. package/element/20_query_builder_base.js +82 -0
  8. package/element/25_query_builder_data.js +139 -0
  9. package/element/alchemy_field.js +19 -2
  10. package/element/alchemy_select.js +40 -2
  11. package/element/alchemy_select_item.js +42 -1
  12. package/element/alchemy_table.js +123 -21
  13. package/element/query_builder.js +90 -0
  14. package/element/query_builder_entry.js +388 -0
  15. package/element/query_builder_group.js +248 -0
  16. package/element/query_builder_value.js +316 -0
  17. package/element/query_builder_variable.js +103 -0
  18. package/helper/form_actions/00_form_action.js +328 -0
  19. package/helper/form_actions/url_action.js +69 -0
  20. package/helper/query_builder_variable_definition/00_variable_definition.js +371 -0
  21. package/helper/query_builder_variable_definition/boolean_variable_definition.js +24 -0
  22. package/helper/query_builder_variable_definition/list_variable_definition.js +38 -0
  23. package/helper/query_builder_variable_definition/number_variable_definition.js +106 -0
  24. package/helper/query_builder_variable_definition/string_variable_definition.js +46 -0
  25. package/helper_field/query_builder_assignment.js +11 -0
  26. package/helper_field/query_builder_field.js +91 -0
  27. package/helper_field/query_builder_value.js +56 -0
  28. package/helper_field/query_builder_variable.js +56 -0
  29. package/package.json +1 -1
  30. package/view/form/elements/alchemy_field_array.hwk +3 -1
  31. package/view/form/elements/alchemy_field_array_entry.hwk +3 -1
  32. package/view/form/elements/alchemy_select_item.hwk +6 -1
  33. package/view/form/elements/query_builder.hwk +1 -0
  34. package/view/form/elements/query_builder_entry.hwk +33 -0
  35. package/view/form/elements/query_builder_group.hwk +64 -0
  36. package/view/form/elements/query_builder_value.hwk +10 -0
  37. package/view/form/elements/query_builder_variable.hwk +6 -0
  38. package/view/form/inputs/edit/query_builder.hwk +5 -0
  39. package/view/form/inputs/edit/query_builder_assignment.hwk +6 -0
  40. package/view/form/inputs/edit/query_builder_value.hwk +11 -0
  41. package/view/form/inputs/edit/query_builder_variable.hwk +10 -0
  42. package/view/form/select/qb_item.hwk +7 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
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
+
9
+ ## 0.1.6 (2022-05-31)
10
+
11
+ * Fix `FormApi#related` action searching through multiple fields in an `and` group
12
+ * Use microcopy translations in buttons
13
+ * Add `Action` class for user interaction
14
+ * Add context-menu support to `alchemy-table`
15
+ * Add support for using custom templates for `alchemy-select` options
16
+ * Add QueryBuilder
17
+
18
+ ## 0.1.5 (2022-03-21)
19
+
20
+ * Print `alchemy-select-item` contents as text, not html
21
+ * Only get a maximum of 50 related items
22
+ * Set the parent `alchemy-select` element when creating `alchemy-select-item` element
23
+
1
24
  ## 0.1.4 (2022-03-16)
2
25
 
3
26
  * Make fields work with the new `Alchemy.Map.Backed` and `Alchemy.Map.Enum` class
@@ -10,4 +10,8 @@ alchemy-field-array-entry {
10
10
  align-content: center;
11
11
  padding-left: 0.5rem;
12
12
  }
13
+
14
+ .button .remove > * {
15
+ writing-mode: vertical-rl;
16
+ }
13
17
  }
@@ -34,6 +34,7 @@ alchemy-toggle {
34
34
  height: 36px;
35
35
  flex: 0 0 134px;
36
36
  border-radius: 4px;
37
+ min-width: 134px;
37
38
 
38
39
  transition: background-color 0.3s cubic-bezier(0, 1, 0.5, 1);
39
40
  background: #848484;
@@ -43,6 +44,7 @@ alchemy-toggle {
43
44
  &:after {
44
45
  text-transform: uppercase;
45
46
  text-align: center;
47
+ box-sizing: inherit;
46
48
  }
47
49
 
48
50
  &:before {
@@ -0,0 +1,185 @@
1
+ :root {
2
+ --qb-border-color: #d3d3d3;
3
+ --qb-btn-background-color: #fafafa;
4
+ --qb-text-color: #3e3e3e;
5
+
6
+ --qb-btn-primary: #286090;
7
+ --qb-btn-primary-border: #204d74;
8
+ --qb-btn-primary-text-color: #fafafa;
9
+
10
+ --qb-btn-active: #3da50e;
11
+ --qb-btn-active-text: #fff;
12
+ --qb-btn-border-color: #d3d3d3;
13
+ }
14
+
15
+ alchemy-query-builder {
16
+ display: block;
17
+ border-color: var(--qb-border-color);
18
+ padding: 1rem;
19
+ position: relative;
20
+ }
21
+
22
+ alchemy-query-builder-group {
23
+ display: block;
24
+ padding: 10px;
25
+ padding-bottom: 6px;
26
+ background-color: rgba(250,240,210,.5);
27
+ border: 1px solid #dcc896;
28
+ position: relative;
29
+
30
+
31
+ margin: 4px 0;
32
+ padding: 5px;
33
+ border: 1px solid #eee;
34
+ border-radius: 3px;
35
+
36
+ .qb-group-header {
37
+ margin-bottom: 10px;
38
+ }
39
+
40
+ .qb-group-actions {
41
+ float: right;
42
+ }
43
+
44
+ .qb-group-body {
45
+ .qb-rules-list {
46
+ display: flex;
47
+ flex-flow: column;
48
+ gap: 1rem;
49
+ padding: 0 0 0 15px;
50
+
51
+ & > :first-child::before {
52
+ top: -11px;
53
+ height: calc(50% + 14px);
54
+ }
55
+
56
+ & > :last-child::before {
57
+ border-radius: 0 0 0 4px;
58
+ }
59
+
60
+ & > ::after {
61
+ top: 50%;
62
+ border-width: 0 0 0 2px;
63
+ }
64
+
65
+ & >:last-child::after {
66
+ display: none;
67
+ }
68
+
69
+ > ::before {
70
+ top: -2px;
71
+ border-width: 0 0 2px 2px;
72
+ }
73
+
74
+ > ::before,
75
+ > ::after {
76
+ content: '';
77
+ position: absolute;
78
+ left: -10px;
79
+ width: 10px;
80
+ height: calc(50% + 4px);
81
+ border-color: #ccc;
82
+ border-style: solid;
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ alchemy-query-builder-value {
89
+ min-width: 10rem;
90
+ }
91
+
92
+ alchemy-query-builder-entry {
93
+ min-width: 40rem;
94
+ }
95
+
96
+ alchemy-query-builder-value,
97
+ alchemy-query-builder-entry {
98
+ display: flex;
99
+ gap: 0.7rem;
100
+
101
+ alchemy-select {
102
+ min-width: 11rem;
103
+ }
104
+
105
+ .qb-delete-wrapper {
106
+ flex: 1;
107
+ text-align: right;
108
+ }
109
+
110
+ .qb-value-wrapper {
111
+ display: flex;
112
+ gap: 0.3rem;
113
+ }
114
+
115
+ .qb-value-input {
116
+ height: 100%;
117
+ color: black;
118
+ padding: 0 0.5rem;
119
+ }
120
+ }
121
+
122
+ .qb-group-invert,
123
+ .qb-button-group,
124
+ .qb-group-type {
125
+ display: inline-flex;
126
+ box-shadow: 0 1px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);
127
+ user-select: none;
128
+
129
+ > input {
130
+ height: 1px;
131
+ width: 1px;
132
+ opacity: 0;
133
+ position: absolute;
134
+ margin: 0 0 0 -1px;
135
+ }
136
+
137
+ > input + label {
138
+ opacity: 0.7;
139
+ }
140
+
141
+ > input:checked + label {
142
+ background-color: var(--qb-btn-active);
143
+ border-color: var(--qb-btn-active);
144
+ color: var(--qb-btn-active-text);
145
+ opacity: 1;
146
+ }
147
+ }
148
+
149
+ .qb-primary {
150
+ --qb-btn-background-color: var(--qb-btn-primary);
151
+ --qb-text-color: var(--qb-btn-primary-text-color);
152
+ --qb-btn-border-color: var(--qb-btn-primary-border);
153
+ }
154
+
155
+ button.qb-btn {
156
+ border-color: var(--qb-btn-border-color);
157
+ }
158
+
159
+ .qb-btn {
160
+ background-color: var(--qb-btn-background-color);
161
+ color: var(--qb-text-color);
162
+ transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
163
+ border-radius: 2px;
164
+ cursor: pointer;
165
+ display: inline-block;
166
+ font-weight: bold;
167
+ text-align: center;
168
+ padding: 2px 12px 1px;
169
+ }
170
+
171
+ .qb-select-item {
172
+ display: flex;
173
+ flex-flow: column;
174
+ padding-right: 1rem;
175
+
176
+ .option-title {
177
+ font-weight: bold;
178
+ font-size: 1rem;
179
+ white-space: nowrap;
180
+ }
181
+
182
+ .option-description {
183
+ min-width: 10rem;
184
+ }
185
+ }
package/config/routes.js CHANGED
@@ -2,4 +2,12 @@ Router.add({
2
2
  name : 'FormApi#related',
3
3
  methods : 'post',
4
4
  paths : '/api/form/data/related',
5
+ policy : 'logged_in',
6
+ });
7
+
8
+ Router.add({
9
+ name : 'FormApi#queryBuilderData',
10
+ methods : 'post',
11
+ paths : '/api/form/data/qbdata',
12
+ policy : 'logged_in',
5
13
  });
@@ -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.1.0
20
+ * @version 0.1.6
21
21
  *
22
22
  * @param {Conduit} conduit
23
23
  */
@@ -26,8 +26,26 @@ FormApi.setAction(async function related(conduit) {
26
26
  const body = conduit.body;
27
27
 
28
28
  const model = this.getModel(body.assoc_model);
29
+ let crit = model.find();
30
+ crit.limit(50);
31
+ crit.setOption('scenario', 'related_data');
32
+
33
+ if (body.config && body.config.search) {
34
+ let display_fields = Array.cast(model.displayField);
35
+
36
+ let or = crit.or();
37
+ let rx = RegExp.interpretWildcard('*' + body.config.search + '*', 'i');
29
38
 
30
- let records = await model.find('all');
39
+ for (let field of display_fields) {
40
+ if (!field) {
41
+ continue;
42
+ }
43
+
44
+ or.where(field).equals(rx);
45
+ }
46
+ }
47
+
48
+ let records = await model.find('all', crit);
31
49
 
32
50
  let result = {
33
51
  available : records.available,
@@ -36,3 +54,34 @@ FormApi.setAction(async function related(conduit) {
36
54
 
37
55
  conduit.end(result);
38
56
  });
57
+
58
+
59
+ /**
60
+ * The related action
61
+ *
62
+ * @author Jelle De Loecker <jelle@elevenways.be>
63
+ * @since 0.1.6
64
+ * @version 0.1.6
65
+ *
66
+ * @param {Conduit} conduit
67
+ */
68
+ FormApi.setAction(async function queryBuilderData(conduit) {
69
+
70
+ const body = conduit.body;
71
+ const config = body.config || {};
72
+ let result;
73
+
74
+ if (body && body.model) {
75
+ const model = this.getModel(body.model);
76
+
77
+ if (body.$pk) {
78
+ const doc = await model.findByPk(body.$pk);
79
+
80
+ if (doc) {
81
+ result = await doc.loadQueryBuilderData(config);
82
+ }
83
+ }
84
+ }
85
+
86
+ conduit.end(result);
87
+ });
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The base abstract query builder custom element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.1.6
6
+ * @version 0.1.6
7
+ */
8
+ const QueryBuilderBase = Function.inherits('Alchemy.Element.Form.Base', 'QueryBuilderBase');
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.6
16
+ * @version 0.1.6
17
+ */
18
+ QueryBuilderBase.setStatic('is_abstract_class', true, false);
19
+
20
+ /**
21
+ * The stylesheet to load for this element
22
+ *
23
+ * @author Jelle De Loecker <jelle@elevenways.be>
24
+ * @since 0.1.6
25
+ * @version 0.1.6
26
+ */
27
+ QueryBuilderBase.setStylesheetFile('form/query_builder');
28
+
29
+ /**
30
+ * Get the dataprovider
31
+ *
32
+ * @author Jelle De Loecker <jelle@elevenways.be>
33
+ * @since 0.1.6
34
+ * @version 0.1.6
35
+ */
36
+ QueryBuilderBase.enforceProperty(function dataprovider(new_value) {
37
+
38
+ if (new_value == null) {
39
+ if (this.assigned_data.dataprovider) {
40
+ new_value = this.assigned_data.dataprovider;
41
+ } else if (this.root_query_builder && this.root_query_builder.dataprovider) {
42
+ new_value = this.root_query_builder.dataprovider;
43
+ }
44
+ } else {
45
+ this.assigned_data.dataprovider = new_value;
46
+ }
47
+
48
+ return new_value;
49
+ });
50
+
51
+ /**
52
+ * Getter for the rules list element
53
+ *
54
+ * @author Jelle De Loecker <jelle@elevenways.be>
55
+ * @since 0.1.6
56
+ * @version 0.1.6
57
+ */
58
+ QueryBuilderBase.setProperty(function root_query_builder() {
59
+ return this.queryParents('alchemy-query-builder');
60
+ });
61
+
62
+ /**
63
+ * Get the value type of the given input
64
+ *
65
+ * @author Jelle De Loecker <jelle@elevenways.be>
66
+ * @since 0.1.6
67
+ * @version 0.1.6
68
+ *
69
+ * @param {HTMLElement}
70
+ *
71
+ * @return {String}
72
+ */
73
+ QueryBuilderBase.setMethod(function getValueType(element) {
74
+
75
+ if (!element) {
76
+ return null;
77
+ }
78
+
79
+ let result = element.value_type || element.type;
80
+
81
+ return result;
82
+ });
@@ -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
+ });
@@ -708,16 +708,33 @@ Field.setMethod(function retained() {
708
708
  *
709
709
  * @author Jelle De Loecker <jelle@elevenways.be>
710
710
  * @since 0.1.0
711
- * @version 0.1.0
711
+ * @version 0.1.6
712
712
  *
713
713
  * @param {Object} config
714
714
  * @param {HTMLElement} element
715
715
  */
716
- Field.setMethod(function loadData(config, element) {
716
+ Field.setMethod(async function loadData(config, element) {
717
717
 
718
718
  let field = this.config;
719
719
 
720
720
  if (field) {
721
+
722
+ let result;
723
+
724
+ if (typeof field.loadData == 'function') {
725
+
726
+ try {
727
+ result = await field.loadData(config, element);
728
+ } catch (err) {
729
+ // Ignore
730
+ console.error('Error loading field data:', err);
731
+ }
732
+
733
+ if (result) {
734
+ return result;
735
+ }
736
+ }
737
+
721
738
  return this.hawkejs_helpers.Alchemy.getResource({
722
739
  name : 'FormApi#related',
723
740
  post : true,
@@ -36,6 +36,26 @@ AlchemySelect.setProperty('_clear_count', 0);
36
36
  */
37
37
  AlchemySelect.setAttribute('total-item-count', {number: true});
38
38
 
39
+ /**
40
+ * The optional template to use for value items
41
+ * (The chosen value)
42
+ *
43
+ * @author Jelle De Loecker <jelle@develry.be>
44
+ * @since 0.1.6
45
+ * @version 0.1.6
46
+ */
47
+ AlchemySelect.setAttribute('value-item-template');
48
+
49
+ /**
50
+ * The optional template to use for option items
51
+ * (The items visible in the dropdown)
52
+ *
53
+ * @author Jelle De Loecker <jelle@develry.be>
54
+ * @since 0.1.6
55
+ * @version 0.1.6
56
+ */
57
+ AlchemySelect.setAttribute('option-item-template');
58
+
39
59
  /**
40
60
  * The hawkejs template to use
41
61
  *
@@ -809,12 +829,16 @@ AlchemySelect.setMethod(function _processPreloadedValues() {
809
829
  *
810
830
  * @author Jelle De Loecker <jelle@develry.be>
811
831
  * @since 0.1.0
812
- * @version 0.1.0
832
+ * @version 0.1.6
813
833
  *
814
834
  * @param {Object} response
815
835
  */
816
836
  AlchemySelect.setMethod(function _processResponseData(response) {
817
837
 
838
+ if (!response) {
839
+ response = {};
840
+ }
841
+
818
842
  if (response.available) {
819
843
  this.total_item_count = response.available;
820
844
  }
@@ -823,6 +847,10 @@ AlchemySelect.setMethod(function _processResponseData(response) {
823
847
  record,
824
848
  item;
825
849
 
850
+ if (!records) {
851
+ records = [];
852
+ }
853
+
826
854
  for (record of records) {
827
855
  item = this._makeOption(record._id || record.id, record);
828
856
  this.addToDropdown(item);
@@ -1166,7 +1194,7 @@ AlchemySelect.setMethod(function close(event) {
1166
1194
  *
1167
1195
  * @author Jelle De Loecker <jelle@develry.be>
1168
1196
  * @since 0.1.0
1169
- * @version 0.1.4
1197
+ * @version 0.1.6
1170
1198
  *
1171
1199
  * @param {String} type "value" or "option"
1172
1200
  * @param {Mixed} value The actual value of this item
@@ -1181,9 +1209,19 @@ AlchemySelect.setMethod(function _makeValueItem(type, value, data) {
1181
1209
  // Set the type ("value" or "option")
1182
1210
  item.type = type;
1183
1211
 
1212
+ // Set the custom template to use, if any
1213
+ let custom_template = this[type + '-item-template'];
1214
+
1215
+ if (custom_template) {
1216
+ item.custom_template = custom_template;
1217
+ }
1218
+
1184
1219
  // Assign the value
1185
1220
  item.value = value;
1186
1221
 
1222
+ // Add a reference to this element
1223
+ item.alchemy_select = this;
1224
+
1187
1225
  if (!data) {
1188
1226
  data = this.getValueData(value);
1189
1227
  }
@@ -37,6 +37,15 @@ Item.setAttribute('type');
37
37
  */
38
38
  Item.setAttribute('selected', {boolean: true});
39
39
 
40
+ /**
41
+ * Should a custom template be used?
42
+ *
43
+ * @author Jelle De Loecker <jelle@elevenways.be>
44
+ * @since 0.1.6
45
+ * @version 0.1.6
46
+ */
47
+ Item.setAttribute('custom-template');
48
+
40
49
  /**
41
50
  * The value of this item
42
51
  *
@@ -53,4 +62,36 @@ Item.setAssignedProperty('value');
53
62
  * @since 0.1.0
54
63
  * @version 0.1.0
55
64
  */
56
- Item.setAssignedProperty('data');
65
+ Item.setAssignedProperty('data');
66
+
67
+ /**
68
+ * The parent alchemy-select item
69
+ *
70
+ * @author Jelle De Loecker <jelle@elevenways.be>
71
+ * @since 0.1.5
72
+ * @version 0.1.5
73
+ */
74
+ Item.enforceProperty(function alchemy_select(new_value) {
75
+
76
+ if (new_value == null) {
77
+ new_value = this.closest('alchemy-select');
78
+ }
79
+
80
+ return new_value;
81
+ });
82
+
83
+ /**
84
+ * The display item
85
+ *
86
+ * @author Jelle De Loecker <jelle@elevenways.be>
87
+ * @since 0.1.5
88
+ * @version 0.1.5
89
+ */
90
+ Item.setProperty(function display_title() {
91
+
92
+ if (!this.data) {
93
+ return '';
94
+ }
95
+
96
+ return this.data.title || this.data.name || this.data.username || this.data.$pk || this.value;
97
+ });