/
githubmirror
/
amphtml
Обзор
Документация
Войти
/
githubmirror
/
amphtml
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
2603010454000
src/video-interface.js
608 строк
15 KB
Alan Orozco
♻️ Prevent `VideoInterface` class from being bundled (#37080)
01 дек 2021, 02:55
Не верифицирован
01 дек 2021, 02:55
c91e704
Код
Авторство
О чём код?
import {devAssertElement} from '#core/assert'; import {whenUpgradedToCustomElement} from '#core/dom/amp-element-helpers'; export const MIN_VISIBILITY_RATIO_FOR_AUTOPLAY = 0.5; /** * VideoInterface defines a common video API which any AMP component that plays * videos is expected to implement. * * AMP runtime uses this common API to provide consistent video experience and * analytics across all video players. * * Components implementing this interface must also extend * {@link ./base-element.BaseElement} and register with the * Video Manager {@link ./service/video-manager-impl.VideoManager} during * their `builtCallback`. * * @interface */ export class VideoInterface { /** @return {!AmpElement} */ get element() {} /** @return {!Window} */ get win() {} /** * See `BaseElement`. * @return {!./utils/signals.Signals} */ signals() {} /** * See `BaseElement`. * @param {function()} unusedMutator * @return {!Promise} */ mutateElementSkipRemeasure(unusedMutator) {} /** * Whether the component supports video playback in the current platform. * If false, component will be not treated as a video component. * @return {boolean} */ supportsPlatform() {} /** * Whether users can interact with the video such as pausing it. * Example of non-interactive videos include design background videos where * all controls are hidden from the user. * * @return {boolean} */ isInteractive() {} /** * Current playback time in seconds at time of trigger. * * This is used for analytics metadata. * * @return {number} */ getCurrentTime() {} /** * Total duration of the video in seconds * * This is used for analytics metadata. * * @return {number} */ getDuration() {} /** * Get a 2d array of start and stop times that the user has watched. * This is used for analytics metadata. * @return {!Array<Array<number>>} */ getPlayedRanges() {} /** * Plays the video. * * @param {boolean} unusedIsAutoplay Whether the call to the `play` method is * triggered by the autoplay functionality. Video players can use this hint * to make decisions such as not playing pre-roll video ads. */ play(unusedIsAutoplay) {} /** * Pauses the video. */ pause() {} /** * Mutes the video. * Implementation is required for autoplay and mute/unmute controls on docked * video. */ mute() {} /** * Unmutes the video. * Implementation is required for autoplay and mute/unmute controls on docked * video. */ unmute() {} /** * Makes the video UI controls visible. * * AMP will not call this method if `controls` attribute is not set. * * Implementation is required for docked video. */ showControls() {} /** * Hides the video UI controls. * * AMP will not call this method if `controls` attribute is not set. * * Implementation is required for docked video. */ hideControls() {} /** * Returns video's meta data (artwork, title, artist, album, etc.) for use * with the Media Session API * @return {!./mediasession-helper.MetadataDef|undefined} metadata * - artwork (Array): URL to the poster image (preferably a 512x512 PNG) * - title (string): Name of the video * - artist (string): Name of the video's author/artist * - album (string): Name of the video's album if it exists */ getMetadata() {} /** * If returning true, it's assumed that the embedded video document internally * implements a feature to enter fullscreen on device rotation, so that the * VideoManager does not override it. * * Otherwise, the feature is implemented automatically when using the * `rotate-to-fullscreen` attribute. * * @return {boolean} */ preimplementsAutoFullscreen() {} /** * If returning true, it's assumed that the embedded video document internally * implements the MediaSession API internally so that the VideoManager won't * replace it. * * Otherwise provided and inferred metadata are used to update the video's * Media Session. * * @return {boolean} */ preimplementsMediaSessionAPI() {} /** * Enables fullscreen on the internal video element * NOTE: While implementing, keep in mind that Safari/iOS do not allow taking * any element other than <video> to fullscreen, if the player has an internal * implementation of fullscreen (flash for example) then check * if Services.platformFor(this.win).isSafari is true and use the internal * implementation instead. If not, it is recommended to take the iframe * to fullscreen using fullscreenEnter from src/core/dom/fullscreen.js */ fullscreenEnter() {} /** * Quits fullscreen mode */ fullscreenExit() {} /** * Returns whether the video is currently in fullscreen mode or not. * @return {boolean} */ isFullscreen() {} /** * Seeks the video to a specified time. * @param {number} unusedTimeSeconds */ seekTo(unusedTimeSeconds) {} } /** * Attributes * * Components implementing the VideoInterface are expected to support * the following attributes. * * @enum {string} */ export const VideoAttributes_Enum = { /** * autoplay * * Whether the developer has configured autoplay on the component. * This is normally done by setting `autoplay` attribute on the component. * * AMP runtime manages autoplay behavior itself using methods such as `play`, * `pause`, `showControls`, `hideControls`, `mute`, etc.. therefore components * should not propagate the autoplay attribute to the underlying player * implementation. * * When a video is requested to autoplay, AMP will automatically * mute and hide the controls for the video, when video is 75% visible in * the viewport, AMP will play the video and later pauses it when 25% * or more of the video exits the viewport. If an auto-playing video also has * controls, AMP will install a tap * handler on the video, and when an end-user taps the video, AMP will show * the controls. * */ AUTOPLAY: 'autoplay', /** * dock * * Setting the `dock` attribute on the component makes the video minimize * to the corner when scrolled out of view and has been interacted with. */ DOCK: 'dock', /** * rotate-to-fullscreen * * If enabled, this automatically expands the currently visible video and * playing to fullscreen when the user changes the device's orientation to * landscape if the video was started following a user interaction * (not autoplay) * * Dependent upon browser support of * http://caniuse.com/#feat=screen-orientation * and http://caniuse.com/#feat=fullscreen */ ROTATE_TO_FULLSCREEN: 'rotate-to-fullscreen', /** * noaudio * * If set and autoplay, the equalizer icon will not be displayed. */ NO_AUDIO: 'noaudio', }; /** * Events * * Components implementing the VideoInterface are expected to dispatch * the following DOM events. * * @enum {string} */ export const VideoEvents_Enum = { /** * registered * * Fired when the video player element is built and has been registered with * the video manager. * * @event registered */ REGISTERED: 'registered', /** * load * * Fired when the video player is loaded and calls to methods such as `play()` * are allowed. * * @event load */ LOAD: 'load', /** * loadedmetadata * * Fired when the video's metadata becomes available (e.g. duration). * * @event loadedmetadata */ LOADEDMETADATA: 'loadedmetadata', /** * loadeddata * * Fired when the user agent can render the media for the first time. * * @event loadeddata */ LOADEDDATA: 'loadeddata', /** * play * * Fired when the video plays (either because of autoplay or the play method). * * Note: Because this event was not originally present in this interface, we * cannot rely on all all implementations to emit it. * * @event play */ PLAY: 'play', /** * playing * * Fired when the video begins playing. * * @event playing */ PLAYING: 'playing', /** * pause * * Fired when the video pauses. * * @event pause */ PAUSE: 'pause', /** * ended * * Fired when the video ends. * * This event should be fired in addition to `pause` when video ends. * * @event ended */ ENDED: 'ended', /** * muted * * Fired when the video is muted. * * @event muted */ MUTED: 'muted', /** * unmuted * * Fired when the video is unmuted. * * @event unmuted */ UNMUTED: 'unmuted', /** * amp:video:visibility * * Fired when the video's visibility changes. * * @event amp:video:visibility * @property {boolean} visible Whether the video player is visible or not. */ VISIBILITY: 'amp:video:visibility', /** * reload * * Fired when the video's src changes. * * @event reloaded */ RELOAD: 'reloaded', /** * pre/mid/post Ad start * * Fired when an Ad starts playing. * * This is used to remove any overlay shims during Ad play during autoplay * or minimized-to-corner version of the player. * * @event ad_start */ AD_START: 'ad_start', /** * pre/mid/post Ad ends * * Fired when an Ad ends playing. * * This is used to restore any overlay shims during Ad play during autoplay * or minimized-to-corner version of the player. * * @event ad_end */ AD_END: 'ad_end', /** * A 3p video player can send signals for analytics whose meaning doesn't * fit for other events. In this case, a `tick` event is sent with additional * information in its data property. * * @event amp:video:tick */ CUSTOM_TICK: 'amp:video:tick', }; /** @typedef {string} */ export let PlayingStateDef; /** * Playing States * * Internal playing states used to distinguish between video playing on user's * command and videos playing automatically * * @enum {string} */ export const PlayingStates_Enum = { /** * playing_manual * * When the video user manually interacted with the video and the video * is now playing * * @event playing_manual */ PLAYING_MANUAL: 'playing_manual', /** * playing_auto * * When the video has autoplay and the user hasn't interacted with it yet * * @event playing_auto */ PLAYING_AUTO: 'playing_auto', /** * paused * * When the video is paused. * * @event paused */ PAUSED: 'paused', }; /** @enum {string} */ export const VideoAnalyticsEvents_Enum = { /** * video-ended * * Indicates that a video ended. * @property {!VideoAnalyticsDetailsDef} details * @event video-ended */ ENDED: 'video-ended', /** * video-pause * * Indicates that a video paused. * @property {!VideoAnalyticsDetailsDef} details * @event video-pause */ PAUSE: 'video-pause', /** * video-play * * Indicates that a video began to play. * @property {!VideoAnalyticsDetailsDef} details * @event video-play */ PLAY: 'video-play', /** * video-session * * Indicates that some segment of the video played. * @property {!VideoAnalyticsDetailsDef} details * @event video-session */ SESSION: 'video-session', /** * video-session-visible * * Indicates that some segment of the video played in the viewport. * @property {!VideoAnalyticsDetailsDef} details * @event video-session-visible */ SESSION_VISIBLE: 'video-session-visible', /** * video-seconds-played * * Indicates that a video was playing when the * video-seconds-played interval fired. * @property {!VideoAnalyticsDetailsDef} details * @event video-session-visible */ SECONDS_PLAYED: 'video-seconds-played', /** * video-hosted-custom * * Indicates that a custom event incoming from a 3p frame is to be logged. * @property {!VideoAnalyticsDetailsDef} details * @event video-custom */ CUSTOM: 'video-hosted-custom', /** * video-percentage-played * * Indicates that a percentage interval has been played. * @property {!VideoAnalyticsDetailsDef} details * @event video-custom */ PERCENTAGE_PLAYED: 'video-percentage-played', /** * video-ad-start * * Indicates that an ad begins to play. * @property {!VideoAnalyticsDetailsDef} details * @event video-ad-start */ AD_START: 'video-ad-start', /** * video-ad-end * * Indicates that an ad ended. * @property {!VideoAnalyticsDetailsDef} details * @event video-ad-end */ AD_END: 'video-ad-end', }; /** * This key can't predictably collide with custom var names as defined in * analytics user configuration. * @type {string} */ export const videoAnalyticsCustomEventTypeKey = '__amp:eventType'; /** * Helper union type to be used internally, so that the compiler treats * `VideoInterface` objects as `BaseElement`s, which they should be anyway. * * WARNING: Don't use to `register` at the Service level. Registering should * only allow `VideoInterface` as a guarding measure. * * @typedef {!VideoInterface|!./base-element.BaseElement} */ export let VideoOrBaseElementDef; /** * @param {!Element} element * @return {boolean} */ export function isDockable(element) { return element.hasAttribute(VideoAttributes_Enum.DOCK); } /** @enum {string} */ export const VideoServiceSignals_Enum = { USER_INTERACTED: 'user-interacted', PLAYBACK_DELEGATED: 'playback-delegated', }; /** @param {!AmpElement|!VideoOrBaseElementDef} video */ export function delegateAutoplay(video) { whenUpgradedToCustomElement(devAssertElement(video)).then((el) => { el.signals().signal(VideoServiceSignals_Enum.PLAYBACK_DELEGATED); }); } /** @param {!AmpElement|!VideoOrBaseElementDef} video */ export function userInteractedWith(video) { video.signals().signal(VideoServiceSignals_Enum.USER_INTERACTED); } /** * Classname that media components should annotate themselves with. * This applies to all video and audio playback components, regardless of * whether they implement a common interface or not. * * TODO(go.amp.dev/issue/26984): This isn't exclusive to video, but there's no * better place to put this now due to OWNERShip. Move. */ export const MEDIA_COMPONENT_CLASSNAME = 'i-amphtml-media-component'; /** * Annotates media component element with a common classname. * This applies to all video and audio playback components, regardless of * whether they implement a common interface or not. * @param {!Element} element * * TODO(go.amp.dev/issue/26984): This isn't exclusive to video, but there's no * better place to put this now due to OWNERShip. Move. */ export function setIsMediaComponent(element) { element.classList.add(MEDIA_COMPONENT_CLASSNAME); }