Skip to content

Commit

Permalink
feat(FEC-9481): distributed keyboard handler to decorator (#464)
Browse files Browse the repository at this point in the history
create keyboard decorator event to implement in each component which use keyboard event on player area.
  • Loading branch information
Yuvalke committed Jan 2, 2020
1 parent 1180ad1 commit af71c20
Show file tree
Hide file tree
Showing 23 changed files with 917 additions and 57 deletions.
145 changes: 145 additions & 0 deletions docs/with-keyboard-event.md
@@ -0,0 +1,145 @@
## Using the keyboard event handler API in your component

### withKeyboardEvent HoC

If your components requires a keyboard event then UI supplies a keyboard event registration as a service.
The keyboard event registration enables add and remove keyboard event for our player.
The registration is for component - when component will be removed the relevant keyboard event should be removed.
For combination of code + altKey + ctrlKey + metaKey + shiftKey could be one handler.
Let's see an example:

> This sample will add listener for combination of F + shiftKey and remove on unmount
```javascript
const h = KalturaPlayer.ui.h;
const withKeyboardEvent = KalturaPlayer.ui.components.withKeyboardEvent;
const Component = KalturaPlayer.ui.preact.Component;

class SampleComponent extends Component {
_keyboardEventHandlers: Array<KeyboardEventHandlers> = [
{
key: {
code: KeyMap.F,
shiftKey: true
},
action: () => {
console.log('F and shiftKey registered');
}
}
];
componentDidMount() {
this.props.registerKeyboardEvents(this._keyboardEventHandlers);
}

render(props) {
return h(props.children);
}
}

export default withKeyboardEvent(SampleComponent);
```

And if you want to use it as a decorator:

```javascript
const h = KalturaPlayer.ui.h;
const withKeyboardEvent = KalturaPlayer.ui.components.withKeyboardEvent;
const Component = KalturaPlayer.ui.preact.Component;

@withKeyboardEvent
class DumbComponent extends Component {
_keyboardEventHandlers: Array<KeyboardEventHandlers> = [
{
key: {
code: KeyMap.F,
shiftKey: true
},
action: () => {
console.log('F and shiftKey registered');
}
}
];

componentDidMount() {
this.props.registerKeyboardEvents(this._keyboardEventHandlers);
}

render(props) {
return <div>{props.children}</div>;
}
}

export default DumbComponent;
```

For using only this component keyboard handlers

```javascript
const h = KalturaPlayer.ui.h;
const withKeyboardEvent = KalturaPlayer.ui.components.withKeyboardEvent;
const Component = KalturaPlayer.ui.preact.Component;
const componentName = 'DUMB_COMPONENT';

@withKeyboardEvent(componentName)
class DumbComponent extends Component {
_keyboardEventHandlers: Array<KeyboardEventHandlers> = [
{
key: {
code: KeyMap.F,
shiftKey: true
},
action: () => {
console.log('F and shiftKey registered');
}
}
];

componentDidMount() {
this.props.registerKeyboardEvents(this._keyboardEventHandlers);
this.props.setKeyboardEventToScope(true);
}

render(props) {
return <div>{props.children}</div>;
}
}

export default DumbComponent;
```

For disabling the keyboard handler

```javascript
const h = KalturaPlayer.ui.h;
const withKeyboardEvent = KalturaPlayer.ui.components.withKeyboardEvent;
const Component = KalturaPlayer.ui.preact.Component;
const componentName = 'DUMB_COMPONENT';

@withKeyboardEvent(componentName)
class DumbComponent extends Component {
componentDidMount() {
this.props.updateIsKeyboardEnabled(false);
}

render(props) {
return <div>{props.children}</div>;
}
}

export default DumbComponent;
```

The usage of this component will be:

```javascript
const h = KalturaPlayer.ui.h;
h(DumbComponent, null, h('p', null, 'You can add here any components and html you want and it will be appended to the DumbComponent'));
```

Or again, if using JSX:

```html
<DumbComponent>
<p>You can add here any components and html you want and it will be appended to the DumbComponent</p>
</DumbComponent>
```
6 changes: 6 additions & 0 deletions flow-typed/types/keyboard-event-handlers.js
@@ -0,0 +1,6 @@
// @flow
declare type KeyboardEventHandlers = {
eventType?: string,
key: KeyboardKey,
action: Function
};
8 changes: 8 additions & 0 deletions flow-typed/types/keyboard-key.js
@@ -0,0 +1,8 @@
// @flow
declare type KeyboardKey = {
code: number,
altKey?: boolean,
ctrlKey?: boolean,
metaKey?: boolean,
shiftKey?: boolean
};
4 changes: 4 additions & 0 deletions src/components/event-dispatcher/event-dispatcher-provider.js
Expand Up @@ -164,6 +164,10 @@ function onClickableComponentsHandler(store: any, action: Object, player: Object
case 'Volume':
onVolumeClicked(store, action, player);
break;

case 'PictureInPicture':
onPictureInPictureClicked(store, action, player);
break;
}
}

