alchemy-form 0.2.2 → 0.2.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.
- package/CHANGELOG.md +16 -0
- package/assets/stylesheets/form/elements/_field_translatable.scss +41 -1
- package/controller/form_api_controller.js +25 -3
- package/element/al_field_schema.js +26 -34
- package/element/al_field_translatable.js +62 -3
- package/element/al_field_translatable_entry.js +19 -1
- package/element/al_form.js +5 -1
- package/element/al_select.js +35 -16
- package/element/al_table.js +2 -3
- package/package.json +1 -1
- package/view/form/elements/alchemy_field_translatable.hwk +17 -2
- package/view/form/inputs/edit/has_one_parent.hwk +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 0.2.4 (2023-02-26)
|
|
2
|
+
|
|
3
|
+
* Don't look for a field when the path is not specified
|
|
4
|
+
* Make `al-field-schema` elements use `Field#getSubSchema()` method
|
|
5
|
+
* Add an icon to the translatable-field entry buttons to see if it has a translation or not
|
|
6
|
+
|
|
7
|
+
## 0.2.3 (2023-02-11)
|
|
8
|
+
|
|
9
|
+
* Use `Scene#pushToHistory()` instead of directly calling `pushState`
|
|
10
|
+
* Select `display_field_select` fields when requesting related data
|
|
11
|
+
* Make local-filtering in `al-select` elements case insensitive
|
|
12
|
+
* Fix `al-select` never getting more than the first page in `getRemoteFetchConfig` method
|
|
13
|
+
* Add `hasOneParent` field support
|
|
14
|
+
* Make `FormApi#related()` action make sure fields exist before querying them
|
|
15
|
+
* Add a workaround so `al-select` actually refreshes elements when removing the search value
|
|
16
|
+
|
|
1
17
|
## 0.2.2 (2023-01-23)
|
|
2
18
|
|
|
3
19
|
* Fix `al-button`'s `activate` event not being cancelable
|
|
@@ -3,6 +3,46 @@ al-field-translatable {
|
|
|
3
3
|
position: relative;
|
|
4
4
|
|
|
5
5
|
.prefix-buttons {
|
|
6
|
-
|
|
6
|
+
button {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-flow: row;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.has-empty-content {
|
|
12
|
+
font-size: 0.7rem;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.has-content {
|
|
16
|
+
font-size: 0.9rem;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.has-empty-content,
|
|
20
|
+
.has-content {
|
|
21
|
+
margin-left: 0.5rem;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
[data-has-content="true"] {
|
|
25
|
+
.has-empty-content {
|
|
26
|
+
display: none;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
[data-has-content="false"] {
|
|
31
|
+
.has-content {
|
|
32
|
+
display: none;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
[icon-name] {
|
|
37
|
+
color: #333;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
[icon-name="ban"] {
|
|
41
|
+
color: tomato;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.has-content {
|
|
45
|
+
color: green;
|
|
46
|
+
}
|
|
7
47
|
}
|
|
8
48
|
}
|
|
@@ -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.
|
|
20
|
+
* @version 0.2.3
|
|
21
21
|
*
|
|
22
22
|
* @param {Conduit} conduit
|
|
23
23
|
*/
|
|
@@ -34,16 +34,34 @@ FormApi.setAction(async function related(conduit) {
|
|
|
34
34
|
if (config.value) {
|
|
35
35
|
crit.where(model.primary_key).equals(config.value);
|
|
36
36
|
} else if (config.search) {
|
|
37
|
-
let display_fields = Array.cast(model.
|
|
37
|
+
let display_fields = Array.cast(model.display_field),
|
|
38
|
+
search_fields = [];
|
|
38
39
|
|
|
39
40
|
let or = crit.or();
|
|
40
41
|
let rx = RegExp.interpretWildcard('*' + body.config.search + '*', 'i');
|
|
41
42
|
|
|
42
43
|
for (let field of display_fields) {
|
|
43
|
-
if (!field) {
|
|
44
|
+
if (!field || !model.getField(field)) {
|
|
44
45
|
continue;
|
|
45
46
|
}
|
|
47
|
+
search_fields.push(field);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!search_fields.length) {
|
|
51
|
+
if (model.getField('title')) {
|
|
52
|
+
search_fields.push('title');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (model.getField('name')) {
|
|
56
|
+
search_fields.push('name');
|
|
57
|
+
}
|
|
46
58
|
|
|
59
|
+
if (model.getField('slug')) {
|
|
60
|
+
search_fields.push('slug');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (let field of search_fields) {
|
|
47
65
|
or.where(field).equals(rx);
|
|
48
66
|
}
|
|
49
67
|
}
|
|
@@ -52,6 +70,10 @@ FormApi.setAction(async function related(conduit) {
|
|
|
52
70
|
crit.page(config.page);
|
|
53
71
|
}
|
|
54
72
|
|
|
73
|
+
if (model.display_field_select) {
|
|
74
|
+
crit.select(model.display_field_select);
|
|
75
|
+
}
|
|
76
|
+
|
|
55
77
|
let records = await model.find('all', crit);
|
|
56
78
|
|
|
57
79
|
let result = {
|
|
@@ -21,47 +21,39 @@ FieldSchema.setTemplateFile('form/elements/alchemy_field_schema');
|
|
|
21
21
|
*
|
|
22
22
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
23
23
|
* @since 0.1.0
|
|
24
|
-
* @version 0.
|
|
24
|
+
* @version 0.2.4
|
|
25
25
|
*/
|
|
26
26
|
FieldSchema.setProperty(function schema() {
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const field_element = this.alchemy_field;
|
|
29
|
+
const field = field_element?.config;
|
|
30
|
+
|
|
31
|
+
if (field?.options) {
|
|
32
|
+
|
|
33
|
+
let schema = field.options.schema;
|
|
30
34
|
|
|
31
35
|
if (typeof schema == 'string') {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (value) {
|
|
48
|
-
if (value.schema) {
|
|
49
|
-
schema = value.schema;
|
|
50
|
-
} else if (value.value) {
|
|
51
|
-
// Enumified values can be wrapped on the server-side
|
|
52
|
-
value = value.value;
|
|
53
|
-
|
|
54
|
-
if (value.schema) {
|
|
55
|
-
schema = value.schema;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!schema) {
|
|
61
|
-
schema = value;
|
|
62
|
-
}
|
|
36
|
+
|
|
37
|
+
let parent_schema_value;
|
|
38
|
+
|
|
39
|
+
let parent_schema = field_element.queryParents('al-field[field-type="schema"]');
|
|
40
|
+
|
|
41
|
+
if (parent_schema) {
|
|
42
|
+
parent_schema_value = parent_schema.value;
|
|
43
|
+
} else {
|
|
44
|
+
|
|
45
|
+
const form = field_element.alchemy_form;
|
|
46
|
+
|
|
47
|
+
let record_value = form.value;
|
|
48
|
+
|
|
49
|
+
if (form.model) {
|
|
50
|
+
record_value = record_value[form.model];
|
|
63
51
|
}
|
|
52
|
+
|
|
53
|
+
parent_schema_value = record_value;
|
|
64
54
|
}
|
|
55
|
+
|
|
56
|
+
return field.getSubschema(parent_schema_value, schema)
|
|
65
57
|
}
|
|
66
58
|
|
|
67
59
|
return schema;
|
|
@@ -75,7 +75,44 @@ FieldTranslatable.setMethod(function showPrefix(prefix) {
|
|
|
75
75
|
element.hidden = true;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check the translation contents
|
|
82
|
+
*
|
|
83
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
84
|
+
* @since 0.2.4
|
|
85
|
+
* @version 0.2.4
|
|
86
|
+
*/
|
|
87
|
+
FieldTranslatable.setMethod(function checkTranslationContents() {
|
|
88
|
+
|
|
89
|
+
let field = this.field_context?.config;
|
|
90
|
+
|
|
91
|
+
let has_content,
|
|
92
|
+
buttons = this.querySelectorAll('button[data-has-content][data-prefix]'),
|
|
93
|
+
button,
|
|
94
|
+
prefix,
|
|
95
|
+
values = this.value,
|
|
96
|
+
value,
|
|
97
|
+
i;
|
|
98
|
+
|
|
99
|
+
for (i = 0; i < buttons.length; i++) {
|
|
100
|
+
button = buttons[i];
|
|
101
|
+
prefix = button.dataset.prefix;
|
|
102
|
+
value = values?.[prefix];
|
|
103
|
+
|
|
104
|
+
if (field) {
|
|
105
|
+
has_content = field.valueHasContent(value);
|
|
106
|
+
} else {
|
|
107
|
+
has_content = value != null && value !== '';
|
|
108
|
+
}
|
|
78
109
|
|
|
110
|
+
if (has_content) {
|
|
111
|
+
button.dataset.hasContent = 'true';
|
|
112
|
+
} else {
|
|
113
|
+
button.dataset.hasContent = 'false';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
79
116
|
});
|
|
80
117
|
|
|
81
118
|
/**
|
|
@@ -83,15 +120,37 @@ FieldTranslatable.setMethod(function showPrefix(prefix) {
|
|
|
83
120
|
*
|
|
84
121
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
85
122
|
* @since 0.1.0
|
|
86
|
-
* @version 0.
|
|
123
|
+
* @version 0.2.4
|
|
87
124
|
*/
|
|
88
125
|
FieldTranslatable.setMethod(function introduced() {
|
|
89
126
|
|
|
90
|
-
const that = this
|
|
127
|
+
const that = this,
|
|
128
|
+
field = this.field_context;
|
|
129
|
+
|
|
130
|
+
let doTranslationCheck = Function.throttle(() => {
|
|
131
|
+
|
|
132
|
+
if (field?.purpose == 'view') {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
that.checkTranslationContents();
|
|
137
|
+
}, 500, true, true);
|
|
91
138
|
|
|
92
139
|
this.onEventSelector('click', '.prefix-buttons button[data-prefix]', function onClick(e) {
|
|
140
|
+
|
|
93
141
|
e.preventDefault();
|
|
94
|
-
|
|
142
|
+
|
|
143
|
+
let button = this.closest('[data-prefix]');
|
|
144
|
+
|
|
145
|
+
if (!button) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
that.showPrefix(button.dataset.prefix);
|
|
150
|
+
doTranslationCheck();
|
|
95
151
|
});
|
|
96
152
|
|
|
153
|
+
this.addEventListener('change', doTranslationCheck);
|
|
154
|
+
this.addEventListener('keyup', doTranslationCheck);
|
|
155
|
+
this.addEventListener('click', doTranslationCheck);
|
|
97
156
|
});
|
|
@@ -25,6 +25,22 @@ FieldTranslatableEntry.setTemplateFile('form/elements/alchemy_field_translatable
|
|
|
25
25
|
*/
|
|
26
26
|
FieldTranslatableEntry.setAttribute('prefix');
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Does this translation entry have a valid value?
|
|
30
|
+
*
|
|
31
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
32
|
+
* @since 0.2.4
|
|
33
|
+
* @version 0.2.4
|
|
34
|
+
*/
|
|
35
|
+
FieldTranslatableEntry.setProperty(function has_content() {
|
|
36
|
+
|
|
37
|
+
let field_translatable_el = this.field_context,
|
|
38
|
+
field_el = field_translatable_el.field_context,
|
|
39
|
+
field = field_el.config;
|
|
40
|
+
|
|
41
|
+
field.valueHasContent(this.value);
|
|
42
|
+
});
|
|
43
|
+
|
|
28
44
|
/**
|
|
29
45
|
* Get the original value
|
|
30
46
|
*
|
|
@@ -34,7 +50,9 @@ FieldTranslatableEntry.setAttribute('prefix');
|
|
|
34
50
|
*/
|
|
35
51
|
FieldTranslatableEntry.setProperty(function original_value() {
|
|
36
52
|
|
|
37
|
-
let
|
|
53
|
+
let field_translatable_el = this.field_context;
|
|
54
|
+
|
|
55
|
+
let context_value = field_translatable_el.original_value;
|
|
38
56
|
|
|
39
57
|
if (context_value) {
|
|
40
58
|
return context_value[this.prefix];
|
package/element/al_form.js
CHANGED
|
@@ -289,7 +289,7 @@ Form.setMethod(async function showViolations(err) {
|
|
|
289
289
|
*
|
|
290
290
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
291
291
|
* @since 0.1.0
|
|
292
|
-
* @version 0.2.
|
|
292
|
+
* @version 0.2.4
|
|
293
293
|
*
|
|
294
294
|
* @param {String} path
|
|
295
295
|
*
|
|
@@ -297,6 +297,10 @@ Form.setMethod(async function showViolations(err) {
|
|
|
297
297
|
*/
|
|
298
298
|
Form.setMethod(function findFieldByPath(path) {
|
|
299
299
|
|
|
300
|
+
if (!path) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
300
304
|
let current = this,
|
|
301
305
|
result,
|
|
302
306
|
pieces = path.split('.'),
|
package/element/al_select.js
CHANGED
|
@@ -924,12 +924,12 @@ AlchemySelect.setMethod(function _processResponseList(list, page) {
|
|
|
924
924
|
*
|
|
925
925
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
926
926
|
* @since 0.2.0
|
|
927
|
-
* @version 0.2.
|
|
927
|
+
* @version 0.2.3
|
|
928
928
|
*/
|
|
929
929
|
AlchemySelect.setMethod(function getRemoteFetchConfig() {
|
|
930
930
|
|
|
931
931
|
// Don't perform request when everything has already been loaded
|
|
932
|
-
if (this.
|
|
932
|
+
if (this.loaded_item_count >= this.total_item_count) {
|
|
933
933
|
return;
|
|
934
934
|
}
|
|
935
935
|
|
|
@@ -970,7 +970,7 @@ AlchemySelect.setMethod(function applyFetchedData(err, result, config) {
|
|
|
970
970
|
*
|
|
971
971
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
972
972
|
* @since 0.1.0
|
|
973
|
-
* @version 0.
|
|
973
|
+
* @version 0.2.3
|
|
974
974
|
*/
|
|
975
975
|
AlchemySelect.setMethod(function recreateDropdownElements() {
|
|
976
976
|
|
|
@@ -979,10 +979,12 @@ AlchemySelect.setMethod(function recreateDropdownElements() {
|
|
|
979
979
|
|
|
980
980
|
Hawkejs.removeChildren(this.dropdown_content);
|
|
981
981
|
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
982
|
+
if (items && typeof items.keys == 'function') {
|
|
983
|
+
for (let key of items.keys()) {
|
|
984
|
+
item = items.get(key);
|
|
985
|
+
item = this._makeOption(item.id, item);
|
|
986
|
+
this.addToDropdown(item);
|
|
987
|
+
}
|
|
986
988
|
}
|
|
987
989
|
|
|
988
990
|
this.refreshResultAmount();
|
|
@@ -1667,7 +1669,7 @@ AlchemySelect.setMethod(function onTypeAreaKeydown(e, is_input) {
|
|
|
1667
1669
|
*
|
|
1668
1670
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1669
1671
|
* @since 0.1.0
|
|
1670
|
-
* @version 0.
|
|
1672
|
+
* @version 0.2.3
|
|
1671
1673
|
*/
|
|
1672
1674
|
AlchemySelect.setMethod(function onTypeAreaKeyup(e, is_input) {
|
|
1673
1675
|
|
|
@@ -1683,15 +1685,20 @@ AlchemySelect.setMethod(function onTypeAreaKeyup(e, is_input) {
|
|
|
1683
1685
|
return;
|
|
1684
1686
|
}
|
|
1685
1687
|
|
|
1686
|
-
|
|
1688
|
+
let search_value = this.search_value,
|
|
1689
|
+
previous = this._previous_typed_search_value || '';
|
|
1687
1690
|
|
|
1691
|
+
if (previous != search_value) {
|
|
1688
1692
|
// Only perform a remote search
|
|
1689
1693
|
// when at least 2 characters have been entered
|
|
1690
|
-
if (
|
|
1694
|
+
if (search_value.length === 0 || search_value.length > 2) {
|
|
1691
1695
|
this.refreshRemote();
|
|
1692
1696
|
}
|
|
1697
|
+
|
|
1693
1698
|
}
|
|
1694
1699
|
|
|
1700
|
+
this._previous_typed_search_value = search_value;
|
|
1701
|
+
|
|
1695
1702
|
this.applyLocalFilter();
|
|
1696
1703
|
});
|
|
1697
1704
|
|
|
@@ -1700,7 +1707,7 @@ AlchemySelect.setMethod(function onTypeAreaKeyup(e, is_input) {
|
|
|
1700
1707
|
*
|
|
1701
1708
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1702
1709
|
* @since 0.1.0
|
|
1703
|
-
* @version 0.
|
|
1710
|
+
* @version 0.2.3
|
|
1704
1711
|
*/
|
|
1705
1712
|
AlchemySelect.setMethod(function applyLocalFilter(query) {
|
|
1706
1713
|
|
|
@@ -1713,7 +1720,7 @@ AlchemySelect.setMethod(function applyLocalFilter(query) {
|
|
|
1713
1720
|
i;
|
|
1714
1721
|
|
|
1715
1722
|
if (query) {
|
|
1716
|
-
query = query.trim();
|
|
1723
|
+
query = query.trim().toLowerCase();
|
|
1717
1724
|
}
|
|
1718
1725
|
|
|
1719
1726
|
for (i = 0; i < this.dropdown_content.children.length; i++) {
|
|
@@ -1722,10 +1729,22 @@ AlchemySelect.setMethod(function applyLocalFilter(query) {
|
|
|
1722
1729
|
|
|
1723
1730
|
if (!query) {
|
|
1724
1731
|
allow = true;
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
if (!allow) {
|
|
1735
|
+
let value = String(element.value).toLowerCase();
|
|
1736
|
+
|
|
1737
|
+
if (value.includes(query)) {
|
|
1738
|
+
allow = true;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
if (!allow) {
|
|
1743
|
+
let text = element.textContent.toLowerCase();
|
|
1744
|
+
|
|
1745
|
+
if (text.includes(query)) {
|
|
1746
|
+
allow = true;
|
|
1747
|
+
}
|
|
1729
1748
|
}
|
|
1730
1749
|
|
|
1731
1750
|
if (allow) {
|
package/element/al_table.js
CHANGED
|
@@ -1121,7 +1121,7 @@ Table.setMethod(function getRemoteFetchConfig() {
|
|
|
1121
1121
|
*
|
|
1122
1122
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1123
1123
|
* @since 0.2.0
|
|
1124
|
-
* @version 0.2.
|
|
1124
|
+
* @version 0.2.3
|
|
1125
1125
|
*/
|
|
1126
1126
|
Table.setMethod(function applyFetchedData(err, result, config) {
|
|
1127
1127
|
|
|
@@ -1142,8 +1142,7 @@ Table.setMethod(function applyFetchedData(err, result, config) {
|
|
|
1142
1142
|
this.updateAnchors();
|
|
1143
1143
|
|
|
1144
1144
|
if (Blast.isBrowser) {
|
|
1145
|
-
|
|
1146
|
-
history.pushState(null, document.title, current_url+'');
|
|
1145
|
+
hawkejs.scene.pushToHistory(null, this.getCurrentStateUrl());
|
|
1147
1146
|
}
|
|
1148
1147
|
});
|
|
1149
1148
|
|
package/package.json
CHANGED
|
@@ -8,9 +8,24 @@
|
|
|
8
8
|
<div class="prefix-buttons">
|
|
9
9
|
<% index = 0 %>
|
|
10
10
|
<% for (prefix in prefixes) { %>
|
|
11
|
-
|
|
11
|
+
<% value = null %>
|
|
12
|
+
<% if (values) value = values[prefix] %>
|
|
13
|
+
|
|
14
|
+
<button
|
|
15
|
+
data-prefix={% prefix %}
|
|
16
|
+
data-has-content=<% alchemy_field.config.valueHasContent(value) ? 'true' : 'false' %>
|
|
17
|
+
>
|
|
12
18
|
<% if (index == 0) $0.classList.add('active') %>
|
|
13
|
-
|
|
19
|
+
|
|
20
|
+
<span class="prefix-name">{{ prefix }}</span>
|
|
21
|
+
|
|
22
|
+
<al-icon-stack class="has-empty-content">
|
|
23
|
+
<al-icon icon-name="language"></al-icon>
|
|
24
|
+
<al-icon icon-name="ban" size=2></al-icon>
|
|
25
|
+
</al-icon-stack>
|
|
26
|
+
|
|
27
|
+
<al-icon class="has-content" icon-name="language"></al-icon>
|
|
28
|
+
|
|
14
29
|
</button>
|
|
15
30
|
|
|
16
31
|
<% index++ %>
|