How To make a JAVASCRIPT extension cross browser
Author : Jbuenol
From TechnologicalWiki
Contents |
[edit] Introduction
JAVASCRIPT is a web lenguage which can be used in all browsers. JAVASCRIPT is the way to get and manipulate data values and the DOM inside the browser engine. The main weakness of JAVASCRIPT is the little accessibility to resources and OS services. This article shows how to create new and useful JAVASCRIPT extensions which can be used from the browser. These extensions allow to the browser accessing to native code, which is closer of the OS. Then, It would be possible to call native methods from the JavaScript layer and even, to notify the events, to the JavaScript layer. What is an event ? An event is anything which occurs in the native layer (e.g. if a class which represents the Address Book has been developed, an event would be a arriving email ).
[edit] What is JNEXT ?
JNEXT is a free cross-browser platform, with that, it's possible to extend the JAVASCRIPT engine in a easy way. JNEXT is in continous update, and it's compatible with more browsers along time. The compatibility a day on October 1, 2008 is the following one:
| Windows | MAC OS | Linux | |
| Internet Explorer | OK | :o | :o |
| Firefox 2 & 3 | OK | OK | OK |
| Google Chrome | OK | NOT | NOT |
| Safari | OK | OK | NOT |
| Opera | OK | ? | OK |
| Konqueror | NOT | NOT | SOK |
| Epiphany | NOT | NOT | ? |
OK - Tested and works fine. SOK - Needs fixing (does not work, or works partially). ? - Not tested yet, should be tested soon. :o - Not considered interesting. Will be tested only if time permits. NOT - Browser does not exist for this OS
[edit] Installation
You can download it from this link
Two packages are available.
- A setup for Windows can be downloaded.(automatically installs JNEXT for IE, Firefox, Safari, Opera and Google Chrome) executable file
- If you wish to download the source code, the link below will download the source code that compiles on Windows, Linux and Mac OS/X. (compiling the Windows ActiveX component ( WAP Version ) currently requires the standard version of VS2005 or VS2008). The sources also contain a sample project to illustrate how to easily create your own JNEXT extension.
If you use the source code, you can find three diferent proyects.
- The first one is a plugin for ActiveX ( Windows ) support, with that you can obtain a ocx object which you must register in the OS to use from the browser. (Win-ActiveX folder) - (Js2n proyect)
- The second one is a plugin for npapi (Wap Version) for MAC. (Mac-npapi folder)
- The third one is a plugin for npapi for Windows / Linux. (Win-Linux-npapi folder) - (nprn proyect)
The plugin for npapi for windows generates a .dll library which is used by the browser.
Below is a table that shows the location of the directory where you have to put the generated dll.
| Firefox | c:\Program Files\Mozilla Firefox\plugins\jnext\ |
| Opera | c:\Program Files\Opera\programs\plugins\jnext\ |
Note : The ocx file will be generated in a folder selected by the user from VS but it's necessary to register it through the command from the windows console :
regsvr32 "Path of the ocx object"
[edit] Structure
The structure built using the JNEXT platform as way to extend the JAVASCRIPT engine, is compound by three diferents layers.
- The first one, situated at the bottom of the structure, is the native code layer. That layer is where the feature is implemented, ie, the layer where the system calls are. That is the nearest layer to the OS.
- The second one, situated in the middle of the structure (between the native code layer and the JAVASCRIPT layer), is made up of the JNEXT plugins (the ocx object and the npapi dll).This layer is the bridge between each JAVASCRIPT object and the native code.
- The third one, situated at the top of the structure, is made up of the JAVASCRIPT wrapper classes. Each elemento which we want to extend, it must be represented by a js file. For example, if we have a native dll which is responsible for representing the Address Book, we will have to create a AddressBook.js file which represents to the Address Book in the browser.
[edit] Site authorization
The set of URLs that are authorized to access JNEXT libraries for a specific browser is defined in a file named auth.txt. The structure of auth.txt is as follows:
url1 lib1[,lib2,...,libn] url2 lib1[,lib2,...,libn] . . . urln lib1[,lib2,...,libn]
...where url1,url2 etc. are a list of urls that are authorized to access JNEXT libraries on the browser and lib1, lib2 ... are the specific JNEXT libraries that each specific url is allowed access to. Specifying '*' for a library enables that url to access all available JNEXT libraries that are installed on the system.
Note that the installed auth.txt file enables any local file full access to JNEXT since the assumption is that you trust the HTML files on your system. Change the settings in auth.txt if you wish to further limit access to JNEXT from your Web browser
Also note that a different copy of auth.txt is used for each browser type. This policy might be changed in the future so that only one file will determine authorizations for all browser types. Below is a table that shows the location of the auth.txt file for various browser types on Windows (location may vary if browser was installed in a location other than the defualt):
Browser type Location of auth.txt
| Internet Explorer | c:\Program Files\Optimistec\JNEXT\auth.txt |
| Firefox | c:\Program Files\Mozilla Firefox\plugins\jnext\auth.txt |
| Opera | c:\Program Files\Opera\programs\plugins\jnext\auth.txt |
| Safari | c:\Program Files\Safari\Plugins\jnext\auth.txt |
| Netscape Navigator 9 | c:\Program Files\Netscape\Navigator 9\plugins\jnext\auth.txt |
[edit] Getting Started
Creating a JNEXT plugin consists of two stages. Fortunately they are both simple:
- Stage 1, you create the native extension.
- Stage 2, you create the JavaScript wrapper class for the extension created in stage 1.
We are going to show how to create a extension from scratch to use it in the browser. When you have installed the JNEXT plugin for each one of the browsers, you will have not any problem to use your extensions in all the browsers. They will be compatible with them. Now, you must create the native extension and the wrappers. we are going to see how to make the AddressBook extension.
[edit] Creating a Native Extension
A native extension is a simple dll which must export the following functions :
/* Dll definition ( def file ) */
SetEventFunc : To get events in the browser from the native extensions.
InvokeFunction : To access to the native functions from the JavaScript wrappers.
A class which represents to the object must be implemented. In our case AddressBook. It must implement the JSExt interface.
InvokeMethod( NameMethod ); : Method which is executed when a method is called
from JavaScript to be executed in native code.
CanDelete( void ); : Standard function.
void NotifyEvent( NameEvent ); : Method which notify to JavaScript Layer
when a event occurrs.
The following two callbacks that have to be implemented. They are invoked from plugin.cpp:
onGetObjList(): returns the identifier of the class.
onCreateObject( strClassName, strObjId ) : Returns a pointer to the created extension object
strClassName : Name of the class requested to be created
Valid named are those that are returned in onGetObjList
strObjId : The unique object id for the class
Example :
// First, constants for methods required.
const char* szmethod1 = "method1";
const char* szmethod2 = "method2";
...
const char* szmethodN = "methodN";
// This method is to know from the plugin the identity of the object.
char* onGetObjList( void )
{
return (char*)szADDRESSBOOK;
}
// Object constructor.
AddressBook::AddressBook(const string& strObjId)
{
m_strObjId = strObjId;
...
// Body of the constructor
}
// This method is executed when is required a object construction.
JSExt* onCreateObject( const string& strClassName, const string& strObjId,const string& params )
{
// Given a class name and identifier, create the relevant object.
if ( strClassName != szADDRESSBOOK )
{
return NULL;
}
return new AddressBook( strObjId );
}
// This method throw the event toward the upper layer.
{
string strEvent = szEvent;
string strFileEvent = m_strObjId + " " + strEvent;
SendPluginEvent(szEvent, m_pContext );
}
// This method manages what to do when a method of the native class is called.
string AddressBook::InvokeMethod( const string& strFullCommand )
{
string strRetVal;
vector<string> arParams;
g_tokenize( strFullCommand, " ", arParams );
// This function allows to separate the parameters
// 0 : Method name.
// 1 - N : Function parameters.
string strCommand = arParams[ 0 ];
// If method name is szmethod1, the Action 1 will be executed.
if ( strCommand == szmethod1 )
{
// Action 1
strRetVal = szOK;
}
// If method name is szmethod2, the Action 2 will be executed.
else if(strCommand == szmethod2 )
{
// Action 2;
strRetVal = szOK;
}
...
// If method name is szmethodN, the Action N will be executed.
else if(strCommand== szmethodN )
{
// Action N;
strRetVal = szOK;
}
else
{
strRetVal = szERROR + m_strObjId + " :Unknown method";
}
return strRetVal;
}
[edit] Creating a JavaScript wrapper class
This is the part nearest to the browser. For each one of the objects which have been developed, we have to create a JavaScript wrapper to represent the native object. It's named with the js file. A js file is the way which is used by the browsers to import JavaScript code. To import this files, write the following header in the body of the html file :
<script src="nameOfTheJSFile.js"></script> ... in our case AddressBook.js
Now, your wrapper definition is loaded.
Let's see how we should implement a wrapper for our example. Only one function is necessary to initialize the object correctly :
init() : This method is called when a wrapper JavaScript is created from the html code
through the new construtor, and it's responssible of the initialize the way of
communication between the layers.
(AddressBook-JavaScript <-----> AddressBook-native).
/* AddressBook.js file */
// The function header is a object definition in this case. This is the form in which // JavaScript defines a object for the DOM.
function AddressBook()
{
var self = this;
self.init = function()
{
// g_JNEXTDispatcher is the jnext plugin wrapper.
// Through of it JavaScript will communicate with native layers
// The first step is loading the library.
if ( !g_JNEXTDispatcher.require( "AddressBook" ) )
{
return false;
}
// The second step is create a instance of the object.
self.m_strObjId = g_JNEXTDispatcher.createObject( "AddressBook" );
if ( self.m_strObjId == "" )
{
alert( "error initializing AddressBook" );
return false;
}
// This is the form how JNEXT makes a register of an event.
g_JNEXTDispatcher.registerEvents( self );
}
self.Function1 = function()
{
// Body of the function 1
}
self.Function2 = function()
{
// Body of the function 2
}
...
self.FunctionN = function()
{
// Body of the function N
}
// m_strObjId indicates a unique ID. It serves to identify the wrapper JavaScript
// class from the jnext plugin
self.getId = function()
{
return self.m_strObjId;
}
self.m_strObjId = "";
self.init();
self.parameter1 = self.getValueParameter1();
self.parameter2 = self.getValueParameter2();
...
self.parameterN = self.getValueParameterN();
}


