-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy patheventDispatcher.ts
154 lines (133 loc) · 4.09 KB
/
eventDispatcher.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
* イベント発光時に引数として渡されるEventクラス
*/
export class MyCustomEvent {
public currentTarget: CustomEventDispatcher | null = null; // eslint-disable-line
static COMPLETE = 'complete';
static CHANGE_PROPERTY = 'changeProperty';
constructor(public type: string) {} // eslint-disable-line
}
/**
* イベントリスナークラス
*/
export class CustomEventListener {
/**
*
* @param type
* @param handler
* @param priority
*/
constructor(public type: string, public handler: (e: MyCustomEvent) => void, public priority: number = 0) {} // eslint-disable-line
/**
* タイプとコールバックからリスナーを比較する
* @param type
* @param handler
* @returns {boolean}
*/
equalCurrentListener(type: string, handler: (e: MyCustomEvent) => void): boolean {
return this.type === type && this.handler === handler;
}
}
/**
* dispatcherとなるクラスでextendして使う
*/
export class CustomEventDispatcher {
listeners: {[key:string]: CustomEventListener[]} = {};
/**
* イベントを発光するメソッド
* @param event
*/
dispatchEvent(event: string | MyCustomEvent): void {
let e: MyCustomEvent;
let type: string;
// 引数がEventオブジェクトだった場合
if (event instanceof MyCustomEvent) {
type = event.type; // eslint-disable-line
e = event;
// 引数がstringだった場合
} else {
type = event;
e = new MyCustomEvent(type);
}
if (this.listeners[type] !== null && this.listeners[type] !== undefined) {
const len: number = this.listeners[type].length;
e.currentTarget = this;
for (let i = 0; i < len; i++) {
const listener: CustomEventListener = this.listeners[type][i];
try {
listener.handler(e);
} catch (error) {
if (error instanceof Error) {
console.error(error.stack);
}
}
}
} else {
console.warn('implement "addEventListener" before dispatch');
}
}
/**
* typeにひもづいたリスナーを登録する
* @param type
* @param callback
* @param priority
*/
addEventListener(type: string, callback: (e: MyCustomEvent) => void, priority = 0): void {
if (!this.listeners[type]) {
this.listeners[type] = [];
}
this.listeners[type].push(new CustomEventListener(type, callback, priority));
this.listeners[type].sort((listener1: CustomEventListener, listener2: CustomEventListener) => listener2.priority - listener1.priority);
}
/**
* typeにひもづいたリスナーを削除する
* @param type
* @param callback
*/
removeEventListener(type: string, callback: (e: MyCustomEvent) => void): void {
if (this.hasEventListener(type, callback)) {
for (let i = 0; i < this.listeners[type].length; i++) {
const listener: CustomEventListener = this.listeners[type][i];
if (listener.equalCurrentListener(type, callback)) {
this.listeners[type].splice(i, 1);
return;
}
}
}
}
/**
* このインスタンスにひもづいている全てのリスナーを解除する
*/
clearEventListener(): void {
this.listeners = {};
}
/**
* インスタンスに指定タイプのリスナーがあるかどうかをチェックする
* @param type
* @returns {boolean}
*/
containEventListener(type: string): boolean {
if (!this.listeners[type]) {
return false;
}
return this.listeners[type].length > 0;
}
/**
* インスタンスに指定タイプかつ、指定のコールバックのリスナーがあるかどうかをチェックする
* @param type
* @param callback
* @returns {boolean}
*/
hasEventListener(type: string, callback: (e: MyCustomEvent) => void): boolean {
if (!this.listeners[type]) {
return false;
}
for (let i = 0; i < this.listeners[type].length; i++) {
const listener: CustomEventListener = this.listeners[type][i];
if (listener.equalCurrentListener(type, callback)) {
return true;
}
}
return false;
}
}