Expand Down
63 changes: 59 additions & 4 deletions src/components/fullscreen/fullscreen.js
Expand Up @@ -3,11 +3,13 @@ import style from '../../styles/style.scss';
import {h, Component} from 'preact';
import {withText} from 'preact-i18n';
import {connect} from 'preact-redux';
import {KeyMap} from '../../utils/key-map';
import {default as Icon, IconType} from '../icon';
import {withPlayer} from '../player';
import {withEventDispatcher} from 'components/event-dispatcher';
import {withKeyboardEvent} from 'components/keyboard';
import {withLogger} from 'components/logger';
import {Tooltip} from 'components/tooltip';
import {withEventDispatcher} from 'components/event-dispatcher';

/**
* mapping state to props
Expand All @@ -24,6 +26,7 @@ const COMPONENT_NAME = 'Fullscreen';
@connect(mapStateToProps)
@withPlayer
@withLogger(COMPONENT_NAME)
@withKeyboardEvent(COMPONENT_NAME)
@withEventDispatcher(COMPONENT_NAME)
@withText({fullscreenText: 'controls.fullscreen'})
/**
Expand All @@ -34,16 +37,68 @@ const COMPONENT_NAME = 'Fullscreen';
* @extends {Component}
*/
class Fullscreen extends Component {
_keyboardEventHandlers: Array<KeyboardEventHandlers> = [
{
key: {
code: KeyMap.F
},
action: event => {
this.handleKeydown(event);
}
},
{
key: {
code: KeyMap.ESC
},
action: event => {
this.handleKeydown(event);
}
}
];
/**
* on component mount
*
* @returns {void}
* @memberof Fullscreen
*/
componentDidMount(): void {
this.props.registerKeyboardEvents(this._keyboardEventHandlers);
}

/**
* handle keyboard events
*
* @param {KeyboardEvent} event - keyboard event
* @returns {void}
* @memberof Fullscreen
*/
handleKeydown(event: KeyboardEvent): void {
switch (event.keyCode) {
case KeyMap.F:
if (!this.props.player.isFullscreen()) {
this.toggleFullscreen();
}
break;
case KeyMap.ESC:
if (this.props.player.isFullscreen()) {
this.toggleFullscreen();
}
break;
default:
break;
}
}
/**
* toggle fullscreen based on current fullscreen state in store
*
* @returns {void}
* @memberof Fullscreen
*/
toggleFullscreen(): void {
this.props.logger.debug(`Toggle fullscreen`);
const playerContainer: HTMLElement | null = document.getElementById(this.props.targetId);
this.props.fullscreen ? this.props.player.exitFullscreen() : this.props.player.enterFullscreen();
const {targetId, logger, player} = this.props;
logger.debug(`Toggle fullscreen`);
const playerContainer: HTMLElement | null = document.getElementById(targetId);
player.isFullscreen ? player.enterFullscreen() : player.exitFullscreen();
if (playerContainer) {
playerContainer.focus();
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/index.js
@@ -1,6 +1,5 @@
import {Cast} from './cast';
import {Fullscreen} from './fullscreen';
import {Keyboard} from './keyboard';
import {Language} from './language';
import {PlayPause} from './play-pause';
import {Rewind} from './rewind';
Expand All @@ -22,6 +21,7 @@ export {DropDown} from './dropdown';
export {EngineConnector} from './engine-connector';
export {ErrorOverlay} from './error-overlay';
export * from './event-dispatcher';
export * from './keyboard';
export {Icon, IconType} from './icon';
export {LiveTag} from './live-tag';
export {Loading} from './loading';
Expand Down Expand Up @@ -55,9 +55,9 @@ export {PlaylistNextScreen} from './playlist-next-screen';
export {PictureInPicture} from './picture-in-picture';
export {PlaybackControls} from './playback-controls';

export {Keyboard as KeyboardControl} from './keyboard';
export {Cast, Cast as CastControl};
export {Fullscreen, Fullscreen as FullscreenControl};
export {Keyboard, Keyboard as KeyboardControl};
export {Language, Language as LanguageControl};
export {PlayPause, PlayPause as PlayPauseControl};
export {Rewind, Rewind as RewindControl};
Expand Down
2 changes: 2 additions & 0 deletions src/components/keyboard/index.js
@@ -1 +1,3 @@
export {Keyboard} from './keyboard';
export {withKeyboardEvent} from './with-keyboard-event';
export {KeyboardEventProvider} from './keyboard-event-provider';

0 comments on commit af71c20

Please sign in to comment.