neo.mjs 6.0.0 → 6.0.2
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/apps/covid/view/MainContainerController.mjs +9 -22
- package/apps/sharedcovid/view/MainContainerController.mjs +11 -30
- package/docs/app/view/MainContainerController.mjs +9 -11
- 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 -11
- package/src/Main.mjs +23 -9
- 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/main/DomEvents.mjs +7 -2
- package/src/main/addon/Stylesheet.mjs +6 -11
- package/src/manager/DomEvent.mjs +1 -0
- package/src/plugin/PrefixField.mjs +304 -0
- package/src/tab/header/Toolbar.mjs +8 -8
- package/src/worker/App.mjs +1 -1
- package/docs/index_no_css_vars.html +0 -17
- package/docs/neo-config-no-css-vars.json +0 -8
package/apps/ServiceWorker.mjs
CHANGED
@@ -390,31 +390,18 @@ class MainContainerController extends ComponentController {
|
|
390
390
|
logo.vdom.src = logoPath + (theme === 'neo-theme-dark' ? 'covid_logo_dark.jpg' : 'covid_logo_light.jpg');
|
391
391
|
logo.update();
|
392
392
|
|
393
|
+
cls = [...component.cls];
|
393
394
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
NeoArray.remove(cls, item);
|
400
|
-
}
|
401
|
-
});
|
395
|
+
component.cls.forEach(item => {
|
396
|
+
if (item.includes('neo-theme')) {
|
397
|
+
NeoArray.remove(cls, item);
|
398
|
+
}
|
399
|
+
});
|
402
400
|
|
403
|
-
|
404
|
-
|
401
|
+
NeoArray.add(cls, theme);
|
402
|
+
component.cls = cls;
|
405
403
|
|
406
|
-
|
407
|
-
iconCls,
|
408
|
-
text: buttonText
|
409
|
-
});
|
410
|
-
} else {
|
411
|
-
Neo.main.addon.Stylesheet.swapStyleSheet({
|
412
|
-
href: href,
|
413
|
-
id : 'neo-theme'
|
414
|
-
}).then(data => {
|
415
|
-
button.text = buttonText;
|
416
|
-
});
|
417
|
-
}
|
404
|
+
button.set({iconCls, text: buttonText});
|
418
405
|
|
419
406
|
if (mapView) {
|
420
407
|
mapView.mapboxStyle = mapViewStyle;
|
@@ -580,42 +580,23 @@ class MainContainerController extends ComponentController {
|
|
580
580
|
logo.vdom.src = logoPath + (theme === 'neo-theme-dark' ? 'covid_logo_dark.jpg' : 'covid_logo_light.jpg');
|
581
581
|
logo.update();
|
582
582
|
|
583
|
+
[component.appName, ...me.connectedApps].forEach(appName => {
|
584
|
+
component = me.getMainView(appName);
|
583
585
|
|
584
|
-
|
585
|
-
[component.appName, ...me.connectedApps].forEach(appName => {
|
586
|
-
component = me.getMainView(appName);
|
586
|
+
cls = [...component.cls];
|
587
587
|
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
NeoArray.remove(cls, item);
|
593
|
-
}
|
594
|
-
});
|
595
|
-
|
596
|
-
NeoArray.add(cls, theme);
|
597
|
-
component.cls = cls;
|
598
|
-
});
|
599
|
-
|
600
|
-
button.set({
|
601
|
-
iconCls,
|
602
|
-
text: buttonText
|
603
|
-
});
|
604
|
-
} else {
|
605
|
-
[component.appName, ...me.connectedApps].forEach(appName => {
|
606
|
-
Neo.main.addon.Stylesheet.swapStyleSheet({
|
607
|
-
appName,
|
608
|
-
href,
|
609
|
-
id: 'neo-theme'
|
610
|
-
});
|
588
|
+
component.cls.forEach(item => {
|
589
|
+
if (item.includes('neo-theme')) {
|
590
|
+
NeoArray.remove(cls, item)
|
591
|
+
}
|
611
592
|
});
|
612
|
-
}
|
613
593
|
|
614
|
-
|
615
|
-
|
616
|
-
text: buttonText
|
594
|
+
NeoArray.add(cls, theme);
|
595
|
+
component.cls = cls;
|
617
596
|
});
|
618
597
|
|
598
|
+
button.set({iconCls, text: buttonText});
|
599
|
+
|
619
600
|
if (mapView) {
|
620
601
|
mapView.mapboxStyle = mapViewStyle;
|
621
602
|
} else {
|
@@ -192,20 +192,18 @@ class MainContainerController extends Component {
|
|
192
192
|
theme = 'neo-theme-dark';
|
193
193
|
}
|
194
194
|
|
195
|
-
|
196
|
-
cls = [...view.cls];
|
195
|
+
cls = [...view.cls];
|
197
196
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
197
|
+
view.cls.forEach(item => {
|
198
|
+
if (item.includes('neo-theme')) {
|
199
|
+
NeoArray.remove(cls, item)
|
200
|
+
}
|
201
|
+
});
|
203
202
|
|
204
|
-
|
205
|
-
|
203
|
+
NeoArray.add(cls, theme);
|
204
|
+
view.cls = cls;
|
206
205
|
|
207
|
-
|
208
|
-
}
|
206
|
+
button.text = buttonText
|
209
207
|
}
|
210
208
|
|
211
209
|
/**
|
@@ -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
@@ -153,7 +153,6 @@ const DefaultConfig = {
|
|
153
153
|
renderCountDeltas: false,
|
154
154
|
/**
|
155
155
|
* Add themes you want to use here. The first theme will get applied.
|
156
|
-
* If config.useCssVars === true, other theme variables will get included as well
|
157
156
|
* @default ['neo-theme-light', 'neo-theme-dark']
|
158
157
|
* @memberOf! module:Neo
|
159
158
|
* @name config.themes
|
@@ -168,14 +167,6 @@ const DefaultConfig = {
|
|
168
167
|
* @type Boolean
|
169
168
|
*/
|
170
169
|
unitTestMode: false,
|
171
|
-
/**
|
172
|
-
* Flag if CSS variable based stylesheets are in use (important for switching themes)
|
173
|
-
* @default true
|
174
|
-
* @memberOf! module:Neo
|
175
|
-
* @name config.useCssVars
|
176
|
-
* @type Boolean
|
177
|
-
*/
|
178
|
-
useCssVars: true,
|
179
170
|
/**
|
180
171
|
* Experimental flag if an offscreen canvas worker should get created.
|
181
172
|
* @default false
|
@@ -245,12 +236,12 @@ const DefaultConfig = {
|
|
245
236
|
useVdomWorker: true,
|
246
237
|
/**
|
247
238
|
* buildScripts/injectPackageVersion.mjs will update this value
|
248
|
-
* @default '6.0.
|
239
|
+
* @default '6.0.2'
|
249
240
|
* @memberOf! module:Neo
|
250
241
|
* @name config.version
|
251
242
|
* @type String
|
252
243
|
*/
|
253
|
-
version: '6.0.
|
244
|
+
version: '6.0.2'
|
254
245
|
};
|
255
246
|
|
256
247
|
Object.assign(DefaultConfig, {
|
package/src/Main.mjs
CHANGED
@@ -50,6 +50,7 @@ class Main extends core.Base {
|
|
50
50
|
'editRoute',
|
51
51
|
'getByPath',
|
52
52
|
'getWindowData',
|
53
|
+
'importAddon',
|
53
54
|
'redirectTo',
|
54
55
|
'setNeoConfig',
|
55
56
|
'setRoute',
|
@@ -192,9 +193,25 @@ class Main extends core.Base {
|
|
192
193
|
};
|
193
194
|
}
|
194
195
|
|
195
|
-
|
196
|
-
|
197
|
-
|
196
|
+
/**
|
197
|
+
* Import main thread addons at run-time from within the app worker
|
198
|
+
* @param {Object} data
|
199
|
+
* @param {String} data.name
|
200
|
+
* @returns {Boolean}
|
201
|
+
*/
|
202
|
+
async importAddon(data) {
|
203
|
+
let name = data.name,
|
204
|
+
module;
|
205
|
+
|
206
|
+
if (name.startsWith('WS/')) {
|
207
|
+
module = await import(`../../../src/main/addon/${name.substring(3)}.mjs`)
|
208
|
+
} else {
|
209
|
+
module = await import(`./main/addon/${name}.mjs`)
|
210
|
+
}
|
211
|
+
|
212
|
+
this.addon[module.default.constructor.name] = module.default;
|
213
|
+
|
214
|
+
return true
|
198
215
|
}
|
199
216
|
|
200
217
|
/**
|
@@ -209,9 +226,6 @@ class Main extends core.Base {
|
|
209
226
|
|
210
227
|
DomAccess.onDomContentLoaded();
|
211
228
|
|
212
|
-
// not in use right now
|
213
|
-
// window.addEventListener('resize', me.globalResizeListener.bind(me));
|
214
|
-
|
215
229
|
// we need different publicPath values for the main thread inside the webpack based dist envs,
|
216
230
|
// depending on the hierarchy level of the app entry point
|
217
231
|
if (config.environment !== 'development') {
|
@@ -229,7 +243,7 @@ class Main extends core.Base {
|
|
229
243
|
|
230
244
|
mainThreadAddons.forEach(addon => {
|
231
245
|
if (addon.startsWith('WS/')) {
|
232
|
-
imports.push(import(`../../../src/main/addon/${addon.
|
246
|
+
imports.push(import(`../../../src/main/addon/${addon.substring(3)}.mjs`));
|
233
247
|
} else {
|
234
248
|
imports.push(import(`./main/addon/${addon}.mjs`));
|
235
249
|
}
|
@@ -245,7 +259,7 @@ class Main extends core.Base {
|
|
245
259
|
|
246
260
|
WorkerManager.onWorkerConstructed({
|
247
261
|
origin: 'main'
|
248
|
-
})
|
262
|
+
})
|
249
263
|
}
|
250
264
|
|
251
265
|
/**
|
@@ -258,7 +272,7 @@ class Main extends core.Base {
|
|
258
272
|
action : 'reply',
|
259
273
|
replyId: data.id,
|
260
274
|
success: true
|
261
|
-
})
|
275
|
+
})
|
262
276
|
}
|
263
277
|
|
264
278
|
/**
|
@@ -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/main/DomEvents.mjs
CHANGED
@@ -118,8 +118,8 @@ class DomEvents extends Base {
|
|
118
118
|
|
119
119
|
let me = this;
|
120
120
|
|
121
|
-
document.addEventListener('selectionchange', me.onSelectionChange .bind(me));
|
122
121
|
document.addEventListener('DOMContentLoaded', me.onDomContentLoaded.bind(me));
|
122
|
+
document.addEventListener('selectionchange', me.onSelectionChange .bind(me));
|
123
123
|
window .addEventListener('hashchange', me.onHashChange .bind(me));
|
124
124
|
|
125
125
|
if (Neo.config.useSharedWorkers) {
|
@@ -332,6 +332,11 @@ class DomEvents extends Base {
|
|
332
332
|
return path
|
333
333
|
}
|
334
334
|
|
335
|
+
/**
|
336
|
+
* @param {Object[]} path
|
337
|
+
* @param {HTMLElement} target
|
338
|
+
* @returns {Object[]}
|
339
|
+
*/
|
335
340
|
getSelectionPath(path, target) {
|
336
341
|
if (target.parentNode && target.id.split('__').length > 1) {
|
337
342
|
path = this.getSelectionPath(path, target.parentNode);
|
@@ -343,7 +348,7 @@ class DomEvents extends Base {
|
|
343
348
|
}
|
344
349
|
|
345
350
|
/**
|
346
|
-
* @param {
|
351
|
+
* @param {HTMLElement} node
|
347
352
|
* @returns {Object}
|
348
353
|
*/
|
349
354
|
getTargetData(node) {
|
@@ -72,7 +72,7 @@ class Stylesheet extends Base {
|
|
72
72
|
addGlobalCss() {
|
73
73
|
let config = Neo.config,
|
74
74
|
themes = config.themes,
|
75
|
-
folders =
|
75
|
+
folders = ['src', ...themes],
|
76
76
|
env = config.environment,
|
77
77
|
path = env.startsWith('dist/') ? '' : config.appPath.includes('docs') ? `../dist/${env}/` : `../../dist/${env}/`,
|
78
78
|
rootPath = config.basePath.substr(6);
|
@@ -87,7 +87,7 @@ class Stylesheet extends Base {
|
|
87
87
|
this.createStyleSheet(
|
88
88
|
null,
|
89
89
|
null,
|
90
|
-
`${rootPath}${path}css
|
90
|
+
`${rootPath}${path}css/${folder}/Global.css`
|
91
91
|
);
|
92
92
|
});
|
93
93
|
}
|
@@ -112,19 +112,14 @@ class Stylesheet extends Base {
|
|
112
112
|
className = className.split('.').join('/');
|
113
113
|
|
114
114
|
data.folders.forEach(folder => {
|
115
|
-
if (
|
116
|
-
folder === 'src' && config.useCssVars || folder.includes('theme-') && (
|
117
|
-
config.useCssVars && config.themes.includes(`neo-${folder}`) ||
|
118
|
-
!config.useCssVars && config.themes[0] === `neo-${folder}`
|
119
|
-
)
|
120
|
-
) {
|
115
|
+
if (folder === 'src' || folder.includes('theme-') && config.themes.includes(`neo-${folder}`)) {
|
121
116
|
this.createStyleSheet(
|
122
117
|
null,
|
123
118
|
null,
|
124
|
-
`${rootPath}${path}css
|
125
|
-
)
|
119
|
+
`${rootPath}${path}css/${folder}/${className}.css`
|
120
|
+
)
|
126
121
|
}
|
127
|
-
})
|
122
|
+
})
|
128
123
|
}
|
129
124
|
|
130
125
|
/**
|
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
|
|
package/src/worker/App.mjs
CHANGED
@@ -313,7 +313,7 @@ class App extends Base {
|
|
313
313
|
super.onRegisterNeoConfig(msg);
|
314
314
|
|
315
315
|
let config = Neo.config,
|
316
|
-
url =
|
316
|
+
url = 'resources/theme-map.json';
|
317
317
|
|
318
318
|
if (config.environment === 'development') {
|
319
319
|
url = `../../${url}`
|
@@ -1,17 +0,0 @@
|
|
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>Neo Docs NoCssVars</title>
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<script type="module">
|
10
|
-
fetch('./neo-config-no-css-vars.json').then(response => response.json()).then(data => {
|
11
|
-
self.Neo = {config: {}};
|
12
|
-
Object.assign(Neo.config, data);
|
13
|
-
import(data.mainPath);
|
14
|
-
});
|
15
|
-
</script>
|
16
|
-
</body>
|
17
|
-
</html>
|