9

I've been working on video.js for like a day so I'm a real newbie when it comes to this stuff Today I just wanted to add a button that will switch between two videos. I did it in jQuery quick and easy. But I would rather do it in javascript to better understand video.js as a whole.

Done so far:
1. I have downloaded the most recent version of video.js from github.
2. Player is working great.
3. Read through the guides.
4. Tried their example code.

Their Code for button creation:

 var myButton = video.controlBar.addChild('MyButton', {
        text: 'Press Me',
        children: {
        buttonChildExample: {
        buttonChildOption: true
       }
      }
     });

Error from console : Uncaught TypeError: undefined is not a function

So no addChild() is defined which is odd because its in their docs/api.

Does anyone know how to add buttons to their controlbar ? Any help would be appreciated and if you need any more info let me know. Thanks.

UPDATE:
1) I have wrapped the above code in a videojs.ready() as the documentation suggests. But still to no avail.

2) component = new window['videojs'][componentClass](this.player_ || this, options);
in video.dev.js (line 1655) throws the error "uncaught TypeError: undefined is not a function"

3) Evaluating new window['videojs'] in console gave me the error " TypeError: The element or ID Supplied is not valid. (videojs).

Again thanks for your help in adavanced.

user3171119
  • 91
  • 1
  • 1
  • 4
  • 1
    My advice is to setup a http://jsfiddle.net/ example, so would be easier to people to answer – catalinux Jan 13 '14 at 19:45
  • Check this out, I wrote about this exact topic -> https://nikushx.com/blog/2019/05/21/creating-custom-components-with-video-js/ – Nikush May 21 '19 at 00:18
  • Follow Step by Step approach to add button with custom Icon : https://stackoverflow.com/a/68647317/10498074 – zukayu Aug 04 '21 at 10:53

4 Answers4

15

The undefined is coming from the fact that MyButton is not a vjs.Component. The documentation around this is a little unclear and it took me a while to understand what is going on.

The documentation states that the first argument is the "class name or instance of a child to add" - it's referring to a JavaScript class rather than a CSS class. The correct way to add a button is as follows:

var myButton = video.controlBar.addChild('button', {
    text: "Press me",
    // other options
  });

myButton.addClass("html-classname");

This will add the following to your controlbar:

<div class="vjs-control html-classname" aria-live="polite" tabindex="0">
  <div class='vjs-control-content">
    <span class="vjs-control-text">Press me</span>
  </div>
</div>
clinton3141
  • 4,751
  • 3
  • 33
  • 46
12

Starting with v5:

var videoJsButtonClass = videojs.getComponent('Button');
var concreteButtonClass = videojs.extend(videoJsButtonClass, {

  // The `init()` method will also work for constructor logic here, but it is 
  // deprecated. If you provide an `init()` method, it will override the
  // `constructor()` method!
  constructor: function() {
    videoJsButtonClass.call(this, videojsInstance);
  }, // notice the comma

  handleClick: function(){
    // Do your stuff
  }
});

var concreteButtonInstance = videojsInstance.controlBar.addChild(new concreteButtonClass());
    concreteButtonInstance.addClass("vjs-" + name);

PROFIT!

deepelement
  • 2,457
  • 1
  • 25
  • 25
  • Could you please describe this a bit more detailed? How to add this button to `controlBar`? How to assign `click` event handler? Thanks. – oleynikd Nov 11 '15 at 23:18
  • FYI, you can totally dig into the button DOM and attach to the 'click' event, but this doesn't capture 'invoke' and stuff like that across frameworks. Just use there inline override to keep out of the 'danger zone' – deepelement Nov 11 '15 at 23:32
  • 1
    Thanks, very useful - if only VideoJS would do proper documentation! More details in the v5 changelist: https://github.com/videojs/video.js/wiki/5.0-Change-Details#videojs-50-subclassing-examples. – And Finally Feb 05 '16 at 15:24
1

(This answer is relevant to videojs 4.9.1)

To add a custom button to videojs's control bar, you need to create a vjs component and add it to the controlbar's children in the player setup options. Here's a setup where I add 3 custom components to the control bar (playebackSpeedPopoverMenu, selectBitrateControlButton, and verticalVolumeMenuButton):

var setup = {
                  'techOrder' : ['html5', 'flash'],
                  'controls' : true,
                  'preload' : 'auto',
                  'children':{
                      'controlBar': {
                          'children': {
                              'playbackSpeedPopoverMenu': {},
                              'selectBitrateControlButton': {src:videosrc},
                              'verticalVolumeMenuButton': {},
                              'volumeControl': false,
                              'muteToggle':false,
                              'liveDisplay':false,
                          }
                      }
                  };
var player = new vjs.Player(vjs.el("id_of_my_video_element_note_that_theres_no_poundsign"),
                            setup,
                            function() {
                               //this is your ready function
                            }));

