How to let jwPlayer plugins interact with other plugins and javascript

This tutorial was originally written for version 4 of the jwPlayer. Version 5 has made alterations to the plugin architecture, so not everything in this tutorial may still be applicable.

When writing plugins for the jwPlayer, you can build them in such a way that they can interact with other plugins and with javascript. In this tutorial, I’ll describe how to do this by building a very simple plugin and then improving upon it in three steps. The method I’ll describe is the one I have used in two of my plugins: the Embed Plugin and the TipJar Plugin.

The tutorial consists of four steps:

  1. Creating a basic plugin
  2. Letting your plugin pass info to other plugins
  3. Calling functions on other plugins
  4. Control your plugin with javascript

And I have created a zip-file containing all examples shown in this tutorial.

Prior knowledge

For this tutorial I assume that you have some knowledge about building a jwPlayer plugin, and that you understand the basic principles of events and listeners. (If you don’t know how to build a plugin, please check out the excellent documentation on longtailvideo.com: Version 4 Plugins and Version 5 Plugins.)

1. Creating a basic plugin

The plugin I’ll create for this tutorial is really simple: it adds a button to the controlbar to show and hide a window containing some information. I’ve called the plugin InfoPlugin. The plugin contains only two MovieClips: a window called infoWin and a button icon called infoBtn. The plugin looks like this: (click the i-button with to toggle the window)

Basic InfoPlugin without events


And here’s the code for InfoPlugin; I’ll explain it below.

package nl.jaron.jwplayer.tutorials.events.info {
	
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import com.jeroenwijering.events.*;
import nl.jaron.util.debug.*;

public class InfoPlugin extends MovieClip implements PluginInterface {

    private var view:AbstractView;//Reference to the view object
	private var clip:MovieClip;//reference to this plugin's stage
	private var win:MovieClip;//reference to information window
	
	//constructor function; does nothing
	public function InfoPlugin() {
	}
	
	//initialization function called by SWFLoader after adding plugin
	public function initializePlugin(vw:AbstractView):void {
		view = vw;
		clip = this;
		initWindow();
		addButton();
	};
	
	private function initWindow() {
		win = clip.infoWin;
		win.visible = false;
		win.x = win.y = 10;
	}
	private function addButton() {
		var btn:MovieClip = clip.infoBtn;
		try {
			view.getPlugin('controlbar').addButton(btn,'infoButton',clickHandler);
		} catch (err:Error) {
			btn.visible = false;
		}
	}

	private function clickHandler(evt:MouseEvent) { 
		win.visible = !win.visible;//toggles window visibility
	};

}

}

How does it work?

Since this article isn’t meant as a basic plugin-tutorial, I’ll only describe briefly what I’m doing here.

initializePlugin

When the plugin is initialized by the player, the function initializePlugin is called. First, this function assigns a variable to the player’s view and the plugin’s stage. Then it calls two functions: initWindow and addButton.

initWindow

initWindow assigns a reference to the information window on the plugin’s stage to the variable win. win is then set to invisible and positioned at (10,10). At this point you would normally do stuff like assigning some dynamic text (set through flashvars or in your config file) to the information window as well, but for the sake of simplicity I’ve chosen not to do any configuration, and to let the window simply display some sample text. Also, I haven’t bothered to align the window to the middle of the player.

addButton

addButton creates a reference to the button icon (an italic i) on the plugin’s stage, and adds that button to the player’s controlbar. It assigns the function clickHandler to be the function in our plugin that’s going to be executed when the i-button is clicked.

clickHandler

clickHandler only does one thing: it toggles the visibility state of win, the information window.

2. Letting your plugin pass info to other plugins

Now that we have build this functionality, we might want to keep track of how often the information window is being opened. We could make our plugin record that itself, but it would be more logical to make a separate statistics plugin that also gathers information about which files are being loaded, played, etcetera.

Using (custom) events

