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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.3.0'
23
+ * @member {String} version='6.3.1'
24
24
  */
25
- version: '6.3.0'
25
+ version: '6.3.1'
26
26
  }
27
27
 
28
28
  /**
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.3.0'
23
+ * @member {String} version='6.3.1'
24
24
  */
25
- version: '6.3.0'
25
+ version: '6.3.1'
26
26
  }
27
27
 
28
28
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "6.3.0",
3
+ "version": "6.3.1",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -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.0'
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.0'
244
+ version: '6.3.1'
245
245
  };
246
246
 
247
247
  Object.assign(DefaultConfig, {
@@ -123,8 +123,8 @@ class Container extends BaseContainer {
123
123
 
124
124
  await this.loadModules();
125
125
 
126
- ComponentManager.getChildComponents(this).forEach(item => {
127
- item instanceof BaseField && fields.push(item)
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
- itemName, key, ns, nsArray, value;
140
+ fieldName, key, ns, nsArray, value;
141
141
 
142
- fields.forEach(item => {
143
- value = item.getValue();
142
+ fields.forEach(field => {
143
+ value = field.getValue();
144
144
 
145
- if (item.name) {
146
- itemName = item.name;
145
+ if (field.name) {
146
+ fieldName = field.name;
147
147
 
148
- if (item.formGroup) {
149
- itemName = item.formGroup + '.' + itemName;
148
+ if (field.formGroup) {
149
+ fieldName = field.formGroup + '.' + fieldName;
150
150
  }
151
151
 
152
- nsArray = itemName.split('.');
152
+ nsArray = fieldName.split('.');
153
153
  key = nsArray.pop();
154
154
  ns = Neo.nsWithArrays(nsArray, true, values);
155
155
  } else {
156
- key = item.id;
156
+ key = field.id;
157
157
  ns = values
158
158
  }
159
159
 
160
160
  // Ensuring that Radios will not return arrays
161
- if (Radio && item instanceof 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 !== item.uncheckedValue) {
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] === item.uncheckedValue) {
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 !== item.uncheckedValue && ns[key].unshift(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(item => {
239
- path = me.getFieldPath(item);
238
+ fields.forEach(field => {
239
+ path = me.getFieldPath(field);
240
240
  value = Neo.nsWithArrays(path, false, values);
241
241
 
242
- item.reset(path ? value : null)
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(item => {
257
- path = me.getFieldPath(item);
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
- item.suspendEvents = true
262
+ field.suspendEvents = true
263
263
  }
264
264
 
265
- isCheckBox = Neo.form.field?.CheckBox && item instanceof 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 (isCheckBox) {
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(item.value)) {
274
+ if (value.includes(field.value)) {
271
275
  fieldConfigs.checked = true
272
276
  }
273
277
  } else {
274
- fieldConfigs.checked = item.value === value
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
- if (isRadio) {
280
- fieldConfigs.checked = item.value === value
281
- }
281
+ delete fieldConfigs.value
282
282
  }
283
283
 
284
- item.set(fieldConfigs)
284
+ field.set(fieldConfigs)
285
285
 
286
286
  if (suspendEvents) {
287
- delete item.suspendEvents
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(item => {
315
- validField = item.validate?.(false);
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;