neo.mjs 4.0.49 → 4.0.52
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 +372 -0
- package/examples/form/field/text/MainContainer.mjs +16 -0
- package/package.json +8 -3
- package/src/data/RecordFactory.mjs +31 -12
- package/src/form/field/Number.mjs +30 -6
- package/src/form/field/Text.mjs +42 -2
- package/src/main/mixin/DeltaUpdates.mjs +6 -2
- package/src/table/Container.mjs +4 -7
|
@@ -0,0 +1,372 @@
|
|
|
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)),
|
|
14
|
+
cwd = process.cwd(),
|
|
15
|
+
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
|
16
|
+
packageJson = requireJson(path.join(__dirname, 'package.json')),
|
|
17
|
+
insideNeo = packageJson.name === 'neo.mjs',
|
|
18
|
+
program = new Command(),
|
|
19
|
+
programName = `${packageJson.name} create-class`,
|
|
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'];
|
|
33
|
+
|
|
34
|
+
program
|
|
35
|
+
.name(programName)
|
|
36
|
+
.version(packageJson.version)
|
|
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(',')}`)
|
|
40
|
+
.option('-b, --baseClass <value>')
|
|
41
|
+
.option('-c, --className <value>')
|
|
42
|
+
.allowUnknownOption()
|
|
43
|
+
.on('--help', () => {
|
|
44
|
+
console.log('\nIn case you have any issues, please create a ticket here:');
|
|
45
|
+
console.log(chalk.cyan(process.env.npm_package_bugs_url));
|
|
46
|
+
})
|
|
47
|
+
.parse(process.argv);
|
|
48
|
+
|
|
49
|
+
const programOpts = program.opts();
|
|
50
|
+
|
|
51
|
+
if (programOpts.info) {
|
|
52
|
+
console.log(chalk.bold('\nEnvironment Info:'));
|
|
53
|
+
console.log(`\n current version of ${packageJson.name}: ${packageJson.version}`);
|
|
54
|
+
console.log(` running from ${cwd}`);
|
|
55
|
+
|
|
56
|
+
envinfo
|
|
57
|
+
.run({
|
|
58
|
+
System : ['OS', 'CPU'],
|
|
59
|
+
Binaries : ['Node', 'npm', 'Yarn'],
|
|
60
|
+
Browsers : ['Chrome', 'Edge', 'Firefox', 'Safari'],
|
|
61
|
+
npmPackages: ['neo.mjs']
|
|
62
|
+
}, {
|
|
63
|
+
duplicates : true,
|
|
64
|
+
showNotFound: true
|
|
65
|
+
})
|
|
66
|
+
.then(console.log);
|
|
67
|
+
} else {
|
|
68
|
+
console.log(chalk.green(programName));
|
|
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 avcailable 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
|
+
|
|
92
|
+
if (!programOpts.className) {
|
|
93
|
+
questions.push({
|
|
94
|
+
type : 'input',
|
|
95
|
+
name : 'className',
|
|
96
|
+
message: 'Please choose the namespace for your class:',
|
|
97
|
+
default: 'Covid.view.HeaderContainerController'
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!programOpts.baseClass) {
|
|
102
|
+
questions.push({
|
|
103
|
+
type : 'list',
|
|
104
|
+
name : 'baseClass',
|
|
105
|
+
message: 'Please pick the base class, which you want to extend:',
|
|
106
|
+
choices: ['component.Base', 'container.Base', 'controller.Component', 'core.Base'],
|
|
107
|
+
default: 'container.Base'
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
inquirer.prompt(questions).then(answers => {
|
|
112
|
+
let baseClass = programOpts.baseClass || answers.baseClass,
|
|
113
|
+
className = programOpts.className || answers.className,
|
|
114
|
+
isDrop = programOpts.drop,
|
|
115
|
+
startDate = new Date(),
|
|
116
|
+
classFolder, file, folderDelta, index, ns, root, rootLowerCase, viewFile;
|
|
117
|
+
|
|
118
|
+
if (className.endsWith('.mjs')) {
|
|
119
|
+
className = className.slice(0, -4);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!isDrop) {
|
|
123
|
+
ns = className.split('.');
|
|
124
|
+
file = ns.pop();
|
|
125
|
+
root = ns.shift();
|
|
126
|
+
rootLowerCase = root.toLowerCase();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (root === 'Neo') {
|
|
130
|
+
console.log('todo: create the file inside the src folder');
|
|
131
|
+
} else {
|
|
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) {
|
|
196
|
+
folderDelta = ns.length + 2;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
fs.mkdirpSync(classFolder);
|
|
200
|
+
|
|
201
|
+
fs.writeFileSync(path.join(classFolder, file + '.mjs'), createContent({baseClass, className, file, folderDelta, ns, root}));
|
|
202
|
+
|
|
203
|
+
if (baseClass === 'controller.Component') {
|
|
204
|
+
index = file.indexOf('Controller');
|
|
205
|
+
|
|
206
|
+
if (index > 0) {
|
|
207
|
+
viewFile = path.join(classFolder, file.substr(0, index) + '.mjs');
|
|
208
|
+
|
|
209
|
+
if (fs.existsSync(viewFile)) {
|
|
210
|
+
adjustView({file, viewFile});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const processTime = (Math.round((new Date - startDate) * 100) / 100000).toFixed(2);
|
|
217
|
+
console.log(`\nTotal time for ${programName}: ${processTime}s`);
|
|
218
|
+
|
|
219
|
+
process.exit();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Adds a comma to the last element of the contentArray
|
|
224
|
+
* @param {String[]} contentArray
|
|
225
|
+
* @returns {String[]}
|
|
226
|
+
*/
|
|
227
|
+
function addComma(contentArray) {
|
|
228
|
+
contentArray[contentArray.length - 1] += ',';
|
|
229
|
+
return contentArray;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Adjusts the views related to controller.Component or model.Component
|
|
234
|
+
* @param {Object} opts
|
|
235
|
+
* @param {String} opts.file
|
|
236
|
+
* @param {String} opts.viewFile
|
|
237
|
+
*/
|
|
238
|
+
function adjustView(opts) {
|
|
239
|
+
let file = opts.file,
|
|
240
|
+
viewFile = opts.viewFile,
|
|
241
|
+
content = fs.readFileSync(viewFile).toString().split(os.EOL),
|
|
242
|
+
fromMaxPosition = 0,
|
|
243
|
+
i = 0,
|
|
244
|
+
len = content.length,
|
|
245
|
+
adjustSpaces, codeLine, fromPosition, importLength, importName, j, spaces;
|
|
246
|
+
|
|
247
|
+
// find the index where we want to insert our import statement
|
|
248
|
+
for (; i < len; i++) {
|
|
249
|
+
codeLine = content[i];
|
|
250
|
+
|
|
251
|
+
if (codeLine === '') {
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
importName = codeLine.substr(7);
|
|
256
|
+
importName = importName.substr(0, importName.indexOf(' '));
|
|
257
|
+
importLength = importName.length;
|
|
258
|
+
|
|
259
|
+
if (importName > file) {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
content.splice(i, 0, `import ${file} from './${file}.mjs';`);
|
|
265
|
+
|
|
266
|
+
// find the longest import module name
|
|
267
|
+
for (i=0; i < len; i++) {
|
|
268
|
+
codeLine = content[i];
|
|
269
|
+
|
|
270
|
+
if (codeLine === '') {
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
fromMaxPosition = Math.max(fromMaxPosition, codeLine.indexOf('from'));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// adjust the block-formatting for imports
|
|
278
|
+
for (i=0; i < len; i++) {
|
|
279
|
+
codeLine = content[i];
|
|
280
|
+
|
|
281
|
+
if (codeLine === '') {
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
fromPosition = codeLine.indexOf('from');
|
|
286
|
+
adjustSpaces = fromMaxPosition - fromPosition;
|
|
287
|
+
|
|
288
|
+
if (adjustSpaces > 0) {
|
|
289
|
+
spaces = '';
|
|
290
|
+
|
|
291
|
+
for (j=0; j < adjustSpaces; j++) {
|
|
292
|
+
spaces += ' ';
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
content[i] = codeLine.substr(0, fromPosition) + spaces + codeLine.substr(fromPosition);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
fs.writeFileSync(viewFile, content.join(os.EOL));
|
|
300
|
+
|
|
301
|
+
console.log(i, opts.file);
|
|
302
|
+
console.log(content);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Creates the content of the neo-class .mjs file
|
|
307
|
+
* @param {Object} opts
|
|
308
|
+
* @param {String} opts.baseClass
|
|
309
|
+
* @param {String} opts.className
|
|
310
|
+
* @param {String} opts.file
|
|
311
|
+
* @param {String} opts.folderDelta
|
|
312
|
+
* @param {String} opts.ns
|
|
313
|
+
* @param {String} opts.root
|
|
314
|
+
* @returns {String}
|
|
315
|
+
*/
|
|
316
|
+
function createContent(opts) {
|
|
317
|
+
let baseClass = opts.baseClass,
|
|
318
|
+
baseClassNs = baseClass.split('.'),
|
|
319
|
+
baseFileName = baseClassNs.pop(),
|
|
320
|
+
className = opts.className,
|
|
321
|
+
file = opts.file,
|
|
322
|
+
i = 0,
|
|
323
|
+
importDelta = '';
|
|
324
|
+
|
|
325
|
+
for (; i < opts.folderDelta; i++) {
|
|
326
|
+
importDelta += '../';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
let classContent = [
|
|
330
|
+
`import ${baseFileName} from '${importDelta}${(insideNeo ? '' : 'node_modules/neo.mjs/')}src/${baseClassNs.join('/')}/${baseFileName}.mjs';`,
|
|
331
|
+
"",
|
|
332
|
+
"/**",
|
|
333
|
+
` * @class ${className}`,
|
|
334
|
+
` * @extends Neo.${baseClass}`,
|
|
335
|
+
" */",
|
|
336
|
+
`class ${file} extends ${baseFileName} {`,
|
|
337
|
+
" static getConfig() {return {",
|
|
338
|
+
" /*",
|
|
339
|
+
` * @member {String} className='${className}'`,
|
|
340
|
+
" * @protected",
|
|
341
|
+
" */",
|
|
342
|
+
` className: '${className}'`
|
|
343
|
+
];
|
|
344
|
+
|
|
345
|
+
baseClass === 'container.Base' && addComma(classContent).push(
|
|
346
|
+
" /*",
|
|
347
|
+
" * @member {Object[]} items",
|
|
348
|
+
" */",
|
|
349
|
+
" items: []"
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
baseClass === 'component.Base' && addComma(classContent).push(
|
|
353
|
+
" /*",
|
|
354
|
+
" * @member {Object} _vdom",
|
|
355
|
+
" */",
|
|
356
|
+
" _vdom:",
|
|
357
|
+
" {}"
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
classContent.push(
|
|
361
|
+
" }}",
|
|
362
|
+
"}",
|
|
363
|
+
"",
|
|
364
|
+
`Neo.applyClassConfig(${file});`,
|
|
365
|
+
"",
|
|
366
|
+
`export default ${file};`,
|
|
367
|
+
""
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
return classContent.join(os.EOL);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
@@ -97,6 +97,22 @@ class MainContainer extends ConfigurationViewport {
|
|
|
97
97
|
minValue : 50,
|
|
98
98
|
stepSize : 5,
|
|
99
99
|
value : me.exampleComponent.labelWidth
|
|
100
|
+
}, {
|
|
101
|
+
module : NumberField,
|
|
102
|
+
labelText: 'maxLength',
|
|
103
|
+
listeners: {change: me.onConfigChange.bind(me, 'maxLength')},
|
|
104
|
+
maxValue : 50,
|
|
105
|
+
minValue : 1,
|
|
106
|
+
stepSize : 1,
|
|
107
|
+
value : me.exampleComponent.maxLength
|
|
108
|
+
}, {
|
|
109
|
+
module : NumberField,
|
|
110
|
+
labelText: 'minLength',
|
|
111
|
+
listeners: {change: me.onConfigChange.bind(me, 'minLength')},
|
|
112
|
+
maxValue : 50,
|
|
113
|
+
minValue : 1,
|
|
114
|
+
stepSize : 1,
|
|
115
|
+
value : me.exampleComponent.minLength
|
|
100
116
|
}, {
|
|
101
117
|
module : TextField,
|
|
102
118
|
clearable: true,
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neo.mjs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.52",
|
|
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",
|
|
@@ -14,6 +17,7 @@
|
|
|
14
17
|
"build-themes": "node ./buildScripts/buildThemes.mjs -f",
|
|
15
18
|
"build-threads": "node ./buildScripts/webpack/buildThreads.mjs -f",
|
|
16
19
|
"create-app": "node ./buildScripts/createApp.mjs",
|
|
20
|
+
"create-class": "node ./buildScripts/createClass.mjs",
|
|
17
21
|
"generate-docs-json": "node ./buildScripts/docs/jsdocx.mjs",
|
|
18
22
|
"server-start": "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open",
|
|
19
23
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
@@ -50,7 +54,7 @@
|
|
|
50
54
|
"neo-jsdoc": "^1.0.1",
|
|
51
55
|
"neo-jsdoc-x": "^1.0.4",
|
|
52
56
|
"postcss": "^8.4.14",
|
|
53
|
-
"sass": "^1.
|
|
57
|
+
"sass": "^1.53.0",
|
|
54
58
|
"webpack": "^5.73.0",
|
|
55
59
|
"webpack-cli": "^4.10.0",
|
|
56
60
|
"webpack-dev-server": "4.9.2",
|
|
@@ -58,7 +62,8 @@
|
|
|
58
62
|
"webpack-node-externals": "^3.0.0"
|
|
59
63
|
},
|
|
60
64
|
"devDependencies": {
|
|
61
|
-
"siesta-lite": "^5.5.2"
|
|
65
|
+
"siesta-lite": "^5.5.2",
|
|
66
|
+
"url": "^0.11.0"
|
|
62
67
|
},
|
|
63
68
|
"funding": {
|
|
64
69
|
"type": "GitHub Sponsors",
|
|
@@ -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,18 @@ 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
|
+
oldValue = recordConfig?.[field.name] || record[field.name],
|
|
235
|
+
type = field.type?.toLowerCase();
|
|
232
236
|
|
|
233
237
|
// only trigger mappings for initial values
|
|
234
238
|
// dynamic changes of a field will not pass the recordConfig
|
|
@@ -240,7 +244,21 @@ class RecordFactory extends Base {
|
|
|
240
244
|
value = ns[key];
|
|
241
245
|
}
|
|
242
246
|
|
|
243
|
-
if (
|
|
247
|
+
if (Object.hasOwn(field, maxLength)) {
|
|
248
|
+
if (value?.toString() > maxLength) {
|
|
249
|
+
console.warn(`Setting record field: ${field} value: ${value} conflicts with the maxLength: ${maxLength}`);
|
|
250
|
+
return oldValue;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (Object.hasOwn(field, minLength)) {
|
|
255
|
+
if (value?.toString() < minLength) {
|
|
256
|
+
console.warn(`Setting record field: ${field} value: ${value} conflicts with the minLength: ${minLength}`);
|
|
257
|
+
return oldValue;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (type === 'date' && Neo.typeOf(value) !== 'Date') {
|
|
244
262
|
return new Date(value);
|
|
245
263
|
}
|
|
246
264
|
|
|
@@ -259,6 +277,7 @@ class RecordFactory extends Base {
|
|
|
259
277
|
|
|
260
278
|
Object.entries(fields).forEach(([key, value]) => {
|
|
261
279
|
oldValue = record[key];
|
|
280
|
+
value = instance.parseRecordValue(record, model.getField(key), value);
|
|
262
281
|
|
|
263
282
|
if (!Neo.isEqual(oldValue, value)) {
|
|
264
283
|
record[Symbol.for(key)] = value; // silent update
|
|
@@ -174,6 +174,28 @@ class Number extends Text {
|
|
|
174
174
|
return this.beforeSetEnumValue(value, oldValue, 'triggerPosition');
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
/**
|
|
178
|
+
* @returns {Boolean}
|
|
179
|
+
*/
|
|
180
|
+
isValid() {
|
|
181
|
+
let me = this,
|
|
182
|
+
value = me.value;
|
|
183
|
+
|
|
184
|
+
if (Neo.isNumber(me.maxValue) && value > me.maxValue) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (Neo.isNumber(me.minValue) && value < me.minValue) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (value % me.stepSize !== 0) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return super.isValid();
|
|
197
|
+
}
|
|
198
|
+
|
|
177
199
|
/**
|
|
178
200
|
*
|
|
179
201
|
*/
|
|
@@ -215,12 +237,13 @@ class Number extends Text {
|
|
|
215
237
|
*/
|
|
216
238
|
onSpinButtonDownClick() {
|
|
217
239
|
let me = this,
|
|
218
|
-
|
|
219
|
-
|
|
240
|
+
stepSize = me.stepSize,
|
|
241
|
+
oldValue = Neo.isNumber(me.value) ? me.value : me.minValue,
|
|
242
|
+
value = (oldValue - stepSize) < me.minValue ? me.maxValue : (oldValue - stepSize);
|
|
220
243
|
|
|
221
244
|
if (me.excludedValues) {
|
|
222
245
|
while(me.excludedValues.includes(value)) {
|
|
223
|
-
value = Math.max(me.minValue, value -
|
|
246
|
+
value = Math.max(me.minValue, value - stepSize);
|
|
224
247
|
}
|
|
225
248
|
}
|
|
226
249
|
|
|
@@ -234,12 +257,13 @@ class Number extends Text {
|
|
|
234
257
|
*/
|
|
235
258
|
onSpinButtonUpClick() {
|
|
236
259
|
let me = this,
|
|
237
|
-
|
|
238
|
-
|
|
260
|
+
stepSize = me.stepSize,
|
|
261
|
+
oldValue = Neo.isNumber(me.value) ? me.value : me.maxValue,
|
|
262
|
+
value = (oldValue + stepSize) > me.maxValue ? me.minValue : (oldValue + stepSize);
|
|
239
263
|
|
|
240
264
|
if (me.excludedValues) {
|
|
241
265
|
while(me.excludedValues.includes(value)) {
|
|
242
|
-
value = Math.min(me.maxValue, value +
|
|
266
|
+
value = Math.min(me.maxValue, value + stepSize);
|
|
243
267
|
}
|
|
244
268
|
}
|
|
245
269
|
|
package/src/form/field/Text.mjs
CHANGED
|
@@ -93,6 +93,16 @@ class Text extends Base {
|
|
|
93
93
|
* @member {Number|String} labelWidth_=150
|
|
94
94
|
*/
|
|
95
95
|
labelWidth_: 150,
|
|
96
|
+
/**
|
|
97
|
+
* The maximum amount of chars which you can enter into this field
|
|
98
|
+
* @member {Number|null} maxLength_=null
|
|
99
|
+
*/
|
|
100
|
+
maxLength_: null,
|
|
101
|
+
/**
|
|
102
|
+
* The minimum amount of chars which you can enter into this field
|
|
103
|
+
* @member {Number|null} minLength_=null
|
|
104
|
+
*/
|
|
105
|
+
minLength_: null,
|
|
96
106
|
/**
|
|
97
107
|
* @member {String|null} placeholderText_=null
|
|
98
108
|
*/
|
|
@@ -358,6 +368,26 @@ class Text extends Base {
|
|
|
358
368
|
}
|
|
359
369
|
}
|
|
360
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Triggered after the maxLength config got changed
|
|
373
|
+
* @param {Number|null} value
|
|
374
|
+
* @param {Number|null} oldValue
|
|
375
|
+
* @protected
|
|
376
|
+
*/
|
|
377
|
+
afterSetMaxLength(value, oldValue) {
|
|
378
|
+
this.changeInputElKey('maxlength', value);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Triggered after the minLength config got changed
|
|
383
|
+
* @param {Number|null} value
|
|
384
|
+
* @param {Number|null} oldValue
|
|
385
|
+
* @protected
|
|
386
|
+
*/
|
|
387
|
+
afterSetMinLength(value, oldValue) {
|
|
388
|
+
this.changeInputElKey('minlength', value);
|
|
389
|
+
}
|
|
390
|
+
|
|
361
391
|
/**
|
|
362
392
|
* Triggered after the mounted config got changed
|
|
363
393
|
* @param {Boolean} value
|
|
@@ -776,9 +806,19 @@ class Text extends Base {
|
|
|
776
806
|
* @returns {Boolean}
|
|
777
807
|
*/
|
|
778
808
|
isValid() {
|
|
779
|
-
let me
|
|
809
|
+
let me = this,
|
|
810
|
+
value = me.value,
|
|
811
|
+
valueLength = value?.toString().length;
|
|
812
|
+
|
|
813
|
+
if (me.required && (!value || valueLength < 1)) {
|
|
814
|
+
return false;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (Neo.isNumber(me.maxLength) && valueLength > me.maxLength) {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
780
820
|
|
|
781
|
-
if (me.
|
|
821
|
+
if (Neo.isNumber(me.minLength) && valueLength < me.minLength) {
|
|
782
822
|
return false;
|
|
783
823
|
}
|
|
784
824
|
|
|
@@ -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
|
|