We’ll let this plugin gather its information using events. A lot of events are already defined by the jwPlayer, but you can also let your plugin send its own custom event to the player’s view. The view then simply passes that event on to all objects that have registered themselves as a listener for that specific event.

So here’s what we’re going to do. First, we’ll define names for two events to be sent when the information window is shown or hidden. Then we’ll change the InfoPlugin to send these events. And finally we’ll create a new plugin called Logger, and make it receive and act upon these events.

Before turning to the code, let’s look at the player, this time with the two plugins:

Version 2: InfoPlugin sends events, Logger plugin receives events

Defining the events

Every event uses a string to identify itself. I have put the identifiers for our events in a separate class called InfoEvent, to make it possible for other plugins to import that class and have access to the identifiers. The class only defines two constants and looks like this:

package nl.jaron.jwplayer.tutorials.events.info {

public class InfoEvent {

	/** Identifiers for the accepted event types. **/
	public static const SHOW_INFO:String = "show_info";
	public static const HIDE_INFO:String = "hide_info";

	//Constructor; does nothing.
	public function InfoEvents() {}

}
}

Changing InfoPlugin

The only thing we have to change in the InfoPlugin is adding two lines to the clickHandler function: depending on the current visibility status of win we determine the identifier of the event to be sent, and then we send it to the view:

private function clickHandler(evt:MouseEvent) { 
	var infoEvent:String = (win.visible ? InfoEvent.HIDE_INFO : InfoEvent.SHOW_INFO);
	view.sendEvent(infoEvent);
	win.visible = !win.visible;//toggles window visibility
};

Creating the Logger Plugin

First I’ll show the code for Logger, and then I’ll explain the most important points:

package nl.jaron.jwplayer.tutorials.events {
	
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import com.jeroenwijering.events.*;
import nl.jaron.util.debug.*;
import nl.jaron.jwplayer.tutorials.events.info.InfoEvent;

public class Logger extends MovieClip implements PluginInterface {

    private var view:AbstractView;//Reference to the view object
	private var clip:MovieClip;//reference to this plugin's stage
	private var infotxt:TextField;//reference to textfield
	
	//constructor function; does nothing
	public function Logger() {
	}
	
	//initialization function called by SWFLoader after adding plugin
	public function initializePlugin(vw:AbstractView):void {
		view = vw;
		
		clip = this;
		infotxt = clip.infoTF;
		clip.x = 220;
		clip.y = 10;
		
		view.addViewListener(InfoEvent.SHOW_INFO,showHandler);
		view.addViewListener(InfoEvent.HIDE_INFO,hideHandler);
	};
	
	private function showHandler(evt:ViewEvent):void {
		infotxt.text = "show infoWindow";
	}
	
	private function hideHandler(evt:ViewEvent):void {
		infotxt.text = "hide infoWindow";
	}

}

}

Importing the InfoEvent class

In order to be able to reference the event identifiers, we have to make sure the Logger class imports our event class InfoEvent (this step wasn’t neccessary for the InfoPlugin since the InfoPlugin and InfoEvent classes reside in the same package).

Initializing the Plugin

Upon initialization, the plugin assigns a variable to the TextField (infoTF) on the plugin’s stage. Then it adds a listener to the view for the ViewEvent with the identifier InfoEvent.SHOW_INFO, and declares the function showHandler to be executed when that event is received. The same is then done for the hide event.

showHandler and hideHandler

The eventhandler functions only display a message in the plugin’s TextField. In a real logging plugin, this is where you would write your data to a database.

Alternative solution: Using literals instead of constants for identifiers

In the Logger plugin, we use the constant InfoEvent.SHOW_INFO as identifier, which is simply a reference to the string “show_info” as defined in the InfoEvent class. Should we not have access to the InfoEvent class (which can be the case if you don’t have the source code of another plugin), than we could also simply use the identifier string: view.addViewListener("show_info",showHandler); As we’ll see later, this is also the only way to sent an identifier using javascript. So if you want your plugin to be accessible by others, you should also include the string-values of your identifiers in your documentation.

