neo.mjs 6.0.0 → 6.0.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.0.0'
23
+ * @member {String} version='6.0.1'
24
24
  */
25
- version: '6.0.0'
25
+ version: '6.0.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.0.0'
23
+ * @member {String} version='6.0.1'
24
24
  */
25
- version: '6.0.0'
25
+ version: '6.0.1'
26
26
  }
27
27
 
28
28
  /**
@@ -0,0 +1,151 @@
1
+ import ConfigurationViewport from '../ConfigurationViewport.mjs';
2
+
3
+ import PrefixPlugin from '../../src/plugin/PrefixField.mjs';
4
+ import SelectField from '../../src/form/field/Select.mjs';
5
+ import TextField from '../../src/form/field/Text.mjs';
6
+
7
+ /**
8
+ * @class Neo.examples.fieldWithPrefix.MainContainer
9
+ * @extends Neo.examples.ConfigurationViewport
10
+ */
11
+ class MainContainer extends ConfigurationViewport {
12
+ static config = {
13
+ className : 'Neo.examples.fieldWithPrefix.MainContainer',
14
+ autoMount : true,
15
+ configItemLabelWidth: 100,
16
+ configItemWidth : 230,
17
+ layout : {ntype: 'hbox', align: 'stretch'},
18
+ cls : ['examples-container-accordion']
19
+ }
20
+
21
+ onPluginConfigChange(config, opts) {
22
+ const textfield = this.exampleComponent.items[0],
23
+ plugin = textfield.getPlugin({flag: 'prefix'});
24
+
25
+ if (config === 'accept') {
26
+ plugin.accept = opts.record.value;
27
+ } else {
28
+ plugin[config] = opts.value;
29
+ textfield.value = '';
30
+ }
31
+ }
32
+
33
+ createConfigurationComponents() {
34
+ let me = this,
35
+ textfield = me.exampleComponent.items[0],
36
+ plugin = textfield.plugins[0];
37
+
38
+ return [{
39
+ module : TextField,
40
+ clearable: true,
41
+ labelText: 'pattern',
42
+ listeners: {change: me.onPluginConfigChange.bind(me, 'pattern')},
43
+ value : plugin.pattern,
44
+ style : {marginTop: '10px'}
45
+ }, {
46
+ module : TextField,
47
+ clearable: true,
48
+ labelText: 'slots',
49
+ listeners: {change: me.onPluginConfigChange.bind(me, 'slots')},
50
+ value : '_',
51
+ style : {marginTop: '10px'}
52
+ }, {
53
+ module: SelectField,
54
+ store : {
55
+ model: {fields: [{name: 'id'}, {name: 'name'}, {name: 'value'}]},
56
+ data : [
57
+ {id: '0', name: 'empty=/\\d/', value: null},
58
+ {id: '1', name: '[0-9]', value: '[0-9]'},
59
+ {id: '2', name: '[A-H]', value: '[A-H]'},
60
+ {id: '3', name: '/\\w/', value: /\w/},
61
+ {id: '4', name: '/\\d/', value: /\d/},
62
+ {id: '5', name: '[0-9a-f]', value: '[0-9a-f]'}
63
+ ]
64
+ },
65
+
66
+ value : '4',
67
+ displayField: 'name',
68
+ valueField : 'value',
69
+
70
+ clearable: true,
71
+ labelText: 'accept',
72
+ listeners: {change: me.onPluginConfigChange.bind(me, 'accept')},
73
+ style : {marginTop: '10px'}
74
+ }];
75
+ }
76
+
77
+ /**
78
+ * @returns {*}
79
+ */
80
+ createExampleComponent() {
81
+ return Neo.ntype({
82
+ ntype : 'container',
83
+ width : 350,
84
+ cls : ['example-fieldWithPrefix'],
85
+ layout: {ntype: 'vbox', align: 'stretch'},
86
+ items : [{
87
+ module : TextField,
88
+ labelText: 'Phone Number',
89
+ plugins : [
90
+ {
91
+ module : PrefixPlugin,
92
+ flag : 'prefix',
93
+ pattern: '+1 (___) ___-___-____',
94
+ slots : '_'
95
+ }
96
+ ]
97
+ }, {
98
+ module : TextField,
99
+ labelText: '[0-9] Date',
100
+ plugins : [
101
+ {
102
+ module : PrefixPlugin,
103
+ flag : 'prefix',
104
+ pattern: 'dd/mm/yyyy hh:mm',
105
+ slots : 'dmyh'
106
+ }
107
+ ]
108
+ }, {
109
+ module : TextField,
110
+ labelText: '[A-H] MAC Adress',
111
+ plugins : [
112
+ {
113
+ module : PrefixPlugin,
114
+ flag : 'prefix',
115
+ pattern: 'XX:XX:XX:XX:XX:XX',
116
+ slots : 'X',
117
+ accept : '[A-H]'
118
+ }
119
+ ]
120
+ }, {
121
+ module : TextField,
122
+ labelText: '/\\w/ Alphanumeric',
123
+ plugins : [
124
+ {
125
+ module : PrefixPlugin,
126
+ flag : 'prefix',
127
+ pattern: '__-__-__-____',
128
+ slots : '_',
129
+ accept : /\w/
130
+ }
131
+ ]
132
+ }, {
133
+ module : TextField,
134
+ labelText: '/\\d/ Credit Card',
135
+ plugins : [
136
+ {
137
+ module : PrefixPlugin,
138
+ flag : 'prefix',
139
+ pattern: '.... .... .... ....',
140
+ slots : '.',
141
+ accept : /\d/
142
+ }
143
+ ]
144
+ }]
145
+ })
146
+ }
147
+ }
148
+
149
+ Neo.applyClassConfig(MainContainer);
150
+
151
+ export default MainContainer;
@@ -0,0 +1,6 @@
1
+ import MainContainer from './MainContainer.mjs';
2
+
3
+ export const onStart = () => Neo.app({
4
+ mainView: MainContainer,
5
+ name : 'Neo.examples.fieldWithPrefix'
6
+ });
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <meta charset="UTF-8">
6
+ <title>Field with Prefix</title>
7
+ </head>
8
+ <body>
9
+ <script src="../../src/MicroLoader.mjs" type="module"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,7 @@
1
+ {
2
+ "appPath" : "examples/fieldWithPrefix/app.mjs",
3
+ "basePath" : "../../",
4
+ "environment": "development",
5
+ "mainPath" : "./Main.mjs",
6
+ "themes" : ["neo-theme-dark", "neo-theme-light"]
7
+ }
@@ -105,7 +105,7 @@ class MainContainer extends ConfigurationViewport {
105
105
  id : 2,
106
106
  fileName : 'test.pdf',
107
107
  size : 10664885,
108
- status : 'UN_DOWNLOADABLE'
108
+ status : 'AVAILABLE'
109
109
  },
