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.
- package/apps/ServiceWorker.mjs +2 -2
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/fieldWithPrefix/MainContainer.mjs +151 -0
- package/examples/fieldWithPrefix/app.mjs +6 -0
- package/examples/fieldWithPrefix/index.html +11 -0
- package/examples/fieldWithPrefix/neo-config.json +7 -0
- package/examples/form/field/fileupload/MainContainer.mjs +1 -1
- package/examples/form/field/fileupload/server.mjs +1 -1
- package/package.json +1 -1
- package/resources/scss/src/examples/fieldWithPrefix/MainContainer.scss +25 -0
- package/resources/scss/src/form/field/FileUpload.scss +21 -8
- package/resources/scss/src/plugin/PrefixField.scss +5 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/component/Splitter.mjs +0 -1
- package/src/draggable/tab/header/toolbar/SortZone.mjs +3 -3
- package/src/form/field/FileUpload.mjs +23 -5
- package/src/form/field/Text.mjs +1 -1
- package/src/manager/DomEvent.mjs +1 -0
- package/src/plugin/PrefixField.mjs +304 -0
- package/src/tab/header/Toolbar.mjs +8 -8
package/apps/ServiceWorker.mjs
CHANGED
@@ -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,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>
|
@@ -105,7 +105,7 @@ class MainContainer extends ConfigurationViewport {
|
|
105
105
|
id : 2,
|
106
106
|
fileName : 'test.pdf',
|
107
107
|
size : 10664885,
|
108
|
-
status : '
|
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":"
|
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
@@ -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.
|
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;
|
package/src/DefaultConfig.mjs
CHANGED
@@ -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.
|
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.
|
253
|
+
version: '6.0.1'
|
254
254
|
};
|
255
255
|
|
256
256
|
Object.assign(DefaultConfig, {
|
@@ -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
|
-
|
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 =
|
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[
|
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[
|
767
|
+
this.vdom.cn[5].cn = [];
|
750
768
|
}
|
751
769
|
|
752
770
|
this.validate();
|
package/src/form/field/Text.mjs
CHANGED
@@ -665,7 +665,7 @@ class Text extends Base {
|
|
665
665
|
|
666
666
|
me.silentVdomUpdate = true;
|
667
667
|
|
668
|
-
|
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
|
|
package/src/manager/DomEvent.mjs
CHANGED
@@ -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
|
|