#63302 Плагин управления клавиатурой
This commit is contained in:
committed by
Юрий Шикин
parent
f23eb300d6
commit
7332fa2928
@@ -2,3 +2,4 @@
|
||||
.idea
|
||||
distribution
|
||||
node_modules
|
||||
tsup.config.bundled_*
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"semi": false,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": true,
|
||||
"printWidth": 80,
|
||||
"arrowParens": "always",
|
||||
"max-len": ["error", 140, 2],
|
||||
"tabWidth": 2,
|
||||
"useTabs": false
|
||||
}
|
||||
+2
-1
@@ -3,6 +3,7 @@
|
||||
"VokaAdvertisementPlugin": false,
|
||||
"VokaStatisticsPlugin": false,
|
||||
"VokaQualityPlugin": false,
|
||||
"VokaCaptionsPlugin": false
|
||||
"VokaCaptionsPlugin": false,
|
||||
"hotkeys": true
|
||||
}
|
||||
}
|
||||
Generated
+16
@@ -18,6 +18,7 @@
|
||||
"keycode": "^2.2.1",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss-preset-env": "^10.1.3",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-bus": "^2.3.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsup": "^8.3.6",
|
||||
@@ -4537,6 +4538,21 @@
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"keycode": "^2.2.1",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss-preset-env": "^10.1.3",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-bus": "^2.3.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsup": "^8.3.6",
|
||||
|
||||
@@ -57,7 +57,7 @@ class BigPlayButton extends Button {
|
||||
|
||||
handleKeyDown(event: Event) {
|
||||
this.mouseused_ = false
|
||||
|
||||
|
||||
super.handleKeyDown(event)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import videojs from 'video.js'
|
||||
const Component = videojs.getComponent('component')
|
||||
import ClickableComponent from './ClickableComponent'
|
||||
const log = videojs.log
|
||||
const Dom = videojs.dom
|
||||
import ClickableComponent from './ClickableComponent'
|
||||
import { assign } from '../utilities/obj'
|
||||
import keycode from 'keycode'
|
||||
const Dom = videojs.dom
|
||||
|
||||
/**
|
||||
* Base class for all buttons.
|
||||
@@ -115,7 +115,7 @@ class Button extends ClickableComponent {
|
||||
super.disable()
|
||||
this.el().setAttribute('disabled', 'disabled')
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This gets called when a `Button` has focus and `keydown` is triggered via a key
|
||||
* press.
|
||||
|
||||
@@ -3,6 +3,7 @@ import ClickableComponent from './ClickableComponent'
|
||||
|
||||
import ClickableComponentOptions = videojs.ClickableComponentOptions
|
||||
import { VideoJsPlayer } from '@types/video.js'
|
||||
import VokaEvent from "@/constants/VokaEvent"
|
||||
import './BigPlayButton'
|
||||
|
||||
/**
|
||||
@@ -23,17 +24,6 @@ class CentralPanel extends ClickableComponent {
|
||||
|
||||
// this.bigPlayButton = this.getChild('BigPlayButton') as videojs.Component
|
||||
this.isClickDisabled = false
|
||||
|
||||
if (this.bigPlayButton) {
|
||||
this.bigPlayButton.el().addEventListener('animationend', () => {
|
||||
;(this.bigPlayButton as videojs.Component).removeClass(
|
||||
'animation-press-play'
|
||||
)
|
||||
;(this.bigPlayButton as videojs.Component).removeClass(
|
||||
'animation-press-pause'
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
enableClick() {
|
||||
@@ -52,8 +42,8 @@ class CentralPanel extends ClickableComponent {
|
||||
*/
|
||||
createEl() {
|
||||
return videojs.dom.createEl('div', {
|
||||
className: 'voka-central-panel'
|
||||
});
|
||||
className: 'voka-central-panel',
|
||||
})
|
||||
}
|
||||
|
||||
handleClick(event: Event) {
|
||||
@@ -62,12 +52,21 @@ class CentralPanel extends ClickableComponent {
|
||||
if (this.isClickDisabled)
|
||||
return
|
||||
|
||||
if (this.player_.paused()) {
|
||||
this.player_.play()
|
||||
if (this.player().paused()) {
|
||||
if (this.player().ended()) {
|
||||
this.player().trigger(VokaEvent.Replay)
|
||||
}
|
||||
|
||||
this.player().play()
|
||||
} else {
|
||||
this.player_.pause()
|
||||
this.player().pause()
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown(event: Event) {
|
||||
// Pass keypress handling up for unsupported keys
|
||||
super.handleKeyDown(event)
|
||||
}
|
||||
}
|
||||
|
||||
videojs.registerComponent('CentralPanel', CentralPanel)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import videojs from 'video.js'
|
||||
const Component = videojs.getComponent('Component')
|
||||
// import ClickableComponentOptions = videojs.ClickableComponentOptions
|
||||
import { VideoJsPlayer, VideoJsPlayerOptions } from '@types/video.js'
|
||||
import keycode from 'keycode'
|
||||
|
||||
const Component = videojs.getComponent('component')
|
||||
const Dom = videojs.dom
|
||||
const browser = videojs.browser
|
||||
const log = videojs.log
|
||||
import { assign } from '../utilities/obj'
|
||||
import keycode from 'keycode'
|
||||
|
||||
export const enum TooltipPosition {
|
||||
top = 'top',
|
||||
@@ -38,16 +38,32 @@ class ClickableComponent extends Component {
|
||||
* The `Player` that this class should be attached to.
|
||||
*
|
||||
* @param {Object} [options]
|
||||
* The key/value store of player options.
|
||||
* The key/value store of component options.
|
||||
*
|
||||
* @param {function} [options.clickHandler]
|
||||
* The function to call when the button is clicked / activated
|
||||
*
|
||||
* @param {string} [options.controlText]
|
||||
* The text to set on the button
|
||||
*
|
||||
* @param {string} [options.className]
|
||||
* A class or space separated list of classes to add the component
|
||||
*
|
||||
*/
|
||||
constructor(player: any, options: any) {
|
||||
constructor(player: VideoJsPlayer, options: VideoJsPlayerOptions) {
|
||||
super(player, options)
|
||||
this.options_ = options
|
||||
|
||||
if (this.options_.controlText) {
|
||||
this.controlText(this.options_.controlText)
|
||||
}
|
||||
|
||||
this.handleMouseOver_ = (e) => this.handleMouseOver(e)
|
||||
this.handleMouseOut_ = (e) => this.handleMouseOut(e)
|
||||
this.handleClick_ = (e) => this.handleClick(e)
|
||||
this.handleKeyDown_ = (e) => this.handleKeyDown(e)
|
||||
|
||||
this.emitTapEvents()
|
||||
|
||||
this.enable()
|
||||
}
|
||||
|
||||
@@ -66,8 +82,8 @@ class ClickableComponent extends Component {
|
||||
* @return {Element}
|
||||
* The element that gets created.
|
||||
*/
|
||||
createEl(tag: string, props?: any, attributes?: any) {
|
||||
props = assign(
|
||||
createEl(tag: string = 'div', props?: any = {}, attributes?: any = {}) {
|
||||
props = Object.assign(
|
||||
{
|
||||
className: this.buildCSSClass(),
|
||||
tabIndex: -1
|
||||
@@ -77,7 +93,7 @@ class ClickableComponent extends Component {
|
||||
|
||||
if (tag === 'button') {
|
||||
log.error(
|
||||
`Creating a ClickableComponent with an HTML element of ${tag} is not supported use a Button instead.`
|
||||
`Creating a ClickableComponent with an HTML element of ${tag} is not supported; use a Button instead.`
|
||||
)
|
||||
}
|
||||
|
||||
@@ -91,38 +107,76 @@ class ClickableComponent extends Component {
|
||||
|
||||
this.tabIndex_ = props.tabIndex
|
||||
|
||||
const el = Dom.createEl(tag, props, attributes, '')
|
||||
const el = Dom.createEl(tag, props, attributes)
|
||||
|
||||
el.appendChild(
|
||||
Dom.createEl(
|
||||
'span',
|
||||
{
|
||||
className: 'voka-icon-placeholder'
|
||||
},
|
||||
{
|
||||
'aria-hidden': true
|
||||
},
|
||||
''
|
||||
if (!this.player_.options_.experimentalSvgIcons) {
|
||||
el.appendChild(
|
||||
Dom.createEl(
|
||||
'span',
|
||||
{
|
||||
className: 'voka-icon-placeholder'
|
||||
},
|
||||
{
|
||||
'aria-hidden': true
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
this.controlText(this.controlText_, el)
|
||||
this.createControlTextEl(el)
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
dispose() {
|
||||
// remove controlTextEl_ on dispose
|
||||
// this.controlTextEl_ = null
|
||||
this.controlTextEl_ = null
|
||||
|
||||
super.dispose()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a control text element on this `ClickableComponent`
|
||||
*
|
||||
* @param {Element} [el]
|
||||
* Parent element for the control text.
|
||||
*
|
||||
* @return {Element}
|
||||
* The control text element that gets created.
|
||||
*/
|
||||
createControlTextEl(el) {
|
||||
this.controlTextEl_ = Dom.createEl(
|
||||
'span',
|
||||
{
|
||||
className: 'voka-control-text'
|
||||
},
|
||||
{
|
||||
// let the screen reader user know that the text of the element may change
|
||||
'aria-live': 'polite'
|
||||
}
|
||||
)
|
||||
|
||||
if (el) {
|
||||
el.appendChild(this.controlTextEl_)
|
||||
}
|
||||
|
||||
this.controlText(this.controlText_, el)
|
||||
|
||||
return this.controlTextEl_
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set the localize text to use for the controls on the `ClickableComponent`.
|
||||
*
|
||||
* @param {string} [text]
|
||||
* Control text for element.
|
||||
*
|
||||
* @param {Element} [el=this.el()]
|
||||
* Element to set the title on.
|
||||
*
|
||||
* @return {string}
|
||||
* - The control text when getting
|
||||
*/
|
||||
// @ts-ignore
|
||||
controlText(
|
||||
text?: string,
|
||||
el: Element = this.el(),
|
||||
@@ -164,12 +218,12 @@ class ClickableComponent extends Component {
|
||||
if (!this.enabled_) {
|
||||
this.enabled_ = true
|
||||
this.removeClass('vjs-disabled')
|
||||
this.el().setAttribute('aria-disabled', 'false')
|
||||
this.el_.setAttribute('aria-disabled', 'false')
|
||||
if (typeof this.tabIndex_ !== 'undefined') {
|
||||
this.el().setAttribute('tabIndex', this.tabIndex_)
|
||||
this.el_.setAttribute('tabIndex', this.tabIndex_)
|
||||
}
|
||||
this.on(['tap', 'click'], this.handleClick)
|
||||
this.on('keydown', this.handleKeyDown)
|
||||
this.on(['tap', 'click'], this.handleClick_)
|
||||
this.on('keydown', this.handleKeyDown_)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,19 +233,16 @@ class ClickableComponent extends Component {
|
||||
disable() {
|
||||
this.enabled_ = false
|
||||
this.addClass('vjs-disabled')
|
||||
this.el().setAttribute('aria-disabled', 'true')
|
||||
this.el_.setAttribute('aria-disabled', 'true')
|
||||
if (typeof this.tabIndex_ !== 'undefined') {
|
||||
this.el().removeAttribute('tabIndex')
|
||||
this.el_.removeAttribute('tabIndex')
|
||||
}
|
||||
this.off('mouseover', this.handleMouseOver)
|
||||
this.off('mouseout', this.handleMouseOut)
|
||||
this.off(['tap', 'click'], this.handleClick)
|
||||
this.off('keydown', this.handleKeyDown)
|
||||
this.off('mouseover', this.handleMouseOver_)
|
||||
this.off('mouseout', this.handleMouseOut_)
|
||||
this.off(['tap', 'click'], this.handleClick_)
|
||||
this.off('keydown', this.handleKeyDown_)
|
||||
}
|
||||
|
||||
handleMouseOver(e: Event) {}
|
||||
handleMouseOut(e: Event) {}
|
||||
|
||||
/**
|
||||
* Handles language change in ClickableComponent for the player in components
|
||||
*
|
||||
@@ -205,7 +256,7 @@ class ClickableComponent extends Component {
|
||||
* Event handler that is called when a `ClickableComponent` receives a
|
||||
* `click` or `tap` event.
|
||||
*
|
||||
* @param {EventTarget~Event} event
|
||||
* @param {Event} event
|
||||
* The `tap` or `click` event that caused this function to be called.
|
||||
*
|
||||
* @listens tap
|
||||
@@ -213,8 +264,9 @@ class ClickableComponent extends Component {
|
||||
* @abstract
|
||||
*/
|
||||
handleClick(event: Event) {
|
||||
event.stopPropagation()
|
||||
if (this.options_.clickHandler) {
|
||||
this.options_.clickHandler()
|
||||
this.options_.clickHandler.call(this, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,25 +276,21 @@ class ClickableComponent extends Component {
|
||||
*
|
||||
* By default, if the key is Space or Enter, it will trigger a `click` event.
|
||||
*
|
||||
* @param {EventTarget~Event} event
|
||||
* @param {KeyboardEvent} event
|
||||
* The `keydown` event that caused this function to be called.
|
||||
*
|
||||
* @listens keydown
|
||||
*/
|
||||
handleKeyDown(event: Event) {
|
||||
handleKeyDown(event: KeyboardEvent) {
|
||||
// Support Space or Enter key operation to fire a click event. Also,
|
||||
// prevent the event from propagating through the DOM and triggering
|
||||
// Player hotkeys.
|
||||
if (
|
||||
keycode.isEventKey(event, 'Space') ||
|
||||
keycode.isEventKey(event, 'Enter')
|
||||
) {
|
||||
if (['space', 'enter'].includes(keycode(event))) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
this.trigger('click')
|
||||
} else {
|
||||
// Pass keypress handling up for unsupported keys
|
||||
// @ts-ignore @todo убрать ignore после PR https://github.com/DefinitelyTyped/DefinitelyTyped/pull/60138
|
||||
super.handleKeyDown(event)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { EventBus } from 'ts-bus'
|
||||
import { IVokaPlayer } from '@/public/IVokaPlayer'
|
||||
import { AutoplayChecker } from '@/internal/utils/AutoplayChecker'
|
||||
import * as languages from '@/languages.json'
|
||||
import '../../plugins/hotkeys'
|
||||
|
||||
import '../../components/Skin'
|
||||
|
||||
@@ -85,6 +86,7 @@ export class VokaPlayerImpl implements IVokaPlayer {
|
||||
//plugins.vokaStatisticsPlugin = {}
|
||||
//plugins.vokaAdvertisementPlugin = {}
|
||||
//plugins.vokaCaptionsPlugin = {}
|
||||
plugins.hotkeys = {}
|
||||
|
||||
const childrenComponents = [
|
||||
// Non-visual component, not in UI layer list.
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import videojs from "video.js";
|
||||
import { VideoJsPlayer } from "@types/video.js"
|
||||
import keycode from 'keycode'
|
||||
import VokaEvent from "@/constants/VokaEvent"
|
||||
|
||||
const Plugin = videojs.getPlugin('plugin');
|
||||
|
||||
export class Hotkeys extends Plugin {
|
||||
player!: VideoJsPlayer
|
||||
volumeStep: number
|
||||
|
||||
constructor(player: VideoJsPlayer) {
|
||||
super(player)
|
||||
this.volumeStep = 0.1
|
||||
|
||||
this.player.el().addEventListener('keydown', (e) => this.handleKeyDown(e));
|
||||
}
|
||||
|
||||
handleKeyDown(event: Event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
switch (keycode(event)) {
|
||||
case 'up':
|
||||
this.changeVolume(this.volumeStep)
|
||||
break
|
||||
|
||||
case 'down':
|
||||
this.changeVolume(-this.volumeStep)
|
||||
break
|
||||
|
||||
case 'm':
|
||||
this.mute()
|
||||
break
|
||||
|
||||
case 'space':
|
||||
case 'enter':
|
||||
this.togglePlay()
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
togglePlay() {
|
||||
if (this.player.paused()) {
|
||||
if (this.player.ended()) {
|
||||
this.player.trigger(VokaEvent.Replay)
|
||||
}
|
||||
|
||||
this.player.play()
|
||||
} else {
|
||||
this.player.pause()
|
||||
}
|
||||
}
|
||||
|
||||
changeVolume(diff: number) {
|
||||
const value = this.player.volume() + diff
|
||||
this.player.volume(value)
|
||||
}
|
||||
|
||||
mute() {
|
||||
this.player.muted(!this.player.muted())
|
||||
}
|
||||
}
|
||||
|
||||
videojs.registerPlugin('hotkeys', Hotkeys);
|
||||
Reference in New Issue
Block a user