110
110
  uploadUrl : 'http://127.0.0.1:3000/file-upload-test',
111
111
  documentStatusUrl : 'http://127.0.0.1:3000/document-status-not-downloadable?documentId={documentId}',
@@ -41,7 +41,7 @@ app.get('/document-status-downloadable', async(req, res) => {
41
41
 
42
42
  app.get('/document-status-not-downloadable', async(req, res) => {
43
43
  res.set('Content-Type', 'application/json');
44
- res.send('{"status":"UN_DOWNLOADABLE","fileName":"testfile.pdf","size":9653413}');
44
+ res.send('{"status":"AVAILABLE","fileName":"testfile.pdf","size":9653413}');
45
45
  });
46
46
 
47
47
  app.get('/document-status-non-existent', async(req, res) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "6.0.0",
3
+ "version": "6.0.1",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -0,0 +1,25 @@
1
+ .example-fieldWithPrefix {
2
+ .neo-prefixfield {
3
+ .neo-input-wrapper {
4
+ position: relative;
5
+ overflow: visible;
6
+
7
+ &::before {
8
+ position: absolute;
9
+ content: "";
10
+ width: 8px;
11
+ height: 8px;
12
+ background-color: indianred;
13
+ border-radius: 50%;
14
+ top: 2px;
15
+ left: -12px;
16
+ }
17
+ }
18
+
19
+ &.neo-focus {
20
+ .neo-input-wrapper::before {
21
+ background-color: darkseagreen;
22
+ }
23
+ }
24
+ }
25
+ }
@@ -15,7 +15,7 @@
15
15
  position : relative;
16
16
  display : flex;
17
17
  align-items : center;
18
- padding : 0.5rem;
18
+ padding : 0.4rem;
19
19
  gap : 0.5rem;
20
20
  border : 1px solid var(--fileuploadfield-border-color);
21
21
  border-radius : 2px;
@@ -73,6 +73,19 @@
73
73
  }
74
74
  }
75
75
 
76
+ .neo-file-upload-label {
77
+ position : absolute;
78
+ top : 0;
79
+ left : 0;
80
+ right : 0;
81
+ bottom : 0;
82
+ display : flex;
83
+ align-items : center;
84
+ justify-content : center;
85
+ background-color : var(--fileuploadfield-background-color);
86
+ cursor : pointer;
87
+ }
88
+
76
89
  .neo-file-upload-filename {
77
90
  font-weight : bold;
78
91
  }
@@ -82,11 +95,12 @@
82
95
  overflow : hidden;
83
96
  text-overflow : ellipsis;
84
97
  color : inherit; // For when it becomes a link
98
+ flex : 0 0 1.2rem;
85
99
  }
