const EventEmitter = require('eventemitter3');
/**
* <h3>Represents browser API for Gallery IPX.</h3>
* <p>
* The API is available on any page that runs one or more Brightcove embedded experiences.
* It is designed to help 3rd parties with Brightcove experiences integration.
* Provides access to current player, videos and state information as well as
* listeners for playback-related events.
* </p>
* <p>
* Before accessing the Client API, you will need to get the correct embedded IPX on the page.
* They can be accessed by the id of the <div> element you used when you embedded it
* by running:
* </p>
* <p>
* <strong>window.top.bcov.gal.getEmbed(bc-embed-<i>exp_id</i>),</strong>
* where <i>exp_id</i> is the experience id.
* </p>
* <p>
* You can also get an object with all IPX available on a page by running <strong>window.top.bcov.gal.getEmbeds()</strong>.
* </p>
* @hideconstructor
*/
class ClientApi extends EventEmitter {
/**
* Returns current player that was active on the page
* @returns {ClientApi~Player}
* @private
*/
getCurrentPlayer () {
/**
* See [Player Documentation]{@link https://brightcovelearning.github.io/Brightcove-API-References/brightcove-player/current-release/Player.html} for more information about the Player object.
* @typedef {Object} ClientApi~Player
*/
return this.player;
}
/**
* Saves current player. If the player has changed, emits 'playerChanged' event
* @param {ClientApi~Player}
* @private
*/
setCurrentPlayer (player) {
if (player !== this.player) {
this.player = player;
/**
* playerChanged event. Emitted when a different player is going to be used for playback.
* Can be generated multiple times for experiences that have multiple players.
* @event ClientApi#playerChanged
* @param {ClientApi~Player}
*/
this.emit('playerChanged', this.player);
}
}
/**
* Returns currently playing video or the last video that was played
* @returns {ClientApi~Video} Video Metadata object
*/
getCurrentVideo () {
/**
* See [Video Metadata Information] {@link https://support.brightcove.com/video-metadata-mediainfo} for more information about the video format.
* for detailed description
* @typedef {Object} ClientApi~Video
*/
return this.video;
}
/**
* Saves current video. If the video has changed, emits 'videoChanged' event
* @param {ClientApi~Video}
* @private
*/
setCurrentVideo (video) {
if (video !== this.video) {
this.video = video;
/**
* videoChanged event. Emitted when current video has changed.
* @event ClientApi#videoChanged
* @param {ClientApi~Video}
*/
this.emit('videoChanged', this.video);
}
}
/**
* Returns current state of the IPX
* @returns {string} State name, for example 'before' or 'after' for Live Event IPX
*/
getCurrentState () {
return this.state;
}
/**
* Saves current state. If the state has changed, emits 'stateChanged' event
* @param {string} state State name
* @private
*/
setCurrentState (state) {
if (state !== this.state) {
this.state = state;
/**
* stateChanged event. Emitted when a state of the embed experience is changed,
* for example from "Pre-event" to "Live".
* @event ClientApi#stateChanged
* @param {string} state. Currently supported states: before, during, after, playback.
*/
this.emit('stateChanged', state);
}
}
/**
* Returns current list of all videos, available for the current state
* @returns {Array.ClientApi~Video} Array of Video Metadata objects
*/
getAllVideos () {
return this.videos;
}
/**
* Emits 'playerLoaded' event when player is initialized. Sends current player to all listeners
* @private
*/
playerLoadStart () {
/**
* playerLoaded event. Emitted when a player is loaded.
* Can be generated multiple times for experiences that have multiple players.
* @event ClientApi#playerLoaded
* @param {ClientApi~Player}
*/
this.emit('playerLoaded', this.player);
}
/**
* Emits 'videoLoaded' event when video is loaded and ready to be played.
* Sends current video to all listeners
* @private
*/
playerLoadedMetadata () {
/**
* videoLoaded event. Emitted when video is fully loaded and ready to play.
* Can be generated multiple times when user changes the video
* @event ClientApi#videoLoaded
* @param {ClientApi~Video}
*/
this.emit('videoLoaded', this.video);
}
/**
* Emits 'videoStarted' event when playback is started or resumed.
* Sends current video to all listeners
* @private
*/
videoStarted () {
/**
* videoStarted event. Emitted when a video playback is started by user
* @event ClientApi#videoStarted
* @param {ClientApi~Video}
*/
this.emit('videoStarted', this.video);
}
/**
* Emits 'videoPaused' event when playback is stopped or finished.
* Sends current video to all listeners
* @private
*/
videoPaused () {
/**
* videoPaused event. Emitted when a video playback is paused by user
* @event ClientApi#videoPaused
* @param {ClientApi~Video}
*/
this.emit('videoPaused', this.video);
}
/**
* Extracts information from an interation object and creates
* Interaction Event.
* Adds information about current playback, like:
* - video id
* - video title
* - current playback time
*
* @param {Object} interaction IPX interaction object
* @returns {ClientApi~InteractivityEvent}
* @private
*/
getInteractionEvent (interaction) {
/**
* Describes current status of an interactivity event. Includes information about the interactivity as well as it's position in the video
* @typedef {Object} ClientApi~InteractivityEvent
* @property {string} element - type of the interaction. For example, 'link', 'card', 'html', 'image'
* @property {string} linkText - link text if applicable
* @property {string} linkUrl - link URL if applicable
* @property {number} videoId - current video id
* @property {string} videoTitle - current video title
* @property {number} videoTime - playback position for the current video
*/
return {
element: interaction.type,
linkText: interaction.text || interaction.linkText,
linkUrl: interaction.href,
videoId: this.video ? this.video.id : '',
videoTitle: this.video ? this.video.name : '',
videoTime: this.player ? this.player.currentTime() : '',
};
}
/**
* Sendns 'interactionStart' event to all subscribers
* @param {ClientApi~InteractivityEvent}
* @private
*/
interactionStarted (interaction) {
/**
* interactionStart event. Emitted when a video interactivity element, like card or a link appears in the video.
* @event ClientApi#interactionStart
* @param {ClientApi~InteractivityEvent}
*/
this.emit('interactionStart', this.getInteractionEvent(interaction));
}
/**
* Sendns 'interactionEnd' event to all subscribers
* @param {ClientApi~InteractivityEvent}
* @private
*/
interactionEnded (interaction) {
/**
* interactionEnd event. Emitted when a video interactivity element, like card or a link disappears from the video.
* @event ClientApi#interactionEnd
* @param {ClientApi~InteractivityEvent}
*/
this.emit('interactionEnd', this.getInteractionEvent(interaction));
}
/**
* Sendns 'interactionClick' event to all subscribers
* @param {ClientApi~InteractivityEvent}
* @private
*/
interactionClicked (interaction) {
/**
* interactionClick event. Emitted when user has clicked on an interactivity element.
* This includes both video interactions as well as custom HTML and image links.
* @event ClientApi#interactionClick
* @param {ClientApi~InteractivityEvent}
*/
this.emit('interactionClick', this.getInteractionEvent(interaction));
}
/**
* Sendns 'interactionCardPanelOpen' event to all subscribers
* @param {ClientApi~InteractivityEvent}
* @private
*/
interactionCardPanelOpen (interactions) {
const interactionEvents = interactions.map(interaction => this.getInteractionEvent(interaction));
/**
* interactionCardPanelOpen event. Emitted when user clicked on the interactivity information link.
* All active interactions become visible in the side panel.
* @event ClientApi#interactionCardPanelOpen
* @param {ClientApi~InteractivityEvent[]}
*/
this.emit('interactionCardPanelOpen', interactionEvents);
}
/**
* Sends 'interactionCardPanelClose' event to all subscribers
* @param {ClientApi~InteractivityEvent}
* @private
*/
interactionCardPanelClose (interactions) {
const interactionEvents = interactions.map(interaction => this.getInteractionEvent(interaction));
/**
* interactionCardPanelClose event. Emitted when user closed the interactivity information side panel.
* @event ClientApi#interactionCardPanelClose
* @param {ClientApi~InteractivityEvent[]}
*/
this.emit('interactionCardPanelClose', interactionEvents);
}
}
/**
* Allows to register a callback for an embedded experience event.
* @method ClientApi#on
* @param {string} Name of the event.
* @param {function} callback
*/
/**
* Allows to register a one-time callback function for the event named eventName.
* The next time eventName is triggered, this callback is removed and then invoked.
* @method ClientApi#once
* @param {string} Name of the event.
* @param {function} callback
*/
/**
* Removes the specified listener callback from the listener array for the event named eventName.
* @method ClientApi#off
* @param {string} Name of the event.
* @param {function} callback
*/
module.exports = {
ClientApi,
};