neo.mjs 4.0.51 → 4.0.54
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/buildScripts/createClass.mjs +131 -29
- package/examples/form/field/text/MainContainer.mjs +29 -5
- package/package.json +7 -3
- package/resources/scss/src/form/field/Text.scss +35 -11
- package/resources/scss/theme-dark/form/field/Text.scss +3 -1
- package/resources/scss/theme-light/form/field/Text.scss +3 -1
- package/src/data/RecordFactory.mjs +39 -12
- package/src/form/field/Number.mjs +17 -10
- package/src/form/field/Text.mjs +18 -0
- package/src/main/mixin/DeltaUpdates.mjs +6 -2
- package/src/table/Container.mjs +4 -7
|
@@ -1,24 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { Command } from 'commander/esm.mjs';
|
|
5
|
+
import envinfo from 'envinfo';
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import inquirer from 'inquirer';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import {fileURLToPath} from 'url';
|
|
11
|
+
|
|
12
|
+
const
|
|
13
|
+
__dirname = fileURLToPath(new URL('../', import.meta.url)),
|
|
10
14
|
cwd = process.cwd(),
|
|
11
15
|
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
|
12
16
|
packageJson = requireJson(path.join(__dirname, 'package.json')),
|
|
13
17
|
insideNeo = packageJson.name === 'neo.mjs',
|
|
14
18
|
program = new Command(),
|
|
15
19
|
programName = `${packageJson.name} create-class`,
|
|
16
|
-
questions = []
|
|
20
|
+
questions = [],
|
|
21
|
+
/**
|
|
22
|
+
* Maintain a list of dir-names recognized as source root directories.
|
|
23
|
+
* When not using dot notation with a class-name, the program assumes
|
|
24
|
+
* that we want to create the class inside the cwd. The proper namespace
|
|
25
|
+
* is then looked up by traversing the directory path up to the first
|
|
26
|
+
* folder that matches an entry in "sourceRootDirs". The owning
|
|
27
|
+
* folder (parent of cwd, child of sourceRootDirs[n]) will then be used as the
|
|
28
|
+
* namespace for this created class.
|
|
29
|
+
* Can be overwritten with the -s option.
|
|
30
|
+
* @type {string[]}
|
|
31
|
+
*/
|
|
32
|
+
sourceRootDirs = ['apps'];
|
|
17
33
|
|
|
18
34
|
program
|
|
19
35
|
.name(programName)
|
|
20
36
|
.version(packageJson.version)
|
|
21
37
|
.option('-i, --info', 'print environment debug info')
|
|
38
|
+
.option('-d, --drop', 'drops class in the currently selected folder')
|
|
39
|
+
.option('-s, --source <value>', `name of the folder containing the project. Defaults to any of ${sourceRootDirs.join(',')}`)
|
|
22
40
|
.option('-b, --baseClass <value>')
|
|
23
41
|
.option('-c, --className <value>')
|
|
24
42
|
.allowUnknownOption()
|
|
@@ -33,7 +51,7 @@ const programOpts = program.opts();
|
|
|
33
51
|
if (programOpts.info) {
|
|
34
52
|
console.log(chalk.bold('\nEnvironment Info:'));
|
|
35
53
|
console.log(`\n current version of ${packageJson.name}: ${packageJson.version}`);
|
|
36
|
-
console.log(` running from ${
|
|
54
|
+
console.log(` running from ${cwd}`);
|
|
37
55
|
|
|
38
56
|
envinfo
|
|
39
57
|
.run({
|
|
@@ -49,6 +67,28 @@ if (programOpts.info) {
|
|
|
49
67
|
} else {
|
|
50
68
|
console.log(chalk.green(programName));
|
|
51
69
|
|
|
70
|
+
if (programOpts.drop) {
|
|
71
|
+
// change source folder if the user wants to
|
|
72
|
+
if (programOpts.source) {
|
|
73
|
+
while (sourceRootDirs.length) {
|
|
74
|
+
sourceRootDirs.pop();
|
|
75
|
+
}
|
|
76
|
+
sourceRootDirs.push(programOpts.source);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!programOpts.className || !programOpts.baseClass) {
|
|
80
|
+
console.error(chalk.red('-d is non interactive. Please provide name base class, and optionally the source parent for the class to create'));
|
|
81
|
+
console.info(chalk.bgCyan('Usage: createClass -d -c <className> -b <baseClass> [-s sourceParent]'));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (programOpts.className.indexOf('.') !== -1) {
|
|
86
|
+
console.error(chalk.red('No .dot-notation available when -d option is selected.'));
|
|
87
|
+
console.info(chalk.bgCyan('Usage: createClass -d -c <className> -b <baseClass> [-s sourceParent]'));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
52
92
|
if (!programOpts.className) {
|
|
53
93
|
questions.push({
|
|
54
94
|
type : 'input',
|
|
@@ -71,6 +111,7 @@ if (programOpts.info) {
|
|
|
71
111
|
inquirer.prompt(questions).then(answers => {
|
|
72
112
|
let baseClass = programOpts.baseClass || answers.baseClass,
|
|
73
113
|
className = programOpts.className || answers.className,
|
|
114
|
+
isDrop = programOpts.drop,
|
|
74
115
|
startDate = new Date(),
|
|
75
116
|
classFolder, file, folderDelta, index, ns, root, rootLowerCase, viewFile;
|
|
76
117
|
|
|
@@ -78,36 +119,97 @@ if (programOpts.info) {
|
|
|
78
119
|
className = className.slice(0, -4);
|
|
79
120
|
}
|
|
80
121
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
122
|
+
if (!isDrop) {
|
|
123
|
+
ns = className.split('.');
|
|
124
|
+
file = ns.pop();
|
|
125
|
+
root = ns.shift();
|
|
126
|
+
rootLowerCase = root.toLowerCase();
|
|
127
|
+
}
|
|
85
128
|
|
|
86
129
|
if (root === 'Neo') {
|
|
87
130
|
console.log('todo: create the file inside the src folder');
|
|
88
131
|
} else {
|
|
89
|
-
if (
|
|
90
|
-
|
|
132
|
+
if (isDrop === true) {
|
|
133
|
+
ns = [];
|
|
134
|
+
|
|
135
|
+
let pathInfo = path.parse(cwd),
|
|
136
|
+
sep = path.sep,
|
|
137
|
+
baseName, loc = baseName = '',
|
|
138
|
+
tmpNs;
|
|
139
|
+
|
|
140
|
+
sourceRootDirs.some(dir => {
|
|
141
|
+
loc = cwd;
|
|
142
|
+
tmpNs = [];
|
|
143
|
+
|
|
144
|
+
while (pathInfo.root !== loc) {
|
|
145
|
+
baseName = path.resolve(loc, './').split(sep).pop();
|
|
146
|
+
|
|
147
|
+
if (baseName === dir) {
|
|
148
|
+
ns = tmpNs.reverse();
|
|
149
|
+
classFolder = path.resolve(loc, ns.join(sep));
|
|
150
|
+
file = className;
|
|
151
|
+
className = ns.concat(className).join('.');
|
|
152
|
+
loc = path.resolve(loc, ns.join(sep));
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
tmpNs.push(baseName);
|
|
157
|
+
loc = path.resolve(loc, '../');
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (!ns.length) {
|
|
162
|
+
console.error(chalk.red(
|
|
163
|
+
'Could not determine namespace for application. Did you provide the ' +
|
|
164
|
+
`correct source parent with -s? (was: ${sourceRootDirs.join(',')}`));
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.info(
|
|
169
|
+
chalk.yellow(`Creating ${chalk.bgGreen(className)} extending ${chalk.bgGreen(baseClass)} in ${loc}${sep}${file}.mjs`)
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
let delta_l = path.normalize(__dirname),
|
|
173
|
+
delta_r = path.normalize(loc);
|
|
174
|
+
|
|
175
|
+
if (delta_r.indexOf(delta_l) !== 0) {
|
|
176
|
+
console.error(chalk.red(`Could not determine ${loc} being a child of ${__dirname}`));
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let delta = delta_r.replace(delta_l, ''),
|
|
181
|
+
parts = delta.split(sep);
|
|
182
|
+
|
|
183
|
+
folderDelta = parts.length;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (isDrop !== true) {
|
|
187
|
+
if (fs.existsSync(path.resolve(__dirname, 'apps', rootLowerCase))) {
|
|
188
|
+
classFolder = path.resolve(__dirname, 'apps', rootLowerCase, ns.join('/'));
|
|
189
|
+
} else {
|
|
190
|
+
console.log('\nNon existing neo app name:', chalk.red(root));
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (folderDelta === undefined) {
|
|
91
196
|
folderDelta = ns.length + 2;
|
|
197
|
+
}
|
|
92
198
|
|
|
93
|
-
|
|
199
|
+
fs.mkdirpSync(classFolder);
|
|
94
200
|
|
|
95
|
-
|
|
201
|
+
fs.writeFileSync(path.join(classFolder, file + '.mjs'), createContent({baseClass, className, file, folderDelta, ns, root}));
|
|
96
202
|
|
|
97
|
-
|
|
98
|
-
|
|
203
|
+
if (baseClass === 'controller.Component') {
|
|
204
|
+
index = file.indexOf('Controller');
|
|
99
205
|
|
|
100
|
-
|
|
101
|
-
|
|
206
|
+
if (index > 0) {
|
|
207
|
+
viewFile = path.join(classFolder, file.substr(0, index) + '.mjs');
|
|
102
208
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
209
|
+
if (fs.existsSync(viewFile)) {
|
|
210
|
+
adjustView({file, viewFile});
|
|
106
211
|
}
|
|
107
212
|
}
|
|
108
|
-
} else {
|
|
109
|
-
console.log('\nNon existing neo app name:', chalk.red(root));
|
|
110
|
-
process.exit(1);
|
|
111
213
|
}
|
|
112
214
|
}
|
|
113
215
|
|
|
@@ -36,6 +36,12 @@ class MainContainer extends ConfigurationViewport {
|
|
|
36
36
|
labelText: 'clearToOriginalValue',
|
|
37
37
|
listeners: {change: me.onConfigChange.bind(me, 'clearToOriginalValue')},
|
|
38
38
|
style : {marginTop: '10px'}
|
|
39
|
+
}, {
|
|
40
|
+
module : CheckBox,
|
|
41
|
+
checked : me.exampleComponent.disabled,
|
|
42
|
+
labelText: 'disabled',
|
|
43
|
+
listeners: {change: me.onConfigChange.bind(me, 'disabled')},
|
|
44
|
+
style : {marginTop: '10px'}
|
|
39
45
|
}, {
|
|
40
46
|
module : CheckBox,
|
|
41
47
|
checked : me.exampleComponent.hideLabel,
|
|
@@ -97,6 +103,22 @@ class MainContainer extends ConfigurationViewport {
|
|
|
97
103
|
minValue : 50,
|
|
98
104
|
stepSize : 5,
|
|
99
105
|
value : me.exampleComponent.labelWidth
|
|
106
|
+
}, {
|
|
107
|
+
module : NumberField,
|
|
108
|
+
labelText: 'maxLength',
|
|
109
|
+
listeners: {change: me.onConfigChange.bind(me, 'maxLength')},
|
|
110
|
+
maxValue : 50,
|
|
111
|
+
minValue : 1,
|
|
112
|
+
stepSize : 1,
|
|
113
|
+
value : me.exampleComponent.maxLength
|
|
114
|
+
}, {
|
|
115
|
+
module : NumberField,
|
|
116
|
+
labelText: 'minLength',
|
|
117
|
+
listeners: {change: me.onConfigChange.bind(me, 'minLength')},
|
|
118
|
+
maxValue : 50,
|
|
119
|
+
minValue : 1,
|
|
120
|
+
stepSize : 1,
|
|
121
|
+
value : me.exampleComponent.minLength
|
|
100
122
|
}, {
|
|
101
123
|
module : TextField,
|
|
102
124
|
clearable: true,
|
|
@@ -129,11 +151,13 @@ class MainContainer extends ConfigurationViewport {
|
|
|
129
151
|
|
|
130
152
|
createExampleComponent() {
|
|
131
153
|
return Neo.create(TextField, {
|
|
132
|
-
clearable
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
154
|
+
clearable : true,
|
|
155
|
+
labelPosition: 'inline',
|
|
156
|
+
labelText : 'Label',
|
|
157
|
+
labelWidth : 70,
|
|
158
|
+
minLength : 3,
|
|
159
|
+
value : 'Hello World',
|
|
160
|
+
width : 200
|
|
137
161
|
});
|
|
138
162
|
}
|
|
139
163
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neo.mjs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.54",
|
|
4
4
|
"description": "The webworkers driven UI framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/neomjs/neo.git"
|
|
9
9
|
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"neo-cc": "./buildScripts/createClass.mjs"
|
|
12
|
+
},
|
|
10
13
|
"scripts": {
|
|
11
14
|
"build-all": "node ./buildScripts/buildAll.mjs -f -n",
|
|
12
15
|
"build-all-questions": "node ./buildScripts/buildAll.mjs -f",
|
|
@@ -51,7 +54,7 @@
|
|
|
51
54
|
"neo-jsdoc": "^1.0.1",
|
|
52
55
|
"neo-jsdoc-x": "^1.0.4",
|
|
53
56
|
"postcss": "^8.4.14",
|
|
54
|
-
"sass": "^1.
|
|
57
|
+
"sass": "^1.53.0",
|
|
55
58
|
"webpack": "^5.73.0",
|
|
56
59
|
"webpack-cli": "^4.10.0",
|
|
57
60
|
"webpack-dev-server": "4.9.2",
|
|
@@ -59,7 +62,8 @@
|
|
|
59
62
|
"webpack-node-externals": "^3.0.0"
|
|
60
63
|
},
|
|
61
64
|
"devDependencies": {
|
|
62
|
-
"siesta-lite": "^5.5.2"
|
|
65
|
+
"siesta-lite": "^5.5.2",
|
|
66
|
+
"url": "^0.11.0"
|
|
63
67
|
},
|
|
64
68
|
"funding": {
|
|
65
69
|
"type": "GitHub Sponsors",
|
|
@@ -8,7 +8,31 @@
|
|
|
8
8
|
|
|
9
9
|
&.neo-focus {
|
|
10
10
|
.neo-input-wrapper {
|
|
11
|
-
border-color: v(textfield-border-color-active);
|
|
11
|
+
border-color: v(textfield-border-color-active) !important;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&.neo-invalid:not(.neo-disabled) {
|
|
16
|
+
.neo-input-wrapper {
|
|
17
|
+
border-color: v(textfield-border-color-invalid);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.neo-label-wrapper {
|
|
21
|
+
.neo-center-border, .neo-left-border, .neo-right-border {
|
|
22
|
+
border-bottom-color: v(textfield-border-color-invalid);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.neo-left-border, .neo-right-border {
|
|
26
|
+
border-top-color: v(textfield-border-color-invalid);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.neo-left-border {
|
|
30
|
+
border-left-color: v(textfield-border-color-invalid);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.neo-right-border {
|
|
34
|
+
border-right-color: v(textfield-border-color-invalid);
|
|
35
|
+
}
|
|
12
36
|
}
|
|
13
37
|
}
|
|
14
38
|
|
|
@@ -36,7 +60,7 @@
|
|
|
36
60
|
}
|
|
37
61
|
|
|
38
62
|
.neo-center-border {
|
|
39
|
-
border-top-color: transparent;
|
|
63
|
+
border-top-color: transparent !important;
|
|
40
64
|
}
|
|
41
65
|
|
|
42
66
|
.neo-left-border {
|
|
@@ -70,7 +94,7 @@
|
|
|
70
94
|
}
|
|
71
95
|
|
|
72
96
|
.neo-input-wrapper {
|
|
73
|
-
border-color: transparent;
|
|
97
|
+
border-color: transparent !important;
|
|
74
98
|
}
|
|
75
99
|
|
|
76
100
|
.neo-label-wrapper {
|
|
@@ -156,10 +180,6 @@
|
|
|
156
180
|
margin : 0; // important for Safari => #1125
|
|
157
181
|
min-height : 25px;
|
|
158
182
|
width : 30px;
|
|
159
|
-
|
|
160
|
-
&:invalid {
|
|
161
|
-
border: 1px solid brown;
|
|
162
|
-
}
|
|
163
183
|
}
|
|
164
184
|
}
|
|
165
185
|
|
|
@@ -179,14 +199,18 @@
|
|
|
179
199
|
outline : none;
|
|
180
200
|
}
|
|
181
201
|
|
|
182
|
-
&:invalid {
|
|
183
|
-
border-color: brown;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
202
|
&::-webkit-input-placeholder {
|
|
187
203
|
color : v(textfield-input-placeholder-color) !important;
|
|
188
204
|
opacity: v(textfield-input-placeholder-opacity) !important;
|
|
189
205
|
}
|
|
206
|
+
|
|
207
|
+
&.neo-invalid {
|
|
208
|
+
border-color: v(textfield-border-color-invalid);
|
|
209
|
+
|
|
210
|
+
&.neo-disabled {
|
|
211
|
+
border-color: inherit;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
190
214
|
}
|
|
191
215
|
|
|
192
216
|
.neo-textfield-label {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
$neoMap: map-merge($neoMap, (
|
|
2
2
|
'textfield-border-color' : #424242,
|
|
3
3
|
'textfield-border-color-active' : #5d83a7,
|
|
4
|
+
'textfield-border-color-invalid' : brown,
|
|
4
5
|
'textfield-border-radius' : 0,
|
|
5
6
|
'textfield-input-background-color' : #2b2b2b,
|
|
6
7
|
'textfield-input-color' : #ccc,
|
|
@@ -13,6 +14,7 @@ $neoMap: map-merge($neoMap, (
|
|
|
13
14
|
:root .neo-theme-dark { // .neo-textfield
|
|
14
15
|
--textfield-border-color : #{neo(textfield-border-color)};
|
|
15
16
|
--textfield-border-color-active : #{neo(textfield-border-color-active)};
|
|
17
|
+
--textfield-border-color-invalid : #{neo(textfield-border-color-invalid)};
|
|
16
18
|
--textfield-border-radius : #{neo(textfield-border-radius)};
|
|
17
19
|
--textfield-input-background-color : #{neo(textfield-input-background-color)};
|
|
18
20
|
--textfield-input-color : #{neo(textfield-input-color)};
|
|
@@ -20,4 +22,4 @@ $neoMap: map-merge($neoMap, (
|
|
|
20
22
|
--textfield-input-placeholder-opacity: #{neo(textfield-input-placeholder-opacity)};
|
|
21
23
|
--textfield-label-color : #{neo(textfield-label-color)};
|
|
22
24
|
}
|
|
23
|
-
}
|
|
25
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
$neoMap: map-merge($neoMap, (
|
|
2
2
|
'textfield-border-color' : #ddd,
|
|
3
3
|
'textfield-border-color-active' : #1c60a0,
|
|
4
|
+
'textfield-border-color-invalid' : brown,
|
|
4
5
|
'textfield-border-radius' : 3px,
|
|
5
6
|
'textfield-input-background-color' : #fff,
|
|
6
7
|
'textfield-input-color' : #000,
|
|
@@ -13,6 +14,7 @@ $neoMap: map-merge($neoMap, (
|
|
|
13
14
|
:root .neo-theme-light { // .neo-textfield
|
|
14
15
|
--textfield-border-color : #{neo(textfield-border-color)};
|
|
15
16
|
--textfield-border-color-active : #{neo(textfield-border-color-active)};
|
|
17
|
+
--textfield-border-color-invalid : #{neo(textfield-border-color-invalid)};
|
|
16
18
|
--textfield-border-radius : #{neo(textfield-border-radius)};
|
|
17
19
|
--textfield-input-background-color : #{neo(textfield-input-background-color)};
|
|
18
20
|
--textfield-input-color : #{neo(textfield-input-color)};
|
|
@@ -20,4 +22,4 @@ $neoMap: map-merge($neoMap, (
|
|
|
20
22
|
--textfield-input-placeholder-opacity: #{neo(textfield-input-placeholder-opacity)};
|
|
21
23
|
--textfield-label-color : #{neo(textfield-label-color)};
|
|
22
24
|
}
|
|
23
|
-
}
|
|
25
|
+
}
|
|
@@ -28,9 +28,9 @@ class RecordFactory extends Base {
|
|
|
28
28
|
*/
|
|
29
29
|
ovPrefix: 'ov_',
|
|
30
30
|
/**
|
|
31
|
-
* @member {String} recordNamespace='Neo.data.record
|
|
31
|
+
* @member {String} recordNamespace='Neo.data.record'
|
|
32
32
|
*/
|
|
33
|
-
recordNamespace: 'Neo.data.record
|
|
33
|
+
recordNamespace: 'Neo.data.record'
|
|
34
34
|
}}
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -39,7 +39,7 @@ class RecordFactory extends Base {
|
|
|
39
39
|
* @returns {Object}
|
|
40
40
|
*/
|
|
41
41
|
createRecord(model, config) {
|
|
42
|
-
let recordClass = Neo.ns(this.recordNamespace
|
|
42
|
+
let recordClass = Neo.ns(`${this.recordNamespace}.${model.className}.${model.id}`);
|
|
43
43
|
|
|
44
44
|
if (!recordClass) {
|
|
45
45
|
recordClass = this.createRecordClass(model);
|
|
@@ -54,7 +54,7 @@ class RecordFactory extends Base {
|
|
|
54
54
|
*/
|
|
55
55
|
createRecordClass(model) {
|
|
56
56
|
if (model instanceof Model) {
|
|
57
|
-
let className = this.recordNamespace
|
|
57
|
+
let className = `${this.recordNamespace}.${model.className}.${model.id}`,
|
|
58
58
|
ns = Neo.ns(className),
|
|
59
59
|
key, nsArray;
|
|
60
60
|
|
|
@@ -76,7 +76,7 @@ class RecordFactory extends Base {
|
|
|
76
76
|
|
|
77
77
|
if (Array.isArray(model.fields)) {
|
|
78
78
|
model.fields.forEach(field => {
|
|
79
|
-
let parsedValue = instance.parseRecordValue(field, config[field.name], config),
|
|
79
|
+
let parsedValue = instance.parseRecordValue(me, field, config[field.name], config),
|
|
80
80
|
symbol = Symbol.for(field.name);
|
|
81
81
|
|
|
82
82
|
properties = {
|
|
@@ -97,9 +97,9 @@ class RecordFactory extends Base {
|
|
|
97
97
|
let me = this,
|
|
98
98
|
oldValue = me[symbol];
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
value = instance.parseRecordValue(field, value, null);
|
|
100
|
+
value = instance.parseRecordValue(me, field, value);
|
|
102
101
|
|
|
102
|
+
if (!Neo.isEqual(value, oldValue)) {
|
|
103
103
|
me[symbol] = value;
|
|
104
104
|
|
|
105
105
|
me._isModified = true;
|
|
@@ -221,14 +221,19 @@ class RecordFactory extends Base {
|
|
|
221
221
|
|
|
222
222
|
/**
|
|
223
223
|
* todo: parse value for more field types
|
|
224
|
+
* @param {Object} record
|
|
224
225
|
* @param {Object} field
|
|
225
226
|
* @param {*} value
|
|
226
|
-
* @param {Object} recordConfig
|
|
227
|
+
* @param {Object} recordConfig=null
|
|
227
228
|
* @returns {*}
|
|
228
229
|
*/
|
|
229
|
-
parseRecordValue(field, value, recordConfig) {
|
|
230
|
-
let mapping
|
|
231
|
-
|
|
230
|
+
parseRecordValue(record, field, value, recordConfig=null) {
|
|
231
|
+
let mapping = field.mapping,
|
|
232
|
+
maxLength = field.maxLength,
|
|
233
|
+
minLength = field.minLength,
|
|
234
|
+
nullable = field.nullable,
|
|
235
|
+
oldValue = recordConfig?.[field.name] || record[field.name],
|
|
236
|
+
type = field.type?.toLowerCase();
|
|
232
237
|
|
|
233
238
|
// only trigger mappings for initial values
|
|
234
239
|
// dynamic changes of a field will not pass the recordConfig
|
|
@@ -240,7 +245,28 @@ class RecordFactory extends Base {
|
|
|
240
245
|
value = ns[key];
|
|
241
246
|
}
|
|
242
247
|
|
|
243
|
-
if (
|
|
248
|
+
if (Object.hasOwn(field, 'maxLength')) {
|
|
249
|
+
if (value?.toString() > maxLength) {
|
|
250
|
+
console.warn(`Setting record field: ${field} value: ${value} conflicts with maxLength: ${maxLength}`);
|
|
251
|
+
return oldValue;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (Object.hasOwn(field, 'minLength')) {
|
|
256
|
+
if (value?.toString() < minLength) {
|
|
257
|
+
console.warn(`Setting record field: ${field} value: ${value} conflicts with minLength: ${minLength}`);
|
|
258
|
+
return oldValue;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (Object.hasOwn(field, 'nullable')) {
|
|
263
|
+
if (nullable === false && value === null) {
|
|
264
|
+
console.warn(`Setting record field: ${field} value: ${value} conflicts with nullable: ${nullable}`);
|
|
265
|
+
return oldValue;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (type === 'date' && Neo.typeOf(value) !== 'Date') {
|
|
244
270
|
return new Date(value);
|
|
245
271
|
}
|
|
246
272
|
|
|
@@ -259,6 +285,7 @@ class RecordFactory extends Base {
|
|
|
259
285
|
|
|
260
286
|
Object.entries(fields).forEach(([key, value]) => {
|
|
261
287
|
oldValue = record[key];
|
|
288
|
+
value = instance.parseRecordValue(record, model.getField(key), value);
|
|
262
289
|
|
|
263
290
|
if (!Neo.isEqual(oldValue, value)) {
|
|
264
291
|
record[Symbol.for(key)] = value; // silent update
|
|
@@ -99,6 +99,7 @@ class Number extends Text {
|
|
|
99
99
|
* @protected
|
|
100
100
|
*/
|
|
101
101
|
afterSetMaxValue(value, oldValue) {
|
|
102
|
+
this.updateValidationIndicators();
|
|
102
103
|
this.changeInputElKey('max', value);
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -109,6 +110,7 @@ class Number extends Text {
|
|
|
109
110
|
* @protected
|
|
110
111
|
*/
|
|
111
112
|
afterSetMinValue(value, oldValue) {
|
|
113
|
+
this.updateValidationIndicators();
|
|
112
114
|
this.changeInputElKey('min', value);
|
|
113
115
|
}
|
|
114
116
|
|
|
@@ -178,14 +180,17 @@ class Number extends Text {
|
|
|
178
180
|
* @returns {Boolean}
|
|
179
181
|
*/
|
|
180
182
|
isValid() {
|
|
181
|
-
let me
|
|
182
|
-
|
|
183
|
+
let me = this,
|
|
184
|
+
maxValue = me.maxValue,
|
|
185
|
+
minValue = me.minValue,
|
|
186
|
+
value = me.value,
|
|
187
|
+
isNumber = Neo.isNumber(value);
|
|
183
188
|
|
|
184
|
-
if (Neo.isNumber(
|
|
189
|
+
if (Neo.isNumber(maxValue) && isNumber && value > maxValue) {
|
|
185
190
|
return false;
|
|
186
191
|
}
|
|
187
192
|
|
|
188
|
-
if (Neo.isNumber(
|
|
193
|
+
if (Neo.isNumber(minValue) && isNumber && value < minValue) {
|
|
189
194
|
return false;
|
|
190
195
|
}
|
|
191
196
|
|
|
@@ -237,12 +242,13 @@ class Number extends Text {
|
|
|
237
242
|
*/
|
|
238
243
|
onSpinButtonDownClick() {
|
|
239
244
|
let me = this,
|
|
240
|
-
|
|
241
|
-
|
|
245
|
+
stepSize = me.stepSize,
|
|
246
|
+
oldValue = Neo.isNumber(me.value) ? me.value : me.minValue,
|
|
247
|
+
value = (oldValue - stepSize) < me.minValue ? me.maxValue : (oldValue - stepSize);
|
|
242
248
|
|
|
243
249
|
if (me.excludedValues) {
|
|
244
250
|
while(me.excludedValues.includes(value)) {
|
|
245
|
-
value = Math.max(me.minValue, value -
|
|
251
|
+
value = Math.max(me.minValue, value - stepSize);
|
|
246
252
|
}
|
|
247
253
|
}
|
|
248
254
|
|
|
@@ -256,12 +262,13 @@ class Number extends Text {
|
|
|
256
262
|
*/
|
|
257
263
|
onSpinButtonUpClick() {
|
|
258
264
|
let me = this,
|
|
259
|
-
|
|
260
|
-
|
|
265
|
+
stepSize = me.stepSize,
|
|
266
|
+
oldValue = Neo.isNumber(me.value) ? me.value : me.maxValue,
|
|
267
|
+
value = (oldValue + stepSize) > me.maxValue ? me.minValue : (oldValue + stepSize);
|
|
261
268
|
|
|
262
269
|
if (me.excludedValues) {
|
|
263
270
|
while(me.excludedValues.includes(value)) {
|
|
264
|
-
value = Math.min(me.maxValue, value +
|
|
271
|
+
value = Math.min(me.maxValue, value + stepSize);
|
|
265
272
|
}
|
|
266
273
|
}
|
|
267
274
|
|
package/src/form/field/Text.mjs
CHANGED
|
@@ -375,6 +375,7 @@ class Text extends Base {
|
|
|
375
375
|
* @protected
|
|
376
376
|
*/
|
|
377
377
|
afterSetMaxLength(value, oldValue) {
|
|
378
|
+
this.updateValidationIndicators();
|
|
378
379
|
this.changeInputElKey('maxlength', value);
|
|
379
380
|
}
|
|
380
381
|
|
|
@@ -385,6 +386,7 @@ class Text extends Base {
|
|
|
385
386
|
* @protected
|
|
386
387
|
*/
|
|
387
388
|
afterSetMinLength(value, oldValue) {
|
|
389
|
+
this.updateValidationIndicators();
|
|
388
390
|
this.changeInputElKey('minlength', value);
|
|
389
391
|
}
|
|
390
392
|
|
|
@@ -437,6 +439,7 @@ class Text extends Base {
|
|
|
437
439
|
* @protected
|
|
438
440
|
*/
|
|
439
441
|
afterSetRequired(value, oldValue) {
|
|
442
|
+
this.updateValidationIndicators();
|
|
440
443
|
this.changeInputElKey('required', value ? value : null);
|
|
441
444
|
}
|
|
442
445
|
|
|
@@ -532,6 +535,7 @@ class Text extends Base {
|
|
|
532
535
|
}
|
|
533
536
|
|
|
534
537
|
NeoArray[me.originalConfig.value !== value ? 'add' : 'remove'](me._cls, 'neo-is-dirty');
|
|
538
|
+
me.updateValidationIndicators();
|
|
535
539
|
|
|
536
540
|
me.vdom = vdom;
|
|
537
541
|
|
|
@@ -1011,6 +1015,20 @@ class Text extends Base {
|
|
|
1011
1015
|
});
|
|
1012
1016
|
});
|
|
1013
1017
|
}
|
|
1018
|
+
|
|
1019
|
+
/**
|
|
1020
|
+
* @param {Boolean} silent=true
|
|
1021
|
+
*/
|
|
1022
|
+
updateValidationIndicators(silent=true) {
|
|
1023
|
+
let me = this,
|
|
1024
|
+
vdom = me.vdom;
|
|
1025
|
+
|
|
1026
|
+
NeoArray[!me.isValid() ? 'add' : 'remove'](me._cls, 'neo-invalid');
|
|
1027
|
+
|
|
1028
|
+
if (!silent) {
|
|
1029
|
+
me.vdom = vdom;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1014
1032
|
}
|
|
1015
1033
|
|
|
1016
1034
|
Neo.applyClassConfig(Text);
|
|
@@ -186,11 +186,15 @@ class DeltaUpdates extends Base {
|
|
|
186
186
|
}
|
|
187
187
|
} else if (key === 'id') {
|
|
188
188
|
node[Neo.config.useDomIds ? 'id' : 'data-neo-id'] = val;
|
|
189
|
-
}else if (key === 'spellcheck' && val === 'false') {
|
|
189
|
+
} else if (key === 'spellcheck' && val === 'false') {
|
|
190
190
|
// see https://github.com/neomjs/neo/issues/1922
|
|
191
191
|
node[key] = false;
|
|
192
192
|
} else {
|
|
193
|
-
|
|
193
|
+
if (key === 'value') {
|
|
194
|
+
node[key] = val;
|
|
195
|
+
} else {
|
|
196
|
+
node.setAttribute(key, val);
|
|
197
|
+
}
|
|
194
198
|
}
|
|
195
199
|
});
|
|
196
200
|
break;
|
package/src/table/Container.mjs
CHANGED
|
@@ -247,9 +247,9 @@ class Container extends BaseContainer {
|
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
if (value) {
|
|
250
|
-
let me = this
|
|
250
|
+
let me = this,
|
|
251
251
|
|
|
252
|
-
|
|
252
|
+
listeners = {
|
|
253
253
|
filter : me.onStoreFilter,
|
|
254
254
|
load : me.onStoreLoad,
|
|
255
255
|
recordChange: me.onStoreRecordChange,
|
|
@@ -258,13 +258,10 @@ class Container extends BaseContainer {
|
|
|
258
258
|
|
|
259
259
|
if (value instanceof Store) {
|
|
260
260
|
value.on(listeners);
|
|
261
|
-
|
|
262
|
-
if (value.getCount() > 0) {
|
|
263
|
-
me.onStoreLoad(value.items);
|
|
264
|
-
}
|
|
261
|
+
value.getCount() > 0 && me.onStoreLoad(value.items);
|
|
265
262
|
} else {
|
|
266
263
|
value = ClassSystemUtil.beforeSetInstance(value, Store, {
|
|
267
|
-
listeners
|
|
264
|
+
listeners
|
|
268
265
|
});
|
|
269
266
|
}
|
|
270
267
|
|