86
100
 
87
- // The file input is only visible in the ready state
101
+ // The file input and label is only visible in the ready state
88
102
  &:not(.neo-file-upload-state-ready) {
89
- input[type="file"] {
103
+ input[type="file"],label {
90
104
  display : none;
91
105
  }
92
106
  }
@@ -217,9 +231,9 @@
217
231
  }
218
232
 
219
233
  .neo-file-upload-state-ready {
220
- // Only the input field is visible when in ready state
234
+ // Only the input field and its label is visible when in ready state
221
235
  // It takes up the whole component, and is the only interactive item
222
- :not(input[type="file"]) {
236
+ :not(input[type="file"],label) {
223
237
  display : none;
224
238
  }
225
239
  input::file-selector-button {
@@ -232,7 +246,6 @@
232
246
  bottom : 0;
233
247
  background-color : var(--fileuploadfield-background-color);
234
248
  color : var(--fileuploadfield-color);
235
- cursor : pointer;
236
249
  }
237
250
  }
238
251
 
@@ -240,10 +253,10 @@
240
253
  flex : 1 1 0%;
241
254
  display : flex;
242
255
  flex-flow : column nowrap;
243
- line-height : 1;
244
256
  gap : 0.2rem;
245
257
  overflow : hidden;
246
- align-items : flex-start;}
258
+ align-items : flex-start;
259
+ }
247
260
 
