neo.mjs 4.0.64 → 4.0.67
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/README.md +3 -3
- package/apps/sharedcovid/view/MainContainerController.mjs +2 -0
- package/buildScripts/createClass.mjs +176 -47
- package/package.json +2 -2
- package/src/controller/Application.mjs +9 -0
- package/src/core/Util.mjs +4 -4
- package/src/form/field/Select.mjs +29 -19
- package/src/worker/App.mjs +9 -0
package/README.md
CHANGED
@@ -236,12 +236,12 @@ More infos: <a href="./BACKERS.md">Sponsors & Backers</a>
|
|
236
236
|
</br></br>
|
237
237
|
<h2 id="jobs">14. Jobs</h2>
|
238
238
|
Accenture is hiring multiple neo.mjs developers for the new Cloud Technology Studio in Kaiserslauern (Germany):</br>
|
239
|
-
|
240
|
-
|
239
|
+
</br>
|
241
240
|
These full-time roles are based on German contracts, so they require living in (or relocating to) Germany.
|
241
|
+
Ping us on LinkedIn or Slack for details.
|
242
242
|
|
243
243
|
</br></br>
|
244
|
-
Logo contributed by <a href="https://www.linkedin.com/in/dinkheller/">Torsten Dinkheller</a>.
|
244
|
+
Logo contributed by <a href="https://www.linkedin.com/in/torsten-dinkheller-614516231/">Torsten Dinkheller</a>.
|
245
245
|
|
246
246
|
</br></br>
|
247
247
|
Build with :heart: in Germany.
|
@@ -14,7 +14,7 @@ const
|
|
14
14
|
cwd = process.cwd(),
|
15
15
|
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
16
16
|
packageJson = requireJson(path.join(__dirname, 'package.json')),
|
17
|
-
insideNeo =
|
17
|
+
insideNeo = process.env.npm_package_name === 'neo.mjs',
|
18
18
|
program = new Command(),
|
19
19
|
programName = `${packageJson.name} create-class`,
|
20
20
|
questions = [],
|
@@ -36,6 +36,7 @@ program
|
|
36
36
|
.version(packageJson.version)
|
37
37
|
.option('-i, --info', 'print environment debug info')
|
38
38
|
.option('-d, --drop', 'drops class in the currently selected folder')
|
39
|
+
.option('-n, --singleton <value>', 'Create a singleton? Pick "yes" or "no"')
|
39
40
|
.option('-s, --source <value>', `name of the folder containing the project. Defaults to any of ${sourceRootDirs.join(',')}`)
|
40
41
|
.option('-b, --baseClass <value>')
|
41
42
|
.option('-c, --className <value>')
|
@@ -103,17 +104,38 @@ if (programOpts.info) {
|
|
103
104
|
type : 'list',
|
104
105
|
name : 'baseClass',
|
105
106
|
message: 'Please pick the base class, which you want to extend:',
|
106
|
-
|
107
|
-
|
107
|
+
default: 'container.Base',
|
108
|
+
|
109
|
+
choices: [
|
110
|
+
'component.Base',
|
111
|
+
'container.Base',
|
112
|
+
'controller.Component',
|
113
|
+
'core.Base',
|
114
|
+
'data.Model',
|
115
|
+
'data.Store',
|
116
|
+
'model.Component'
|
117
|
+
]
|
118
|
+
});
|
119
|
+
}
|
120
|
+
|
121
|
+
if (!programOpts.singleton) {
|
122
|
+
questions.push({
|
123
|
+
type : 'list',
|
124
|
+
name : 'singleton',
|
125
|
+
message: 'Singleton?',
|
126
|
+
default: 'no',
|
127
|
+
choices: ['yes', 'no']
|
108
128
|
});
|
109
129
|
}
|
110
130
|
|
111
131
|
inquirer.prompt(questions).then(answers => {
|
112
|
-
let baseClass
|
113
|
-
className
|
114
|
-
|
115
|
-
|
116
|
-
|
132
|
+
let baseClass = programOpts.baseClass || answers.baseClass,
|
133
|
+
className = programOpts.className || answers.className,
|
134
|
+
singleton = programOpts.singleton || answers.singleton || 'no',
|
135
|
+
isDrop = programOpts.drop,
|
136
|
+
isSingleton = singleton === 'yes',
|
137
|
+
startDate = new Date(),
|
138
|
+
baseFileName, baseType, classFolder, configName, file, folderDelta, importName, importPath, index, ns, root, rootLowerCase, viewFile;
|
117
139
|
|
118
140
|
if (className.endsWith('.mjs')) {
|
119
141
|
className = className.slice(0, -4);
|
@@ -184,8 +206,8 @@ if (programOpts.info) {
|
|
184
206
|
}
|
185
207
|
|
186
208
|
if (isDrop !== true) {
|
187
|
-
if (fs.existsSync(path.resolve(
|
188
|
-
classFolder = path.resolve(
|
209
|
+
if (fs.existsSync(path.resolve(cwd, 'apps', rootLowerCase))) {
|
210
|
+
classFolder = path.resolve(cwd, 'apps', rootLowerCase, ns.join('/'));
|
189
211
|
} else {
|
190
212
|
console.log('\nNon existing neo app name:', chalk.red(root));
|
191
213
|
process.exit(1);
|
@@ -198,31 +220,86 @@ if (programOpts.info) {
|
|
198
220
|
|
199
221
|
fs.mkdirpSync(classFolder);
|
200
222
|
|
201
|
-
|
223
|
+
baseFileName = baseClass.split('.').pop();
|
224
|
+
|
225
|
+
if (baseFileName === file) {
|
226
|
+
baseFileName = baseClass.split('.');
|
227
|
+
baseFileName = baseFileName.map(e => capitalize(e)).join('');
|
228
|
+
}
|
229
|
+
|
230
|
+
fs.writeFileSync(path.join(classFolder, file + '.mjs'), createContent({
|
231
|
+
baseClass,
|
232
|
+
baseFileName,
|
233
|
+
className,
|
234
|
+
isSingleton,
|
235
|
+
file,
|
236
|
+
folderDelta,
|
237
|
+
ns,
|
238
|
+
root
|
239
|
+
}));
|
240
|
+
|
241
|
+
switch(baseClass) {
|
242
|
+
case 'controller.Component': {
|
243
|
+
baseType = 'Neo.controller.Component';
|
244
|
+
configName = 'controller';
|
245
|
+
importName = file;
|
246
|
+
importPath = `./${importName}.mjs`;
|
247
|
+
index = file.indexOf('Controller');
|
248
|
+
|
249
|
+
if (index > 0) {
|
250
|
+
viewFile = path.join(classFolder, file.substr(0, index) + '.mjs');
|
251
|
+
|
252
|
+
if (fs.existsSync(viewFile)) {
|
253
|
+
adjustView({baseType, configName, importName, importPath, viewFile});
|
254
|
+
}
|
255
|
+
}
|
256
|
+
break;
|
257
|
+
}
|
258
|
+
|
259
|
+
case 'data.Store': {
|
260
|
+
baseType = 'Neo.data.Model';
|
261
|
+
configName = 'model';
|
262
|
+
importName = className.replace('.store.', '.model.');
|
202
263
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
264
|
+
if (importName.endsWith('ies')) {
|
265
|
+
importName.replace(new RegExp('ies$'), 'y')
|
266
|
+
} else {
|
267
|
+
importName = importName.slice(0, -1);
|
268
|
+
}
|
269
|
+
|
270
|
+
viewFile = importName.split('.');
|
271
|
+
viewFile.shift();
|
207
272
|
|
208
|
-
|
209
|
-
viewFile
|
273
|
+
importPath = `../${viewFile.join('/')}.mjs`;
|
274
|
+
viewFile = path.join(classFolder, importPath);
|
210
275
|
|
276
|
+
// checking for the data.Model file
|
211
277
|
if (fs.existsSync(viewFile)) {
|
212
|
-
|
278
|
+
// adjusting the data.Store file
|
279
|
+
viewFile = path.join(classFolder, file + '.mjs');
|
280
|
+
importName = importName.split('.');
|
281
|
+
importName = importName.pop();
|
282
|
+
|
283
|
+
adjustView({baseType, configName, importName, importPath, viewFile});
|
213
284
|
}
|
285
|
+
break;
|
214
286
|
}
|
215
|
-
} else if (baseClass === 'model.Component') {
|
216
|
-
baseType = 'Neo.model.Component';
|
217
|
-
configName = 'model';
|
218
|
-
index = file.indexOf('Model');
|
219
287
|
|
220
|
-
|
221
|
-
|
288
|
+
case 'model.Component': {
|
289
|
+
baseType = 'Neo.model.Component';
|
290
|
+
configName = 'model';
|
291
|
+
importName = file;
|
292
|
+
importPath = `./${importName}.mjs`;
|
293
|
+
index = file.indexOf('Model');
|
222
294
|
|
223
|
-
if (
|
224
|
-
|
295
|
+
if (index > 0) {
|
296
|
+
viewFile = path.join(classFolder, file.substr(0, index) + '.mjs');
|
297
|
+
|
298
|
+
if (fs.existsSync(viewFile)) {
|
299
|
+
adjustView({baseType, configName, importName, importPath, viewFile});
|
300
|
+
}
|
225
301
|
}
|
302
|
+
break;
|
226
303
|
}
|
227
304
|
}
|
228
305
|
}
|
@@ -274,19 +351,20 @@ if (programOpts.info) {
|
|
274
351
|
* @param {Object} opts
|
275
352
|
* @param {String} opts.baseType
|
276
353
|
* @param {String} opts.configName
|
277
|
-
* @param {String} opts.
|
354
|
+
* @param {String} opts.importName
|
355
|
+
* @param {String} opts.importPath
|
278
356
|
* @param {String} opts.viewFile
|
279
357
|
*/
|
280
358
|
function adjustView(opts) {
|
281
359
|
let baseType = opts.baseType,
|
282
360
|
configName = opts.configName,
|
283
|
-
|
361
|
+
importName = opts.importName,
|
284
362
|
viewFile = opts.viewFile,
|
285
363
|
content = fs.readFileSync(viewFile).toString().split(os.EOL),
|
286
364
|
fromMaxPosition = 0,
|
287
365
|
i = 0,
|
288
366
|
len = content.length,
|
289
|
-
adjustSpaces, className, codeLine, fromPosition, importLength,
|
367
|
+
adjustSpaces, className, codeLine, existingImportName, fromPosition, importLength, j, nextLine, spaces;
|
290
368
|
|
291
369
|
// find the index where we want to insert our import statement
|
292
370
|
for (; i < len; i++) {
|
@@ -296,16 +374,16 @@ if (programOpts.info) {
|
|
296
374
|
break;
|
297
375
|
}
|
298
376
|
|
299
|
-
|
300
|
-
|
301
|
-
importLength
|
377
|
+
existingImportName = codeLine.substr(7);
|
378
|
+
existingImportName = existingImportName.substr(0, existingImportName.indexOf(' '));
|
379
|
+
importLength = existingImportName.length;
|
302
380
|
|
303
|
-
if (
|
381
|
+
if (existingImportName > importName) {
|
304
382
|
break;
|
305
383
|
}
|
306
384
|
}
|
307
385
|
|
308
|
-
content.splice(i, 0, `import ${
|
386
|
+
content.splice(i, 0, `import ${importName} from '${opts.importPath}';`);
|
309
387
|
|
310
388
|
// find the longest import module name
|
311
389
|
for (i=0; i < len; i++) {
|
@@ -357,7 +435,7 @@ if (programOpts.info) {
|
|
357
435
|
addComma(content, i - 1);
|
358
436
|
addConfig({
|
359
437
|
baseType,
|
360
|
-
className :
|
438
|
+
className : importName,
|
361
439
|
configName,
|
362
440
|
contentArray: content,
|
363
441
|
index : i,
|
@@ -379,7 +457,7 @@ if (programOpts.info) {
|
|
379
457
|
if (content[j].includes('/**')) {
|
380
458
|
addConfig({
|
381
459
|
baseType,
|
382
|
-
className :
|
460
|
+
className : importName,
|
383
461
|
configName,
|
384
462
|
contentArray: content,
|
385
463
|
index : j,
|
@@ -396,11 +474,22 @@ if (programOpts.info) {
|
|
396
474
|
fs.writeFileSync(viewFile, content.join(os.EOL));
|
397
475
|
}
|
398
476
|
|
477
|
+
/**
|
478
|
+
* Makes the first character of a string uppercase
|
479
|
+
* @param {String} value
|
480
|
+
* @returns {Boolean|String} Returns false for non string inputs
|
481
|
+
*/
|
482
|
+
function capitalize(value) {
|
483
|
+
return typeof value === 'string' && value[0].toUpperCase() + value.slice(1);
|
484
|
+
}
|
485
|
+
|
399
486
|
/**
|
400
487
|
* Creates the content of the neo-class .mjs file
|
401
488
|
* @param {Object} opts
|
402
489
|
* @param {String} opts.baseClass
|
490
|
+
* @param {String} opts.baseFileName
|
403
491
|
* @param {String} opts.className
|
492
|
+
* @param {Boolean} opts.isSingleton
|
404
493
|
* @param {String} opts.file
|
405
494
|
* @param {String} opts.folderDelta
|
406
495
|
* @param {String} opts.ns
|
@@ -408,24 +497,32 @@ if (programOpts.info) {
|
|
408
497
|
* @returns {String}
|
409
498
|
*/
|
410
499
|
function createContent(opts) {
|
411
|
-
let baseClass
|
412
|
-
|
413
|
-
|
414
|
-
className
|
415
|
-
|
416
|
-
|
417
|
-
|
500
|
+
let baseClass = opts.baseClass,
|
501
|
+
baseFileName = opts.baseFileName,
|
502
|
+
baseClassPath = baseClass.split('.').join('/'),
|
503
|
+
className = opts.className,
|
504
|
+
isSingleton = opts.isSingleton,
|
505
|
+
file = opts.file,
|
506
|
+
i = 0,
|
507
|
+
importDelta = '';
|
418
508
|
|
419
509
|
for (; i < opts.folderDelta; i++) {
|
420
510
|
importDelta += '../';
|
421
511
|
}
|
422
512
|
|
423
513
|
let classContent = [
|
424
|
-
`import ${baseFileName} from '${importDelta}${(insideNeo ? '' : 'node_modules/neo.mjs/')}src/${
|
514
|
+
`import ${baseFileName} from '${importDelta}${(insideNeo ? '' : 'node_modules/neo.mjs/')}src/${baseClassPath}.mjs';`,
|
425
515
|
"",
|
426
516
|
"/**",
|
427
517
|
` * @class ${className}`,
|
428
|
-
` * @extends Neo.${baseClass}
|
518
|
+
` * @extends Neo.${baseClass}`
|
519
|
+
];
|
520
|
+
|
521
|
+
isSingleton && classContent.push(
|
522
|
+
" * @singleton"
|
523
|
+
);
|
524
|
+
|
525
|
+
classContent.push(
|
429
526
|
" */",
|
430
527
|
`class ${file} extends ${baseFileName} {`,
|
431
528
|
" static getConfig() {return {",
|
@@ -434,7 +531,17 @@ if (programOpts.info) {
|
|
434
531
|
" * @protected",
|
435
532
|
" */",
|
436
533
|
` className: '${className}'`
|
437
|
-
|
534
|
+
);
|
535
|
+
|
536
|
+
baseClass === 'data.Model' && addComma(classContent).push(
|
537
|
+
" /*",
|
538
|
+
" * @member {Object[]} fields",
|
539
|
+
" */",
|
540
|
+
" fields: [{",
|
541
|
+
" name: 'id',",
|
542
|
+
" type: 'String'",
|
543
|
+
" }]"
|
544
|
+
);
|
438
545
|
|
439
546
|
baseClass === 'container.Base' && addComma(classContent).push(
|
440
547
|
" /*",
|
@@ -443,6 +550,14 @@ if (programOpts.info) {
|
|
443
550
|
" items: []"
|
444
551
|
);
|
445
552
|
|
553
|
+
isSingleton && addComma(classContent).push(
|
554
|
+
" /*",
|
555
|
+
" * @member {Boolean} singleton=true",
|
556
|
+
" * @protected",
|
557
|
+
" */",
|
558
|
+
" singleton: true"
|
559
|
+
);
|
560
|
+
|
446
561
|
baseClass === 'component.Base' && addComma(classContent).push(
|
447
562
|
" /*",
|
448
563
|
" * @member {Object} _vdom",
|
@@ -456,8 +571,22 @@ if (programOpts.info) {
|
|
456
571
|
"}",
|
457
572
|
"",
|
458
573
|
`Neo.applyClassConfig(${file});`,
|
574
|
+
""
|
575
|
+
);
|
576
|
+
|
577
|
+
isSingleton && classContent.push(
|
578
|
+
`let instance = Neo.create(${file});`,
|
459
579
|
"",
|
460
|
-
|
580
|
+
"Neo.applyToGlobalNs(instance);",
|
581
|
+
"",
|
582
|
+
"export default instance;"
|
583
|
+
);
|
584
|
+
|
585
|
+
!isSingleton && classContent.push(
|
586
|
+
`export default ${file};`
|
587
|
+
);
|
588
|
+
|
589
|
+
classContent.push(
|
461
590
|
""
|
462
591
|
);
|
463
592
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "4.0.
|
3
|
+
"version": "4.0.67",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -62,7 +62,7 @@
|
|
62
62
|
"webpack-node-externals": "^3.0.0"
|
63
63
|
},
|
64
64
|
"devDependencies": {
|
65
|
-
"siesta-lite": "
|
65
|
+
"siesta-lite": "5.5.2",
|
66
66
|
"url": "^0.11.0"
|
67
67
|
},
|
68
68
|
"funding": {
|
@@ -99,6 +99,15 @@ class Application extends Base {
|
|
99
99
|
|
100
100
|
return null;
|
101
101
|
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Unregister the app from the CSS map
|
105
|
+
* @param args
|
106
|
+
*/
|
107
|
+
destroy(...args) {
|
108
|
+
Neo.currentWorker.removeAppFromThemeMap(this.name);
|
109
|
+
super.destroy(...args);
|
110
|
+
}
|
102
111
|
}
|
103
112
|
|
104
113
|
Neo.applyClassConfig(Application);
|
package/src/core/Util.mjs
CHANGED
@@ -40,11 +40,11 @@ class Util extends Base {
|
|
40
40
|
|
41
41
|
/**
|
42
42
|
* Makes the first character of a string uppercase
|
43
|
-
* @param {String}
|
43
|
+
* @param {String} value
|
44
44
|
* @returns {Boolean|String} Returns false for non string inputs
|
45
45
|
*/
|
46
|
-
static capitalize(
|
47
|
-
return Util.isString(
|
46
|
+
static capitalize(value) {
|
47
|
+
return Util.isString(value) && value[0].toUpperCase() + value.slice(1);
|
48
48
|
}
|
49
49
|
|
50
50
|
/**
|
@@ -100,7 +100,7 @@ class Util extends Base {
|
|
100
100
|
}
|
101
101
|
|
102
102
|
/**
|
103
|
-
* Transforms all uppercase characters of a string into lowercase.
|
103
|
+
* Transforms all uppercase characters of a string into -lowercase.
|
104
104
|
* Does not touch special characters.
|
105
105
|
* @param {String} value The input containing uppercase characters
|
106
106
|
* @returns {String} The lowercase output
|
@@ -463,24 +463,8 @@ class Select extends Picker {
|
|
463
463
|
* @protected
|
464
464
|
*/
|
465
465
|
onListItemClick(record) {
|
466
|
-
|
467
|
-
|
468
|
-
oldValue = me.value,
|
469
|
-
value = record[displayField];
|
470
|
-
|
471
|
-
if (me.value !== value) {
|
472
|
-
me.hintRecordId = null;
|
473
|
-
me.record = record;
|
474
|
-
me._value = value;
|
475
|
-
me.getInputHintEl().value = null;
|
476
|
-
|
477
|
-
me.afterSetValue(value, oldValue, true); // prevent the list from getting filtered
|
478
|
-
|
479
|
-
me.fire('select', {
|
480
|
-
record,
|
481
|
-
value: record[displayField]
|
482
|
-
});
|
483
|
-
}
|
466
|
+
this.onListItemChange(record);
|
467
|
+
this.hidePicker();
|
484
468
|
}
|
485
469
|
|
486
470
|
/**
|
@@ -518,12 +502,38 @@ class Select extends Picker {
|
|
518
502
|
this.focusInputEl();
|
519
503
|
}
|
520
504
|
|
505
|
+
|
506
|
+
/**
|
507
|
+
* @param {Object} record
|
508
|
+
* @protected
|
509
|
+
*/
|
510
|
+
onListItemChange(record) {
|
511
|
+
let me = this,
|
512
|
+
displayField = me.displayField,
|
513
|
+
oldValue = me.value,
|
514
|
+
value = record[displayField];
|
515
|
+
|
516
|
+
if (me.value !== value) {
|
517
|
+
me.hintRecordId = null;
|
518
|
+
me.record = record;
|
519
|
+
me._value = value;
|
520
|
+
me.getInputHintEl().value = null;
|
521
|
+
|
522
|
+
me.afterSetValue(value, oldValue, true); // prevent the list from getting filtered
|
523
|
+
|
524
|
+
me.fire('select', {
|
525
|
+
record,
|
526
|
+
value: record[displayField]
|
527
|
+
});
|
528
|
+
}
|
529
|
+
}
|
530
|
+
|
521
531
|
/**
|
522
532
|
* @param {Object} record
|
523
533
|
* @protected
|
524
534
|
*/
|
525
535
|
onListItemNavigate(record) {
|
526
|
-
this.
|
536
|
+
this.onListItemChange(record);
|
527
537
|
}
|
528
538
|
|
529
539
|
/**
|
package/src/worker/App.mjs
CHANGED
@@ -270,6 +270,15 @@ class App extends Base {
|
|
270
270
|
});
|
271
271
|
}
|
272
272
|
|
273
|
+
/**
|
274
|
+
* Unregister the app from the CSS map
|
275
|
+
* Only needed for SharedWorkers
|
276
|
+
* @param {String} appName
|
277
|
+
*/
|
278
|
+
removeAppFromThemeMap(appName) {
|
279
|
+
delete Neo.cssMap[appName.toLowerCase()];
|
280
|
+
}
|
281
|
+
|
273
282
|
/**
|
274
283
|
* @private
|
275
284
|
*/
|