From fa21ba4f25257ee24b2915bb14d8697672c732fc Mon Sep 17 00:00:00 2001 From: Lukas Heiligenbrunner Date: Thu, 28 Jan 2021 19:50:26 +0000 Subject: [PATCH] bind enter events as a submit to Popups add s as key to submit a reshuffle in shuffled videos --- src/elements/ActorTile/ActorTile.tsx | 2 - .../AddActorPopup/AddActorPopup.test.js | 12 ++++ .../Popups/AddActorPopup/AddActorPopup.tsx | 71 +++++++++++++++---- .../Popups/AddTagPopup/AddTagPopup.tsx | 1 - .../Popups/NewTagPopup/NewTagPopup.tsx | 2 +- src/elements/Popups/PopupBase.test.js | 18 ++++- src/elements/Popups/PopupBase.tsx | 11 ++- src/pages/RandomPage/RandomPage.test.js | 18 +++++ src/pages/RandomPage/RandomPage.tsx | 22 +++++- src/utils/ShortkeyHandler.ts | 15 ++++ 10 files changed, 146 insertions(+), 26 deletions(-) create mode 100644 src/utils/ShortkeyHandler.ts diff --git a/src/elements/ActorTile/ActorTile.tsx b/src/elements/ActorTile/ActorTile.tsx index a508a7b..2fdb549 100644 --- a/src/elements/ActorTile/ActorTile.tsx +++ b/src/elements/ActorTile/ActorTile.tsx @@ -28,11 +28,9 @@ class ActorTile extends React.Component { ); } - } renderActorTile(customclickhandler: (actor: ActorType) => void): JSX.Element { - console.log(this.props.actor); return (
customclickhandler(this.props.actor)}>
diff --git a/src/elements/Popups/AddActorPopup/AddActorPopup.test.js b/src/elements/Popups/AddActorPopup/AddActorPopup.test.js index 186ecf8..1051656 100644 --- a/src/elements/Popups/AddActorPopup/AddActorPopup.test.js +++ b/src/elements/Popups/AddActorPopup/AddActorPopup.test.js @@ -74,4 +74,16 @@ describe('', function () { expect(wrapper.find('PopupBase').find('ActorTile')).toHaveLength(0); }); + + it('test Enter submit if only one element left', function () { + const wrapper = shallow(); + + callAPIMock({}); + + wrapper.setState({actors: [{name: 'test', actor_id: 1}]}); + + wrapper.find('PopupBase').props().ParentSubmit(); + + expect(callAPI).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/elements/Popups/AddActorPopup/AddActorPopup.tsx b/src/elements/Popups/AddActorPopup/AddActorPopup.tsx index 5920388..af988f4 100644 --- a/src/elements/Popups/AddActorPopup/AddActorPopup.tsx +++ b/src/elements/Popups/AddActorPopup/AddActorPopup.tsx @@ -9,6 +9,7 @@ import {GeneralSuccess} from '../../../types/GeneralTypes'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faFilter, faTimes} from '@fortawesome/free-solid-svg-icons'; import {Button} from '../../GPElements/Button'; +import {addKeyHandler, removeKeyHandler} from '../../../utils/ShortkeyHandler'; interface props { onHide: () => void; @@ -41,6 +42,19 @@ class AddActorPopup extends React.Component { this.tileClickHandler = this.tileClickHandler.bind(this); this.filterSearch = this.filterSearch.bind(this); + this.parentSubmit = this.parentSubmit.bind(this); + this.keypress = this.keypress.bind(this); + } + + componentWillUnmount(): void { + removeKeyHandler(this.keypress); + } + + componentDidMount(): void { + addKeyHandler(this.keypress); + + // fetch the available actors + this.loadActors(); } render(): JSX.Element { @@ -52,18 +66,13 @@ class AddActorPopup extends React.Component { className={style.newactorbutton} onClick={(): void => { this.setState({contentDefault: false}); - }}>Create new Actor}> + }}>Create new Actor} ParentSubmit={this.parentSubmit}> {this.resolvePage()} ); } - componentDidMount(): void { - // fetch the available actors - this.loadActors(); - } - /** * selector for current showing popup page * @returns {JSX.Element} @@ -101,15 +110,13 @@ class AddActorPopup extends React.Component { this.setState({filter: '', filtervisible: false}); }}/> : -
{this.state.actors.filter(this.filterSearch).map((el) => ())} @@ -120,6 +127,16 @@ class AddActorPopup extends React.Component { } } + /** + * enable filterfield and focus into searchbar + */ + private enableFilterField(): void { + this.setState({filtervisible: true}, () => { + // focus filterfield after state update + this.filterfield?.focus(); + }); + } + /** * event handling for ActorTile Click */ @@ -155,6 +172,30 @@ class AddActorPopup extends React.Component { private filterSearch(actor: ActorType): boolean { return actor.name.toLowerCase().includes(this.state.filter.toLowerCase()); } + + /** + * handle a Popupbase parent submit action + */ + private parentSubmit(): void { + // allow submit only if one item is left in selection + const filteredList = this.state.actors.filter(this.filterSearch); + + if (filteredList.length === 1) { + // simulate click if parent submit + this.tileClickHandler(filteredList[0]); + } + } + + /** + * key event handling + * @param event keyevent + */ + private keypress(event: KeyboardEvent): void { + // hide if escape is pressed + if (event.key === 'f') { + this.enableFilterField(); + } + } } export default AddActorPopup; diff --git a/src/elements/Popups/AddTagPopup/AddTagPopup.tsx b/src/elements/Popups/AddTagPopup/AddTagPopup.tsx index 266653d..5e3fcb0 100644 --- a/src/elements/Popups/AddTagPopup/AddTagPopup.tsx +++ b/src/elements/Popups/AddTagPopup/AddTagPopup.tsx @@ -26,7 +26,6 @@ class AddTagPopup extends React.Component { componentDidMount(): void { callAPI('tags.php', {action: 'getAllTags'}, (result: TagType[]) => { - console.log(result); this.setState({ items: result }); diff --git a/src/elements/Popups/NewTagPopup/NewTagPopup.tsx b/src/elements/Popups/NewTagPopup/NewTagPopup.tsx index eb06ffd..fd25a07 100644 --- a/src/elements/Popups/NewTagPopup/NewTagPopup.tsx +++ b/src/elements/Popups/NewTagPopup/NewTagPopup.tsx @@ -16,7 +16,7 @@ class NewTagPopup extends React.Component { render(): JSX.Element { return ( - + this.storeselection()}>
{ this.value = v.target.value; }}/>
diff --git a/src/elements/Popups/PopupBase.test.js b/src/elements/Popups/PopupBase.test.js index d67d10d..bb4e2d7 100644 --- a/src/elements/Popups/PopupBase.test.js +++ b/src/elements/Popups/PopupBase.test.js @@ -8,12 +8,16 @@ describe('', function () { wrapper.unmount(); }); - it('simulate keypress', function () { - let events = []; + let events; + function mockKeyPress(){ + events = []; document.addEventListener = jest.fn((event, cb) => { events[event] = cb; }); + } + it('simulate keypress', function () { + mockKeyPress(); const func = jest.fn(); shallow( func()}/>); @@ -23,4 +27,14 @@ describe('', function () { expect(func).toBeCalledTimes(1); }); + it('test an Enter sumit', function () { + mockKeyPress(); + const func = jest.fn(); + shallow( func()}/>); + + // trigger the keypress event + events.keyup({key: 'Enter'}); + + expect(func).toBeCalledTimes(1); + }); }); diff --git a/src/elements/Popups/PopupBase.tsx b/src/elements/Popups/PopupBase.tsx index 7216b8e..451daf2 100644 --- a/src/elements/Popups/PopupBase.tsx +++ b/src/elements/Popups/PopupBase.tsx @@ -2,13 +2,15 @@ import GlobalInfos from '../../utils/GlobalInfos'; import style from './PopupBase.module.css'; import {Line} from '../PageTitle/PageTitle'; import React, {RefObject} from 'react'; +import {addKeyHandler, removeKeyHandler} from '../../utils/ShortkeyHandler'; interface props { width?: string; height?: string; banner?: JSX.Element; title: string; - onHide: () => void + onHide: () => void; + ParentSubmit?: () => void; } /** @@ -38,7 +40,7 @@ class PopupBase extends React.Component { componentDidMount(): void { document.addEventListener('mousedown', this.handleClickOutside); - document.addEventListener('keyup', this.keypress); + addKeyHandler(this.keypress); // add element drag drop events if (this.wrapperRef != null) { @@ -49,7 +51,7 @@ class PopupBase extends React.Component { componentWillUnmount(): void { // remove the appended listeners document.removeEventListener('mousedown', this.handleClickOutside); - document.removeEventListener('keyup', this.keypress); + removeKeyHandler(this.keypress); } render(): JSX.Element { @@ -86,6 +88,9 @@ class PopupBase extends React.Component { // hide if escape is pressed if (event.key === 'Escape') { this.props.onHide(); + } else if (event.key === 'Enter') { + // call a parentsubmit if defined + if (this.props.ParentSubmit) this.props.ParentSubmit(); } } diff --git a/src/pages/RandomPage/RandomPage.test.js b/src/pages/RandomPage/RandomPage.test.js index a2d6ea4..26166b4 100644 --- a/src/pages/RandomPage/RandomPage.test.js +++ b/src/pages/RandomPage/RandomPage.test.js @@ -1,6 +1,8 @@ import {shallow} from 'enzyme'; import React from 'react'; import RandomPage from './RandomPage'; +import {callAPI} from '../../utils/Api'; +import PopupBase from '../../elements/Popups/PopupBase'; describe('', function () { it('renders without crashing ', function () { @@ -45,4 +47,20 @@ describe('', function () { expect(wrapper.find('Tag')).toHaveLength(2); }); + + it('test shortkey press', function () { + let events = []; + document.addEventListener = jest.fn((event, cb) => { + events[event] = cb; + }); + + shallow(); + + callAPIMock({rows: [], tags: []}); + + // trigger the keypress event + events.keyup({key: 's'}); + + expect(callAPI).toBeCalledTimes(1); + }); }); diff --git a/src/pages/RandomPage/RandomPage.tsx b/src/pages/RandomPage/RandomPage.tsx index 41c23a6..208db01 100644 --- a/src/pages/RandomPage/RandomPage.tsx +++ b/src/pages/RandomPage/RandomPage.tsx @@ -7,6 +7,7 @@ import VideoContainer from '../../elements/VideoContainer/VideoContainer'; import {callAPI} from '../../utils/Api'; import {TagType} from '../../types/VideoTypes'; import {VideoTypes} from '../../types/ApiTypes'; +import {addKeyHandler, removeKeyHandler} from '../../utils/ShortkeyHandler'; interface state { videos: VideoTypes.VideoUnloadedType[]; @@ -29,12 +30,20 @@ class RandomPage extends React.Component<{}, state> { videos: [], tags: [] }; + + this.keypress = this.keypress.bind(this); } componentDidMount(): void { + addKeyHandler(this.keypress); + this.loadShuffledvideos(4); } + componentWillUnmount(): void { + removeKeyHandler(this.keypress); + } + render(): JSX.Element { return (
@@ -75,8 +84,6 @@ class RandomPage extends React.Component<{}, state> { */ loadShuffledvideos(nr: number): void { callAPI('video.php', {action: 'getRandomMovies', number: nr}, result => { - console.log(result); - this.setState({videos: []}); // needed to trigger rerender of main videoview this.setState({ videos: result.rows, @@ -84,6 +91,17 @@ class RandomPage extends React.Component<{}, state> { }); }); } + + /** + * key event handling + * @param event keyevent + */ + private keypress(event: KeyboardEvent): void { + // bind s to shuffle + if (event.key === 's') { + this.loadShuffledvideos(4); + } + } } export default RandomPage; diff --git a/src/utils/ShortkeyHandler.ts b/src/utils/ShortkeyHandler.ts new file mode 100644 index 0000000..aebb18a --- /dev/null +++ b/src/utils/ShortkeyHandler.ts @@ -0,0 +1,15 @@ +/** + * add a new keyhandler + * @param handler function to be called onkeyup + */ +export const addKeyHandler = (handler: (event: KeyboardEvent) => void): void => { + document.addEventListener('keyup', handler); +}; + +/** + * delete keyhandler + * @param handler handler to be removed + */ +export const removeKeyHandler = (handler: (event: KeyboardEvent) => void): void => { + document.removeEventListener('keyup', handler); +}