248
261
  .neo-file-upload-error-message {
249
262
  display : none;
@@ -0,0 +1,5 @@
1
+ .neo-prefixfield {
2
+ input.neo-prefixfield-input {
3
+ font-family: 'Andalé Mono', Lucida, Monaco, Courier Menlo, 'Courier New', Courier, monospace;
4
+ }
5
+ }
@@ -245,12 +245,12 @@ const DefaultConfig = {
245
245
  useVdomWorker: true,
246
246
  /**
247
247
  * buildScripts/injectPackageVersion.mjs will update this value
248
- * @default '6.0.0'
248
+ * @default '6.0.1'
249
249
  * @memberOf! module:Neo
250
250
  * @name config.version
251
251
  * @type String
252
252
  */
253
- version: '6.0.0'
253
+ version: '6.0.1'
254
254
  };
255
255
 
256
256
  Object.assign(DefaultConfig, {
@@ -170,7 +170,6 @@ class Splitter extends Component {
170
170
  newSize = data.clientX - data.offsetX - size - parentRect.left;
171
171
 
172
172
  if (resizeNext) {
173
- console.log(parentRect);
174
173
  newSize = parentRect.width - newSize - 2 * size
175
174
  } else {
176
175
  newSize += size
@@ -31,7 +31,7 @@ class SortZone extends BaseSortZone {
31
31
  * @param {Number} toIndex
32
32
  */
33
33
  moveTo(fromIndex, toIndex) {
34
- this.owner.up().moveTo(fromIndex, toIndex);
34
+ this.owner.up().moveTo(fromIndex, toIndex)
35
35
  }
36
36
 
37
37
  /**
@@ -47,7 +47,7 @@ class SortZone extends BaseSortZone {
47
47
 
48
48
  NeoArray.remove(cls, 'neo-no-animation');
49
49
  owner.cls = cls;
50
- }, 300);
50
+ }, 300)
51
51
  }
52
52
 
53
53
  /**
@@ -61,7 +61,7 @@ class SortZone extends BaseSortZone {
61
61
  NeoArray.add(cls, 'neo-no-animation');
62
62
  owner.cls = cls;
63
63
 
64
- super.onDragStart(data);
64
+ super.onDragStart(data)
65
65
  }
66
66
  }
67
67
 
@@ -122,6 +122,10 @@ class FileUpload extends Base {
122
122
  tag : 'input',
123
123
  type : 'file'
124
124
  },
125
+ {
126
+ cls : 'neo-file-upload-label',
127
+ tag : 'label'
128
+ },
125
129
  {
126
130
  cls : 'neo-file-upload-error-message'
127
131
  }
@@ -149,7 +153,7 @@ class FileUpload extends Base {
149
153
  UPLOADING : 'scanning',
150
154
 
151
155
  MALWARE_DETECTED : 'scan-failed',
152
- UN_DOWNLOADABLE : 'not-downloadable',
156
+ AVAILABLE : 'not-downloadable',
153
157
  DOWNLOADABLE : 'downloadable',
154
158
  DELETED : 'deleted'
155
159
  },
@@ -311,6 +315,7 @@ class FileUpload extends Base {
311
315
  error_ : null,
312
316
 
313
317
  // UI strings which can be overridden for other languages
318
+ chooseFile : 'Choose file',
314
319
  documentText : 'Document',
315
320
  pleaseUseTheseTypes : 'Please use these file types',
316
321
  fileSizeMoreThan : 'File size exceeds',
@@ -319,6 +324,7 @@ class FileUpload extends Base {
319
324
  documentStatusError : 'Document status service error',
320
325
  uploadFailed : 'Upload failed',
321
326
  scanning : 'Scanning',
327
+ uploading : 'Uploading...',
322
328
  malwareFoundInFile : 'Malware found in file',
323
329
  pleaseCheck : 'Please check the file and try again',
324
330
  successfullyUploaded : 'Successfully uploaded',
@@ -339,6 +345,18 @@ class FileUpload extends Base {
339
345
  ]);
340
346
  }
341
347
 
348
+ afterSetId(value, oldValue) {
349
+ const
350
+ labelEl = this.vdom.cn[4],
351
+ inputElId = `${this.id}-input`;
352
+
353
+ this.getInputEl().id = labelEl.for = inputElId;
354
+ labelEl.html = this.chooseFile;
355
+
356
+ // silent vdom update, the super call will trigger the engine
357
+ super.afterSetId?.(value, oldValue);
358
+ }
359
+
342
360
  /**
343
361
  * @returns {Object}
344
362
  */
@@ -428,7 +446,7 @@ class FileUpload extends Base {
428
446
 
429
447
  /**
430
448
  * This event fires before every HTTP request is sent to the server via any of the configured URLs.
431
- *
449
+ *
432
450
  * @event beforeRequest
433
451
  * @param {Object} event The event
434
452
  * @param {Object} event.headers An object containing the configured {@link #property-headers}
@@ -452,7 +470,7 @@ class FileUpload extends Base {
452
470
 
453
471
  (vdom.style || (vdom.style = {}))['--upload-progress'] = `${progress}turn`;
454
472
 
455
- vdom.cn[1].cn[1].innerHTML = `Uploading... (${Math.round(progress * 100)}%)`;
473
+ vdom.cn[1].cn[1].innerHTML = `${this.uploading}... (${Math.round(progress * 100)}%)`;
456
474
 
457
475
  this.uploadSize = loaded;
458
476
  this.update();
@@ -740,13 +758,13 @@ class FileUpload extends Base {
740
758
 
741
759
  afterSetError(text) {
742
760
  if (text) {
743
- this.vdom.cn[4].cn = [{
761
+ this.vdom.cn[5].cn = [{
744
762
  vtype : 'text',
745
763
  html : text
746
764
  }];
747
765
  }
748
766
  else {
749
- this.vdom.cn[4].cn = [];
767
+ this.vdom.cn[5].cn = [];
750
768
  }
751
769
 
752
770
  this.validate();
@@ -665,7 +665,7 @@ class Text extends Base {
665
665
 
666
666
  me.silentVdomUpdate = true;
667
667
 
668
- !me.clean && me.validate(false);
668
+ me.validate(false);
669
669
  me.changeInputElKey('required', value ? value : null);
670
670
  me.labelText = me.labelText; // apply the optional text if needed
671
671
 
@@ -31,6 +31,7 @@ const globalDomEvents = [
31
31
  'mouseleave',
32
32
  'mouseup',
33
33
  'scroll',
34
+ 'selectionchange',
34
35
  'wheel'
35
36
  ];
36
37
 
@@ -0,0 +1,304 @@
1
+ import Base from './Base.mjs';
2
+
3
+ /**
4
+ * @class Neo.plugin.PrefixField
5
+ * @extends Neo.plugin.Base
6
+ *
7
+ * @example
8
+ *
9
+ * {
10
+ * module : TextField,
11
+ * labelText: 'Credit Card',
12
+ * plugins : [{
13
+ * module : PrefixPlugin, // import PrefixPlugin from '../../src/plugin/PrefixField.mjs';
14
+ * flag : 'prefix', // textField.getPlugins({flag: 'prefix'})
15
+ * pattern: 'dd/mm/yyyy',
16
+ * slots : 'dmy', // characters allowed to replace
17
+ * accept : /\d/ // either '[A-Z]' or regex or undefined
18
+ * }]
19
+ * }
20
+ */
21
+ class PrefixField extends Base {
22
+ static config = {
23
+ /**
24
+ * @member {String} className='Neo.plugin.PrefixField'
25
+ * @protected
26
+ */
27
+ className: 'Neo.plugin.PrefixField',
28
+ /**
29
+ * @member {String} ntype='plugin-prefixfield'
30
+ * @protected
31
+ */
32
+ ntype: 'plugin-prefixfield',
33
+
34
+ /**
35
+ * Custom cls added to the inputEl
36
+ * @member {String} inputCls='neo-prefixfield-input'
37
+ */
38
+ inputCls: 'neo-prefixfield-input',
39
+ /**
40
+ * Custom cls added to the inputEl
41
+ * @member {String} inputCls='neo-prefixfield-input'
42
+ */
43
+ labelCls: 'neo-prefixfield-label',
44
+ /**
45
+ * Custom cls to add to the owner component
46
+ * @member {String} ownerCls='neo-prefixfield'
47
+ */
48
+ ownerCls: 'neo-prefixfield',
49
+
50
+ /**
51
+ * regex to calculate if entered value is acceptable
52
+ * Preset to numbers only
53
+ *
54
+ * @member {regex|null} accept
55
+ */
56
+ accept_: null,
57
+ /**
58
+ * @member {String} pattern=null
59
+ */
60
+ pattern_: null,
61
+ /**
62
+ * Only add a String. A Set will be automatically created
63
+ * @member {String|Set|null} slots=null
64
+ */
65
+ slots_: null
66
+ }
67
+
68
+ /**
69
+ * First accepted place to enter a value
70
+ * @member {Number} first
71
+ * @protected
72
+ */
73
+ first = null;
74
+ /**
75
+ * Array of numbers, which shows the previous entry point
76
+ * @member {Array[]} prev
77
+ * @protected
78
+ */
79
+ prev = null;
80
+ /**
81
+ * Position of the cursor inside input element
82
+ * @member {Object} selection
83
+ * @protected
84
+ */
85
+ selection = null;
86
+
87
+ /**
88
+ * State if selection should be updated
89
+ * @member {Boolean} ignoreSelection
90
+ * @protected
91
+ */
92
+ ignoreSelection = false;
93
+ /**
94
+ * State if last entry was the back button
95
+ * @member {Boolean} back
96
+ * @protected
97
+ */
98
+ back = false;
99
+
100
+ /**
101
+ * @param {Object} config
102
+ */
103
+ construct(config) {
104
+ let me = this;
105
+
106
+ super.construct(config);
107
+
108
+ me.addListeners();
109
+ me.addCss();
110
+ }
111
+
112
+ /**
113
+ * Add a custom cls to the owner component
114
+ */
115
+ addCss() {
116
+ const me = this,
117
+ owner = me.owner,
118
+ inputEl = owner.getInputEl(),
119
+ labelEl = owner.getLabelEl();
120
+
121
+ owner .addCls(me.ownerCls);
122
+ inputEl.cls.push(me.inputCls);
123
+ labelEl.cls.push(me.labelCls);
124
+ }
125
+
126
+ /**
127
+ * Add listeners
128
+ * @protected
129
+ */
130
+ addListeners() {
131
+ const me = this;
132
+ let listenerId;
133
+
134
+ me.owner.addDomListeners([
135
+ {keydown : me.onFieldKeyDown , scope: me},
136
+ {focusin : me.onFieldFocus , scope: me},
137
+ {focusout : me.onFieldBlur , scope: me},
138
+ {selectionchange: me.onFieldSelectionChange, scope: me}
139
+ ]);
140
+
141
+ listenerId = me.owner.on('mounted', (test) => {
142
+ Neo.currentWorker.insertThemeFiles(me.owner.appName, me.__proto__);
143
+
144
+ me.owner.un('mounted', listenerId);
145
+ listenerId = null;
146
+ });
147
+ }
148
+
149
+
150
+ /**
151
+ * After setting accept format output
152
+ * @param {String} value
153
+ * @param {String} oldValue
154
+ * @protected
155
+ */
156
+ afterSetAccept(value, oldValue) {
157
+ if (this.owner.value) this.format();
158
+ }
159
+
160
+ /**
161
+ * After setting pattern recalc other values and set placeholder
162
+ * @param {Set} value
163
+ * @param {Set} oldValue
164
+ * @protected
165
+ */
166
+ afterSetPattern(value, oldValue) {
167
+ this.owner.placeholderText = value;
168
+ this.recalcFirstAndPref();
169
+ }
170
+
171
+ /**
172
+ * After setting slots recalc other values
173
+ * @param {Set} value
174
+ * @param {Set} oldValue
175
+ * @protected
176
+ */
177
+ afterSetSlots(value, oldValue) {
178
+ this.recalcFirstAndPref();
179
+ }
180
+
181
+ /**
182
+ * Before the new value for slots will be set we create a Set from the string
183
+ * @param {String} value
184
+ * @return {Set}
185
+ * @protected
186
+ */
187
+ beforeSetSlots(value) {
188
+ return new Set(value || "_");
189
+ }
190
+
191
+ /**
192
+ * Remove unwanted entries and limit length
193
+ * @param {String} input
194
+ * @returns {any[]}
195
+ * @protected
196
+ */
197
+ clean(input) {
198
+ const me = this,
199
+ accept = new RegExp(this.accept || "\\d", "g");
200
+
201
+ input = input.match(accept) || [];
202
+ input = Array.from(me.pattern, c =>
203
+ input[0] === c || me.slots.has(c) ? input.shift() || c : c
204
+ );
205
+
206
+ return input.slice(0, me.pattern.length);
207
+ }
208
+
209
+ /**
210
+ * Calculate position and output correct String to Field
211
+ * @protected
212
+ */
213
+ format() {
214
+ const me = this,
215
+ el = me.owner,
216
+ selection = me.selection,
217
+ prev = me.prev,
218
+ clean = me.clean.bind(me);
219
+ let value = el.value || '';
220
+
221
+ const [i, j] = [selection.start, selection.end].map(i => {
222
+ i = me.clean(value.slice(0, i)).findIndex(c => me.slots.has(c));
223
+ return i < 0 ? prev[prev.length - 1] : me.back ? prev[i - 1] || me.first : i;
224
+ });
225
+
226
+ el.value = clean(value).join``;
227
+ this.ignoreSelection = true;
228
+
229
+ Neo.main.DomAccess.selectNode({id: el.getInputElId(), start: i, end: j});
230
+ this.ignoreSelection = false;
231
+
232
+ this.back = false;
233
+ }
234
+
235
+ /**
236
+ * Event
237
+ * @param {Object} data
238
+ * @returns {false|string}
239
+ * @protected
240
+ */
241
+ onFieldBlur(data) {
242
+ const pattern = this.pattern,
243
+ el = this.owner;
244
+
245
+ return el.value === pattern && (el.value = "");
246
+ }
247
+
248
+ /**
249
+ * Event
250
+ * @param {Object} data
251
+ * @protected
252
+ */
253
+ onFieldFocus(data) {
254
+ this.format();
255
+ }
256
+
257
+ /**
258
+ * Event
259
+ * @param {Object} data
260
+ * @protected
261
+ */
262
+ onFieldKeyDown(data) {
263
+ this.back = (data.key === "Backspace");
264
+ }
265
+
266
+ /**
267
+ * Event
268
+ * @param {Object} data
269
+ * @protected
270
+ */
271
+ onFieldSelectionChange(data) {
272
+ let sel = this.selection,
273
+ dSel = data.selection;
274
+
275
+ // Do not run, if ignore state or same start and end data
276
+ if (this.ignoreSelection || (dSel.start === sel.start && dSel.end === sel.end)) {
277
+ return;
278
+ }
279
+
280
+ this.selection = dSel;
281
+ this.format();
282
+ }
283
+
284
+ /**
285
+ * Calc values for first and prev
286
+ * @protected
287
+ */
288
+ recalcFirstAndPref() {
289
+ const me = this,
290
+ pattern = me.pattern,
291
+ slots = me.slots;
292
+
293
+ me.prev = (j => Array.from(pattern, (c, i) => slots.has(c) ? j = i + 1 : j))(0);
294
+ me.first = [...pattern].findIndex(c => slots.has(c));
295
+
296
+ me.selection = {start: me.first, end: me.first};
297
+
298
+ if (me.owner.value) me.format();
299
+ }
300
+ }
301
+
302
+ Neo.applyClassConfig(PrefixField);
303
+
304
+ export default PrefixField;
@@ -43,8 +43,8 @@ class Toolbar extends BaseToolbar {
43
43
  boundaryContainerId: me.id,
44
44
  owner : me,
45
45
  ...me.sortZoneConfig
46
- });
47
- });
46
+ })
47
+ })
48
48
  }
