Skip to content

Commit

Permalink
Merge pull request #826 from tf/hide-info-box-for-text-tracks
Browse files Browse the repository at this point in the history
Improve text tracks and info box display logic
  • Loading branch information
tf authored Aug 9, 2017
2 parents 4fc48ba + 4498833 commit 1a05719
Show file tree
Hide file tree
Showing 25 changed files with 260 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
pageflow.VideoPlayer.cueSettingsMethods = function(player) {
player.updateCueLineSettings = function(line, forceUpdate) {
var value = line.split('.')[0];
/**
* Specify the display position of text tracks. This method can also
* be used to make VideoJS reposition the text tracks after the
* margins of the text track display have been changed (e.g. to
* translate text tracks when player controls are displayed).
*
* To force such an update, the passed string has to differ from the
* previously passed string. You can append a dot and an arbitrary
* string (e.g. `"auto.translated"`), to keep the current setting but
* still force repositioning.
*
* On the other hand, it is possible to change the positioning but
* have VideoJS apply the change only when the next cue is
* displayed. This way we can prevent moving a cue that the user
* might just be reading. Simply append the string `".lazy"`
* (e.g. `"auto.lazy"`).
*
* @param {string} line
* Either `"top"` to move text tracks to the first line or
* `"auto"` to stick with automatic positioning, followed by a tag
* to either force or prevent immediate update.
*/
player.updateCueLineSettings = function(line) {
var components = line.split('.');
var value = components[0];
var command = components[1];

value = value == 'top' ? 1 : value;

var changed = false;
Expand All @@ -24,7 +49,7 @@ pageflow.VideoPlayer.cueSettingsMethods = function(player) {
// track changed since the last call, i.e. `line` has been changed
// for a cue even though the previous call had the same
// parameters.
if (this.prevLine !== line || changed) {
if ((this.prevLine !== line || changed) && (command != 'lazy')) {
player.tech({IWillNotUseThisInPlugins: true}).trigger('texttrackchange');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ $classic-player-controls-typography: $player-controls-typography !default;
}

&-paused,
&-unplayed,
&-has_been_faded {
&-unplayed {
// Unused, but have to be defined for @extend to work
display: block;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ $classic-player-controls-timestamp-position: "left" !default;
}
}

&-page_with_progress_bar {
&-page-with_progress_bar {
%player_controls-control_bar_text {
display: none;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
&-menu_bar {
right: 10px;
}

&-toggle_info_box_menu_button {
display: none;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,10 @@ $slim-player-controls-info-box-header-typography: () !default;
}

@include desktop {
.js &-container-has_been_faded %player_controls-info_box {
.js &-info_box-hidden_during_playback {
@include faded;
}

.js &-container:hover %player_controls-info_box,
.js &-container-paused %player_controls-info_box {
@include transition-delay(0);
@include visible;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@
right: 20px;
}
}

%player_controls-page-audio .player_controls-toggle_info_box_menu_button {
display: none;
}

@include phone {
.player_controls-toggle_info_box_menu_button {
display: none;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Map placeholder names to concrete vjs css class names.

$vjs-selector-mapping: (
page_with_progress_bar: ".audioPage, .videoPage",
page-with_progress_bar: ".audioPage, .videoPage",
page-audio: ".audioPage",

background: ".page_background-for_page_with_player_controls",

Expand Down Expand Up @@ -30,23 +31,13 @@ $vjs-selector-mapping: (
container-hover: ".is_control_bar_hovered .controls",
container-focused: ".is_control_bar_focused .controls",

// `has_been_faded` is set by the video page type after the user has
// become inactive for the first time during video playback.
//
// This is used in the slim player controls to keep displaying the
// info box a little longer on initial playback. Especially on auto
// play pages this lets the user finish reading the info box
// text. When the user re-displays the info box though by moving the
// cursor above the control bar, it fades immediately once the
// cursor leaves the control bar again.
container-has_been_faded: ".controls.has_been_faded",

container-video: ".videoPage .controls",
container-fading: ".videoPage .controls",

container-unplayed: ".unplayed .controls",

info_box: ".add_info_box",
info_box-hidden_during_playback: ".add_info_box-hidden_during_playback",
control_bar: ".vjs-control-bar",
control_bar_text: ".control_bar_text",

Expand Down
3 changes: 2 additions & 1 deletion node_package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"react-redux": "^5.0.3",
"redux": "^3.6.0",
"redux-saga": "^0.13.0",
"reselect": "^2.5.4"
"reselect": "^2.5.4",
"striptags": "^2.2.1"
}
}
27 changes: 20 additions & 7 deletions node_package/src/components/PlayerControls/InfoBox.jsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
import classNames from 'classnames';
import withVisibilityWatching from '../withVisibilityWatching';
import {isBlank} from 'utils';

function InfoBox(props) {
return (
<div className={wrapperClassNames(props)}>
{header(props)}
<p dangerouslySetInnerHTML={{__html: props.description}} />
{description(props)}
</div>
);
}

function wrapperClassNames(props) {
return classNames('add_info_box', {
'empty': !props.title && !props.description,
'title_empty': !props.title,
'description_empty': !props.description
'empty': isEmpty(props),
'title_empty': isBlank(props.title),
'description_empty': isBlank(props.description),
'add_info_box-hidden_during_playback': props.hiddenDuringPlayback
});
}

function header(props) {
if (props.title) {
if (!isBlank(props.title)) {
return (
<h3>{props.title}</h3>
);
}
}

export default withVisibilityWatching(InfoBox);
function description(props) {
if (!isBlank(props.description)) {
return (
<p dangerouslySetInnerHTML={{__html: props.description}} />
);
}
}

export function isEmpty(props) {
return isBlank(props.title) && isBlank(props.description);
}

export default InfoBox;
18 changes: 13 additions & 5 deletions node_package/src/components/PlayerControls/MenuBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ MenuBar.propTypes = {
additionalButtons: React.PropTypes.arrayOf(
React.PropTypes.shape({
name: React.PropTypes.string.isRequired,
label: React.PropTypes.string.isRequired
label: React.PropTypes.string.isRequired,
className: React.PropTypes.string,
iconName: React.PropTypes.string
})
),
hiddenOnPhone: React.PropTypes.bool,
Expand Down Expand Up @@ -57,14 +59,20 @@ function renderAdditionalButtons(props) {
return (
<MenuBarButton title={additionalButton.label}
iconName={additionalButton.iconName}
className={additionalButton.className}
key={additionalButton.name}
onClick={additionalButtonClickHandler(props, additionalButton.name)} />
onClick={createHandler(props.onAdditionalButtonClick,
additionalButton.name)}
onMouseEnter={createHandler(props.onAdditionalButtonMouseEnter,
additionalButton.name)}
onMouseLeave={createHandler(props.onAdditionalButtonMouseLeave,
additionalButton.name)}/>
);
});
}

function additionalButtonClickHandler(props, name) {
if (props.onAdditionalButtonClick) {
return () => props.onAdditionalButtonClick(name);
function createHandler(handler, name) {
if (handler) {
return () => handler(name);
}
}
10 changes: 10 additions & 0 deletions node_package/src/components/PlayerControls/MenuBarButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,18 @@ export default class MenuBarButton extends React.Component {
if (this.props.subMenuItems.length > 0) {
this.setState({subMenuVisible: true});
}

if (this.props.onMouseEnter) {
this.props.onMouseEnter();
}
};

this.onMouseLeave = () => {
this.closeMenu();

if (this.props.onMouseEnter) {
this.props.onMouseLeave();
}
};

this.onFocus = () => {
Expand Down Expand Up @@ -88,6 +96,8 @@ MenuBarButton.propTypes = {
})
),
onClick: React.PropTypes.func,
onMouseEnter: React.PropTypes.func,
onMouseLeave: React.PropTypes.func,
onSubMenuItemClick: React.PropTypes.func
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import InfoBox from '../InfoBox';
import InfoBox, {isEmpty} from '../InfoBox';

import {mount} from 'enzyme';
import {expect} from 'support/chai';
Expand All @@ -22,3 +22,17 @@ describe('InfoBox', () => {
expect(result.html()).to.contain('<b>text</b>');
});
});

describe('isEmpty', () => {
it('returns true if all props are blank', () => {
const result = isEmpty({title: '', description: '<b></b>'});

expect(result).to.eq(true);
});

it('returns false if at least one prop is present', () => {
const result = isEmpty({title: 'Some title'});

expect(result).to.eq(false);
});
});
12 changes: 8 additions & 4 deletions node_package/src/components/PlayerControls/index.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import classNames from 'classnames';

import InfoBox from './InfoBox';
import InfoBox, {isEmpty as isInfoBoxEmpty} from './InfoBox';
import Container from './Container';
import LoadingSpinner from './LoadingSpinner';
import PlayButton from './PlayButton';
Expand All @@ -18,9 +18,7 @@ function PlayerControls(props) {
<span className="hint">{props.hint}</span>

<InfoBox {...props.infoBox}
watchVisibility={props.watchVisibility}
onVisible={props.onInfoBoxVisible}
onHidden={props.onInfoBoxHidden} />
hiddenDuringPlayback={props.infoBoxHiddenDuringPlayback}/>

<div className={controlBarClassNames(props)}>
{renderLoadingSpinner(props)}
Expand All @@ -37,6 +35,10 @@ function PlayerControls(props) {
</div>

<MenuBar standAlone={false}
additionalButtons={props.additionalMenuBarButtons}
onAdditionalButtonClick={props.onAdditionalButtonClick}
onAdditionalButtonMouseEnter={props.onAdditionalButtonMouseEnter}
onAdditionalButtonMouseLeave={props.onAdditionalButtonMouseLeave}
qualityMenuButtonTitle={props.qualityMenuButtonTitle}
qualityMenuItems={props.qualityMenuItems}
onQualityMenuItemClick={props.onQualityMenuItemClick}
Expand Down Expand Up @@ -91,4 +93,6 @@ PlayerControls.propTypes = {
onPlayButtonClick: React.PropTypes.func
};

export {isInfoBoxEmpty};

export default withVisibilityWatching(PlayerControls);
11 changes: 11 additions & 0 deletions node_package/src/components/icons/Info.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Container from './Container';

export default function(props) {
return (
<Container {...props} viewBoxLeft={5} viewBoxTop={5} viewBoxWidth={145} viewBoxHeight={145}>
<path d="m80 15c-35.88 0-65 29.12-65 65s29.12 65 65 65 65-29.12 65-65-29.12-65-65-65zm0 10c30.36 0 55 24.64 55 55s-24.64 55-55 55-55-24.64-55-55 24.64-55 55-55z"/>
<path d="m57.373 18.231a9.3834 9.1153 0 1 1 -18.767 0 9.3834 9.1153 0 1 1 18.767 0z" transform="matrix(1.1989 0 0 1.2342 21.214 28.75)"/>
<path d="m90.665 110.96c-0.069 2.73 1.211 3.5 4.327 3.82l5.008 0.1v5.12h-39.073v-5.12l5.503-0.1c3.291-0.1 4.082-1.38 4.327-3.82v-30.813c0.035-4.879-6.296-4.113-10.757-3.968v-5.074l30.665-1.105"/>
</Container>
);
}
2 changes: 2 additions & 0 deletions node_package/src/components/icons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import Checkmark from './Checkmark';
import CircleWithNotch from './CircleWithNotch';
import Disk from './Disk';
import Gear from './Gear';
import Info from './Info';
import Subtitles from './Subtitles';

export default {
Checkmark,
CircleWithNotch,
Disk,
Gear,
Info,
Subtitles
};
1 change: 1 addition & 0 deletions node_package/src/components/icons/mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import icons from '../icons';
* @alias pageflow.react.iconMapping
*/
export default {
toggleInfoBox: icons.Info,
mediaQuality: icons.Gear,
textTracks: icons.Subtitles,
activeMenuItem: icons.Checkmark,
Expand Down
18 changes: 12 additions & 6 deletions node_package/src/media/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ export const FOCUS_ENTERED_CONTROLS = 'MEDIA_FOCUS_ENTERED_CONTROLS';
export const FOCUS_LEFT_CONTROLS = 'MEDIA_FOCUS_LEFT_CONTROLS';

export const CONTROLS_HIDDEN = 'MEDIA_CONTROLS_HIDDEN';
export const INFO_BOX_VISIBLE = 'INFO_BOX_VISIBLE';
export const INFO_BOX_HIDDEN = 'INFO_BOX_HIDDEN';

export const SHOW_INFO_BOX_DURING_PLAYBACK = 'SHOW_INFO_BOX_DURING_PLAYBACK';
export const HIDE_INFO_BOX_DURING_PLAYBACK = 'HIDE_INFO_BOX_DURING_PLAYBACK';
export const TOGGLE_INFO_BOX_DURING_PLAYBACK = 'TOGGLE_INFO_BOX_DURING_PLAYBACK';

export function actionCreators({scope = 'default'} = {}) {
return {
Expand Down Expand Up @@ -181,13 +183,17 @@ export function actionCreators({scope = 'default'} = {}) {
return pageAction(CONTROLS_HIDDEN);
},

infoBoxVisible() {
return pageAction(INFO_BOX_VISIBLE);
showInfoBoxDuringPlayback() {
return pageAction(SHOW_INFO_BOX_DURING_PLAYBACK);
},

infoBoxHidden() {
return pageAction(INFO_BOX_HIDDEN);
hideInfoBoxDuringPlayback() {
return pageAction(HIDE_INFO_BOX_DURING_PLAYBACK);
},

toggleInfoBoxDuringPlayback() {
return pageAction(TOGGLE_INFO_BOX_DURING_PLAYBACK);
}
};

function pageAction(type, payload = {}) {
Expand Down
Loading

0 comments on commit 1a05719

Please sign in to comment.