1
1
// @flow
2
2
import { isArray , isElement , isString , isHTMLString , hypenate , isFunction , isEmpty , isPosterityNode , isObject , isBoolean , $ , setStyle , getStyle , setAttr , addEvent , getAttr , removeEvent , addClassName , Log , isEvent } from 'chimee-helper' ;
3
- import { videoEvents , domEvents } from 'helper/const' ;
3
+ import { videoEvents , domEvents , passiveEvents } from 'helper/const' ;
4
4
import esFullscreen from 'es-fullscreen' ;
5
5
import { autobind , before , waituntil } from 'toxic-decorators' ;
6
6
function targetCheck ( target : string , ...args ) {
@@ -75,6 +75,7 @@ export default class Dom {
75
75
__videoExtendedNodes = [ ] ;
76
76
isFullscreen = false ;
77
77
fullscreenElement = undefined ;
78
+
78
79
constructor ( wrapper : string | Element , dispatcher : Dispatcher ) {
79
80
this . __dispatcher = dispatcher ;
80
81
if ( ! isElement ( wrapper ) && ! isString ( wrapper ) ) throw new TypeError ( `Wrapper can only be string or HTMLElement, but not ${ typeof wrapper } ` ) ;
@@ -100,17 +101,12 @@ export default class Dom {
100
101
* referrence of video's dom element
101
102
*/
102
103
this . installVideo ( videoElement ) ;
103
- domEvents . forEach ( key => {
104
- const cfn = ( ...args : any ) => this . __dispatcher . bus . triggerSync ( 'c_' + key , ...args ) ;
105
- this . containerDomEventHandlerList . push ( cfn ) ;
106
- addEvent ( this . container , key , cfn ) ;
107
- const wfn = ( ...args : any ) => this . __dispatcher . bus . triggerSync ( 'w_' + key , ...args ) ;
108
- this . wrapperDomEventHandlerList . push ( wfn ) ;
109
- addEvent ( this . wrapper , key , wfn ) ;
110
- } ) ;
104
+ this . _addDomEvents ( this . container , this . containerDomEventHandlerList , key => ( ...args : any ) => this . __dispatcher . bus . triggerSync ( 'c_' + key , ...args ) ) ;
105
+ this . _addDomEvents ( this . wrapper , this . wrapperDomEventHandlerList , key => ( ...args : any ) => this . __dispatcher . bus . triggerSync ( 'w_' + key , ...args ) ) ;
111
106
this . _fullscreenMonitor ( ) ;
112
107
esFullscreen . on ( 'fullscreenchange' , this . _fullscreenMonitor ) ;
113
108
}
109
+
114
110
installVideo ( videoElement : HTMLVideoElement ) : HTMLVideoElement {
115
111
this . __videoExtendedNodes . push ( videoElement ) ;
116
112
setAttr ( videoElement , 'tabindex' , - 1 ) ;
@@ -143,14 +139,11 @@ export default class Dom {
143
139
this . videoEventHandlerList . push ( fn ) ;
144
140
addEvent ( videoElement , key , fn ) ;
145
141
} ) ;
146
- domEvents . forEach ( key => {
147
- const fn = this . _getEventHandler ( key , { penetrate : true } ) ;
148
- this . videoDomEventHandlerList . push ( fn ) ;
149
- addEvent ( videoElement , key , fn ) ;
150
- } ) ;
142
+ this . _addDomEvents ( videoElement , this . videoDomEventHandlerList , key => this . _getEventHandler ( key , { penetrate : true } ) ) ;
151
143
this . videoElement = videoElement ;
152
144
return videoElement ;
153
145
}
146
+
154
147
removeVideo ( ) : HTMLVideoElement {
155
148
const videoElement = this . videoElement ;
156
149
this . _autoFocusToVideo ( this . videoElement , false ) ;
@@ -166,6 +159,7 @@ export default class Dom {
166
159
delete this . videoElement ;
167
160
return videoElement ;
168
161
}
162
+
169
163
/**
170
164
* each plugin has its own dom node, this function will create one or them.
171
165
* we support multiple kind of el
@@ -209,11 +203,7 @@ export default class Dom {
209
203
// auto forward the event if this plugin can be penetrate
210
204
if ( penetrate ) {
211
205
this . __domEventHandlerList [ id ] = this . __domEventHandlerList [ id ] || [ ] ;
212
- domEvents . forEach ( key => {
213
- const fn = this . _getEventHandler ( key , { penetrate } ) ;
214
- addEvent ( node , key , fn ) ;
215
- this . __domEventHandlerList [ id ] . push ( fn ) ;
216
- } ) ;
206
+ this . _addDomEvents ( node , this . __domEventHandlerList [ id ] , key => this . _getEventHandler ( key , { penetrate } ) ) ;
217
207
this . __videoExtendedNodes . push ( node ) ;
218
208
}
219
209
if ( outerElement . lastChild === originElement ) {
@@ -223,6 +213,7 @@ export default class Dom {
223
213
outerElement . insertBefore ( node , originElement . nextSibling ) ;
224
214
return node ;
225
215
}
216
+
226
217
/**
227
218
* remove plugin's dom
228
219
*/
@@ -241,13 +232,15 @@ export default class Dom {
241
232
}
242
233
delete this . plugins [ id ] ;
243
234
}
235
+
244
236
/**
245
237
* Set zIndex for a plugins list
246
238
*/
247
239
setPluginsZIndex ( plugins : Array < string > ) : void {
248
240
// $FlowFixMe: there are videoElment and container here
249
241
plugins. forEach ( ( key , index ) => setStyle ( key . match ( / ^ ( v i d e o E l e m e n t | c o n t a i n e r ) $ / ) ? this [ key ] : this . plugins [ key ] , 'z-index' , ++ index ) ) ;
250
242
}
243
+
251
244
/**
252
245
* set attribute on our dom
253
246
* @param {string } attr attribute's name
@@ -260,37 +253,45 @@ export default class Dom {
260
253
// $FlowFixMe: flow do not support computed property/element on class, which is silly here.
261
254
setAttr ( this [ target ] , attr , val ) ;
262
255
}
256
+
263
257
@before ( attrOperationCheck , targetCheck )
264
258
getAttr ( target : string , attr : string ) : string {
265
259
// $FlowFixMe: flow do not support computed property/element on class, which is silly here.
266
260
return getAttr ( this [ target ] , attr ) ;
267
261
}
262
+
268
263
@before ( attrOperationCheck , targetCheck )
269
264
setStyle ( target : string , attr : string , val : any ) : void {
270
265
// $FlowFixMe: flow do not support computed property/element on class, which is silly here.
271
266
setStyle ( this [ target ] , attr , val ) ;
272
267
}
268
+
273
269
@before ( attrOperationCheck , targetCheck )
274
270
getStyle ( target : string , attr : string ) : string {
275
271
// $FlowFixMe: flow do not support computed property/element on class, which is silly here.
276
272
return getStyle ( this [ target ] , attr ) ;
277
273
}
274
+
278
275
@before ( targetCheck )
279
276
requestFullscreen ( target : string ) {
280
277
// $FlowFixMe: flow do not support computed property/element on document, which is silly here.
281
278
return esFullscreen . open ( this [ target ] ) ;
282
279
}
280
+
283
281
exitFullscreen ( ) : boolean {
284
282
return esFullscreen . exit ( ) ;
285
283
}
284
+
286
285
fullscreen ( request : boolean = true , target : string = 'container' , ...args : any ) : boolean {
287
286
return request
288
287
? this . requestFullscreen ( target , ...args )
289
288
: this . exitFullscreen ( ...args ) ;
290
289
}
290
+
291
291
focus ( ) {
292
292
this . videoElement . focus ( ) ;
293
293
}
294
+
294
295
/**
295
296
* function called when we distory
296
297
*/
@@ -305,17 +306,36 @@ export default class Dom {
305
306
delete this . wrapper ;
306
307
delete this . plugins ;
307
308
}
309
+
310
+ /**
311
+ * bind all dom events on one element
312
+ * we will use passive mode if it support
313
+ */
314
+ _addDomEvents ( element : Element , handlerList : Array < Function > , handlerGenerate : Function ) {
315
+ domEvents . forEach ( key => {
316
+ const fn = handlerGenerate ( key ) ;
317
+ handlerList . push ( fn ) ;
318
+ if ( passiveEvents . indexOf ( key ) > - 1 ) {
319
+ addEvent ( element , key , fn , false , { passive : true } ) ;
320
+ return ;
321
+ }
322
+ addEvent ( element , key , fn ) ;
323
+ } ) ;
324
+ }
325
+
308
326
_autoFocusToVideo ( element : Element , remove : boolean = false ) : void {
309
327
( remove ? removeEvent : addEvent ) ( element , 'mouseup' , this . _focusToVideo , false , true ) ;
310
328
( remove ? removeEvent : addEvent ) ( element , 'touchend' , this . _focusToVideo , false , true ) ;
311
329
}
330
+
312
331
@autobind
313
332
_focusToVideo ( ) {
314
333
const x = window . scrollX ;
315
334
const y = window . scrollY ;
316
335
isFunction ( this . videoElement . focus ) && this . videoElement . focus ( ) ;
317
336
window . scrollTo ( x , y ) ;
318
337
}
338
+
319
339
@autobind
320
340
_fullscreenMonitor ( evt ? : Event ) {
321
341
const element = esFullscreen . fullscreenElement ;
@@ -337,6 +357,7 @@ export default class Dom {
337
357
this . __dispatcher . bus . triggerSync ( 'fullscreenchange' , evt ) ;
338
358
}
339
359
}
360
+
340
361
/**
341
362
* get the event handler for dom to bind
342
363
*/
0 commit comments