49
49
  }
50
50
 
@@ -61,10 +61,10 @@ class Toolbar extends BaseToolbar {
61
61
  me.items.forEach(item => {
62
62
  // silent updates
63
63
  item._useActiveTabIndicator = value;
64
- item.updateUseActiveTabIndicator(true);
64
+ item.updateUseActiveTabIndicator(true)
65
65
  });
66
66
 
67
- me.update();
67
+ me.update()
68
68
  }
69
69
  }
70
70
 
@@ -78,7 +78,7 @@ class Toolbar extends BaseToolbar {
78
78
  defaults.useActiveTabIndicator = me.useActiveTabIndicator;
79
79
  me.itemDefaults = defaults;
80
80
 
81
- super.createItems();
81
+ super.createItems()
82
82
  }
83
83
 
84
84
  /**
@@ -116,7 +116,7 @@ class Toolbar extends BaseToolbar {
116
116
  break;
117
117
  }
118
118
 
119
- return layoutConfig;
119
+ return layoutConfig
120
120
  }
121
121
 
122
122
  /**
@@ -131,10 +131,10 @@ class Toolbar extends BaseToolbar {
131
131
  if (fromIndex !== toIndex) {
132
132
  this.items.forEach((item, index) => {
133
133
  item.index = index;
134
- });
134
+ })
135
135
  }
136
136
 
137
- return returnValue;
137
+ return returnValue
138
138
  }
139
139
  }
140
140