neo.mjs 6.3.0 → 6.3.1
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/apps/ServiceWorker.mjs +2 -2
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +1 -1
- package/src/DefaultConfig.mjs +2 -2
- package/src/form/Container.mjs +34 -34
- package/src/main/addon/PrefixField.mjs +149 -0
- package/src/plugin/Popover.mjs +194 -0
package/apps/ServiceWorker.mjs
CHANGED
package/package.json
CHANGED
package/src/DefaultConfig.mjs
CHANGED
@@ -236,12 +236,12 @@ const DefaultConfig = {
|
|
236
236
|
useVdomWorker: true,
|
237
237
|
/**
|
238
238
|
* buildScripts/injectPackageVersion.mjs will update this value
|
239
|
-
* @default '6.3.
|
239
|
+
* @default '6.3.1'
|
240
240
|
* @memberOf! module:Neo
|
241
241
|
* @name config.version
|
242
242
|
* @type String
|
243
243
|
*/
|
244
|
-
version: '6.3.
|
244
|
+
version: '6.3.1'
|
245
245
|
};
|
246
246
|
|
247
247
|
Object.assign(DefaultConfig, {
|
package/src/form/Container.mjs
CHANGED
@@ -123,8 +123,8 @@ class Container extends BaseContainer {
|
|
123
123
|
|
124
124
|
await this.loadModules();
|
125
125
|
|
126
|
-
ComponentManager.getChildComponents(this).forEach(
|
127
|
-
|
126
|
+
ComponentManager.getChildComponents(this).forEach(field => {
|
127
|
+
field instanceof BaseField && fields.push(field)
|
128
128
|
});
|
129
129
|
|
130
130
|
return fields
|
@@ -137,31 +137,31 @@ class Container extends BaseContainer {
|
|
137
137
|
let fields = await this.getFields(),
|
138
138
|
Radio = Neo.form.field.Radio,
|
139
139
|
values = {},
|
140
|
-
|
140
|
+
fieldName, key, ns, nsArray, value;
|
141
141
|
|
142
|
-
fields.forEach(
|
143
|
-
value =
|
142
|
+
fields.forEach(field => {
|
143
|
+
value = field.getValue();
|
144
144
|
|
145
|
-
if (
|
146
|
-
|
145
|
+
if (field.name) {
|
146
|
+
fieldName = field.name;
|
147
147
|
|
148
|
-
if (
|
149
|
-
|
148
|
+
if (field.formGroup) {
|
149
|
+
fieldName = field.formGroup + '.' + fieldName;
|
150
150
|
}
|
151
151
|
|
152
|
-
nsArray =
|
152
|
+
nsArray = fieldName.split('.');
|
153
153
|
key = nsArray.pop();
|
154
154
|
ns = Neo.nsWithArrays(nsArray, true, values);
|
155
155
|
} else {
|
156
|
-
key =
|
156
|
+
key = field.id;
|
157
157
|
ns = values
|
158
158
|
}
|
159
159
|
|
160
160
|
// Ensuring that Radios will not return arrays
|
161
|
-
if (Radio &&
|
161
|
+
if (Radio && field instanceof Radio) {
|
162
162
|
// Only overwrite an existing value with a checked value
|
163
163
|
if (Object.hasOwn(ns, key)) {
|
164
|
-
if (value !==
|
164
|
+
if (value !== field.uncheckedValue) {
|
165
165
|
ns[key] = value
|
166
166
|
}
|
167
167
|
} else {
|
@@ -174,13 +174,13 @@ class Container extends BaseContainer {
|
|
174
174
|
* (multiple fields using the same name)
|
175
175
|
*/
|
176
176
|
else if (Object.hasOwn(ns, key) && value !== undefined) {
|
177
|
-
if (ns[key] ===
|
177
|
+
if (ns[key] === field.uncheckedValue) {
|
178
178
|
ns[key] = []
|
179
179
|
} else if (!Array.isArray(ns[key])) {
|
180
180
|
ns[key] = [ns[key]]
|
181
181
|
}
|
182
182
|
|
183
|
-
value !==
|
183
|
+
value !== field.uncheckedValue && ns[key].unshift(value)
|
184
184
|
} else if (value !== undefined) {
|
185
185
|
ns[key] = value
|
186
186
|
}
|
@@ -235,11 +235,11 @@ class Container extends BaseContainer {
|
|
235
235
|
fields = await me.getFields(),
|
236
236
|
path, value;
|
237
237
|
|
238
|
-
fields.forEach(
|
239
|
-
path = me.getFieldPath(
|
238
|
+
fields.forEach(field => {
|
239
|
+
path = me.getFieldPath(field);
|
240
240
|
value = Neo.nsWithArrays(path, false, values);
|
241
241
|
|
242
|
-
|
242
|
+
field.reset(path ? value : null)
|
243
243
|
})
|
244
244
|
}
|
245
245
|
|
@@ -253,38 +253,38 @@ class Container extends BaseContainer {
|
|
253
253
|
fields = await me.getFields(),
|
254
254
|
fieldConfigs, isCheckBox, isRadio, path, value;
|
255
255
|
|
256
|
-
fields.forEach(
|
257
|
-
path = me.getFieldPath(
|
256
|
+
fields.forEach(field => {
|
257
|
+
path = me.getFieldPath(field);
|
258
258
|
fieldConfigs = Neo.nsWithArrays(path, false, configs);
|
259
259
|
|
260
260
|
if (fieldConfigs) {
|
261
261
|
if (suspendEvents) {
|
262
|
-
|
262
|
+
field.suspendEvents = true
|
263
263
|
}
|
264
264
|
|
265
|
-
isCheckBox = Neo.form.field?.CheckBox &&
|
265
|
+
isCheckBox = Neo.form.field?.CheckBox && field instanceof Neo.form.field.CheckBox;
|
266
|
+
isRadio = Neo.form.field?.Radio && field instanceof Neo.form.field.Radio;
|
266
267
|
value = fieldConfigs.value;
|
267
268
|
|
268
|
-
if (
|
269
|
+
if (isRadio) {
|
270
|
+
fieldConfigs.checked = field.value === value;
|
271
|
+
delete fieldConfigs.value
|
272
|
+
} else if (isCheckBox) {
|
269
273
|
if (Neo.typeOf(value) === 'Array') {
|
270
|
-
if (value.includes(
|
274
|
+
if (value.includes(field.value)) {
|
271
275
|
fieldConfigs.checked = true
|
272
276
|
}
|
273
277
|
} else {
|
274
|
-
fieldConfigs.checked =
|
278
|
+
fieldConfigs.checked = field.value === value
|
275
279
|
}
|
276
|
-
} else if (value !== undefined) {
|
277
|
-
isRadio = Neo.form.field?.Radio && item instanceof Neo.form.field.Radio;
|
278
280
|
|
279
|
-
|
280
|
-
fieldConfigs.checked = item.value === value
|
281
|
-
}
|
281
|
+
delete fieldConfigs.value
|
282
282
|
}
|
283
283
|
|
284
|
-
|
284
|
+
field.set(fieldConfigs)
|
285
285
|
|
286
286
|
if (suspendEvents) {
|
287
|
-
delete
|
287
|
+
delete field.suspendEvents
|
288
288
|
}
|
289
289
|
}
|
290
290
|
})
|
@@ -311,8 +311,8 @@ class Container extends BaseContainer {
|
|
311
311
|
fields = await this.getFields(),
|
312
312
|
validField;
|
313
313
|
|
314
|
-
fields.forEach(
|
315
|
-
validField =
|
314
|
+
fields.forEach(field => {
|
315
|
+
validField = field.validate?.(false);
|
316
316
|
|
317
317
|
if (!validField) {
|
318
318
|
isValid = false
|
@@ -0,0 +1,149 @@
|
|
1
|
+
import Base from '../../core/Base.mjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Helper class to include Google's Material Web Components into your neo.mjs app
|
5
|
+
* https://www.amcharts.com/docs/v4/
|
6
|
+
* @class Neo.main.addon.PrefixField
|
7
|
+
* @extends Neo.core.Base
|
8
|
+
* @singleton
|
9
|
+
*/
|
10
|
+
class PrefixField extends Base {
|
11
|
+
static config = {
|
12
|
+
/**
|
13
|
+
* @member {String} className='Neo.main.addon.PrefixField'
|
14
|
+
* @protected
|
15
|
+
*/
|
16
|
+
className: 'Neo.main.addon.PrefixField',
|
17
|
+
/**
|
18
|
+
* @member {Boolean} singleton=true
|
19
|
+
* @protected
|
20
|
+
*/
|
21
|
+
singleton: true,
|
22
|
+
/**
|
23
|
+
* Remote method access for other workers
|
24
|
+
* @member {Object} remote
|
25
|
+
* @protected
|
26
|
+
*/
|
27
|
+
remote: {
|
28
|
+
app: [
|
29
|
+
'initialize',
|
30
|
+
'destroy',
|
31
|
+
'updateAccept',
|
32
|
+
'updatePattern',
|
33
|
+
'updateSlots',
|
34
|
+
]
|
35
|
+
},
|
36
|
+
|
37
|
+
/**
|
38
|
+
* regex to calculate if entered value is acceptable
|
39
|
+
* Preset to numbers only
|
40
|
+
*
|
41
|
+
* @member {regex|null} accept
|
42
|
+
*/
|
43
|
+
accept_: null,
|
44
|
+
/**
|
45
|
+
* @member {String} pattern=null
|
46
|
+
*/
|
47
|
+
pattern_: null,
|
48
|
+
/**
|
49
|
+
* Only add a String. A Set will be automatically created
|
50
|
+
* @member {String|Set|null} slots=null
|
51
|
+
*/
|
52
|
+
slots_: null
|
53
|
+
}
|
54
|
+
|
55
|
+
destroy() {
|
56
|
+
|
57
|
+
}
|
58
|
+
|
59
|
+
elIds = new Map();
|
60
|
+
|
61
|
+
prev;
|
62
|
+
|
63
|
+
back = false;
|
64
|
+
|
65
|
+
/**
|
66
|
+
*
|
67
|
+
* @param {Object} data
|
68
|
+
* @param {String} data.elId
|
69
|
+
* @param {String} data.pattern
|
70
|
+
* @param {String} data.slots
|
71
|
+
* @param {String} data.accept
|
72
|
+
*/
|
73
|
+
initialize(data) {
|
74
|
+
const me = this;
|
75
|
+
|
76
|
+
me.elId = data.elId;
|
77
|
+
|
78
|
+
const el = me.el = document.getElementById(data.elId),
|
79
|
+
pattern = me.pattern = data.pattern,
|
80
|
+
slots = me.slots = new Set(data.slots || "_");
|
81
|
+
|
82
|
+
me.accept = data.accept;
|
83
|
+
me.prev = (j => Array.from(pattern, (c, i) => slots.has(c) ? j = i + 1 : j))(0);
|
84
|
+
me.first = [...pattern].findIndex(c => slots.has(c));
|
85
|
+
|
86
|
+
me.addListeners();
|
87
|
+
me.addCss();
|
88
|
+
}
|
89
|
+
|
90
|
+
addCss() {
|
91
|
+
this.el.classList.add('tiny-prefix-field-input');
|
92
|
+
}
|
93
|
+
|
94
|
+
addListeners() {
|
95
|
+
const me = this,
|
96
|
+
el = me.el,
|
97
|
+
formatFn = me.format.bind(me);
|
98
|
+
|
99
|
+
el.addEventListener("keypress", me.onKeyDown.bind(me));
|
100
|
+
el.addEventListener("input", formatFn);
|
101
|
+
el.addEventListener("focusin", formatFn);
|
102
|
+
el.addEventListener("focusout", me.onBlur.bind(me));
|
103
|
+
}
|
104
|
+
|
105
|
+
onBlur() {
|
106
|
+
const pattern = this.pattern,
|
107
|
+
el = this.el;
|
108
|
+
|
109
|
+
return el.value === pattern && (el.value = "");
|
110
|
+
}
|
111
|
+
|
112
|
+
onKeyDown(event) {
|
113
|
+
this.back = (event.key === "Backspace");
|
114
|
+
}
|
115
|
+
|
116
|
+
clean(input) {
|
117
|
+
const el = this.el,
|
118
|
+
accept = new RegExp(this.accept || "\\d", "g"),
|
119
|
+
pattern = this.pattern,
|
120
|
+
slots = this.slots;
|
121
|
+
|
122
|
+
input = input.match(accept) || [];
|
123
|
+
|
124
|
+
return Array.from(pattern, c =>
|
125
|
+
input[0] === c || slots.has(c) ? input.shift() || c : c
|
126
|
+
);
|
127
|
+
}
|
128
|
+
|
129
|
+
format() {
|
130
|
+
const me = this,
|
131
|
+
el = this.el,
|
132
|
+
prev = this.prev,
|
133
|
+
clean = this.clean.bind(this);
|
134
|
+
console.log(el.selectionStart, el.selectionEnd);
|
135
|
+
const [i, j] = [el.selectionStart, el.selectionEnd].map(i => {
|
136
|
+
i = clean(el.value.slice(0, i)).findIndex(c => me.slots.has(c));
|
137
|
+
return i < 0 ? prev[prev.length - 1] : me.back ? prev[i - 1] || me.first : i;
|
138
|
+
});
|
139
|
+
|
140
|
+
el.value = clean(el.value).join``;
|
141
|
+
el.setSelectionRange(i, j);
|
142
|
+
|
143
|
+
this.back = false;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
let instance = Neo.applyClassConfig(PrefixField);
|
148
|
+
|
149
|
+
export default instance;
|
@@ -0,0 +1,194 @@
|
|
1
|
+
import Base from './Base.mjs';
|
2
|
+
import Container from '../container/Base.mjs'
|
3
|
+
import NeoArray from "../util/Array.mjs";
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Popover usable as tooltip
|
7
|
+
* @class Neo.plugin.Popover
|
8
|
+
* @extends Neo.plugin.Base
|
9
|
+
*
|
10
|
+
* @example
|
11
|
+
*
|
12
|
+
* module : Button,
|
13
|
+
* width : 200,
|
14
|
+
* text : 'Click Me',
|
15
|
+
* plugins: [{
|
16
|
+
* module: PopoverPlugin,
|
17
|
+
* align : 'bc-tc',
|
18
|
+
* items : [{
|
19
|
+
* ntype : 'panel',
|
20
|
+
* headers: [{
|
21
|
+
* dock: 'top',
|
22
|
+
* html: 'HEADER'
|
23
|
+
* }],
|
24
|
+
* items : [{
|
25
|
+
* html: 'This is a comment about the button'
|
26
|
+
* }]
|
27
|
+
* }]
|
28
|
+
* }]
|
29
|
+
*/
|
30
|
+
class Popover extends Base {
|
31
|
+
/**
|
32
|
+
* Valid values for align
|
33
|
+
* @member {String[]} alignValues=['bc-tc','tc-bc','tl-tr','tr-tl','cl-cr','cr-cl',null]
|
34
|
+
* @protected
|
35
|
+
* @static
|
36
|
+
*
|
37
|
+
* todo add more
|
38
|
+
*/
|
39
|
+
static alignValues = ['bc-tc', 'tc-bc', 'tl-tr', 'tr-tl', 'cl-cr', 'cr-cl', null]
|
40
|
+
|
41
|
+
static config = {
|
42
|
+
/**
|
43
|
+
* @member {String} className='Neo.plugin.Popover'
|
44
|
+
* @protected
|
45
|
+
*/
|
46
|
+
className: 'Neo.plugin.Popover',
|
47
|
+
/**
|
48
|
+
* @member {String} ntype='popover'
|
49
|
+
* @protected
|
50
|
+
*/
|
51
|
+
ntype: 'plugin-popover',
|
52
|
+
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Define popover to popovertarget alignment
|
56
|
+
* Defaults to bottom center of popover is aligned to top center of owner
|
57
|
+
* @type {string} align='bc-tc'
|
58
|
+
*/
|
59
|
+
align_: 'bc-tc',
|
60
|
+
/**
|
61
|
+
* Custom cls to add to the owner component
|
62
|
+
* @member {String} ownerCls='neo-prefixfield'
|
63
|
+
*/
|
64
|
+
popovertargetCls: 'neo-popover-target',
|
65
|
+
/**
|
66
|
+
* Custom cls to add to the owner component
|
67
|
+
* @member {String} ownerCls='neo-prefixfield'
|
68
|
+
*/
|
69
|
+
popoverBaseCls: 'neo-popover',
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* @param {Object} config
|
74
|
+
*/
|
75
|
+
construct(config) {
|
76
|
+
let me = this;
|
77
|
+
|
78
|
+
super.construct(config);
|
79
|
+
|
80
|
+
me.popoverId = Neo.getId('popover');
|
81
|
+
|
82
|
+
// prepare owner
|
83
|
+
me.preparePopoverTarget();
|
84
|
+
me.addPopover();
|
85
|
+
|
86
|
+
me.addListeners();
|
87
|
+
}
|
88
|
+
|
89
|
+
/**
|
90
|
+
* Add listeners
|
91
|
+
* @protected
|
92
|
+
*/
|
93
|
+
addListeners() {
|
94
|
+
const me = this;
|
95
|
+
|
96
|
+
me.owner.addDomListeners([
|
97
|
+
{mouseover: me.onTargetMouseOver, scope: me},
|
98
|
+
{mouseout: me.onTargetMouseOut, scope: me}
|
99
|
+
]);
|
100
|
+
}
|
101
|
+
|
102
|
+
/**
|
103
|
+
* Create the popover and add it to the parent component of the owner
|
104
|
+
* @protected
|
105
|
+
*/
|
106
|
+
addPopover() {
|
107
|
+
const me = this,
|
108
|
+
owner = me.owner,
|
109
|
+
parent = Neo.get(me.owner.parentId),
|
110
|
+
popover = {
|
111
|
+
module: Container,
|
112
|
+
id : me.popoverId,
|
113
|
+
|
114
|
+
baseCls: [me.popoverBaseCls],
|
115
|
+
cls : [me.align],
|
116
|
+
|
117
|
+
layout: 'base',
|
118
|
+
items : me.items || [],
|
119
|
+
|
120
|
+
vdom: {
|
121
|
+
// Possible Values are auto, manual.
|
122
|
+
popover: 'auto',
|
123
|
+
anchor : owner.id
|
124
|
+
}
|
125
|
+
};
|
126
|
+
|
127
|
+
parent.add(popover);
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
* Checks if the new value for "align" is valid
|
132
|
+
* @param {String|null} value
|
133
|
+
* @param {String|null} oldValue
|
134
|
+
* @protected
|
135
|
+
* @returns {String|null} value
|
136
|
+
*/
|
137
|
+
beforeSetAlign(value, oldValue) {
|
138
|
+
return this.testInputValue(value, oldValue, 'alignValues', 'align');
|
139
|
+
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* @event mouseout
|
143
|
+
* @param {Object} data
|
144
|
+
* @protected
|
145
|
+
*/
|
146
|
+
onTargetMouseOut(data) {
|
147
|
+
Neo.main.addon.Popover.hide({id: data.component.id});
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* @event mouseover
|
152
|
+
* @param {Object} data
|
153
|
+
* @protected
|
154
|
+
*/
|
155
|
+
onTargetMouseOver(data) {
|
156
|
+
Neo.main.addon.Popover.show({id: data.component.id});
|
157
|
+
}
|
158
|
+
|
159
|
+
/**
|
160
|
+
* @protected
|
161
|
+
*/
|
162
|
+
preparePopoverTarget() {
|
163
|
+
const me = this,
|
164
|
+
target = me.owner,
|
165
|
+
targetVdom = target.vdom;
|
166
|
+
|
167
|
+
target.addCls(me.popovertargetCls);
|
168
|
+
targetVdom.popovertarget = me.popoverId;
|
169
|
+
}
|
170
|
+
|
171
|
+
/**
|
172
|
+
* Checks if the new value for propertyName is valid
|
173
|
+
* @param {String|null} value
|
174
|
+
* @param {String|null} oldValue
|
175
|
+
* @param {String} validValuesName
|
176
|
+
* @param {String} propertyName
|
177
|
+
* @protected
|
178
|
+
* @returns {String|null} value
|
179
|
+
*/
|
180
|
+
testInputValue(value, oldValue, validValuesName, propertyName) {
|
181
|
+
const validValues = this.getStaticConfig(validValuesName);
|
182
|
+
|
183
|
+
if (!NeoArray.hasItem(validValues, value)) {
|
184
|
+
Neo.logError(this.id + ' -> layout: supported values for "' + propertyName + '" are', validValues);
|
185
|
+
return oldValue;
|
186
|
+
}
|
187
|
+
|
188
|
+
return value;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
Neo.applyClassConfig(Popover);
|
193
|
+
|
194
|
+
export default Popover;
|