Browser Plugin Detection

Have you ever wondered how to detect plugins loaded by your browser using JavaScript? In this tutorial you will learn to detect plugins in IE way and for other browsers. You will also learn to use Lazy Function Definition pattern to optimize your object detection code.

Where Plugin Information is Stored?

navigator.plugins of type PluginArray contains information related to plugins which are loaded with your browser. Each item in navigator.plugins is actually Plugin object. Try it yourself by typing navigator.plugins in Firebug console. You will see following line as output.

PluginArray { 0=Plugin, 1=Plugin, 2=Plugin, more...}

Then try navigator.plugins[ 0 ] in console.

Plugin { 0=MimeType, 1=MimeType, length=2, more...}

Click on above line in Firebug console. It will take you to the DOM tab as shown below.

Plugin Object

Plugin Detection Code

The important thing to note in the above figure is the “name” property. This is where the name of the plugin is stored. So we can detect a plugin by looping over navigator.plugins and search the input string in navigator.plugins[ i ].name for the required plugin. Here’s source code of it.

function detectPlugin( name ) {
   name = name.toLowerCase();
 
   for( var i = 0; navigator.plugins[ i ]; ++i ) {
      if( navigator.plugins[ i ].name.toLowerCase().indexOf( name ) > -1 )
         return true;
   }
 
   return false;
}

  • The parameter “name” is the name of the plugin whose existance you want to check.
  • On second line all alphabets of parameter name are lowered.
  • A for loop is used to iterate over navigator.plugins (PluginArray). Note the condition of for loop. navigator.plugins[ i ] will terminate the loop when it will return undefined. Actually when you pass over the upper bound of PluginArray, it will start returning undefined.
  • The navigator.plugins[ i ].name of the plugin is lowered before comparing it with the parameter “name”. indexOf is used to find the parameter name in navigator.plugins[ i ].name. It returns -1 if parameter name is not found. Otherwise it return the index from where the name starts in navigator.plugins[ i ].name.
  • true is returned if plugin name is found.
  • If no plugin found in navigator.plugins, return false after the loop.

Detect Plugins in IE Way

As usual this code won’t gonna work in IE. There’s an ActiveXObject which can help us to detect plugin existance. ActiveX is Microsoft’s proprietary technology used to create ActiveX controls which act like plugins in other browsers.

“ActiveX is a framework for defining reusable software components in a programming language-independent way.” ‐ Wikipedia

“ActiveX controls, mini program building blocks, can serve to create distributed applications working over the Internet through web browsers. Examples include customized applications for gathering data, viewing certain kinds of files, and displaying animation.” ‐ Wikipedia

To detect a plugin, all you have to do is instantiate ActiveX control using ActiveXObject. It will throw an exception if control don’t exist. But there’s a problem with this technique. Each ActiveX control is uniquely identified with a string. For example flash control is identified with “ShockwaveFlash.ShockwaveFlash”. Here’s source of it.

function detectActiveX( name ) {
   try {
       new ActiveXObject( name );
       return true;
   } catch( e ) {
       return false;
   }
}

Lazy Function Definition pattern

I have created two functions which detech plugins in IE and other browsers. To avoid browser detection everytime you need to use them, create a browser independent method in an object. Also place the above functions (detectPlugin and detectActiveX) in this new object.

var Plugin = {
   detect: function( name ) {
      if( navigator.plugins ) {
         this.detect = this.detectPlugin;
      }
      else {
         this.detect = this.detectActiveX;
      }
 
      return this.detect( name );
   },
 
   detectPlugin: function( name ) {
      name = name.toLowerCase();
 
      for( var i = 0; navigator.plugins[ i ]; ++i ) {
         if( navigator.plugins[ i ].name.toLowerCase().indexOf( name ) > -1 )
            return true;
      }
 
      return false;
   },
 
   detectActiveX: function( name ) {
      try {
         new ActiveXObject( name );
         return true;
      } catch( e ) {
         return false;
      }
   }
};

“detect” is the new browser independent method in the above object. detect method simply checks the existance of navigator.plugins. If it exist then it replaces the “detect” identifier to point to detectPlugin. Otherwise it points to detectActiveX. Note that object detection will be done only once when this method runs for the first time. Afterwards it will always call detectPlugin or detectActiveX directly without running any browser detection code. This pattern is called Lazy Function Definition.

Finally add the following code in the Plugin object as well before detect method.

var Plugin = {
   controls = {
      flash: "ShockwaveFlash.ShockwaveFlash",
      silverlight: "AgControl.AgControl",
      quicktime: "QuickTime.QuickTime"
   },
 
   checkIE: function() {
      if( navigator.plugins ) this.isIE = false;
      else this.isIE = true;
   },
 
   detect: function( name ) {
   //rest of the code same as above...
};

“controls” property is added for ActiveX control names. As I mentioned before that ActiveX controls are identified with a unique string. To avoid passing the unique identifier of control to detect method, you can use Plugin.controls.flash.

checkIE method is used to detect if a browser supports standard PluginArray or ActiveXObject. It sets the isIE variable to true if ActiveX is supported. Here’s the example code of using this Plugin object.

Plugin.checkIE();
 
if( Plugin.isIE ) {
   Plugin.detect( Plugin.controls.flash );
} else {
   Plugin.detect( "Flash" );
}

As you can see you still need to write code to check Plugin.isIE. To avoid writing this kind of code, you can create methods in Plugin object specific to plugins (like flash, silverlight) which you want to detect frequently. For example you want to detect flash many times in your JavaScript application. Here’s what you can to write less code.

var Plugin = {
   //code above same as before...
 
   detectFlash: function() {
      this.checkIE();
 
      if( !this.isIE )
         return this.detect( "Flash" );
      else
         return this.detect( this.controls.flash );
   }
};

With this new method, you only need to call it and check if it returns true or not. true means Flash plugin is loaded.


comments powered by Disqus