Hierarchical event bubbling - 1
Reviewed By: @fkgozali Differential Revision: D2469495
This commit is contained in:
parent
30e9bf6077
commit
b2049e3ccb
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* @providesModule NavigationTreeNode
|
||||||
|
* @flow
|
||||||
|
* @typechecks
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var invariant = require('invariant');
|
||||||
|
var immutable = require('immutable');
|
||||||
|
|
||||||
|
var {List} = immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to build a tree of nodes.
|
||||||
|
* Note that this tree does not perform cyclic redundancy check
|
||||||
|
* while appending child node.
|
||||||
|
*/
|
||||||
|
class NavigationTreeNode {
|
||||||
|
__parent: ?NavigationTreeNode;
|
||||||
|
|
||||||
|
_children: List<NavigationTreeNode>;
|
||||||
|
|
||||||
|
_value: any;
|
||||||
|
|
||||||
|
constructor(value: any) {
|
||||||
|
this.__parent = null;
|
||||||
|
this._children = new List();
|
||||||
|
this._value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): any {
|
||||||
|
return this._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getParent(): ?NavigationTreeNode {
|
||||||
|
return this.__parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
getChildrenCount(): number {
|
||||||
|
return this._children.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
getChildAt(index: number): ?NavigationTreeNode {
|
||||||
|
return index > -1 && index < this._children.size ?
|
||||||
|
this._children.get(index) :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
appendChild(child: NavigationTreeNode): void {
|
||||||
|
if (child.__parent) {
|
||||||
|
child.__parent.removeChild(child);
|
||||||
|
}
|
||||||
|
child.__parent = this;
|
||||||
|
this._children = this._children.push(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeChild(child: NavigationTreeNode): void {
|
||||||
|
var index = this._children.indexOf(child);
|
||||||
|
|
||||||
|
invariant(
|
||||||
|
index > -1,
|
||||||
|
'The node to be removed is not a child of this node.'
|
||||||
|
);
|
||||||
|
|
||||||
|
child.__parent = null;
|
||||||
|
|
||||||
|
this._children = this._children.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
indexOf(child: NavigationTreeNode): number {
|
||||||
|
return this._children.indexOf(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
forEach(callback: Function, context: any): void {
|
||||||
|
this._children.forEach(callback, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
map(callback: Function, context: any): Array<NavigationTreeNode> {
|
||||||
|
return this._children.map(callback, context).toJS();
|
||||||
|
}
|
||||||
|
|
||||||
|
some(callback: Function, context: any): boolean {
|
||||||
|
return this._children.some(callback, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = NavigationTreeNode;
|
|
@ -0,0 +1,111 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
jest
|
||||||
|
.dontMock('Map')
|
||||||
|
.dontMock('NavigationTreeNode')
|
||||||
|
.dontMock('invariant')
|
||||||
|
.dontMock('immutable');
|
||||||
|
|
||||||
|
var NavigationTreeNode = require('NavigationTreeNode');
|
||||||
|
|
||||||
|
describe('NavigationTreeNode-test', () => {
|
||||||
|
it('should be empty', () => {
|
||||||
|
var node = new NavigationTreeNode();
|
||||||
|
expect(node.getValue()).toEqual(undefined);
|
||||||
|
expect(node.getParent()).toEqual(null);
|
||||||
|
expect(node.getChildrenCount()).toEqual(0);
|
||||||
|
expect(node.getChildAt(0)).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should contain value', () => {
|
||||||
|
var node = new NavigationTreeNode(123);
|
||||||
|
expect(node.getValue()).toEqual(123);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should appendChild', () => {
|
||||||
|
var papa = new NavigationTreeNode('hedger');
|
||||||
|
var baby = new NavigationTreeNode('hedger jr');
|
||||||
|
papa.appendChild(baby);
|
||||||
|
expect(papa.getChildAt(0)).toEqual(baby);
|
||||||
|
expect(papa.getChildrenCount()).toEqual(1);
|
||||||
|
expect(baby.getParent()).toEqual(papa);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should removeChild', () => {
|
||||||
|
var papa = new NavigationTreeNode('Eddard Stark');
|
||||||
|
var baby = new NavigationTreeNode('Robb Stark');
|
||||||
|
papa.appendChild(baby);
|
||||||
|
|
||||||
|
papa.removeChild(baby);
|
||||||
|
expect(papa.getChildAt(0)).toEqual(null);
|
||||||
|
expect(papa.getChildrenCount()).toEqual(0);
|
||||||
|
expect(baby.getParent()).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not remove non-child', () => {
|
||||||
|
var papa = new NavigationTreeNode('dog');
|
||||||
|
var baby = new NavigationTreeNode('cat');
|
||||||
|
expect(papa.removeChild.bind(papa, baby)).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find child', () => {
|
||||||
|
var papa = new NavigationTreeNode('Eddard Stark');
|
||||||
|
var baby = new NavigationTreeNode('Robb Stark');
|
||||||
|
|
||||||
|
papa.appendChild(baby);
|
||||||
|
expect(papa.indexOf(baby)).toEqual(0);
|
||||||
|
|
||||||
|
papa.removeChild(baby);
|
||||||
|
expect(papa.indexOf(baby)).toEqual(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should traverse each child', () => {
|
||||||
|
var parent = new NavigationTreeNode();
|
||||||
|
parent.appendChild(new NavigationTreeNode('a'));
|
||||||
|
parent.appendChild(new NavigationTreeNode('b'));
|
||||||
|
parent.appendChild(new NavigationTreeNode('c'));
|
||||||
|
var result = [];
|
||||||
|
parent.forEach((child, index) => {
|
||||||
|
result[index] = child.getValue();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual(['a', 'b', 'c']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map children', () => {
|
||||||
|
var parent = new NavigationTreeNode();
|
||||||
|
parent.appendChild(new NavigationTreeNode('a'));
|
||||||
|
parent.appendChild(new NavigationTreeNode('b'));
|
||||||
|
parent.appendChild(new NavigationTreeNode('c'));
|
||||||
|
var result = parent.map((child, index) => {
|
||||||
|
return child.getValue();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual(['a', 'b', 'c']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should traverse some children', () => {
|
||||||
|
var parent = new NavigationTreeNode();
|
||||||
|
parent.appendChild(new NavigationTreeNode('a'));
|
||||||
|
parent.appendChild(new NavigationTreeNode('b'));
|
||||||
|
parent.appendChild(new NavigationTreeNode('c'));
|
||||||
|
|
||||||
|
var result = [];
|
||||||
|
var value = parent.some((child, index) => {
|
||||||
|
if (index > 1) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
result[index] = child.getValue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(value).toEqual(true);
|
||||||
|
expect(result).toEqual(['a', 'b']);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue