Creating a Video.js Social Plugin
August 5, 2014 8:56 pmIn this tutorial we’ll be walking through a simple sharing plugin similar to the Sublime Video share button and overlay.
You can view a demo here: http://brianpkelley.github.io/video-js-4-plugins/demos/socialOverlay.html
We’ll be using:
- Javascript
- CSS
- FontAwesome 4.1.0
The Plugin Setup
When creating a plugin file for Video.js it is a best practice to enclose your functions inside a closure.
[markdown]
“`javascript
(function() {
‘use strict’;
})();
“`
[/markdown]
This allows all of code to be accessible without cluttering up the global namespace, keeping everything nice and tidy.
videojs.plugin
The videojs.plugin function passes your plugin function an options
object which we’ll set up later in this tutorial, and its initial scope is the player that is initializing the plugin, so this
references the player object.
We’ll be creating a function that will call the constructor for our plugin and passing it to the videojs.plugin
function.
[markdown]
“`javascript
(function() {
‘use strict’;
// Plugin components will go here
/******************************************/
/* The Plugin Function */
/******************************************/
// This function will be called by video.js when it loops through all of the registered plugins.
var pluginFn = function( options ) {
};
videojs.plugin( ‘sharingPlugin’, pluginFn );
})();
“`
[/markdown]
Video.js Components
The video.js components are the building blocks for almost every UI object in a player. Some examples are:
- Big Play Button
- Play / Pause Toggle
- The Control Bar
- The Video.js Poster Image
As you can see, it is quite the flexible base class that provides heaps of core functionality from showing and hiding to adding and removing children, events, and plenty more. For a complete look at it, check out the component documentation provided by the Video.js team.
We’re first going to create the button used to open the overlay. To do this, we’ll be using a child class of videojs.Component
convienently named videojs.Button
[markdown]
“`javascript:Lines 7-30
(function() {
‘use strict’;
/******************************************/
/* The Share Button */
/******************************************/
// Create the button
videojs.ShareButton = videojs.Button.extend({
init: function( player, options ) {
// Initialize the button using the default constructor
videojs.Button.call( this, player, options );
}
});
// Set the text for the button
videojs.ShareButton.prototype.buttonText = ‘Share Video’;
// These are the defaults for this class.
videojs.ShareButton.prototype.options_ = {};
// videojs.Button uses this function to build the class name.
videojs.ShareButton.prototype.buildCSSClass = function() {
// Add our className to the returned className
return ‘vjs-share-button ‘ + videojs.Button.prototype.buildCSSClass.call(this);
};
// videojs.Button already sets up the onclick event handler, we just need to overwrite the function
videojs.ShareButton.prototype.onClick = function( e ) {
// Add specific click actions here.
};
/******************************************/
/* The Plugin Function */
/******************************************/
// This function will be called by video.js when it loops through all of the registered plugins.
var pluginFn = function( options ) {
};
videojs.plugin( ‘sharingPlugin’, pluginFn );
})();
“`
[/markdown]
The above code has a lot going on.
- The extend method of
videojs.Component
creates a child class of itself, so the ShareButton family tree would resemble
Component -> Button -> ShareButton - The
init
function initializes our plugin, and in our case, we just need to use the defaultvideojs.Button
init method. videojs.ShareButton.prototype.buttonText
is the label for the new button. This will be hidden to normal users, but is used by screen readers and other types of non visual browsers.videojs.ShareButton.prototype.options_
are the class variable defaults. Thevideojs.Component
consturctor merges the options object you pass it with the defult options specified.videojs.ShareButton.prototype.buildCSSClass
constructs the className string used by thecreateEl
method. This is where we add our specialized classes and call thevideojs.Button
buildCSSClass method to get core classNames used by the ancestor classes.videojs.ShareButton.prototype.onClick
is defined in the basevideojs.Button
class which also sets up the event handling for click and touch events.
The videojs.Component
consturctor does some heavy lifting for you, it calls your objects createEl
method which creates and returns the HTML structure of you component in the form of this.el_
. Generally buttons have a main root element as this.el_
which uses the css ::before
psuedo element for the text and contains an element that is hidden that contains the text of the button. This gives you an HTML structure which should look like this.
Let’s Add the Button
Now that we have a component to use, we can add it to the player. To accomplish this we modify our plugin function and first instantiate the ShareButton
object and then use the videojs.Componenet
method addChild
.
[markdown]
“`javascript:Lines 38-42
(function() {
‘use strict’;
/******************************************/
/* The Share Button */
/******************************************/
// Create the button
videojs.ShareButton = videojs.Button.extend({
init: function( player, options ) {
// Initialize the button using the default constructor
videojs.Button.call( this, player, options );
}
});
// Set the text for the button
videojs.ShareButton.prototype.buttonText = ‘Share Video’;
// These are the defaults for this class.
videojs.ShareButton.prototype.options_ = {};
// videojs.Button uses this function to build the class name.
videojs.ShareButton.prototype.buildCSSClass = function() {
// Add our className to the returned className
return ‘vjs-share-button ‘ + videojs.Button.prototype.buildCSSClass.call(this);
};
// videojs.Button already sets up the onclick event handler, we just need to overwrite the function
videojs.ShareButton.prototype.onClick = function( e ) {
// Add specific click actions here.
};
/******************************************/
/* The Plugin Function */
/******************************************/
// This function will be called by video.js when it loops through all of the registered plugins.
var pluginFn = function( options ) {
// We need to pass off the options to the button.
var shareComponent = new videojs.ShareButton( this, options );
// Now lets add it to the player.
var shareButton = this.addChild( shareComponent );
};
videojs.plugin( ‘sharingPlugin’, pluginFn );
})();
“`
[/markdown]
Creating the Overlay
Here is our first custom component. We need to define the components HTML structure, we’ll be using just a simple overlay background and container. Generally, the root element and the content element (where children components are added) are the same element. In our caes, the root element needs to be the overlay, while future children (Social Logos) need to be added to the container. To acheive this behavior we need to assign the container to this.contentEl_
while which ever element we return from createEl
(the overlay) will automatically become this.el_
.
[markdown]
“`javascript:Lines 36-70
(function() {
‘use strict’;
/******************************************/
/* The Share Button */
/******************************************/
// Create the button
videojs.ShareButton = videojs.Button.extend({
init: function( player, options ) {
// Initialize the button using the default constructor
videojs.Button.call( this, player, options );
}
});
// Set the text for the button
videojs.ShareButton.prototype.buttonText = ‘Share Video’;
// These are the defaults for this class.
videojs.ShareButton.prototype.options_ = {};
// videojs.Button uses this function to build the class name.
videojs.ShareButton.prototype.buildCSSClass = function() {
// Add our className to the returned className
return ‘vjs-share-button ‘ + videojs.Button.prototype.buildCSSClass.call(this);
};
// videojs.Button already sets up the onclick event handler, we just need to overwrite the function
videojs.ShareButton.prototype.onClick = function( e ) {
// Add specific click actions here.
};
/******************************************/
/* The Share Overlay */
/******************************************/
// Create the overlay and container for the links
videojs.ShareContainer = videojs.Component.extend({
init: function( player, options ) {
// call the parent constructor
videojs.Component.call( this, player, options );
}
});
// These are the child objects of this component. Add or remove to show/hide from the overlay
videojs.ShareContainer.prototype.options_ = {
children: {}
};
// This function will be called by the videojs.Component constructor.
videojs.ShareContainer.prototype.createEl = function( tagName, props ) {
// Create the elements
// The black and blury overlay
var overlay = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-overlay’
});
// The container for the links/logos of the social sites we wish to offer
var container = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-container’
});
// this.contentEl is the element that children (links/logos) are added to.
this.contentEl_ = container;
overlay.appendChild( this.contentEl_ );
// This will become “this.el_”
return overlay;
};
/******************************************/
/* The Plugin Function */
/******************************************/
// This function will be called by video.js when it loops through all of the registered plugins.
var pluginFn = function( options ) {
// We need to pass off the options to the button.
var shareComponent = new videojs.ShareButton( this, options );
// Now lets add it to the player.
var shareButton = this.addChild( shareComponent );
};
videojs.plugin( ‘sharingPlugin’, pluginFn );
})();
“`
[/markdown]
Launching and Hiding the Overlay
We begin by overwriting the standard videojs.Button.prototype.onClick
method with our own videojs.ShareButton.prototype.onClick
. In this function we will create an overlay object, add it to the player, and tell it to show itself as well as assign a one time event listener for a click event on the window that will tell the overlay to close.
[markdown]
“`javascript:Lines 28-63
(function() {
‘use strict’;
/******************************************/
/* The Share Button */
/******************************************/
// Create the button
videojs.ShareButton = videojs.Button.extend({
init: function( player, options ) {
// Initialize the button using the default constructor
videojs.Button.call( this, player, options );
}
});
// Set the text for the button
videojs.ShareButton.prototype.buttonText = ‘Share Video’;
// These are the defaults for this class.
videojs.ShareButton.prototype.options_ = {};
// videojs.Button uses this function to build the class name.
videojs.ShareButton.prototype.buildCSSClass = function() {
// Add our className to the returned className
return ‘vjs-share-button ‘ + videojs.Button.prototype.buildCSSClass.call(this);
};
// videojs.Button already sets up the onclick event handler, we just need to overwrite the callback
videojs.ShareButton.prototype.onClick = function( e ) {
// We need to stop this event before it bubbles up to “window” for our event listener below.
e.stopImmediatePropagation();
// There are a few ways to accomplish opening the overlay
// I chose to create and destroy the overlay to demonstrate
// the dispose method. Creating the component as a child is
// the direction I would choose.
this.overlay_ = new videojs.ShareContainer( this.player_, this.options_ );
// We need to add an event listener to close the overlay when the user clicks outside the overlay / player.
// Because we are destroying the overlay, we only need to listen to this once.
videojs.one( window, ‘click’, videojs.bind( this, this.windowClick ) );
// Add the overlay to the player
this.player_.addChild( this.overlay_ );
// Call the show method to apply effects and display the overlay
this.overlay_.show();
// Pause the video
this.player_.pause();
};
videojs.ShareButton.prototype.windowClick = function( e ) {
// Remove it from the parent (player)
this.player_.removeChild( this.overlay_ );
// Now remove it from memory.
// The dispose method removes the element and component.
this.overlay_.dispose();
// We no longer use this variable so release it.
delete this.overlay_;
};
/******************************************/
/* The Share Overlay */
/******************************************/
// Create the overlay and container for the links
videojs.ShareContainer = videojs.Component.extend({
init: function( player, options ) {
// call the parent constructor
videojs.Component.call( this, player, options );
}
});
// These are the child objects of this component. Add or remove to show/hide from the overlay
videojs.ShareContainer.prototype.options_ = {
children: {}
};
// This function will be called by the videojs.Component constructor.
videojs.ShareContainer.prototype.createEl = function( tagName, props ) {
// Create the elements
// The black and blury overlay
var overlay = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-overlay’
});
// The container for the links/logos of the social sites we wish to offer
var container = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-container’
});
// this.contentEl is the element that children (links/logos) are added to.
this.contentEl_ = container;
overlay.appendChild( this.contentEl_ );
// This will become “this.el_”
return overlay;
};
/******************************************/
/* The Plugin Function */
/******************************************/
// This function will be called by video.js when it loops through all of the registered plugins.
var pluginFn = function( options ) {
// We need to pass off the options to the button.
var shareComponent = new videojs.ShareButton( this, options );
// Now lets add it to the player.
var shareButton = this.addChild( shareComponent );
};
videojs.plugin( ‘sharingPlugin’, pluginFn );
})();
“`
[/markdown]
Creating the Custom Social Buttons
Now we just need some social icons to click! We’ll be creating a child of videojs.Button
as a parent object for each type or brand of icon. We’ve set up this class to use a text
and icon
option, with the icon
being optional and falling back to the text after being lowercased.
[markdown]
“`javascript
/******************************************/
/* The Social Icons */
/******************************************/
// This is the base class for the share items. Each Icon can be passed a “Name” and an icon class.
videojs.OverlaySocialButton = videojs.Button.extend({
init: function( player, options ) {
videojs.Button.call(this, player, options );
}
});
videojs.OverlaySocialButton.prototype.createEl = function(type, props){
var el;
// Add standard Aria and Tabindex info
props = vjs.obj.merge({
className: this.buildCSSClass(),
‘role’: ‘button’,
‘aria-live’: ‘polite’, // let the screen reader user know that the text of the button may change
tabIndex: 0
}, props);
// ‘i’ is needed for the Font-Awesome icons
el = vjs.Component.prototype.createEl.call(this, ‘i’, props);
// if innerHTML hasn’t been overridden (bigPlayButton), add content elements
if (!props.innerHTML) {
this.contentEl_ = vjs.createEl(‘div’, {
className: ‘vjs-control-content’
});
this.controlText_ = vjs.createEl(‘span’, {
className: ‘vjs-control-text’,
innerHTML: this.options_.text || ‘Need Text’
});
this.contentEl_.appendChild(this.controlText_);
el.appendChild(this.contentEl_);
}
return el;
};
videojs.OverlaySocialButton.prototype.buildCSSClass = function() {
// We do not use the videojs.Button.prototype.buildCSSClass because we are not creating a typical component.
return ‘vjs-share-icon fa fa-‘ + this.options_.icon + ‘-square fa-5x’;
};
“`
[/markdown]
Now we have our base class we just need to extend it and add in the specialized onclick functions (I’ll be leaving these empty to allow you choose which method best suits yourself)
[markdown]
“`javascript:Lines 108-208
(function() {
‘use strict’;
/******************************************/
/* The Share Button */
/******************************************/
// Create the button
videojs.ShareButton = videojs.Button.extend({
init: function( player, options ) {
// Initialize the button using the default constructor
videojs.Button.call( this, player, options );
}
});
// Set the text for the button
videojs.ShareButton.prototype.buttonText = ‘Share Video’;
// These are the defaults for this class.
videojs.ShareButton.prototype.options_ = {};
// videojs.Button uses this function to build the class name.
videojs.ShareButton.prototype.buildCSSClass = function() {
// Add our className to the returned className
return ‘vjs-share-button ‘ + videojs.Button.prototype.buildCSSClass.call(this);
};
// videojs.Button already sets up the onclick event handler, we just need to overwrite the callback
videojs.ShareButton.prototype.onClick = function( e ) {
// We need to stop this event before it bubbles up to “window” for our event listener below.
e.stopImmediatePropagation();
// There are a few ways to accomplish opening the overlay
// I chose to create and destroy the overlay to demonstrate
// the dispose method. Creating the component as a child is
// the direction I would choose.
this.overlay_ = new videojs.ShareContainer( this.player_, this.options_ );
// We need to add an event listener to close the overlay when the user clicks outside the overlay / player.
// Because we are destroying the overlay, we only need to listen to this once.
videojs.one( window, ‘click’, videojs.bind( this, this.windowClick ) );
// Add the overlay to the player
this.player_.addChild( this.overlay_ );
// Call the show method to apply effects and display the overlay
this.overlay_.show();
// Pause the video
this.player_.pause();
};
videojs.ShareButton.prototype.windowClick = function( e ) {
// Remove it from the parent (player)
this.player_.removeChild( this.overlay_ );
// Now remove it from memory.
// The dispose method removes the element and component.
this.overlay_.dispose();
// We no longer use this variable so release it.
delete this.overlay_;
};
/******************************************/
/* The Share Overlay */
/******************************************/
// Create the overlay and container for the links
videojs.ShareContainer = videojs.Component.extend({
init: function( player, options ) {
// call the parent constructor
videojs.Component.call( this, player, options );
}
});
// These are the child objects of this component. Add or remove to show/hide from the overlay
videojs.ShareContainer.prototype.options_ = {
children: {}
};
// This function will be called by the videojs.Component constructor.
videojs.ShareContainer.prototype.createEl = function( tagName, props ) {
// Create the elements
// The black and blury overlay
var overlay = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-overlay’
});
// The container for the links/logos of the social sites we wish to offer
var container = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-container’
});
// this.contentEl is the element that children (links/logos) are added to.
this.contentEl_ = container;
overlay.appendChild( this.contentEl_ );
// This will become “this.el_”
return overlay;
};
/******************************************/
/* The Social Icons */
/******************************************/
// This is the base class for the share items. Each Icon can be passed a “Name” and an icon class.
videojs.OverlaySocialButton = videojs.Button.extend({
init: function( player, options ) {
videojs.Button.call(this, player, options );
}
});
videojs.OverlaySocialButton.prototype.createEl = function(type, props){
var el;
// Add standard Aria and Tabindex info
props = vjs.obj.merge({
className: this.buildCSSClass(),
‘role’: ‘button’,
‘aria-live’: ‘polite’, // let the screen reader user know that the text of the button may change
tabIndex: 0
}, props);
// ‘i’ is needed for the Font-Awesome icons
el = vjs.Component.prototype.createEl.call(this, ‘i’, props);
// if innerHTML hasn’t been overridden (bigPlayButton), add content elements
if (!props.innerHTML) {
this.contentEl_ = vjs.createEl(‘div’, {
className: ‘vjs-control-content’
});
this.controlText_ = vjs.createEl(‘span’, {
className: ‘vjs-control-text’,
innerHTML: this.options_.text || ‘Need Text’
});
this.contentEl_.appendChild(this.controlText_);
el.appendChild(this.contentEl_);
}
return el;
};
videojs.OverlaySocialButton.prototype.buildCSSClass = function() {
// We do not use the videojs.Button.prototype.buildCSSClass because we are not creating a typical component.
return ‘vjs-share-icon fa fa-‘ + ( this.options_.icon || this.options_.text.toLowerCase() ) + ‘-square fa-5x’;
};
// These are the indvidual buttons for each type of share.
// Twitter
videojs.TwitterShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.TwitterShare.prototype.options_ = { text: ‘Twitter’ };
videojs.TwitterShare.prototype.onClick = function() {
// Do Share action here
};
// Facebook
videojs.FacebookShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.FacebookShare.prototype.options_ = { text: ‘Facebook’ };
videojs.FacebookShare.prototype.onClick = function() {
// Do Share action here
};
// Pinterest
videojs.PinterestShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.PinterestShare.prototype.options_ = { text: ‘Pinterest’ };
videojs.PinterestShare.prototype.onClick = function() {
// Do Share action here
};
// Google Plus
videojs.GooglePlusShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.GooglePlusShare.prototype.options_ = { icon: ‘google-plus’, text: ‘Google+’ };
videojs.GooglePlusShare.prototype.onClick = function() {
// Do Share action here
};
// LinkedIn
videojs.LinkedInShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.LinkedInShare.prototype.options_ = { text: ‘LinkedIn’ };
videojs.LinkedInShare.prototype.onClick = function() {
// Do Share action here
};
/******************************************/
/* The Plugin Function */
/******************************************/
// This function will be called by video.js when it loops through all of the registered plugins.
var pluginFn = function( options ) {
// We need to pass off the options to the button.
var shareComponent = new videojs.ShareButton( this, options );
// Now lets add it to the player.
var shareButton = this.addChild( shareComponent );
};
videojs.plugin( ‘sharingPlugin’, pluginFn );
})();
“`
[/markdown]
Adding the Icons to the Overlay
Next we specify which social logos we would like displayed. The videojs.ShareContainer.prototype.options_.children
object contains the name of the social logo buttons we will create in the coming steps. Durring a components initialization process, these will be automatically created and appended to this.contentEl_
.
[markdown]
“`javascript:Lines 80-84
(function() {
‘use strict’;
/******************************************/
/* The Share Button */
/******************************************/
// Create the button
videojs.ShareButton = videojs.Button.extend({
init: function( player, options ) {
// Initialize the button using the default constructor
videojs.Button.call( this, player, options );
}
});
// Set the text for the button
videojs.ShareButton.prototype.buttonText = ‘Share Video’;
// These are the defaults for this class.
videojs.ShareButton.prototype.options_ = {};
// videojs.Button uses this function to build the class name.
videojs.ShareButton.prototype.buildCSSClass = function() {
// Add our className to the returned className
return ‘vjs-share-button ‘ + videojs.Button.prototype.buildCSSClass.call(this);
};
// videojs.Button already sets up the onclick event handler, we just need to overwrite the callback
videojs.ShareButton.prototype.onClick = function( e ) {
// We need to stop this event before it bubbles up to “window” for our event listener below.
e.stopImmediatePropagation();
// There are a few ways to accomplish opening the overlay
// I chose to create and destroy the overlay to demonstrate
// the dispose method. Creating the component as a child is
// the direction I would choose.
this.overlay_ = new videojs.ShareContainer( this.player_, this.options_ );
// We need to add an event listener to close the overlay when the user clicks outside the overlay / player.
// Because we are destroying the overlay, we only need to listen to this once.
videojs.one( window, ‘click’, videojs.bind( this, this.windowClick ) );
// Add the overlay to the player
this.player_.addChild( this.overlay_ );
// Call the show method to apply effects and display the overlay
this.overlay_.show();
// Pause the video
this.player_.pause();
};
videojs.ShareButton.prototype.windowClick = function( e ) {
// Remove it from the parent (player)
this.player_.removeChild( this.overlay_ );
// Now remove it from memory.
// The dispose method removes the element and component.
this.overlay_.dispose();
// We no longer use this variable so release it.
delete this.overlay_;
};
/******************************************/
/* The Share Overlay */
/******************************************/
// Create the overlay and container for the links
videojs.ShareContainer = videojs.Component.extend({
init: function( player, options ) {
// call the parent constructor
videojs.Component.call( this, player, options );
}
});
// These are the child objects of this component. Add or remove to show/hide from the overlay
videojs.ShareContainer.prototype.options_ = {
children: {
‘facebookShare’: {},
‘twitterShare’: {},
‘pinterestShare’: {},
‘googlePlusShare’: {},
‘linkedInShare’: {}
}
};
// This function will be called by the videojs.Component constructor.
videojs.ShareContainer.prototype.createEl = function( tagName, props ) {
// Create the elements
// The black and blury overlay
var overlay = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-overlay’
});
// The container for the links/logos of the social sites we wish to offer
var container = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-container’
});
// this.contentEl is the element that children (links/logos) are added to.
this.contentEl_ = container;
overlay.appendChild( this.contentEl_ );
// This will become “this.el_”
return overlay;
};
/******************************************/
/* The Social Icons */
/******************************************/
// This is the base class for the share items. Each Icon can be passed a “Name” and an icon class.
videojs.OverlaySocialButton = videojs.Button.extend({
init: function( player, options ) {
videojs.Button.call(this, player, options );
}
});
videojs.OverlaySocialButton.prototype.createEl = function(type, props){
var el;
// Add standard Aria and Tabindex info
props = vjs.obj.merge({
className: this.buildCSSClass(),
‘role’: ‘button’,
‘aria-live’: ‘polite’, // let the screen reader user know that the text of the button may change
tabIndex: 0
}, props);
// ‘i’ is needed for the Font-Awesome icons
el = vjs.Component.prototype.createEl.call(this, ‘i’, props);
// if innerHTML hasn’t been overridden (bigPlayButton), add content elements
if (!props.innerHTML) {
this.contentEl_ = vjs.createEl(‘div’, {
className: ‘vjs-control-content’
});
this.controlText_ = vjs.createEl(‘span’, {
className: ‘vjs-control-text’,
innerHTML: this.options_.text || ‘Need Text’
});
this.contentEl_.appendChild(this.controlText_);
el.appendChild(this.contentEl_);
}
return el;
};
videojs.OverlaySocialButton.prototype.buildCSSClass = function() {
// We do not use the videojs.Button.prototype.buildCSSClass because we are not creating a typical component.
return ‘vjs-share-icon fa fa-‘ + ( this.options_.icon || this.options_.text.toLowerCase() ) + ‘-square fa-5x’;
};
// These are the indvidual buttons for each type of share.
// Twitter
videojs.TwitterShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.TwitterShare.prototype.options_ = { text: ‘Twitter’ };
videojs.TwitterShare.prototype.onClick = function() {
// Do Share action here
};
// Facebook
videojs.FacebookShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.FacebookShare.prototype.options_ = { text: ‘Facebook’ };
videojs.FacebookShare.prototype.onClick = function() {
// Do Share action here
};
// Pinterest
videojs.PinterestShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.PinterestShare.prototype.options_ = { text: ‘Pinterest’ };
videojs.PinterestShare.prototype.onClick = function() {
// Do Share action here
};
// Google Plus
videojs.GooglePlusShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.GooglePlusShare.prototype.options_ = { icon: ‘google-plus’, text: ‘Google+’ };
videojs.GooglePlusShare.prototype.onClick = function() {
// Do Share action here
};
// LinkedIn
videojs.LinkedInShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.LinkedInShare.prototype.options_ = { text: ‘LinkedIn’ };
videojs.LinkedInShare.prototype.onClick = function() {
// Do Share action here
};
/******************************************/
/* The Plugin Function */
/******************************************/
// This function will be called by video.js when it loops through all of the registered plugins.
var pluginFn = function( options ) {
// We need to pass off the options to the button.
var shareComponent = new videojs.ShareButton( this, options );
// Now lets add it to the player.
var shareButton = this.addChild( shareComponent );
};
videojs.plugin( ‘sharingPlugin’, pluginFn );
})();
“`
[/markdown]
Styling
At this point, we pretty much have a working plugin, albeit an unstyled working plugin. To acheive the blur effect we’ll need to apply some styling to the players root element and code up some pretty quick css.
In order to apply and remove the styles and class names we need on the root element and the display: table
we use to center all the icons, we overwrite the default show
, hide
, and dispose
methods.
[markdown]
“`javascript:Lines 111-160
(function() {
‘use strict’;
/******************************************/
/* The Share Button */
/******************************************/
// Create the button
videojs.ShareButton = videojs.Button.extend({
init: function( player, options ) {
// Initialize the button using the default constructor
videojs.Button.call( this, player, options );
}
});
// Set the text for the button
videojs.ShareButton.prototype.buttonText = ‘Share Video’;
// These are the defaults for this class.
videojs.ShareButton.prototype.options_ = {};
// videojs.Button uses this function to build the class name.
videojs.ShareButton.prototype.buildCSSClass = function() {
// Add our className to the returned className
return ‘vjs-share-button ‘ + videojs.Button.prototype.buildCSSClass.call(this);
};
// videojs.Button already sets up the onclick event handler, we just need to overwrite the callback
videojs.ShareButton.prototype.onClick = function( e ) {
// We need to stop this event before it bubbles up to “window” for our event listener below.
e.stopImmediatePropagation();
// There are a few ways to accomplish opening the overlay
// I chose to create and destroy the overlay to demonstrate
// the dispose method. Creating the component as a child is
// the direction I would choose.
this.overlay_ = new videojs.ShareContainer( this.player_, this.options_ );
// We need to add an event listener to close the overlay when the user clicks outside the overlay / player.
// Because we are destroying the overlay, we only need to listen to this once.
videojs.one( window, ‘click’, videojs.bind( this, this.windowClick ) );
// Add the overlay to the player
this.player_.addChild( this.overlay_ );
// Call the show method to apply effects and display the overlay
this.overlay_.show();
// Pause the video
this.player_.pause();
};
videojs.ShareButton.prototype.windowClick = function( e ) {
// Remove it from the parent (player)
this.player_.removeChild( this.overlay_ );
// Now remove it from memory.
// The dispose method removes the element and component.
this.overlay_.dispose();
// We no longer use this variable so release it.
delete this.overlay_;
};
/******************************************/
/* The Share Overlay */
/******************************************/
// Create the overlay and container for the links
videojs.ShareContainer = videojs.Component.extend({
init: function( player, options ) {
// call the parent constructor
videojs.Component.call( this, player, options );
}
});
// These are the child objects of this component. Add or remove to show/hide from the overlay
videojs.ShareContainer.prototype.options_ = {
children: {
‘facebookShare’: {},
‘twitterShare’: {},
‘pinterestShare’: {},
‘googlePlusShare’: {},
‘linkedInShare’: {}
}
};
// This function will be called by the videojs.Component constructor.
videojs.ShareContainer.prototype.createEl = function( tagName, props ) {
// Create the elements
// The black and blury overlay
var overlay = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-overlay’
});
// The container for the links/logos of the social sites we wish to offer
var container = videojs.createEl( ‘div’, {
className: ‘vjs-sharing-container’
});
// this.contentEl is the element that children (links/logos) are added to.
this.contentEl_ = container;
overlay.appendChild( this.contentEl_ );
// This will become “this.el_”
return overlay;
};
// To enable the video to blur, we must add some classess/styling to the root element.
videojs.ShareContainer.prototype.show = function() {
var techEl;
var playerEl;
// Do the default show method
this.el_.style.display = ‘table’;
// To get the blur effect, we need to add it to the tech element.
// But we do not want to waste our time with trying to blur a flash element.
if ( this.player_.techName != “Flash” ) {
techEl = this.player_.tech.el();
playerEl = this.player_.el();
// We have to set the clip property here because it is dependent on the size of the player
techEl.style.clip = ‘rect(0 0 ‘ + playerEl.offsetWidth + ‘px ‘ + playerEl.offsetHeight + ‘px)’;
// Add our class to blur the video.
videojs.addClass( techEl, ‘vjs-blur’ );
}
// Hide the controls, using opacity = 0 will use the default transition timing.
this.player_.controlBar.el().style.opacity = ‘0’;
this.el_.style.opacity = ‘1’;
};
videojs.ShareContainer.prototype.hide = function() {
var techEl = this.player_.tech.el();
// Do the default hide method
videojs.Component.prototype.hide.call( this );
// This time we don’t care if it is flash, html, youtube etc
techEl.style.clip = ”;
videojs.removeClass( techEl, ‘vjs-blur’ );
// Show the controls, using opacity = ” will use the default opacity.
this.player_.controlBar.el().style.opacity = ”;
};
videojs.ShareContainer.prototype.dispose = function() {
// Hide and remove classes from the tech element
this.hide();
// Do the default dispose method
videojs.Component.prototype.dispose.call( this );
};
/******************************************/
/* The Social Icons */
/******************************************/
// This is the base class for the share items. Each Icon can be passed a “Name” and an icon class.
videojs.OverlaySocialButton = videojs.Button.extend({
init: function( player, options ) {
videojs.Button.call(this, player, options );
}
});
videojs.OverlaySocialButton.prototype.createEl = function(type, props){
var el;
// Add standard Aria and Tabindex info
props = vjs.obj.merge({
className: this.buildCSSClass(),
‘role’: ‘button’,
‘aria-live’: ‘polite’, // let the screen reader user know that the text of the button may change
tabIndex: 0
}, props);
// ‘i’ is needed for the Font-Awesome icons
el = vjs.Component.prototype.createEl.call(this, ‘i’, props);
// if innerHTML hasn’t been overridden (bigPlayButton), add content elements
if (!props.innerHTML) {
this.contentEl_ = vjs.createEl(‘div’, {
className: ‘vjs-control-content’
});
this.controlText_ = vjs.createEl(‘span’, {
className: ‘vjs-control-text’,
innerHTML: this.options_.text || ‘Need Text’
});
this.contentEl_.appendChild(this.controlText_);
el.appendChild(this.contentEl_);
}
return el;
};
videojs.OverlaySocialButton.prototype.buildCSSClass = function() {
// We do not use the videojs.Button.prototype.buildCSSClass because we are not creating a typical component.
return ‘vjs-share-icon fa fa-‘ + ( this.options_.icon || this.options_.text.toLowerCase() ) + ‘-square fa-5x’;
};
// These are the indvidual buttons for each type of share.
// Twitter
videojs.TwitterShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.TwitterShare.prototype.options_ = { text: ‘Twitter’ };
videojs.TwitterShare.prototype.onClick = function() {
// Do Share action here
};
// Facebook
videojs.FacebookShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.FacebookShare.prototype.options_ = { text: ‘Facebook’ };
videojs.FacebookShare.prototype.onClick = function() {
// Do Share action here
};
// Pinterest
videojs.PinterestShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.PinterestShare.prototype.options_ = { text: ‘Pinterest’ };
videojs.PinterestShare.prototype.onClick = function() {
// Do Share action here
};
// Google Plus
videojs.GooglePlusShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.GooglePlusShare.prototype.options_ = { icon: ‘google-plus’, text: ‘Google+’ };
videojs.GooglePlusShare.prototype.onClick = function() {
// Do Share action here
};
// LinkedIn
videojs.LinkedInShare = videojs.OverlaySocialButton.extend({
init: function( player, options ) {
videojs.OverlaySocialButton.call( this, player, options );
}
});
videojs.LinkedInShare.prototype.options_ = { text: ‘LinkedIn’ };
videojs.LinkedInShare.prototype.onClick = function() {
// Do Share action here
};
/******************************************/
/* The Plugin Function */
/******************************************/
// This function will be called by video.js when it loops through all of the registered plugins.
var pluginFn = function( options ) {
// We need to pass off the options to the button.
var shareComponent = new videojs.ShareButton( this, options );
// Now lets add it to the player.
var shareButton = this.addChild( shareComponent );
};
videojs.plugin( ‘sharingPlugin’, pluginFn );
})();
“`
[/markdown]
And the CSS
[markdown]
“`css
/* We are using the font awesome set. */
@import url(‘//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css’);
/* This applies the blur filter to the video/preview etc */
.video-js .vjs-tech.vjs-blur {
-webkit-transition: .75s all;
transition: .75s all;
-webkit-filter: blur(5px);
filter: blur(5px);
}
/* Basic overlay styles, we are using the table-cell layout hack to center the content */
.video-js .vjs-sharing-overlay {
background: rgba( 0, 0, 0, 0.6 );
position: absolute;
top: 0;
left: 0;
opacity: 0;
-webkit-transition: .75s all;
transition: .75s all;
/* Root “Table” element for hack */
display: table;
height: 100%;
width: 100%;
}
/* Icon for our initial button */
.vjs-control.vjs-share-button {
cursor: pointer;
}
.vjs-control.vjs-share-button:before {
font-family: FontAwesome;
}
/* The styles for an on-screen button */
.video-js > .vjs-control.vjs-share-button {
position: absolute;
top: 1em;
right: 1em;
}
.video-js > .vjs-control.vjs-share-button:hover:before {
text-shadow: 0 0 .3em rgba( 255,255,255,0.8);
}
/* The styles for the button on a control bar */
.vjs-control-bar .vjs-control.vjs-share-button:before {
content: ‘\f064’;
}
.video-js > .vjs-control.vjs-share-button:before {
content: ‘\f064’;
font-size: 1.5em;
color: rgba(255,255,255,0.75);
background: rgba(7,20,30,.7);
padding: 10px;
height: 1em;
line-height: 1em;
border-radius: 15%;
width: auto;
}
/* Styling for the icons */
.vjs-sharing-container {
/* The table-cell of the hack */
display: table-cell;
height: 100%;
width: 100%;
vertical-align: middle;
text-align: center;
}
/* Icon body */
.vjs-sharing-container .vjs-share-icon {
font-size: 7em;
margin: .2em;
cursor: pointer;
position: relative;
}
/* The actual Icon */
.vjs-sharing-container .vjs-share-icon:hover:before {
color: #fff;
text-shadow: 0 0 .5em rgba(255,255,255,0.5);
}
/* Show the text that is usually hidden in a videojs.Button */
.vjs-sharing-container .vjs-share-icon .vjs-control-text {
position: absolute;
width: 100%;
font-size: .15em;
font-weight: 700;
text-align: center;
left: 0;
bottom: -1em;
clip: initial;
height: initial;
margin: 0;
}
/* To show/hide the onscreen button. Duplicate the showing / hiding of the control bar */
.vjs-has-started.vjs-user-inactive.vjs-playing > .vjs-control.vjs-share-button,
.video-js > .vjs-control.vjs-share-button {
display: block;
visibility: hidden;
opacity: 0;
-webkit-transition: visibility 1s, opacity 1s;
-moz-transition: visibility 1s, opacity 1s;
-o-transition: visibility 1s, opacity 1s;
transition: visibility 1s, opacity 1s;
}
.vjs-has-started > .vjs-control.vjs-share-button {
display: block;
visibility: visible;
opacity: 1;
-webkit-transition: visibility 0.1s, opacity 0.1s;
-moz-transition: visibility 0.1s, opacity 0.1s;
-o-transition: visibility 0.1s, opacity 0.1s;
transition: visibility 0.1s, opacity 0.1s;
}
“`
[/markdown]
10 Comments
Todd
It’s driving me crazy. How do you change the share button? This uses fa fa-share (http://fortawesome.github.io/Font-Awesome/icon/share/) and I want to alter that. I can’t find the place where that class is called, so I have no idea how to go about this. I found the place to change the sharing buttons, but I can’t narrow this down. Can you give me an idea where to look for this?
I also want to use this to display embed code and a short link to the video. If you have ideas how to add that to this overlay, throw those out, too. Much appreciated, both for this tutorial (which works quite well) and for any other advice you can give.
Todd
Got it. It’s in the CSS. content: ‘\f064’; is what’s there now. A quick trip over to the FontAwesome CSS (http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css) will give you the character code to use.
Next question! How can this icon only appear on rollover? I don’t want the share icon to be there the whole time.
Brian Kelley
Sorry, I must have missed the email notification for this.
I’ve added in an embed feature for the plugin where I work, though it pretty specialize for our customized player. I’ll see if I can throw together something to help you.
sufyan
I want to create field where i give my embed iframe and share link of my video in this share overlay how could i do this
Todd
The icon (along with the control bar at the bottom) goes away after a few seconds of not being rolledover. I should have just waited.
Anyhow, thanks for this tutorial! I’ll be putting it to good use soon.
Greg
This is nice, why does it require the _dev version of video.js? That’s a much larger file.
Brian Kelley
Thanks!
The dev version may or may not be required.
I’ve become accustomed to using the dev version and just use it by default to avoid any headaches associated with tracking down certain methods or variables named “a” and “o” which can be renamed randomly in the next release. I also use a custom build process that minimizes without renaming variables.
The videojs team has been pretty consistent on only revealing a very select group of core videojs functions. This makes it difficult to create a library agnostic plugin.
nerarosa
Not working with videojs 4.12. how to fix, please???
Steven Sheffey
It seems this tutorial doesn’t do anything after I put in the plugin code, nor does it give any errors. It simple does not work, I’m using video.js 4.10.2. Can anyone shed some light on how to get this to work?
Abhishek
Can anyone tell me how to make it work with videojs 4.12 ? or fix the bug?