3. Calling functions on other plugins

In the jwPlayer version 4.3 and up, interaction through actionscript is made very easy: using the view’s getPlugin method, you can simply call any public function in another plugin. To demonstrate this, I’ve built a third plugin called Sender. Sender adds another window to the player, with a button in it. Clicking the button sends a function call to the InfoPlugin. Let’s se it in action:

Version 3: InfoPlugin sends events, Logger plugin receives events, Sender plugin calls public function on InfoPlugin

Changes to InfoPlugin

To make this possible, only one line of code has to be changed in InfoPlugin:

public function clickHandler(evt:MouseEvent=null) { 

By making the function clickHandler public, we allow it to be called by other objects. Also, I have given the evt argument a default value of null. This way, we can call the function without having to pass it an event.

The Sender plugin

Let’s take a look at the Sender plugin:

package nl.jaron.jwplayer.tutorials.events {
	
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import com.jeroenwijering.events.*;
import nl.jaron.jwplayer.tutorials.events.info.InfoEvent;

public class Sender extends MovieClip implements PluginInterface {

    private var view:AbstractView;//Reference to the view object
	private var clip:MovieClip;//reference to this plugin's stage
	
	//constructor function; does nothing
	public function Sender() {
	}
	
	//initialization function called by SWFLoader after adding plugin
	public function initializePlugin(vw:AbstractView):void {
		view = vw;
		
		clip = this;
		clip.x = 220;
		clip.y = 100;
		
		clip.callBtn.addEventListener(MouseEvent.CLICK, this.callBtnHandler);
	};
	
	private function callBtnHandler(evt:MouseEvent):void {
		try {
			view.getPlugin('infoplugin').clickHandler();
		} catch(e) {
		}
	}

}

}

In this plugin, function callBtnHandler is set up as the function to be called when the Button callFunction is clicked. Through the view, it gets a reference to the InfoPlugin, and calls its clickHandler function. The argument passed to the getPlugin function is the name of the plugin as used in the flashvar, converted to lowercase (and without .swf or any directory path). To prevent errors in older player versions, please make sure to wrap the getPlugin function in a try-catch block.

4. Control your plugin with javascript

The getPlugin method works great for actionscript interaction. Unfortunately, it does not have a javascript equivalent. But when we use events in a clever way, we can also make it possible for javascript to control your plugin. And as a bonus: this also works in older versions of the player.

To achieve this, we’ll modify the InfoPlugin to start listening for events itself. We’ll also change the Sender plugin to send events to the view that InfoPlugin can listen for.

One more time, let’s first look at the player – now with the InfoPlugin, the (unmodified) Logger plugin, the Sender plugin and javascript support:

Final version: InfoPlugin sends and receives events, Logger plugin receives events, Sender plugin sends events and calls function directly, javascript can send events to show and hide

Changing InfoPlugin

Though not that much has changed, I’ll post the complete code of the InfoPlugin, since this will be the final version:

package nl.jaron.jwplayer.tutorials.events.info {
	
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import com.jeroenwijering.events.*;
import nl.jaron.util.debug.*;

public class InfoPlugin extends MovieClip implements PluginInterface {

    private var view:AbstractView;//Reference to the view object
	private var clip:MovieClip;//reference to this plugin's stage
	private var win:MovieClip;//reference to information window
	
	//constructor function; does nothing
	public function InfoPlugin() {
	}
	
	//initialization function called by SWFLoader after adding plugin
	public function initializePlugin(vw:AbstractView):void {
		view = vw;
		clip = this;
		initWindow();
		addButton();
		
		view.addViewListener(InfoEvent.SHOW_INFO,showHandler);
		view.addViewListener(InfoEvent.HIDE_INFO,hideHandler);
	};
	
	private function initWindow() {
		win = clip.infoWin;
		win.visible = false;
		win.x = win.y = 10;
	}
	
	private function addButton() {
		var btn:MovieClip = clip.infoBtn;
		try {
			view.getPlugin('controlbar').addButton(btn,'infoButton',clickHandler);
		} catch (err:Error) {
			btn.visible = false;
		}
	}

	public function clickHandler(evt:MouseEvent=null) { 
		var infoEvent:String = (win.visible ? InfoEvent.HIDE_INFO : InfoEvent.SHOW_INFO);
		view.sendEvent(infoEvent);
	}
	
	private function showHandler(evt:ViewEvent):void {
		win.visible = true;
	}
	
	private function hideHandler(evt:ViewEvent):void {
		win.visible = false;
	}

}

}

initializePlugin

Just like in the Logging plugin, I've added listeners for the SHOW_INFO and HIDE_INFO events, and linked those to the new showHandler and hideHandler functions. The only thing these new functions do, is showing or hiding the information window win.

clickHandler

This is the most interesting change: instead of directly toggling the window's visibility, clickHandler now only sends an HIDE_INFO or SHOW_INFO event to the view. And since we've set up the plugin as a listener for these events, it will receive the events it has just sent itself, and show or hide the information window accordingly.

Changes to the Sender plugin

public function initializePlugin(vw:AbstractView):void {
	view = vw;
	
	clip = this;
	clip.x = 220;
	clip.y = 100;
	
	clip.showBtn.addEventListener(MouseEvent.CLICK, this.showBtnHandler);
	clip.hideBtn.addEventListener(MouseEvent.CLICK, this.hideBtnHandler);
	clip.callBtn.addEventListener(MouseEvent.CLICK, this.callBtnHandler);
};

private function showBtnHandler(evt:MouseEvent):void {
	view.sendEvent(InfoEvent.SHOW_INFO);
}

private function hideBtnHandler(evt:MouseEvent):void {
	view.sendEvent(InfoEvent.HIDE_INFO);
}


The Sender plugin now has two new Show and Hide buttons, which each get linked to an event handler function. The buttons simply send events for showing or hiding the information window to the view, just like the InfoPlugin does. And since we modified the InfoPlugin to listen for these events, it shows and hides the window.

Javascript interaction

Finally, the javascript interaction works much the same like the actionscript interaction: it simply calls a function on the swf-object to send an event identifier:

<script src="text/javascript">
document.getElementById('player').sendEvent('hide_info')
</script>


Support for handling this sendEvent function is already built in in the jwPlayer. However, the javascript communication has a few caveats. Javascript will off course not be able to use the actionscript class InfoEvent, so it has to use the string literal for the identifier: "show_info" instead of InfoEvent.SHOW_INFO. Furthermore, although you can add listeners in javascript for the jwPlayer's default events, as far as I know it is not possible to add listeners for custom events. Also, please remember that (due to security issues) you have to view the plugin online or through a local webserver to make javascript interaction possible. (And viewing the player online or through a webserver has the side-effect that by default all plugins are loaded from Longtail's central repository. This can be circumvented by changing the basedir variable in the player's SPLoader class to an empty string. The player.swf in the tutorial's zip file already has this change made to it.)

Summary

So, to sum things up, if you want your plugin to be able to interact with other plugins or javascript:

  • Send custom events to the view
  • Make a separate class defining those events
  • Import that class in other plugins you want to listen for your plugin's events
  • Make that class available for other developers...
  • ...Or at least document the event identifiers' string literals
  • For easy actionscript interaction, create public functions (and document them)
  • For javascript interaction, make sure your plugin listens for events itself

Download the tutorial files

You can download the sourcecode of all examples in this tutorial. Feel free to use it however you like.

3 comments on “How to let jwPlayer plugins interact with other plugins and javascript”

  1. Good tutorial really. Thanks a lot.

  2. Thanx for this tuto, i found the answer for my problem
    sorry for my bad english

  3. i need fla of player. nice tuts

    zegt you can share player.fla?

Would you use this solution? Do you know a better one? Leave a comment.

Fields marked with * are required

*
(will not be shown)
*