The reason the controlbar compnents are declared like 'selectBitrateControlButton': {src:videosrc} is because whatever is included in the object literal will get injected into the components init() function as the options parameter. This works great working with the videojs.dev.js file, not the closure-compiled cdn version (that's a whole 'nother story) These are some examples of defining vjs components that appear on the controlbar:

https://github.com/videojs/video.js/blob/master/src/js/control-bar/play-toggle.js#L8 https://github.com/videojs/video.js/blob/master/src/js/control-bar/fullscreen-toggle.js#L8

I fully recommend getting the latest code from the videojs git repo on git hub, which will make it easier to look up the various sources in your IDE. The ui component framework isn't terribly complicated and can be mastered in a couple days with some patient sourcecode drilling.

Sammie Edwards
  • 111
  • 1
  • 4
0

I tried the 2 top answers here and they both worked but didn't address other problems, such as the button not showing text or an icon and missing a title.

Here's my solution:

const customInvertFilterButton: videojs.Button = this.video.controlBar.addChild('button')

customInvertFilterButton.addClass('vjs-custom-invert-filter-button')
customInvertFilterButton.addClass('vjs-icon-spinner')
customInvertFilterButton.setAttribute('title', 'Invert')

customInvertFilterButton.on('click', () => {
  this.invertFilter = !this.invertFilter
  customInvertFilterButton.setAttribute('title', this.invertFilter ? 'Uninvert' : 'Invert')
})

Here, the vjs-icon-spinner class is a vjs icon. All their icons are here:

https://videojs.github.io/font

Optionally, to read more about their icons check this out (I didn't find it overly useful):

https://github.com/videojs/font

Finally, the icons were rendering too small. You can adjust their size and look with this SCSS:

.vjs-custom-invert-filter-button {
  cursor: pointer;

  &.vjs-icon-spinner:before {
    font-size: 1.8em;
    line-height: 1.67;
  }
}

Hope it helps. Much love in HIM! Yes, J^e^s^u^s

OPTIONAL ADDITIONAL INFO FOR MORE ICONS

The VJS icon set is a subset of the Material Icons set.

Its possible to use any Material Icon as follows:

// https://github.com/google/material-design-icons/tree/master/font
// https://google.github.io/material-design-icons/#setup-method-2-self-hosting

@font-face {
  font-family: 'VJS Material Icons';
  font-style: normal;
  font-weight: 400;
  src: local('Material Icons'), local('MaterialIcons-Regular'), url(/assets/fonts/vjs-mat-icons/MaterialIcons-Regular.ttf) format('truetype');
}

.vjs-material-icons {
  font-family: 'VJS Material Icons', sans-serif;
  font-weight: normal;
  font-style: normal;
  font-size: 24px; /* Preferred icon size but also suggests 18px, 24px, 36px, 48px */
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;

  /* Support for all WebKit browsers. */
  -webkit-font-smoothing: antialiased;
  /* Support for Safari and Chrome. */
  text-rendering: optimizeLegibility;

  /* Support for Firefox. */
  -moz-osx-font-smoothing: grayscale;

  /* Support for IE. */
  font-feature-settings: 'liga';
}

The above font file can be downloaded from https://github.com/google/material-design-icons/tree/master/font

Then to use any Material icon:

// https://fonts.google.com/icons

.vjs-custom-brightness-down-button {
  cursor: pointer;

  &.vjs-icon-brightness-down {
    font-family: 'VJS Material Icons', serif;
    font-weight: normal;
    font-style: normal;

    &:before {
      content: "\e1ad"; // this relates to a specific icon
      font-size: 1.4em;
      line-height: 1.67;
    }
  }
}

Note that the unicode code seen in the CSS content property can be gotten from https://fonts.google.com/icons

And finally, the .ts for this:

private initCustomBrightnessDownButton() {

  const customBrightnessDownButton: videojs.Button = this.video.controlBar.addChild('button')

  customBrightnessDownButton.addClass('vjs-custom-brightness-down-button')
  customBrightnessDownButton.addClass('vjs-material-icons')
  customBrightnessDownButton.addClass('vjs-icon-brightness-down')
  customBrightnessDownButton.setAttribute('title', 'Brightness -')

  customBrightnessDownButton.on('click', () => {
    this.brightness = this.brightness > 10 ? this.brightness - 10 : this.brightness
  })
}
danday74
  • 52,471
  • 49
  • 232
  • 283