neo.mjs 4.0.39 → 4.0.42
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/watchThemes.mjs +99 -0
- package/package.json +7 -6
- package/resources/scss/src/button/Base.scss +1 -1
- package/resources/scss/src/component/Carousel.scss +70 -0
- package/src/component/Base.mjs +127 -0
- package/src/component/Carousel.mjs +266 -0
- package/src/form/field/trigger/Base.mjs +0 -4
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import autoprefixer from 'autoprefixer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import postcss from 'postcss';
|
|
6
|
+
import sass from 'sass';
|
|
7
|
+
|
|
8
|
+
let cwd = process.cwd(),
|
|
9
|
+
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
|
10
|
+
packageJson = requireJson(path.resolve(cwd, 'package.json')),
|
|
11
|
+
neoPath = packageJson.name === 'neo.mjs' ? './' : './node_modules/neo.mjs/',
|
|
12
|
+
mixinPath = path.resolve(neoPath, 'resources/scss/mixins/_all.scss'),
|
|
13
|
+
scssPath = path.resolve(cwd, 'resources/scss');
|
|
14
|
+
|
|
15
|
+
if (path.sep === '\\') {
|
|
16
|
+
mixinPath = mixinPath.replace(/\\/g, '/');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fs.watch(scssPath, {
|
|
20
|
+
recursive: true
|
|
21
|
+
}, (eventType, filename) => {
|
|
22
|
+
if (filename.endsWith('.scss')) {
|
|
23
|
+
switch(eventType) {
|
|
24
|
+
case 'change': {
|
|
25
|
+
buildFile(filename);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
function buildFile(filename) {
|
|
32
|
+
console.log('start processing', filename);
|
|
33
|
+
|
|
34
|
+
let filePath = path.join(scssPath, filename),
|
|
35
|
+
destPath = path.join(cwd, 'dist/development/css', filename.replace('.scss', '.css')),
|
|
36
|
+
startDate = new Date(),
|
|
37
|
+
data, map;
|
|
38
|
+
|
|
39
|
+
data = [
|
|
40
|
+
`@use "sass:map";`,
|
|
41
|
+
`@use "sass:math";`,
|
|
42
|
+
`$neoMap: ();`,
|
|
43
|
+
`$useCssVars: true;`,
|
|
44
|
+
`@import "${mixinPath}";`
|
|
45
|
+
].join('');
|
|
46
|
+
|
|
47
|
+
fs.readFile(filePath).then(content => {
|
|
48
|
+
try {
|
|
49
|
+
let result = sass.renderSync({
|
|
50
|
+
data : data + content.toString(),
|
|
51
|
+
outFile : destPath,
|
|
52
|
+
sourceMap : true,
|
|
53
|
+
sourceMapEmbed: false
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
map = result.map?.toString();
|
|
57
|
+
|
|
58
|
+
if (map) {
|
|
59
|
+
// https://github.com/neomjs/neo/issues/1970
|
|
60
|
+
map = JSON.parse(map);
|
|
61
|
+
|
|
62
|
+
let filenameSlash = filename;
|
|
63
|
+
|
|
64
|
+
if (path.sep === '\\') {
|
|
65
|
+
filenameSlash = filenameSlash.replace(/\\/g, '/');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let len = filenameSlash.split('/').length,
|
|
69
|
+
src = `/scss/${filenameSlash}`,
|
|
70
|
+
i = 0;
|
|
71
|
+
|
|
72
|
+
for (; i < len; i++) {
|
|
73
|
+
src = '../' + src;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
map.sources = [src];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
postcss([autoprefixer]).process(result.css, {
|
|
80
|
+
from: filePath,
|
|
81
|
+
to : destPath,
|
|
82
|
+
map : {
|
|
83
|
+
prev: map && JSON.stringify(map)
|
|
84
|
+
}
|
|
85
|
+
}).then(result => {
|
|
86
|
+
fs.writeFileSync(destPath, result.css, () => true);
|
|
87
|
+
|
|
88
|
+
if (result.map) {
|
|
89
|
+
fs.writeFileSync(result.opts.to + '.map', result.map.toString());
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const processTime = (Math.round((new Date - startDate) * 100) / 100000).toFixed(2);
|
|
93
|
+
console.log('Updated file:', (chalk.blue(`${processTime}s`)), destPath);
|
|
94
|
+
});
|
|
95
|
+
} catch(error) {
|
|
96
|
+
console.log('SCSS build failed for', chalk.red(filename));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neo.mjs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.42",
|
|
4
4
|
"description": "The webworkers driven UI framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"create-app": "node ./buildScripts/createApp.mjs",
|
|
17
17
|
"generate-docs-json": "node ./buildScripts/docs/jsdocx.mjs",
|
|
18
18
|
"server-start": "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open",
|
|
19
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
19
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
20
|
+
"watch-themes": "node ./buildScripts/watchThemes.mjs"
|
|
20
21
|
},
|
|
21
22
|
"keywords": [
|
|
22
23
|
"javascript",
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"chalk": "^5.0.1",
|
|
42
43
|
"clean-webpack-plugin": "^4.0.0",
|
|
43
44
|
"commander": "^9.3.0",
|
|
44
|
-
"cssnano": "^5.1.
|
|
45
|
+
"cssnano": "^5.1.11",
|
|
45
46
|
"envinfo": "^7.8.1",
|
|
46
47
|
"fs-extra": "^10.1.0",
|
|
47
48
|
"highlightjs-line-numbers.js": "^2.8.0",
|
|
@@ -49,10 +50,10 @@
|
|
|
49
50
|
"neo-jsdoc": "^1.0.1",
|
|
50
51
|
"neo-jsdoc-x": "^1.0.4",
|
|
51
52
|
"postcss": "^8.4.14",
|
|
52
|
-
"sass": "^1.52.
|
|
53
|
-
"webpack": "^5.
|
|
53
|
+
"sass": "^1.52.3",
|
|
54
|
+
"webpack": "^5.73.0",
|
|
54
55
|
"webpack-cli": "^4.9.2",
|
|
55
|
-
"webpack-dev-server": "4.9.
|
|
56
|
+
"webpack-dev-server": "4.9.2",
|
|
56
57
|
"webpack-hook-plugin": "^1.0.7",
|
|
57
58
|
"webpack-node-externals": "^3.0.0"
|
|
58
59
|
},
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CAROUSEL TRANSFORM
|
|
3
|
+
*/
|
|
4
|
+
.neo-carousel {
|
|
5
|
+
/**
|
|
6
|
+
* VARS
|
|
7
|
+
*/
|
|
8
|
+
--neo-carousel-translate-x: 0;
|
|
9
|
+
--neo-carousel-translate-y: 0;
|
|
10
|
+
--neo-carousel-transition-timing: cubic-bezier(.4,0,.2,1);
|
|
11
|
+
--neo-carousel-duration: .7s;
|
|
12
|
+
|
|
13
|
+
.neo-carousel-inner {
|
|
14
|
+
position: relative;
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
|
|
17
|
+
.neo-carousel-item {
|
|
18
|
+
transition-timing-function: var(--neo-carousel-transition-timing);
|
|
19
|
+
transition-duration: var(--neo-carousel-duration);
|
|
20
|
+
transition-property: all;
|
|
21
|
+
z-index: 10;
|
|
22
|
+
inset: 0;
|
|
23
|
+
position: absolute;
|
|
24
|
+
transform: translate(var(--neo-carousel-translate-x), var(--neo-carousel-translate-y));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.neo-carousel--translate-x-full{
|
|
30
|
+
--neo-carousel-translate-x: -100%;
|
|
31
|
+
transform: translate(var(--neo-carousel-translate-x),var(--neo-carousel-translate-y));
|
|
32
|
+
}
|
|
33
|
+
.neo-carousel-translate-x-0{
|
|
34
|
+
--neo-carousel-translate-x: 0;
|
|
35
|
+
transform: translate(var(--neo-carousel-translate-x),var(--neo-carousel-translate-y));
|
|
36
|
+
}
|
|
37
|
+
.neo-carousel-translate-x-full{
|
|
38
|
+
--neo-carousel-translate-x: 100%;
|
|
39
|
+
transform: translate(var(--neo-carousel-translate-x),var(--neo-carousel-translate-y));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* BASE STYLING
|
|
44
|
+
*/
|
|
45
|
+
.neo-carousel {
|
|
46
|
+
padding: 15px;
|
|
47
|
+
height: 14rem;
|
|
48
|
+
background: var(--container-background-color);
|
|
49
|
+
|
|
50
|
+
.neo-carousel-btn-bar {
|
|
51
|
+
text-align: end;
|
|
52
|
+
|
|
53
|
+
.neo-carousel-btn {
|
|
54
|
+
padding: 15px;
|
|
55
|
+
font-size: 18px;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
.neo-carousel-inner {
|
|
59
|
+
border-radius: 5px;
|
|
60
|
+
height: 9rem;
|
|
61
|
+
overflow: hidden;
|
|
62
|
+
background-color: var(--button-active-color);
|
|
63
|
+
color: var(--button-background-color);
|
|
64
|
+
|
|
65
|
+
.neo-carousel-item {
|
|
66
|
+
height: 9rem;
|
|
67
|
+
padding: 15px;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/component/Base.mjs
CHANGED
|
@@ -17,6 +17,13 @@ import VNodeUtil from '../util/VNode.mjs';
|
|
|
17
17
|
*/
|
|
18
18
|
class Base extends CoreBase {
|
|
19
19
|
static getStaticConfig() {return {
|
|
20
|
+
/**
|
|
21
|
+
* Valid values for hideMode
|
|
22
|
+
* @member {String[]} hideModes=['removeDom','visibility']
|
|
23
|
+
* @protected
|
|
24
|
+
* @static
|
|
25
|
+
*/
|
|
26
|
+
hideModes: ['removeDom', 'visibility'],
|
|
20
27
|
/**
|
|
21
28
|
* True automatically applies the core/Observable.mjs mixin
|
|
22
29
|
* @member {Boolean} observable=true
|
|
@@ -147,6 +154,18 @@ class Base extends CoreBase {
|
|
|
147
154
|
* @member {Number|String|null} height_=null
|
|
148
155
|
*/
|
|
149
156
|
height_: null,
|
|
157
|
+
/**
|
|
158
|
+
* Initial setting to hide or show the component and
|
|
159
|
+
* you can use either hide()/show() or change this config directly to change the hidden state
|
|
160
|
+
* @member {Boolean} hidden_=false
|
|
161
|
+
*/
|
|
162
|
+
hidden_: false,
|
|
163
|
+
/**
|
|
164
|
+
* Used for hide and show and defines if the component
|
|
165
|
+
* should use css visibility:'hidden' or vdom:removeDom
|
|
166
|
+
* @member {String} hideMode_='visibility'
|
|
167
|
+
*/
|
|
168
|
+
hideMode_: 'visibility',
|
|
150
169
|
/**
|
|
151
170
|
* The top level innerHTML of the component
|
|
152
171
|
* @member {String|null} html_=null
|
|
@@ -402,6 +421,17 @@ class Base extends CoreBase {
|
|
|
402
421
|
}
|
|
403
422
|
}
|
|
404
423
|
|
|
424
|
+
/**
|
|
425
|
+
* Add a new cls to the vdomRoot
|
|
426
|
+
* @param {String} value
|
|
427
|
+
*/
|
|
428
|
+
addCls(value) {
|
|
429
|
+
let cls = this.cls;
|
|
430
|
+
|
|
431
|
+
NeoArray.add(cls, value);
|
|
432
|
+
this.cls = cls;
|
|
433
|
+
}
|
|
434
|
+
|
|
405
435
|
/**
|
|
406
436
|
* Either a string like 'color: red; background-color: blue;'
|
|
407
437
|
* or an object containing style attributes
|
|
@@ -520,6 +550,18 @@ class Base extends CoreBase {
|
|
|
520
550
|
this.changeVdomRootKey('height', value);
|
|
521
551
|
}
|
|
522
552
|
|
|
553
|
+
/**
|
|
554
|
+
* Triggered after the hidden config got changed
|
|
555
|
+
* @param {Boolean} value
|
|
556
|
+
* @param {Boolean} oldValue
|
|
557
|
+
* @protected
|
|
558
|
+
*/
|
|
559
|
+
afterSetHidden(value, oldValue) {
|
|
560
|
+
if (!(!value && oldValue === undefined)) {
|
|
561
|
+
this[value ? 'hide' : 'show']();
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
523
565
|
/**
|
|
524
566
|
* Triggered after the html config got changed
|
|
525
567
|
* @param {String|null} value
|
|
@@ -725,6 +767,16 @@ class Base extends CoreBase {
|
|
|
725
767
|
return value || [];
|
|
726
768
|
}
|
|
727
769
|
|
|
770
|
+
/**
|
|
771
|
+
* Triggered before the hideMode config gets changed
|
|
772
|
+
* @param {String} value
|
|
773
|
+
* @param {String} oldValue
|
|
774
|
+
* @protected
|
|
775
|
+
*/
|
|
776
|
+
beforeSetHideMode(value, oldValue) {
|
|
777
|
+
return this.beforeSetEnumValue(value, oldValue, 'hideMode');
|
|
778
|
+
}
|
|
779
|
+
|
|
728
780
|
/**
|
|
729
781
|
* Triggered before the keys config gets changed.
|
|
730
782
|
* Creates a KeyNavigation instance if needed.
|
|
@@ -1061,6 +1113,38 @@ class Base extends CoreBase {
|
|
|
1061
1113
|
return this.vnode;
|
|
1062
1114
|
}
|
|
1063
1115
|
|
|
1116
|
+
/**
|
|
1117
|
+
* Hide the component.
|
|
1118
|
+
* hideMode: 'removeDom' uses vdom removeDom.
|
|
1119
|
+
* hideMode: 'visibility' uses css visibility.
|
|
1120
|
+
* If hideMode === 'removeDom' you can pass a timeout for custom css class hiding.
|
|
1121
|
+
* @param {Number} timeout
|
|
1122
|
+
*/
|
|
1123
|
+
hide(timeout) {
|
|
1124
|
+
let me = this,
|
|
1125
|
+
doRemove = me.hideMode !== 'visibility';
|
|
1126
|
+
|
|
1127
|
+
if (doRemove) {
|
|
1128
|
+
let removeFn = function() {
|
|
1129
|
+
let vdom = me.vdom;
|
|
1130
|
+
vdom.removeDom = true;
|
|
1131
|
+
me.vdom = vdom;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
if (timeout) {
|
|
1135
|
+
setTimeout(removeFn, timeout);
|
|
1136
|
+
} else {
|
|
1137
|
+
removeFn();
|
|
1138
|
+
}
|
|
1139
|
+
} else {
|
|
1140
|
+
let style = me.style;
|
|
1141
|
+
style.visibility = 'hidden';
|
|
1142
|
+
me.style = style;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
this._hidden = true;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1064
1148
|
/**
|
|
1065
1149
|
*
|
|
1066
1150
|
*/
|
|
@@ -1282,6 +1366,17 @@ class Base extends CoreBase {
|
|
|
1282
1366
|
});
|
|
1283
1367
|
}
|
|
1284
1368
|
|
|
1369
|
+
/**
|
|
1370
|
+
* Remove a cls from the vdomRoot
|
|
1371
|
+
* @param {String} value
|
|
1372
|
+
*/
|
|
1373
|
+
removeCls(value) {
|
|
1374
|
+
let cls = this.cls;
|
|
1375
|
+
|
|
1376
|
+
NeoArray.remove(cls, value);
|
|
1377
|
+
this.cls = cls;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1285
1380
|
/**
|
|
1286
1381
|
* @param {Array|Object} value
|
|
1287
1382
|
*/
|
|
@@ -1404,6 +1499,28 @@ class Base extends CoreBase {
|
|
|
1404
1499
|
return this.set(values, true);
|
|
1405
1500
|
}
|
|
1406
1501
|
|
|
1502
|
+
/**
|
|
1503
|
+
* Show the component.
|
|
1504
|
+
* hideMode: 'removeDom' uses vdom removeDom.
|
|
1505
|
+
* hideMode: 'visibility' uses css visibility.
|
|
1506
|
+
*/
|
|
1507
|
+
show() {
|
|
1508
|
+
let me = this,
|
|
1509
|
+
doAdd = me.hideMode !== 'visibility';
|
|
1510
|
+
|
|
1511
|
+
if (doAdd) {
|
|
1512
|
+
let vdom = me.vdom;
|
|
1513
|
+
vdom.removeDom = false;
|
|
1514
|
+
me.vdom = vdom;
|
|
1515
|
+
} else {
|
|
1516
|
+
let style = me.style;
|
|
1517
|
+
style.visibility = 'visible';
|
|
1518
|
+
me.style = style;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
this._hidden = false;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1407
1524
|
/**
|
|
1408
1525
|
* Placeholder method for util.VDom.syncVdomIds to allow overriding (disabling) it
|
|
1409
1526
|
* @param {Neo.vdom.VNode} [vnode=this.vnode]
|
|
@@ -1473,7 +1590,17 @@ class Base extends CoreBase {
|
|
|
1473
1590
|
let end = performance.now();
|
|
1474
1591
|
console.log('syncVnodeTree', me.id, end - start);
|
|
1475
1592
|
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
/**
|
|
1596
|
+
* Toggle a cls inside the vdomRoot of the component
|
|
1597
|
+
* @param {String} value
|
|
1598
|
+
*/
|
|
1599
|
+
toggleCls(value) {
|
|
1600
|
+
let cls = this.cls;
|
|
1476
1601
|
|
|
1602
|
+
NeoArray.toggle(cls, value);
|
|
1603
|
+
this.cls = cls;
|
|
1477
1604
|
}
|
|
1478
1605
|
|
|
1479
1606
|
/**
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import ClassSystemUtil from '../util/ClassSystem.mjs';
|
|
2
|
+
import Component from './Base.mjs';
|
|
3
|
+
import Store from '../data/Store.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @class Neo.component.Carousel
|
|
7
|
+
* @extends Neo.component.Base
|
|
8
|
+
*/
|
|
9
|
+
class Carousel extends Component {
|
|
10
|
+
/**
|
|
11
|
+
* Defines the currently visible item in the middle
|
|
12
|
+
* This gets updated everytime a button is clicked to reflect the current order
|
|
13
|
+
* @member {Number} itemIndex=1
|
|
14
|
+
*/
|
|
15
|
+
itemIndex = 1
|
|
16
|
+
/**
|
|
17
|
+
* Defines the order of the item in the carousel
|
|
18
|
+
* This gets updated everytime a button is clicked to reflect the current order
|
|
19
|
+
* @member {String[]} positionArray
|
|
20
|
+
*/
|
|
21
|
+
positionArray = ['neo-carousel--translate-x-full', 'neo-carousel-translate-x-0', 'neo-carousel-translate-x-full']
|
|
22
|
+
|
|
23
|
+
static getConfig() {return {
|
|
24
|
+
/**
|
|
25
|
+
* @member {String} className='Neo.component.Carousel'
|
|
26
|
+
* @protected
|
|
27
|
+
*/
|
|
28
|
+
className: 'Neo.component.Carousel',
|
|
29
|
+
/**
|
|
30
|
+
* @member {String} ntype='carousel'
|
|
31
|
+
* @protected
|
|
32
|
+
*/
|
|
33
|
+
ntype: 'carousel',
|
|
34
|
+
/**
|
|
35
|
+
* @member {String[]} cls=['neo-carousel']
|
|
36
|
+
*/
|
|
37
|
+
cls : ['neo-carousel'],
|
|
38
|
+
/**
|
|
39
|
+
* Custom cls added to each item
|
|
40
|
+
* This is only a single string
|
|
41
|
+
*
|
|
42
|
+
* @member {String|null} itemCls=null
|
|
43
|
+
*/
|
|
44
|
+
itemCls: null,
|
|
45
|
+
/**
|
|
46
|
+
* Template for each item
|
|
47
|
+
* The format is the same as for literals,
|
|
48
|
+
* but it is a string instead of surrounding "`"
|
|
49
|
+
* @member {String|null} tpl=null
|
|
50
|
+
* @example
|
|
51
|
+
* record = {foo: ... , bar: ...}
|
|
52
|
+
* "[{cls: 'css-foo-class', html: '${foo}'}, {html: '${baa}'}]"
|
|
53
|
+
*/
|
|
54
|
+
itemTpl_: null,
|
|
55
|
+
/**
|
|
56
|
+
* Store to be used.
|
|
57
|
+
*
|
|
58
|
+
* @member {Neo.data.Store|null} store=null
|
|
59
|
+
*/
|
|
60
|
+
store_: null,
|
|
61
|
+
/**
|
|
62
|
+
* @member {Object} _vdom
|
|
63
|
+
*/
|
|
64
|
+
_vdom:
|
|
65
|
+
{cn: [
|
|
66
|
+
{cls: ['neo-carousel'], cn: [
|
|
67
|
+
{cls: ['neo-carousel-btn-bar'], cn: [
|
|
68
|
+
{tag: 'a', 'data-carouselaction': 'back', cls: ['neo-carousel-btn', 'fa', 'fa-chevron-left']},
|
|
69
|
+
{tag: 'a', 'data-carouselaction': 'forward', cls: ['neo-carousel-btn', 'fa', 'fa-chevron-right']}
|
|
70
|
+
]},
|
|
71
|
+
{cls: ['neo-carousel-inner'], cn: []}
|
|
72
|
+
]}
|
|
73
|
+
]}
|
|
74
|
+
}}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {Object} config
|
|
78
|
+
*/
|
|
79
|
+
construct(config) {
|
|
80
|
+
super.construct(config);
|
|
81
|
+
|
|
82
|
+
let me = this,
|
|
83
|
+
domListeners = me.domListeners;
|
|
84
|
+
|
|
85
|
+
domListeners.push({
|
|
86
|
+
click: {
|
|
87
|
+
fn : me.onCarouselBtnClick,
|
|
88
|
+
delegate: '.neo-carousel-btn',
|
|
89
|
+
scope : me
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
me.domListeners = domListeners;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Triggered after the store config got changed
|
|
98
|
+
* @param {Neo.data.Store|Object|null} value
|
|
99
|
+
* @param {Neo.data.Store|null} oldValue
|
|
100
|
+
* @protected
|
|
101
|
+
*/
|
|
102
|
+
afterSetStore(value, oldValue) {
|
|
103
|
+
let me = this;
|
|
104
|
+
|
|
105
|
+
value?.on({
|
|
106
|
+
load : 'onStoreLoad',
|
|
107
|
+
scope: me
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
value?.getCount() > 0 && me.onStoreLoad();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Ensure the itemTpl is setup correctly to match a valid JSON
|
|
115
|
+
* @param {String} value
|
|
116
|
+
* @returns {String}
|
|
117
|
+
* @protected
|
|
118
|
+
*/
|
|
119
|
+
beforeSetItemTpl(value) {
|
|
120
|
+
let itemTpl = value.replaceAll('\'', '"');
|
|
121
|
+
|
|
122
|
+
itemTpl = itemTpl.replace(/(\w+:)|(\w+ :)/g, function(matchedStr) {
|
|
123
|
+
return `"${matchedStr.substring(0, matchedStr.length - 1)}":`;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return itemTpl;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Triggered before the store config gets changed.
|
|
131
|
+
* @param {Neo.data.Store|Object|null} value
|
|
132
|
+
* @param {Neo.data.Store|null} oldValue
|
|
133
|
+
* @returns {Neo.data.Store}
|
|
134
|
+
* @protected
|
|
135
|
+
*/
|
|
136
|
+
beforeSetStore(value, oldValue) {
|
|
137
|
+
oldValue?.destroy();
|
|
138
|
+
return ClassSystemUtil.beforeSetInstance(value, Store);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Create the initial three items and add them to the vdom
|
|
143
|
+
*/
|
|
144
|
+
createBaseItems() {
|
|
145
|
+
let me = this,
|
|
146
|
+
vdom = me._vdom,
|
|
147
|
+
itemRoot = me.#getItemRoot(),
|
|
148
|
+
items = [],
|
|
149
|
+
i = 0;
|
|
150
|
+
|
|
151
|
+
for (i; i < 3; i++) {
|
|
152
|
+
items.push(me.createItem(i, i));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
itemRoot.cn = items;
|
|
156
|
+
me.vdom = vdom;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Everytime we rotate we create items
|
|
161
|
+
* @param {Number} recordIndex - index inside store
|
|
162
|
+
* @param {Number} positionIndex - based on positionArray
|
|
163
|
+
* @returns {Object}
|
|
164
|
+
*/
|
|
165
|
+
createItem(recordIndex, positionIndex) {
|
|
166
|
+
let me = this,
|
|
167
|
+
itemCls = me.itemCls,
|
|
168
|
+
positionArray = me.positionArray,
|
|
169
|
+
store = me.store,
|
|
170
|
+
data = store.getAt(recordIndex),
|
|
171
|
+
itemTpl = me.#formatTpl(me.itemTpl, data),
|
|
172
|
+
|
|
173
|
+
newItem = {
|
|
174
|
+
cls: [positionArray[positionIndex], 'neo-carousel-item'],
|
|
175
|
+
cn : itemTpl,
|
|
176
|
+
recordIndex
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
itemCls && newItem.cls.push(itemCls);
|
|
180
|
+
|
|
181
|
+
return newItem;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Rotate the three items and fill in a new record
|
|
186
|
+
* @param {Object} event
|
|
187
|
+
* @param {Object} event.target - clicked button
|
|
188
|
+
*/
|
|
189
|
+
onCarouselBtnClick(event) {
|
|
190
|
+
let me = this,
|
|
191
|
+
action = event.target.data.carouselaction,
|
|
192
|
+
store = me.store,
|
|
193
|
+
countItems = store.getCount(),
|
|
194
|
+
vdom = me.vdom,
|
|
195
|
+
index = me.itemIndex,
|
|
196
|
+
positionArray = me.positionArray,
|
|
197
|
+
root = me.#getItemRoot(),
|
|
198
|
+
newRecordIndex, positionCls, recordIndex, vdomCls;
|
|
199
|
+
|
|
200
|
+
if (action === 'forward') {
|
|
201
|
+
vdomCls = 'neo-carousel-translate-x-full';
|
|
202
|
+
index = index + 2
|
|
203
|
+
newRecordIndex = index % countItems;
|
|
204
|
+
|
|
205
|
+
me.itemIndex = newRecordIndex - 1;
|
|
206
|
+
positionArray = me.#arrayRotate(positionArray, -1);
|
|
207
|
+
} else {
|
|
208
|
+
vdomCls = 'neo-carousel--translate-x-full';
|
|
209
|
+
index = index - 2;
|
|
210
|
+
newRecordIndex = index < 0 ? (countItems + index) : index;
|
|
211
|
+
|
|
212
|
+
me.itemIndex = newRecordIndex + 1;
|
|
213
|
+
positionArray = me.#arrayRotate(positionArray, 1);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
me.positionArray = positionArray;
|
|
217
|
+
|
|
218
|
+
root.cn = root.cn.map(function(cn, mappingIndex) {
|
|
219
|
+
positionCls = positionArray[mappingIndex];
|
|
220
|
+
recordIndex = cn.recordIndex;
|
|
221
|
+
|
|
222
|
+
cn.cls.shift();
|
|
223
|
+
cn.cls.unshift(positionCls);
|
|
224
|
+
|
|
225
|
+
// Update new Record
|
|
226
|
+
if (positionCls === vdomCls) {
|
|
227
|
+
recordIndex = newRecordIndex;
|
|
228
|
+
cn = me.createItem(recordIndex, mappingIndex);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return cn;
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
me.vdom = vdom;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* As soon as the store is loaded we want to
|
|
239
|
+
* - create the three items
|
|
240
|
+
* - fill the first three records
|
|
241
|
+
*/
|
|
242
|
+
onStoreLoad() {
|
|
243
|
+
this.createBaseItems();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* HELPERS
|
|
248
|
+
*/
|
|
249
|
+
#getItemRoot() {
|
|
250
|
+
return this.vdom.cn[0].cn[1];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
#arrayRotate(arr, n) {
|
|
254
|
+
return n ? [...arr.slice(n, arr.length), ...arr.slice(0, n)] : arr;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
#formatTpl(tpl, record) {
|
|
258
|
+
let resultStr = tpl.replace(/\$\{[^\}]+\}/g, (m) => record[m.slice(2, -1).trim()]);
|
|
259
|
+
|
|
260
|
+
return JSON.parse(resultStr);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
Neo.applyClassConfig(Carousel);
|
|
265
|
+
|
|
266
|
+
export default Carousel;
|