Skip to content

Commit

Permalink
[fix] Add mustListenDomEents
Browse files Browse the repository at this point in the history
what:
1. add mustListenDomEvents
2. fix penetrate event remove bug
why: the mouseenter and mouseleave must always listened
because we need to know the relation between video and mouse
  • Loading branch information
toxic-johann committed Apr 21, 2018
1 parent 4f75061 commit dc82d96
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 38 deletions.
Expand Up @@ -127,11 +127,32 @@ describe("chimee's binder", () => {
expect(rawFn).toHaveBeenCalledTimes(1);
});

test('mouseleave video to outside should trigger', async () => {
test('mouseleave video to to outside should trigger', async () => {
const fn = jest.fn();
const rawFn = jest.fn();
const plugin = {
name: 'mouseleave video to outside',
name: 'mouseleave video to outside node',
penetrate: true,
events: {
mouseleave: fn,
},
};
Chimee.install(plugin);
const { $video } = await player.use(plugin.name);
$video.dispatchEvent(new Event('mouseenter'));
const event = new Event('mouseleave');
// event.relatedTarget = $dom;
$video.addEventListener('mouseleave', rawFn);
$video.dispatchEvent(event);
expect(fn).toHaveBeenCalledTimes(1);
expect(rawFn).toHaveBeenCalledTimes(1);
});

test('mouseleave video to to inside node should not trigger', async () => {
const fn = jest.fn();
const rawFn = jest.fn();
const plugin = {
name: 'mouseleave video to inside node',
penetrate: true,
events: {
mouseleave: fn,
Expand Down
102 changes: 67 additions & 35 deletions src/dispatcher/binder.js
Expand Up @@ -5,7 +5,7 @@
*/

import Bus from './bus';
import { videoEvents, domEvents, kernelEvents, passiveEvents,esFullscreenEvents } from 'helper/const';
import { videoEvents, domEvents, kernelEvents, passiveEvents,esFullscreenEvents, mustListenVideoDomEvents } from 'helper/const';
import { camelize, Log, isString, addEvent, removeEvent, isEmpty, isFunction } from 'chimee-helper';
import { before, runnable } from 'toxic-decorators';
import Dispatcher from './index';
Expand Down Expand Up @@ -219,18 +219,61 @@ export default class Binder {

// when we create a penetrate plugin, we need to rebind video events on it
bindEventOnPenetrateNode(node: Element, remove: boolean = false) {
this.bindedEventInfo['video-dom'].forEach(([ name, fn ]) => {
remove
? removeEvent(node, name, fn)
: this._addEventOnDom(node, name, fn);
});
this.bindedEventInfo['video-dom']
.forEach(([ name, fn ]) => {
remove
? removeEvent(node, name, fn)
: this._addEventOnDom(node, name, fn);
});
}

// when we switch kernel, we will create a new video.
// we need to transfer the event from the oldvideo to it.
bindEventOnVideo(node: Element, remove: boolean = false) {
this.bindedEventInfo['video-dom'].concat(this.bindedEventInfo.video).forEach(([ name, fn ]) => {
remove
? removeEvent(node, name, fn)
: this._addEventOnDom(node, name, fn);
this.bindedEventInfo['video-dom']
.concat(this.bindedEventInfo.video)
.forEach(([ name, fn ]) => {
remove
? removeEvent(node, name, fn)
: this._addEventOnDom(node, name, fn);
});
}

// As penetrate plugin is considered to be part of video
// we need to transfer event for it
// so we need some specail event handler
listenOnMouseMoveEvent(node: Element) {
const dom = this.__dispatcher.dom;
const target = 'video-dom';
const id = '_vm';
mustListenVideoDomEvents.forEach(name => {
const fn = (...args) => {
const { toElement, currentTarget, relatedTarget, type } = args[0];
const to = toElement || relatedTarget;
// As we support penetrate plugin, the video dom event may be differnet.
if (dom.mouseInVideo && type === 'mouseleave' && !dom.isNodeInsideVideo(to)) {
dom.mouseInVideo = false;
return this.triggerSync({
target,
name,
id,
}, ...args);
}
if (!dom.mouseInVideo && type === 'mouseenter' && dom.isNodeInsideVideo(currentTarget)) {
dom.mouseInVideo = true;
return this.triggerSync({
target,
name,
id,
}, ...args);
}
};
this._addEventOnDom(node, name, fn);
if (this.bindedEventNames[target].indexOf(name) < 0) {
this.bindedEventNames[target].push(name);
// $FlowFixMe: fn must be function now
this.bindedEventInfo[target].push([ name, fn ]);
}
});
}

Expand Down Expand Up @@ -283,9 +326,7 @@ export default class Binder {
target: binderTarget,
id: string,
}) {
// the plugin target do not need us to transfer
// so we do not need to bind
if (target === 'plugin' || target === 'esFullscreen') return;
if (!this._isEventNeedToBeHandled(target, name)) return;
let fn;
// if this event has been binded, return;
if (this.bindedEventNames[target].indexOf(name) > -1) return;
Expand All @@ -302,26 +343,8 @@ export default class Binder {
this._addEventOnDom(targetDom, name, fn);
} else if (target === 'video-dom') {
const { penetrate = false } = Dispatcher.getPluginConfig(id) || {};
if (!penetrate || [ 'mouseenter', 'mouseleave' ].indexOf(name) < 0) {
fn = (...args) => this.triggerSync({ target, name, id: target }, ...args);
} else {
const dom = this.__dispatcher.dom;
fn = (...args) => {
const { toElement, currentTarget, relatedTarget, type } = args[0];
const to = toElement || relatedTarget;

// As we support penetrate plugin, the video dom event may be differnet.
if (dom.mouseInVideo && type === 'mouseleave' && !dom.isNodeInsideVideo(to)) {
dom.mouseInVideo = false;
return this.triggerSync({ target, name, id: target }, ...args);
}
if (!dom.mouseInVideo && type === 'mouseenter' && dom.isNodeInsideVideo(currentTarget)) {
dom.mouseInVideo = true;
return this.triggerSync({ target, name, id: target }, ...args);
}
};
dom.videoExtendedNodes.forEach(node => this._addEventOnDom(node, name, fn));
}
fn = (...args) => this.triggerSync({ target, name, id: target }, ...args);
if (penetrate) this.__dispatcher.dom.videoExtendedNodes.forEach(node => this._addEventOnDom(node, name, fn));
this._addEventOnDom(targetDom, name, fn);
}
this.bindedEventNames[target].push(name);
Expand All @@ -340,8 +363,7 @@ export default class Binder {
name: string,
target: binderTarget,
}) {
// plugin event do not need us to bind on the target
if (target === 'plugin') return;
if (!this._isEventNeedToBeHandled(target, name)) return;
const eventNamesList = this.bindedEventNames[target];
const nameIndex = eventNamesList.indexOf(name);
// if we have not bind this event before, we omit it
Expand Down Expand Up @@ -395,4 +417,14 @@ export default class Binder {
}
return targetDom;
}

_isEventNeedToBeHandled(target: binderTarget, name: string): boolean {
// the plugin target do not need us to transfer
// we have listened on esFullscreen in dom
// we have listened mustListenVideoDomEvents
// so the events above do not need to rebind
return target !== 'plugin' &&
target !== 'esFullscreen' &&
mustListenVideoDomEvents.indexOf(name) < 0;
}
}
4 changes: 3 additions & 1 deletion src/dispatcher/dom.js
Expand Up @@ -2,6 +2,7 @@
import { isArray, isElement, isString, isHTMLString, hypenate, isFunction, isPosterityNode, isObject, isBoolean, $, setStyle, getStyle, setAttr, addEvent, getAttr, removeEvent, addClassName, Log, isEvent } from 'chimee-helper';
import esFullscreen from 'es-fullscreen';
import { autobind, before, waituntil } from 'toxic-decorators';
import Dispatcher from './index';
function targetCheck(target: string, ...args) {
if (target === 'video') target = 'videoElement';
if (!isElement(this[target])) throw new TypeError(`Your target "${target}" is not a legal HTMLElement`);
Expand Down Expand Up @@ -199,7 +200,8 @@ export default class Dom {
dom.parentNode && dom.parentNode.removeChild(dom);
this._autoFocusToVideo(dom, true);
}
this.__dispatcher.binder.bindEventOnPenetrateNode(this.plugins[id], true);
const { penetrate = false } = Dispatcher.getPluginConfig(id) || {};
if (penetrate) this.__dispatcher.binder.bindEventOnPenetrateNode(dom, true);
delete this.plugins[id];
}

Expand Down
1 change: 1 addition & 0 deletions src/dispatcher/index.js
Expand Up @@ -109,6 +109,7 @@ export default class Dispatcher {
delete config.plugins;
}
this.binder = new Binder(this);
this.binder.listenOnMouseMoveEvent(this.dom.videoElement);
// use the plugin user want to use
this._initUserPlugin(config.plugin);
// add default config for container
Expand Down
4 changes: 4 additions & 0 deletions src/helper/const.js
Expand Up @@ -92,6 +92,10 @@ export const selfProcessorEvents = [
'silentLoad',
'fullscreen',
];
export const mustListenVideoDomEvents = [
'mouseenter',
'mouseleave',
];
export const kernelMethods = [
'play',
'pause',
Expand Down

0 comments on commit dc82d96

Please sign in to comment.