neo.mjs 5.1.0 → 5.1.2
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/.github/CODING_GUIDELINES.md +8 -5
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/realworld/view/HomeComponent.mjs +16 -16
- package/apps/realworld/view/MainContainerController.mjs +7 -0
- package/apps/website/data/blog.json +13 -0
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/toolbar/breadcrumb/view/MainContainer.mjs +31 -2
- package/package.json +1 -1
- package/resources/scss/src/form/field/Select.scss +1 -0
- package/resources/scss/src/form/field/Text.scss +1 -1
- package/resources/scss/src/toolbar/Breadcrumb.scss +17 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/Neo.mjs +3 -3
- package/src/container/Base.mjs +5 -0
- package/src/controller/Component.mjs +11 -0
- package/src/core/Base.mjs +16 -16
- package/src/core/Observable.mjs +3 -1
- package/src/form/field/Number.mjs +2 -2
- package/src/form/field/Picker.mjs +22 -0
- package/src/form/field/Select.mjs +1 -1
- package/src/form/field/Text.mjs +34 -13
- package/src/main/DomEvents.mjs +13 -4
- package/src/toolbar/Breadcrumb.mjs +88 -0
@@ -419,18 +419,21 @@ fields: [{
|
|
419
419
|
* (39) `if (/**/) {` if, blank char, parenthesis, blank char, curly bracket
|
420
420
|
* (40) `for (/**/) {` for, blank char, parenthesis, blank char, curly bracket
|
421
421
|
* (41) `switch(/**/) {` switch, parenthesis, blank char, curly bracket `// could get changed to use a blank char as well
|
422
|
-
* (42)
|
422
|
+
* (42) `while (/**/) {` while, blank char, parenthesis, blank char, curly bracket
|
423
|
+
* (43) Use optional chaining => `?.` where it makes sense
|
423
424
|
+ Bad: `myView && myView.myFn && myView.myFn();`
|
424
425
|
+ Good: `myView?.myFn?.();`
|
425
426
|
+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
|
426
|
-
* (
|
427
|
+
* (44) Use method definitions (meaning avoid using the term `function`)
|
427
428
|
+ Bad: `let obj = {a: function() {/**/}};`
|
428
429
|
+ Good: `let obj = {a() {/**/}};`
|
429
430
|
+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions
|
430
|
-
* (
|
431
|
+
* (45) Use shorthand property names when possible
|
431
432
|
+ Bad: `let obj = {record: record}`
|
432
433
|
+ Good: `let obj = {record};`
|
433
434
|
+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#property_definitions
|
434
|
-
* (
|
435
|
-
+ Bad: `let obj = {a: 1,}
|
435
|
+
* (46) Do not use killing commas (while IE6 is luckily no longer an issue => file size)
|
436
|
+
+ Bad: `let obj = {a: 1,};`
|
437
|
+
+ Bad: `let arr = [1,];`
|
436
438
|
+ Good: `let obj = {a: 1};`
|
439
|
+
+ Good: `let arr = [1];`
|
package/apps/ServiceWorker.mjs
CHANGED
@@ -62,26 +62,26 @@ class HomeComponent extends Component {
|
|
62
62
|
* @member {Object} _vdom
|
63
63
|
*/
|
64
64
|
_vdom:
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
]}
|
65
|
+
{cn: [
|
66
|
+
{cls: ['banner'], cn: [
|
67
|
+
{cls: ['container'], cn: [
|
68
|
+
{tag: 'h1', cls: ['logo-font'], html: 'conduit'},
|
69
|
+
{tag: 'p', html: 'A place to share your knowledge.'}
|
70
|
+
]}
|
71
|
+
]},
|
72
|
+
{cls: ['container', 'page'], cn: [
|
73
|
+
{cls: ['row'], cn: [
|
74
|
+
{cls: ['col-md-9'], cn: [
|
75
|
+
{cls: ['feed-toggle'], cn: [
|
76
|
+
{tag: 'ul', cls: ['nav', 'nav-pills', 'outline-active'], flag: 'feed-header', cn: []}
|
77
|
+
]},
|
78
|
+
{tag: 'nav', cn: [
|
79
|
+
{tag: 'ul', cls: ['pagination'], flag: 'pagination'}
|
81
80
|
]}
|
82
81
|
]}
|
83
82
|
]}
|
84
83
|
]}
|
84
|
+
]}
|
85
85
|
}
|
86
86
|
|
87
87
|
/**
|
@@ -11,6 +11,13 @@ import UserApi from '../api/User.mjs';
|
|
11
11
|
* @extends Neo.controller.Component
|
12
12
|
*/
|
13
13
|
class MainContainerController extends ComponentController {
|
14
|
+
/**
|
15
|
+
* True automatically applies the core.Observable mixin
|
16
|
+
* @member {Boolean} observable=false
|
17
|
+
* @static
|
18
|
+
*/
|
19
|
+
static observable = true
|
20
|
+
|
14
21
|
static config = {
|
15
22
|
/**
|
16
23
|
* @member {String} className='RealWorld.view.MainContainerController'
|
@@ -1,4 +1,17 @@
|
|
1
1
|
[
|
2
|
+
{
|
3
|
+
"author" : "Torsten Dinkheller",
|
4
|
+
"authorImage" : "author_TorstenDinkheller.jpg",
|
5
|
+
"date" : "Feb 03, 2023",
|
6
|
+
"id" : 57,
|
7
|
+
"image" : "leveraging-overrides.jpg",
|
8
|
+
"name" : "Leveraging Overrides for Resilient Customizations and Effective Bugfixes in JavaScript Frameworks",
|
9
|
+
"provider" : "Medium",
|
10
|
+
"publisher" : "ITNEXT",
|
11
|
+
"selectedInto": [],
|
12
|
+
"type" : "Blog Post",
|
13
|
+
"url" : "https://itnext.io/leveraging-overrides-for-resilient-customizations-and-effective-bugfixes-in-javascript-frameworks-5b8ccfec0f8?source=friends_link&sk=790e868aac8b8570f0eee093adc30c00"
|
14
|
+
},
|
2
15
|
{
|
3
16
|
"author" : "Torsten Dinkheller",
|
4
17
|
"authorImage" : "author_TorstenDinkheller.jpg",
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import BreadcrumbToolbar from '../../../../src/toolbar/Breadcrumb.mjs';
|
2
|
+
import Store from '../../../../src/data/Store.mjs';
|
2
3
|
import Viewport from '../../../../src/container/Viewport.mjs';
|
3
4
|
|
4
5
|
/**
|
@@ -16,8 +17,36 @@ class MainContainer extends Viewport {
|
|
16
17
|
* @member {Object[]} items
|
17
18
|
*/
|
18
19
|
items: [{
|
19
|
-
module: BreadcrumbToolbar,
|
20
|
-
|
20
|
+
module : BreadcrumbToolbar,
|
21
|
+
activeKey: 2,
|
22
|
+
flex : 'none',
|
23
|
+
|
24
|
+
store: {
|
25
|
+
module: Store,
|
26
|
+
|
27
|
+
model: {
|
28
|
+
fields: [{
|
29
|
+
name: 'id',
|
30
|
+
type: 'Integer'
|
31
|
+
}, {
|
32
|
+
name: 'name',
|
33
|
+
type: 'String'
|
34
|
+
}, {
|
35
|
+
name: 'parentId',
|
36
|
+
type: 'Integer'
|
37
|
+
}, {
|
38
|
+
name: 'route',
|
39
|
+
type: 'String'
|
40
|
+
}]
|
41
|
+
},
|
42
|
+
|
43
|
+
data: [
|
44
|
+
{id: 1, name: 'Home', parentId: null, route: '/home/'},
|
45
|
+
{id: 2, name: 'Accessibility', parentId: 1, route: '/home/accessibility/'},
|
46
|
+
{id: 3, name: 'Imprint', parentId: 1, route: '/home/imprint/'},
|
47
|
+
{id: 4, name: 'News', parentId: 1, route: '/home/news/'},
|
48
|
+
]
|
49
|
+
}
|
21
50
|
}],
|
22
51
|
/**
|
23
52
|
* @member {Object} layout={ntype:'vbox',align:'stretch'}
|
package/package.json
CHANGED
@@ -309,7 +309,6 @@
|
|
309
309
|
flex-shrink : 1;
|
310
310
|
margin : 0; // important for Safari => #1125
|
311
311
|
min-height : v(textfield-input-height);
|
312
|
-
width : 30px;
|
313
312
|
}
|
314
313
|
}
|
315
314
|
|
@@ -331,6 +330,7 @@
|
|
331
330
|
min-width : 50px;
|
332
331
|
padding : v(textfield-input-padding);
|
333
332
|
transition : 250ms border-color cubic-bezier(0.4, 0, 0.2, 1);
|
333
|
+
width : 100%;
|
334
334
|
|
335
335
|
&:focus {
|
336
336
|
outline: none;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
.neo-breadcrumb-toolbar {
|
2
|
+
.neo-button {
|
3
|
+
&:not(:last-child) {
|
4
|
+
margin-right: 30px;
|
5
|
+
|
6
|
+
&::after {
|
7
|
+
color : v(button-text-color);
|
8
|
+
content : "\f105";
|
9
|
+
display : block;
|
10
|
+
font-family : "Font Awesome 5 Free";
|
11
|
+
font-weight : 600;
|
12
|
+
position : absolute;
|
13
|
+
right : -20px;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
package/src/DefaultConfig.mjs
CHANGED
@@ -237,12 +237,12 @@ const DefaultConfig = {
|
|
237
237
|
useVdomWorker: true,
|
238
238
|
/**
|
239
239
|
* buildScripts/injectPackageVersion.mjs will update this value
|
240
|
-
* @default '5.1.
|
240
|
+
* @default '5.1.2'
|
241
241
|
* @memberOf! module:Neo
|
242
242
|
* @name config.version
|
243
243
|
* @type String
|
244
244
|
*/
|
245
|
-
version: '5.1.
|
245
|
+
version: '5.1.2'
|
246
246
|
};
|
247
247
|
|
248
248
|
Object.assign(DefaultConfig, {
|
package/src/Neo.mjs
CHANGED
@@ -70,13 +70,13 @@ Neo = globalThis.Neo = Object.assign({
|
|
70
70
|
|
71
71
|
protos.forEach(element => {
|
72
72
|
let mixins;
|
73
|
-
|
73
|
+
|
74
74
|
ctor = element.constructor;
|
75
75
|
|
76
76
|
cfg = ctor.config || {};
|
77
77
|
|
78
|
-
if (Neo.
|
79
|
-
ctor.
|
78
|
+
if (Neo.overwrites) {
|
79
|
+
ctor.applyOverwrites(cfg);
|
80
80
|
}
|
81
81
|
|
82
82
|
Object.entries(cfg).forEach(([key, value]) => {
|
package/src/container/Base.mjs
CHANGED
@@ -215,6 +215,11 @@ class Base extends Component {
|
|
215
215
|
|
216
216
|
case 'NeoInstance': {
|
217
217
|
item.set(config);
|
218
|
+
|
219
|
+
// In case an item got created outside a VC or VM based hierarchy, there might be bindings or string
|
220
|
+
// based listeners which still need to get resolved.
|
221
|
+
item.getController()?.parseConfig(item);
|
222
|
+
item.getModel() ?.parseConfig(item);
|
218
223
|
break;
|
219
224
|
}
|
220
225
|
|
@@ -141,6 +141,7 @@ class Component extends Base {
|
|
141
141
|
let me = this,
|
142
142
|
listeners = component.listeners,
|
143
143
|
reference = component.reference,
|
144
|
+
validator = component.validator,
|
144
145
|
eventHandler, handlerScope;
|
145
146
|
|
146
147
|
if (listeners) {
|
@@ -174,6 +175,16 @@ class Component extends Base {
|
|
174
175
|
});
|
175
176
|
}
|
176
177
|
|
178
|
+
if (Neo.isString(validator)) {
|
179
|
+
handlerScope = me.getHandlerScope(validator);
|
180
|
+
|
181
|
+
if (!handlerScope) {
|
182
|
+
Logger.logError('Unknown validator for', component.id, component);
|
183
|
+
} else {
|
184
|
+
component.validator = handlerScope[validator].bind(handlerScope);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
177
188
|
if (reference) {
|
178
189
|
me.references[reference] = component;
|
179
190
|
}
|
package/src/core/Base.mjs
CHANGED
@@ -23,10 +23,10 @@ class Base {
|
|
23
23
|
*/
|
24
24
|
static observable = false
|
25
25
|
/**
|
26
|
-
* Keep the
|
26
|
+
* Keep the overwritten methods
|
27
27
|
* @type {Object}
|
28
28
|
*/
|
29
|
-
static
|
29
|
+
static overwrittenMethods = {}
|
30
30
|
|
31
31
|
/**
|
32
32
|
* Set this one to false in case you don't want to stick
|
@@ -150,29 +150,29 @@ class Base {
|
|
150
150
|
}
|
151
151
|
|
152
152
|
/**
|
153
|
-
* Applying
|
153
|
+
* Applying overwrites and adding overwrittenMethods to the class constructors
|
154
154
|
* @param {Object} cfg
|
155
155
|
* @protected
|
156
156
|
*/
|
157
|
-
static
|
158
|
-
let
|
157
|
+
static applyOverwrites(cfg) {
|
158
|
+
let overwrites = Neo.ns(cfg.className, false, Neo.overwrites),
|
159
159
|
cls, item;
|
160
160
|
|
161
|
-
if (
|
161
|
+
if (overwrites) {
|
162
162
|
// Apply all methods
|
163
|
-
for (item in
|
164
|
-
if (Neo.isFunction(
|
163
|
+
for (item in overwrites) {
|
164
|
+
if (Neo.isFunction(overwrites[item])) {
|
165
165
|
// Already existing ones
|
166
166
|
cls = this.prototype;
|
167
167
|
|
168
168
|
if (cls[item]) {
|
169
|
-
// add to
|
170
|
-
cls.constructor.
|
169
|
+
// add to overwrittenMethods
|
170
|
+
cls.constructor.overwrittenMethods[item] = cls[item];
|
171
171
|
}
|
172
172
|
}
|
173
173
|
}
|
174
174
|
// Apply configs to prototype
|
175
|
-
|
175
|
+
overwrites && Object.assign(cfg, overwrites);
|
176
176
|
}
|
177
177
|
}
|
178
178
|
|
@@ -196,12 +196,12 @@ class Base {
|
|
196
196
|
}
|
197
197
|
|
198
198
|
/**
|
199
|
-
* From within an
|
199
|
+
* From within an overwrite, a method can call a parent method, by using callOverwritten.
|
200
200
|
*
|
201
201
|
* @example
|
202
202
|
* afterSetHeight(value, oldValue) {
|
203
203
|
* // do the standard
|
204
|
-
* this.
|
204
|
+
* this.callOverwritten(...arguments);
|
205
205
|
* // do you own stuff
|
206
206
|
* }
|
207
207
|
*
|
@@ -209,17 +209,17 @@ class Base {
|
|
209
209
|
* This is based on the following error structure, e.g. afterSetHeight.
|
210
210
|
*
|
211
211
|
* Error
|
212
|
-
* at Base.
|
212
|
+
* at Base.callOverwritten (Base.mjs:176:21)
|
213
213
|
* at Base.afterSetHeight (Overrides.mjs:19:26)
|
214
214
|
*
|
215
215
|
* @param args
|
216
216
|
*/
|
217
|
-
|
217
|
+
callOverwritten(...args) {
|
218
218
|
let stack = new Error().stack,
|
219
219
|
regex = Base.methodNameRegex,
|
220
220
|
methodName = stack.match(regex)[1];
|
221
221
|
|
222
|
-
this.__proto__.constructor.
|
222
|
+
this.__proto__.constructor.overwrittenMethods[methodName].call(this, ...args);
|
223
223
|
}
|
224
224
|
|
225
225
|
/**
|
package/src/core/Observable.mjs
CHANGED
@@ -148,8 +148,10 @@ class Observable extends Base {
|
|
148
148
|
}
|
149
149
|
|
150
150
|
while (proto?.constructor.isClass) {
|
151
|
+
ctor = proto.constructor;
|
152
|
+
|
151
153
|
if (ctor.observable && !ctor.listeners) {
|
152
|
-
Object.assign(
|
154
|
+
Object.assign(ctor, {
|
153
155
|
addListener : me.addListener,
|
154
156
|
fire : me.fire,
|
155
157
|
listeners : {},
|
@@ -242,7 +242,7 @@ class Number extends Text {
|
|
242
242
|
value = (oldValue - stepSize) < me.minValue ? me.maxValue : (oldValue - stepSize);
|
243
243
|
|
244
244
|
if (me.excludedValues) {
|
245
|
-
while(me.excludedValues.includes(value)) {
|
245
|
+
while (me.excludedValues.includes(value)) {
|
246
246
|
value = Math.max(me.minValue, value - stepSize);
|
247
247
|
}
|
248
248
|
}
|
@@ -262,7 +262,7 @@ class Number extends Text {
|
|
262
262
|
value = (oldValue + stepSize) > me.maxValue ? me.minValue : (oldValue + stepSize);
|
263
263
|
|
264
264
|
if (me.excludedValues) {
|
265
|
-
while(me.excludedValues.includes(value)) {
|
265
|
+
while (me.excludedValues.includes(value)) {
|
266
266
|
value = Math.min(me.maxValue, value + stepSize);
|
267
267
|
}
|
268
268
|
}
|
@@ -115,6 +115,20 @@ class Picker extends Text {
|
|
115
115
|
this.cls = cls;
|
116
116
|
}
|
117
117
|
|
118
|
+
/**
|
119
|
+
* Triggered after the mounted config got changed
|
120
|
+
* @param {Boolean} value
|
121
|
+
* @param {Boolean} oldValue
|
122
|
+
* @protected
|
123
|
+
*/
|
124
|
+
afterSetMounted(value, oldValue) {
|
125
|
+
if (value === false && oldValue && this.pickerIsMounted) {
|
126
|
+
this.picker.hide();
|
127
|
+
}
|
128
|
+
|
129
|
+
super.afterSetMounted(value, oldValue);
|
130
|
+
}
|
131
|
+
|
118
132
|
/**
|
119
133
|
* @param {Boolean} silent
|
120
134
|
*/
|
@@ -186,6 +200,14 @@ class Picker extends Text {
|
|
186
200
|
return null;
|
187
201
|
}
|
188
202
|
|
203
|
+
/**
|
204
|
+
* @param args
|
205
|
+
*/
|
206
|
+
destroy(...args) {
|
207
|
+
this.picker?.destroy();
|
208
|
+
super.destroy(...args);
|
209
|
+
}
|
210
|
+
|
189
211
|
/**
|
190
212
|
* @param {Function} [callback]
|
191
213
|
* @param {Object} [callbackScope]
|
package/src/form/field/Text.mjs
CHANGED
@@ -158,6 +158,11 @@ class Text extends Base {
|
|
158
158
|
* @member {Object|Object[]|null} triggers_=null
|
159
159
|
*/
|
160
160
|
triggers_: null,
|
161
|
+
/**
|
162
|
+
* A string based value will get resolved into the closest controller which implements it
|
163
|
+
* @member {Function|String|null} validator=null
|
164
|
+
*/
|
165
|
+
validator: null,
|
161
166
|
/**
|
162
167
|
* @member {Object} _vdom
|
163
168
|
*/
|
@@ -525,7 +530,17 @@ class Text extends Base {
|
|
525
530
|
* @protected
|
526
531
|
*/
|
527
532
|
afterSetPlaceholderText(value, oldValue) {
|
528
|
-
this
|
533
|
+
let me = this,
|
534
|
+
cls = me.cls;
|
535
|
+
|
536
|
+
me.changeInputElKey('placeholder', value === '' ? null : value);
|
537
|
+
|
538
|
+
// a non-empty placeholder needs to keep the 'neo-has-content' rule
|
539
|
+
// => labelPosition: 'inline' should keep the label at the top
|
540
|
+
if (Neo.isEmpty(value) !== Neo.isEmpty(oldValue)) {
|
541
|
+
NeoArray[value !== null && value.toString().length > 0 ? 'add' : 'remove'](cls, 'neo-has-content');
|
542
|
+
me.cls = cls;
|
543
|
+
}
|
529
544
|
}
|
530
545
|
|
531
546
|
/**
|
@@ -681,21 +696,19 @@ class Text extends Base {
|
|
681
696
|
* @protected
|
682
697
|
*/
|
683
698
|
afterSetValue(value, oldValue) {
|
684
|
-
let me
|
685
|
-
cls
|
686
|
-
|
687
|
-
|
688
|
-
|
699
|
+
let me = this,
|
700
|
+
cls = me.cls,
|
701
|
+
placeholderText = me.placeholderText,
|
702
|
+
hasContent = placeholderText?.length > 0 || value !== null && value.toString().length > 0,
|
703
|
+
originalValue = me.originalConfig.value,
|
704
|
+
isDirty = value !== originalValue && Neo.isEmpty(value) !== Neo.isEmpty(originalValue);
|
689
705
|
|
690
706
|
me.silentVdomUpdate = true;
|
691
707
|
|
692
708
|
me.getInputEl().value = value;
|
693
709
|
|
694
|
-
|
695
|
-
|
696
|
-
}
|
697
|
-
|
698
|
-
NeoArray[isDirty ? 'add' : 'remove'](cls, 'neo-is-dirty');
|
710
|
+
NeoArray[hasContent ? 'add' : 'remove'](cls, 'neo-has-content');
|
711
|
+
NeoArray[isDirty ? 'add' : 'remove'](cls, 'neo-is-dirty');
|
699
712
|
me.cls = cls;
|
700
713
|
|
701
714
|
me.validate(); // silent
|
@@ -1289,9 +1302,17 @@ class Text extends Base {
|
|
1289
1302
|
value = me.value,
|
1290
1303
|
valueLength = value?.toString().length,
|
1291
1304
|
isEmpty = !value || valueLength < 1,
|
1292
|
-
errorParam = {maxLength, minLength, valueLength}
|
1305
|
+
errorParam = {maxLength, minLength, valueLength},
|
1306
|
+
errorText;
|
1293
1307
|
|
1294
|
-
if (
|
1308
|
+
if (Neo.isFunction(me.validator)) {
|
1309
|
+
errorText = me.validator(me);
|
1310
|
+
|
1311
|
+
if (errorText !== true) {
|
1312
|
+
me[errorField] = errorText;
|
1313
|
+
returnValue = false;
|
1314
|
+
}
|
1315
|
+
} else if (required && isEmpty) {
|
1295
1316
|
me[errorField] = me.errorTextRequired;
|
1296
1317
|
returnValue = false;
|
1297
1318
|
} else if (Neo.isNumber(maxLength) && valueLength > maxLength) {
|
package/src/main/DomEvents.mjs
CHANGED
@@ -407,11 +407,20 @@ class DomEvents extends Base {
|
|
407
407
|
* @param {Object} event
|
408
408
|
*/
|
409
409
|
onChange(event) {
|
410
|
-
|
410
|
+
let target = event.target,
|
411
|
+
|
412
|
+
data = {
|
411
413
|
...this.getEventData(event),
|
412
|
-
valid:
|
413
|
-
value:
|
414
|
-
}
|
414
|
+
valid: target.checkValidity(),
|
415
|
+
value: target.value
|
416
|
+
};
|
417
|
+
|
418
|
+
// input and change events can pass a FileList for input type file
|
419
|
+
if (target.files) {
|
420
|
+
data.files = target.files;
|
421
|
+
}
|
422
|
+
|
423
|
+
this.sendMessageToApp(data);
|
415
424
|
}
|
416
425
|
|
417
426
|
/**
|
@@ -13,6 +13,19 @@ class Breadcrumb extends Toolbar {
|
|
13
13
|
* @protected
|
14
14
|
*/
|
15
15
|
className: 'Neo.toolbar.Breadcrumb',
|
16
|
+
/**
|
17
|
+
* @member {String} ntype='breadcrumb-toolbar'
|
18
|
+
* @protected
|
19
|
+
*/
|
20
|
+
ntype: 'breadcrumb-toolbar',
|
21
|
+
/**
|
22
|
+
* @member {String[]} baseCls=['neo-breadcrumb-toolbar','neo-toolbar']
|
23
|
+
*/
|
24
|
+
baseCls: ['neo-breadcrumb-toolbar', 'neo-toolbar'],
|
25
|
+
/**
|
26
|
+
* @member {Number|String|null} activeKey_=null
|
27
|
+
*/
|
28
|
+
activeKey_: null,
|
16
29
|
/**
|
17
30
|
* @member {Object[]} items
|
18
31
|
*/
|
@@ -23,6 +36,16 @@ class Breadcrumb extends Toolbar {
|
|
23
36
|
store_: null
|
24
37
|
}
|
25
38
|
|
39
|
+
/**
|
40
|
+
* Triggered after the activeKey config got changed
|
41
|
+
* @param {Number|String|null} value
|
42
|
+
* @param {Number|String|null} oldValue
|
43
|
+
* @protected
|
44
|
+
*/
|
45
|
+
afterSetActiveKey(value, oldValue) {
|
46
|
+
this.store.getCount?.() > 0 && this.updateItems()
|
47
|
+
}
|
48
|
+
|
26
49
|
/**
|
27
50
|
* Triggered after the store config got changed
|
28
51
|
* @param {Neo.data.Store|Object} value
|
@@ -30,7 +53,14 @@ class Breadcrumb extends Toolbar {
|
|
30
53
|
* @protected
|
31
54
|
*/
|
32
55
|
afterSetStore(value, oldValue) {
|
56
|
+
let me = this;
|
57
|
+
|
58
|
+
value.on({
|
59
|
+
load: this.onStoreLoad,
|
60
|
+
scope: me
|
61
|
+
});
|
33
62
|
|
63
|
+
value?.getCount() > 0 && me.onStoreLoad(value.items)
|
34
64
|
}
|
35
65
|
|
36
66
|
/**
|
@@ -44,6 +74,64 @@ class Breadcrumb extends Toolbar {
|
|
44
74
|
oldValue?.destroy();
|
45
75
|
return ClassSystemUtil.beforeSetInstance(value, Store);
|
46
76
|
}
|
77
|
+
|
78
|
+
/**
|
79
|
+
* @returns {Object[]}
|
80
|
+
*/
|
81
|
+
getPathItems() {
|
82
|
+
let items = [],
|
83
|
+
parentId = this.activeKey,
|
84
|
+
store = this.store,
|
85
|
+
item;
|
86
|
+
|
87
|
+
while (parentId !== null) {
|
88
|
+
item = store.get(parentId);
|
89
|
+
|
90
|
+
items.unshift(item);
|
91
|
+
|
92
|
+
parentId = item.parentId;
|
93
|
+
}
|
94
|
+
|
95
|
+
return items;
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* @param {Object[]} items
|
100
|
+
*/
|
101
|
+
onStoreLoad(items) {
|
102
|
+
this.activeKey !== null && this.updateItems()
|
103
|
+
}
|
104
|
+
|
105
|
+
/**
|
106
|
+
*
|
107
|
+
*/
|
108
|
+
updateItems() {
|
109
|
+
let me = this,
|
110
|
+
items = me.items,
|
111
|
+
pathItems = me.getPathItems(),
|
112
|
+
i = 0,
|
113
|
+
len = pathItems.length,
|
114
|
+
newItems = [],
|
115
|
+
config, item
|
116
|
+
|
117
|
+
for (; i < len; i++) {
|
118
|
+
item = pathItems[i];
|
119
|
+
|
120
|
+
config = {
|
121
|
+
editRoute: false,
|
122
|
+
route : item.route,
|
123
|
+
text : item.name
|
124
|
+
};
|
125
|
+
|
126
|
+
if (items[i]) {
|
127
|
+
items[i].set(config);
|
128
|
+
} else {
|
129
|
+
newItems.push(config);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
newItems.length > 0 && me.add(newItems);
|
134
|
+
}
|
47
135
|
}
|
48
136
|
|
49
137
|
Neo.applyClassConfig(Breadcrumb);
|