neo.mjs 4.1.0 → 4.2.0
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/addConfig.mjs +398 -0
- package/buildScripts/createApp.mjs +3 -3
- package/buildScripts/createClass.mjs +7 -7
- package/examples/grid/covid/GridContainer.mjs +113 -0
- package/examples/grid/covid/GridContainerController.mjs +62 -0
- package/examples/grid/covid/MainContainer.mjs +36 -0
- package/examples/grid/covid/Model.mjs +65 -0
- package/examples/grid/covid/Store.mjs +35 -0
- package/examples/grid/covid/Util.mjs +165 -0
- package/examples/grid/covid/app.mjs +6 -0
- package/examples/grid/covid/index.html +11 -0
- package/examples/grid/covid/neo-config.json +8 -0
- package/package.json +5 -4
- package/resources/scss/src/examples/grid/covid/GridContainer.scss +21 -0
- package/resources/scss/src/grid/Container.scss +6 -34
- package/resources/scss/src/grid/View.scss +73 -1
- package/resources/scss/src/grid/header/Button.scss +67 -7
- package/resources/scss/src/grid/header/Toolbar.scss +6 -2
- package/resources/scss/src/table/View.scss +2 -2
- package/resources/scss/theme-dark/grid/Container.scss +17 -0
- package/resources/scss/theme-dark/grid/View.scss +29 -0
- package/resources/scss/theme-dark/grid/_all.scss +3 -0
- package/resources/scss/theme-dark/grid/header/Button.scss +15 -0
- package/resources/scss/theme-dark/grid/header/Toolbar.scss +0 -0
- package/resources/scss/theme-dark/grid/header/_all.scss +2 -0
- package/resources/scss/theme-light/grid/Container.scss +17 -0
- package/resources/scss/theme-light/grid/View.scss +29 -0
- package/resources/scss/theme-light/grid/_all.scss +3 -0
- package/resources/scss/theme-light/grid/header/Button.scss +15 -0
- package/resources/scss/theme-light/grid/header/Toolbar.scss +0 -0
- package/resources/scss/theme-light/grid/header/_all.scss +2 -0
- package/src/grid/Container.mjs +252 -83
- package/src/grid/View.mjs +206 -11
- package/src/grid/header/Button.mjs +127 -2
- package/src/grid/header/Toolbar.mjs +42 -54
- package/src/selection/grid/CellColumnModel.mjs +122 -0
- package/src/selection/grid/CellColumnRowModel.mjs +122 -0
- package/src/selection/grid/CellModel.mjs +184 -0
- package/src/selection/grid/CellRowModel.mjs +164 -0
- package/src/selection/grid/ColumnModel.mjs +185 -0
- package/src/selection/grid/RowModel.mjs +188 -0
- package/src/selection/table/RowModel.mjs +26 -32
- package/src/table/Container.mjs +9 -13
- package/src/table/header/Toolbar.mjs +1 -1
@@ -0,0 +1,398 @@
|
|
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
|
+
|
11
|
+
const
|
12
|
+
__dirname = path.resolve(),
|
13
|
+
cwd = process.cwd(),
|
14
|
+
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
15
|
+
packageJson = requireJson(path.join(__dirname, 'package.json')),
|
16
|
+
program = new Command(),
|
17
|
+
programName = `${packageJson.name} add-config`;
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Adds a comma to the last element of the contentArray
|
21
|
+
* @param {String[]} contentArray
|
22
|
+
* @param {Number} index=contentArray.length - 1
|
23
|
+
* @returns {String[]}
|
24
|
+
*/
|
25
|
+
function addComma(contentArray, index=contentArray.length - 1) {
|
26
|
+
contentArray[index] += ',';
|
27
|
+
return contentArray;
|
28
|
+
}
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Adds a config to the given index of the contentArray
|
32
|
+
* @param {Object} opts
|
33
|
+
* @param {String} opts.configName
|
34
|
+
* @param {String} opts.defaultValue
|
35
|
+
* @param {String[]} opts.contentArray
|
36
|
+
* @param {Boolean} opts.isLastConfig
|
37
|
+
* @param {Number} opts.index
|
38
|
+
* @param {String} opts.type
|
39
|
+
* @returns {String[]}
|
40
|
+
*/
|
41
|
+
function addConfig(opts) {
|
42
|
+
if (opts.type === 'String' && opts.defaultValue !== 'null') {
|
43
|
+
opts.defaultValue = `'${opts.defaultValue}'`;
|
44
|
+
}
|
45
|
+
|
46
|
+
const config = [
|
47
|
+
' /**',
|
48
|
+
` * @member {${opts.type}} ${opts.configName}_=${opts.defaultValue}`,
|
49
|
+
' */',
|
50
|
+
` ${opts.configName}_: ${opts.defaultValue}`
|
51
|
+
];
|
52
|
+
|
53
|
+
!opts.isLastConfig && addComma(config);
|
54
|
+
|
55
|
+
opts.contentArray.splice(opts.index, 0, config.join(os.EOL));
|
56
|
+
return opts.contentArray;
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Adds a config hook at the matching index
|
61
|
+
* @param {Object} opts
|
62
|
+
* @param {String} opts.comment
|
63
|
+
* @param {String[]} opts.contentArray
|
64
|
+
* @param {String} opts.name
|
65
|
+
* @param {Boolean} opts.oldValueParam
|
66
|
+
* @param {Boolean} opts.returnValue
|
67
|
+
* @param {String} opts.type
|
68
|
+
* @returns {String[]}
|
69
|
+
*/
|
70
|
+
function addHook(opts) {
|
71
|
+
let contentArray = opts.contentArray,
|
72
|
+
i = 0,
|
73
|
+
inserted = false,
|
74
|
+
len = contentArray.length,
|
75
|
+
j, methodName, nextLine,
|
76
|
+
|
77
|
+
method = [
|
78
|
+
'',
|
79
|
+
' /**',
|
80
|
+
` * ${opts.comment}`,
|
81
|
+
` * @param {${opts.type}} value`
|
82
|
+
];
|
83
|
+
|
84
|
+
if (opts.oldValueParam) {
|
85
|
+
method.push(
|
86
|
+
` * @param {${opts.type}} oldValue`
|
87
|
+
);
|
88
|
+
}
|
89
|
+
|
90
|
+
if (opts.returnValue) {
|
91
|
+
method.push(
|
92
|
+
` * @returns {${opts.type}}`
|
93
|
+
);
|
94
|
+
}
|
95
|
+
|
96
|
+
method.push(
|
97
|
+
' * @protected',
|
98
|
+
' */'
|
99
|
+
);
|
100
|
+
|
101
|
+
if (opts.oldValueParam) {
|
102
|
+
method.push(
|
103
|
+
` ${opts.name}(value, oldValue) {`
|
104
|
+
);
|
105
|
+
} else {
|
106
|
+
method.push(
|
107
|
+
` ${opts.name}(value) {`
|
108
|
+
);
|
109
|
+
}
|
110
|
+
|
111
|
+
if (opts.returnValue) {
|
112
|
+
method.push(
|
113
|
+
' return value;'
|
114
|
+
);
|
115
|
+
} else {
|
116
|
+
method.push(
|
117
|
+
' '
|
118
|
+
);
|
119
|
+
}
|
120
|
+
|
121
|
+
method.push(
|
122
|
+
' }'
|
123
|
+
);
|
124
|
+
|
125
|
+
for (; i < len; i++) {
|
126
|
+
if (contentArray[i].includes('}}')) {
|
127
|
+
break;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
for (; i < len; i++) {
|
132
|
+
if (contentArray[i].includes('*/')) {
|
133
|
+
nextLine = contentArray[i + 1]
|
134
|
+
methodName = nextLine.substring(0, nextLine.indexOf('(')).trim();
|
135
|
+
|
136
|
+
if (methodName === 'construct') {
|
137
|
+
continue;
|
138
|
+
}
|
139
|
+
|
140
|
+
if (methodName > opts.name) {
|
141
|
+
for (j=i; j > 0; j--) {
|
142
|
+
if (contentArray[j].includes('/**')) {
|
143
|
+
contentArray.splice(j - 1, 0, method.join(os.EOL));
|
144
|
+
inserted = true;
|
145
|
+
break;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
if (!inserted) {
|
154
|
+
for (i=contentArray.length - 1; i > 0; i--) {
|
155
|
+
if (contentArray[i].includes('}')) {
|
156
|
+
contentArray.splice(i, 0, method.join(os.EOL));
|
157
|
+
break;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
return contentArray;
|
163
|
+
}
|
164
|
+
|
165
|
+
|
166
|
+
/**
|
167
|
+
* Makes the first character of a string uppercase
|
168
|
+
* @param {String} value
|
169
|
+
* @returns {Boolean|String} Returns false for non string inputs
|
170
|
+
*/
|
171
|
+
function capitalize(value) {
|
172
|
+
return value[0].toUpperCase() + value.slice(1);
|
173
|
+
}
|
174
|
+
|
175
|
+
program
|
176
|
+
.name(programName)
|
177
|
+
.version(packageJson.version)
|
178
|
+
.option('-i, --info', 'print environment debug info')
|
179
|
+
.option('-c, --className <value>')
|
180
|
+
.option('-d, --defaultValue <value>')
|
181
|
+
.option('-h, --hooks <value>')
|
182
|
+
.option('-n, --configName <value>')
|
183
|
+
.option('-t, --type <value>')
|
184
|
+
.allowUnknownOption()
|
185
|
+
.on('--help', () => {
|
186
|
+
console.log('\nIn case you have any issues, please create a ticket here:');
|
187
|
+
console.log(chalk.cyan(process.env.npm_package_bugs_url));
|
188
|
+
})
|
189
|
+
.parse(process.argv);
|
190
|
+
|
191
|
+
const programOpts = program.opts();
|
192
|
+
|
193
|
+
if (programOpts.info) {
|
194
|
+
console.log(chalk.bold('\nEnvironment Info:'));
|
195
|
+
console.log(`\n current version of ${packageJson.name}: ${packageJson.version}`);
|
196
|
+
console.log(` running from ${cwd}`);
|
197
|
+
|
198
|
+
envinfo
|
199
|
+
.run({
|
200
|
+
System : ['OS', 'CPU'],
|
201
|
+
Binaries : ['Node', 'npm', 'Yarn'],
|
202
|
+
Browsers : ['Chrome', 'Edge', 'Firefox', 'Safari'],
|
203
|
+
npmPackages: ['neo.mjs']
|
204
|
+
}, {
|
205
|
+
duplicates : true,
|
206
|
+
showNotFound: true
|
207
|
+
})
|
208
|
+
.then(console.log);
|
209
|
+
} else {
|
210
|
+
console.log(chalk.green(programName));
|
211
|
+
|
212
|
+
let answers = {},
|
213
|
+
answer;
|
214
|
+
|
215
|
+
if (!programOpts.className) {
|
216
|
+
answer = await inquirer.prompt({
|
217
|
+
type : 'input',
|
218
|
+
name : 'className',
|
219
|
+
message: 'Please choose the namespace of your class:',
|
220
|
+
default: 'Covid.view.MainContainer'
|
221
|
+
});
|
222
|
+
|
223
|
+
Object.assign(answers, answer);
|
224
|
+
}
|
225
|
+
|
226
|
+
let className = programOpts.className || answers.className,
|
227
|
+
ns = className.split('.'),
|
228
|
+
root = ns.shift().toLowerCase(),
|
229
|
+
classPath = path.resolve(cwd, root === 'neo' ? 'src' : `apps/${root}`, `${ns.join('/')}.mjs`);
|
230
|
+
|
231
|
+
if (!fs.existsSync(path.resolve(classPath))) {
|
232
|
+
console.log(chalk.red(`File not found for ${className} => ${classPath}`));
|
233
|
+
process.exit(1);
|
234
|
+
}
|
235
|
+
|
236
|
+
if (!programOpts.configName) {
|
237
|
+
answer = await inquirer.prompt({
|
238
|
+
type : 'input',
|
239
|
+
name : 'configName',
|
240
|
+
message: 'Please enter a name for your class config:'
|
241
|
+
});
|
242
|
+
|
243
|
+
Object.assign(answers, answer);
|
244
|
+
}
|
245
|
+
|
246
|
+
let configName = programOpts.configName || answers.configName;
|
247
|
+
|
248
|
+
if (configName.endsWith('_')) {
|
249
|
+
configName = configName.slice(0, -1);
|
250
|
+
}
|
251
|
+
|
252
|
+
let uConfigName = capitalize(configName);
|
253
|
+
|
254
|
+
if (!programOpts.type) {
|
255
|
+
answer = await inquirer.prompt({
|
256
|
+
type : 'list',
|
257
|
+
name : 'type',
|
258
|
+
message: 'Please choose a type for your class config:',
|
259
|
+
default: 'Custom',
|
260
|
+
choices: [
|
261
|
+
'Custom',
|
262
|
+
'Object',
|
263
|
+
'Object[]',
|
264
|
+
'Number',
|
265
|
+
'Number[]',
|
266
|
+
'String',
|
267
|
+
'String[]'
|
268
|
+
]
|
269
|
+
});
|
270
|
+
|
271
|
+
Object.assign(answers, answer);
|
272
|
+
}
|
273
|
+
|
274
|
+
if (answers.type === 'Custom') {
|
275
|
+
answer = await inquirer.prompt({
|
276
|
+
type : 'input',
|
277
|
+
name : 'type',
|
278
|
+
message: 'Please enter the type for your class config:'
|
279
|
+
});
|
280
|
+
|
281
|
+
Object.assign(answers, answer);
|
282
|
+
}
|
283
|
+
|
284
|
+
if (!programOpts.defaultValue) {
|
285
|
+
answer = await inquirer.prompt({
|
286
|
+
type : 'input',
|
287
|
+
name : 'defaultValue',
|
288
|
+
message: 'Please enter a defaultValue:',
|
289
|
+
default: 'null'
|
290
|
+
});
|
291
|
+
|
292
|
+
Object.assign(answers, answer);
|
293
|
+
}
|
294
|
+
|
295
|
+
if (!programOpts.hooks) {
|
296
|
+
answer = await inquirer.prompt({
|
297
|
+
type : 'checkbox',
|
298
|
+
name : 'hooks',
|
299
|
+
message: 'Please choose the hooks for your class config:',
|
300
|
+
choices: [`afterSet${uConfigName}()`, `beforeGet${uConfigName}()`, `beforeSet${uConfigName}()`],
|
301
|
+
default: [`afterSet${uConfigName}()`]
|
302
|
+
});
|
303
|
+
|
304
|
+
Object.assign(answers, answer);
|
305
|
+
}
|
306
|
+
|
307
|
+
let defaultValue = programOpts.defaultValue || answers.defaultValue,
|
308
|
+
hooks = programOpts.hooks || answers.hooks,
|
309
|
+
type = programOpts.type || answers.type,
|
310
|
+
contentArray = fs.readFileSync(classPath).toString().split(os.EOL),
|
311
|
+
i = 0,
|
312
|
+
len = contentArray.length,
|
313
|
+
codeLine, existingConfigName, j, nextLine;
|
314
|
+
|
315
|
+
for (; i < len; i++) {
|
316
|
+
if (contentArray[i].includes('static getConfig')) {
|
317
|
+
break;
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
321
|
+
for (; i < len; i++) {
|
322
|
+
codeLine = contentArray[i];
|
323
|
+
|
324
|
+
if (codeLine.includes('}}')) {
|
325
|
+
addComma(contentArray, i - 1);
|
326
|
+
addConfig({
|
327
|
+
configName,
|
328
|
+
defaultValue,
|
329
|
+
contentArray,
|
330
|
+
index : i,
|
331
|
+
isLastConfig: true,
|
332
|
+
type
|
333
|
+
});
|
334
|
+
break;
|
335
|
+
}
|
336
|
+
|
337
|
+
if (codeLine.includes('*/')) {
|
338
|
+
nextLine = contentArray[i + 1]
|
339
|
+
existingConfigName = nextLine.substring(0, nextLine.indexOf(':')).trim();
|
340
|
+
|
341
|
+
if (existingConfigName === 'className' || existingConfigName === 'ntype') {
|
342
|
+
continue;
|
343
|
+
}
|
344
|
+
|
345
|
+
if (existingConfigName > configName) {
|
346
|
+
for (j=i; j > 0; j--) {
|
347
|
+
if (contentArray[j].includes('/**')) {
|
348
|
+
addConfig({
|
349
|
+
configName,
|
350
|
+
contentArray,
|
351
|
+
defaultValue,
|
352
|
+
index : j,
|
353
|
+
isLastConfig: false,
|
354
|
+
type
|
355
|
+
});
|
356
|
+
break;
|
357
|
+
}
|
358
|
+
}
|
359
|
+
break;
|
360
|
+
}
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
if (hooks.includes(`afterSet${uConfigName}()`)) {
|
365
|
+
addHook({
|
366
|
+
comment : `Triggered after the ${configName} config got changed`,
|
367
|
+
contentArray,
|
368
|
+
name : `afterSet${uConfigName}`,
|
369
|
+
oldValueParam: true,
|
370
|
+
returnValue : false,
|
371
|
+
type
|
372
|
+
});
|
373
|
+
}
|
374
|
+
|
375
|
+
if (hooks.includes(`beforeGet${uConfigName}()`)) {
|
376
|
+
addHook({
|
377
|
+
comment : `Gets triggered when accessing the value of the ${configName} config`,
|
378
|
+
contentArray,
|
379
|
+
name : `beforeGet${uConfigName}`,
|
380
|
+
oldValueParam: false,
|
381
|
+
returnValue : true,
|
382
|
+
type
|
383
|
+
});
|
384
|
+
}
|
385
|
+
|
386
|
+
if (hooks.includes(`beforeSet${uConfigName}()`)) {
|
387
|
+
addHook({
|
388
|
+
comment : `Triggered before the ${configName} config gets changed`,
|
389
|
+
contentArray,
|
390
|
+
name : `beforeSet${uConfigName}`,
|
391
|
+
oldValueParam: true,
|
392
|
+
returnValue : true,
|
393
|
+
type
|
394
|
+
});
|
395
|
+
}
|
396
|
+
|
397
|
+
fs.writeFileSync(classPath, contentArray.join(os.EOL));
|
398
|
+
}
|
@@ -221,16 +221,16 @@ if (programOpts.info) {
|
|
221
221
|
" */",
|
222
222
|
"class MainContainer extends Viewport {",
|
223
223
|
" static getConfig() {return {",
|
224
|
-
"
|
224
|
+
" /**",
|
225
225
|
" * @member {String} className='" + appName + ".view.MainContainer'",
|
226
226
|
" * @protected",
|
227
227
|
" */",
|
228
228
|
" className: '" + appName + ".view.MainContainer',",
|
229
|
-
"
|
229
|
+
" /**",
|
230
230
|
" * @member {Boolean} autoMount=true",
|
231
231
|
" */",
|
232
232
|
" autoMount: true,",
|
233
|
-
"
|
233
|
+
" /**",
|
234
234
|
" * @member {Object[]} items",
|
235
235
|
" */",
|
236
236
|
" items: [{",
|
@@ -576,7 +576,7 @@ if (programOpts.info) {
|
|
576
576
|
" */",
|
577
577
|
`class ${file} extends ${baseFileName} {`,
|
578
578
|
" static getConfig() {return {",
|
579
|
-
"
|
579
|
+
" /**",
|
580
580
|
` * @member {String} className='${className}'`,
|
581
581
|
" * @protected",
|
582
582
|
" */",
|
@@ -584,7 +584,7 @@ if (programOpts.info) {
|
|
584
584
|
);
|
585
585
|
|
586
586
|
baseClass === 'table.Container' && addComma(classContent).push(
|
587
|
-
"
|
587
|
+
" /**",
|
588
588
|
" * @member {Object[]} columns",
|
589
589
|
" */",
|
590
590
|
" columns: [{",
|
@@ -597,7 +597,7 @@ if (programOpts.info) {
|
|
597
597
|
);
|
598
598
|
|
599
599
|
baseClass === 'data.Model' && addComma(classContent).push(
|
600
|
-
"
|
600
|
+
" /**",
|
601
601
|
" * @member {Object[]} fields",
|
602
602
|
" */",
|
603
603
|
" fields: [{",
|
@@ -607,14 +607,14 @@ if (programOpts.info) {
|
|
607
607
|
);
|
608
608
|
|
609
609
|
baseClass === 'container.Base' && addComma(classContent).push(
|
610
|
-
"
|
610
|
+
" /**",
|
611
611
|
" * @member {Object[]} items",
|
612
612
|
" */",
|
613
613
|
" items: []"
|
614
614
|
);
|
615
615
|
|
616
616
|
baseClass === 'tab.Container' && addComma(classContent).push(
|
617
|
-
"
|
617
|
+
" /**",
|
618
618
|
" * @member {Object[]} items",
|
619
619
|
" */",
|
620
620
|
" items: [{",
|
@@ -635,7 +635,7 @@ if (programOpts.info) {
|
|
635
635
|
);
|
636
636
|
|
637
637
|
isSingleton && addComma(classContent).push(
|
638
|
-
"
|
638
|
+
" /**",
|
639
639
|
" * @member {Boolean} singleton=true",
|
640
640
|
" * @protected",
|
641
641
|
" */",
|
@@ -643,7 +643,7 @@ if (programOpts.info) {
|
|
643
643
|
);
|
644
644
|
|
645
645
|
baseClass === 'component.Base' && addComma(classContent).push(
|
646
|
-
"
|
646
|
+
" /**",
|
647
647
|
" * @member {Object} _vdom",
|
648
648
|
" */",
|
649
649
|
" _vdom:",
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import BaseGridContainer from '../../../src/grid/Container.mjs';
|
2
|
+
import GridContainerController from './GridContainerController.mjs';
|
3
|
+
import Store from './Store.mjs';
|
4
|
+
import Util from './Util.mjs';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @class Neo.examples.grid.covid.GridContainer
|
8
|
+
* @extends Neo.grid.Container
|
9
|
+
*/
|
10
|
+
class GridContainer extends BaseGridContainer {
|
11
|
+
static getConfig() {return {
|
12
|
+
/**
|
13
|
+
* @member {String} className='Neo.examples.grid.covid.GridContainer'
|
14
|
+
* @protected
|
15
|
+
*/
|
16
|
+
className: 'Neo.examples.grid.covid.GridContainer',
|
17
|
+
/**
|
18
|
+
* @member {String[]} cls=['covid-country-grid', 'neo-grid-container']
|
19
|
+
*/
|
20
|
+
cls: ['covid-country-grid', 'neo-grid-container'],
|
21
|
+
/**
|
22
|
+
* Default configs for each column
|
23
|
+
* @member {Object} columnDefaults
|
24
|
+
*/
|
25
|
+
columnDefaults: {
|
26
|
+
align : 'right',
|
27
|
+
defaultSortDirection: 'DESC',
|
28
|
+
renderer : Util.formatNumber,
|
29
|
+
width : 100
|
30
|
+
},
|
31
|
+
/**
|
32
|
+
* @member {Object[]} columns
|
33
|
+
*/
|
34
|
+
columns: [{
|
35
|
+
cls : ['neo-index-column', 'neo-grid-header-button'],
|
36
|
+
dock : 'left',
|
37
|
+
field : 'index',
|
38
|
+
minWidth: 40,
|
39
|
+
text : '#',
|
40
|
+
renderer: Util.indexRenderer,
|
41
|
+
width : 40
|
42
|
+
}, {
|
43
|
+
align : 'left',
|
44
|
+
defaultSortDirection: 'ASC',
|
45
|
+
dock : 'left',
|
46
|
+
field : 'country',
|
47
|
+
text : 'Country',
|
48
|
+
width : 200,
|
49
|
+
|
50
|
+
renderer: data => {
|
51
|
+
return {
|
52
|
+
cls : ['neo-country-column', 'neo-grid-cell'],
|
53
|
+
html: [
|
54
|
+
'<div style="display: flex; align-items: center">',
|
55
|
+
'<img style="height:20px; margin-right:10px; width:20px;" src="' + Util.getCountryFlagUrl(data.value) + '">' + data.value,
|
56
|
+
'</div>'
|
57
|
+
].join('')
|
58
|
+
};
|
59
|
+
}
|
60
|
+
}, {
|
61
|
+
field: 'cases',
|
62
|
+
text : 'Cases'
|
63
|
+
}, {
|
64
|
+
field: 'casesPerOneMillion',
|
65
|
+
text : 'Cases / 1M'
|
66
|
+
}, {
|
67
|
+
field : 'infected',
|
68
|
+
text : 'Infected',
|
69
|
+
renderer: data => Util.formatInfected(data)
|
70
|
+
}, {
|
71
|
+
field : 'active',
|
72
|
+
text : 'Active',
|
73
|
+
renderer: data => Util.formatNumber(data, '#64B5F6')
|
74
|
+
}, {
|
75
|
+
field : 'recovered',
|
76
|
+
text : 'Recovered',
|
77
|
+
renderer: data => Util.formatNumber(data, '#28ca68')
|
78
|
+
}, {
|
79
|
+
field : 'critical',
|
80
|
+
text : 'Critical',
|
81
|
+
renderer: data => Util.formatNumber(data, 'orange')
|
82
|
+
}, {
|
83
|
+
field : 'deaths',
|
84
|
+
text : 'Deaths',
|
85
|
+
renderer: data => Util.formatNumber(data, '#fb6767')
|
86
|
+
}, {
|
87
|
+
field: 'todayCases',
|
88
|
+
text : 'Cases today'
|
89
|
+
}, {
|
90
|
+
field : 'todayDeaths',
|
91
|
+
text : 'Deaths today',
|
92
|
+
renderer: data => Util.formatNumber(data, '#fb6767')
|
93
|
+
}, {
|
94
|
+
field: 'tests',
|
95
|
+
text : 'Tests'
|
96
|
+
}, {
|
97
|
+
field: 'testsPerOneMillion',
|
98
|
+
text : 'Tests / 1M'
|
99
|
+
}],
|
100
|
+
/**
|
101
|
+
* @member {Neo.controller.Component} controller=GridContainerController
|
102
|
+
*/
|
103
|
+
controller: GridContainerController,
|
104
|
+
/**
|
105
|
+
* @member {Object[]} store=Store
|
106
|
+
*/
|
107
|
+
store: Store
|
108
|
+
}}
|
109
|
+
}
|
110
|
+
|
111
|
+
Neo.applyClassConfig(GridContainer);
|
112
|
+
|
113
|
+
export default GridContainer;
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import Controller from '../../../src/controller/Component.mjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @class Neo.examples.grid.covid.GridContainerController
|
5
|
+
* @extends Neo.controller.Component
|
6
|
+
*/
|
7
|
+
class GridContainerController extends Controller {
|
8
|
+
/**
|
9
|
+
* @member {String} apiUrl='https://disease.sh/v3/covid-19/countries'
|
10
|
+
*/
|
11
|
+
apiUrl = 'https://disease.sh/v3/covid-19/countries'
|
12
|
+
|
13
|
+
static getConfig() {return {
|
14
|
+
/**
|
15
|
+
* @member {String} className='Neo.examples.grid.covid.GridContainerController'
|
16
|
+
* @protected
|
17
|
+
*/
|
18
|
+
className: 'Neo.examples.grid.covid.GridContainerController'
|
19
|
+
}}
|
20
|
+
|
21
|
+
/**
|
22
|
+
* @param {Object} config
|
23
|
+
*/
|
24
|
+
construct(config) {
|
25
|
+
super.construct(config);
|
26
|
+
this.loadData();
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* @param {Object[]} data
|
31
|
+
*/
|
32
|
+
addStoreItems(data) {
|
33
|
+
let store = this.component.store;
|
34
|
+
|
35
|
+
data.forEach(item => {
|
36
|
+
if (item.country.includes('"')) {
|
37
|
+
item.country = item.country.replace('"', "\'");
|
38
|
+
}
|
39
|
+
|
40
|
+
item.casesPerOneMillion = item.casesPerOneMillion > item.cases ? 'N/A' : item.casesPerOneMillion || 0;
|
41
|
+
item.infected = item.casesPerOneMillion;
|
42
|
+
});
|
43
|
+
|
44
|
+
store.data = data;
|
45
|
+
}
|
46
|
+
|
47
|
+
/**
|
48
|
+
*
|
49
|
+
*/
|
50
|
+
loadData() {
|
51
|
+
let me = this;
|
52
|
+
|
53
|
+
fetch(me.apiUrl)
|
54
|
+
.then(response => response.json())
|
55
|
+
.catch(err => console.log('Can’t access ' + me.apiUrl, err))
|
56
|
+
.then(data => me.addStoreItems(data));
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
Neo.applyClassConfig(GridContainerController);
|
61
|
+
|
62
|
+
export default GridContainerController;
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import GridContainer from './GridContainer.mjs';
|
2
|
+
import Viewport from '../../../src/container/Viewport.mjs';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @class Neo.examples.grid.covid.MainContainer
|
6
|
+
* @extends Neo.container.Viewport
|
7
|
+
*/
|
8
|
+
class MainContainer extends Viewport {
|
9
|
+
static getConfig() {return {
|
10
|
+
/**
|
11
|
+
* @member {String} className='Neo.examples.grid.covid.MainContainer'
|
12
|
+
* @protected
|
13
|
+
*/
|
14
|
+
className: 'Neo.examples.grid.covid.MainContainer',
|
15
|
+
/**
|
16
|
+
* @member {Boolean} autoMount=true
|
17
|
+
*/
|
18
|
+
autoMount: true,
|
19
|
+
/**
|
20
|
+
* @member {Object[]} items=[GridContainer]
|
21
|
+
*/
|
22
|
+
items: [GridContainer],
|
23
|
+
/**
|
24
|
+
* @member {Object} layout={ntype:'fit'}
|
25
|
+
*/
|
26
|
+
layout: {ntype: 'fit'},
|
27
|
+
/**
|
28
|
+
* @member {Object} style={padding:'20px'}
|
29
|
+
*/
|
30
|
+
style: {padding: '20px'}
|
31
|
+
}}
|
32
|
+
}
|
33
|
+
|
34
|
+
Neo.applyClassConfig(MainContainer);
|
35
|
+
|
36
|
+
export default MainContainer;
|