A proposed plug-in capability
for overLIB
By Robert E. Boughner

1. Requirements for an overLIB plug-in

A plug-in capability for overLIB requires, at a minimum, that consideration be given to the following points.

  1. Be able to easily add new parameters, along with any values that may be associated with them.
  2. Be able to easily establish the runtime and default variables associated with these parameters as global variables and to set values for the default variables. Here, I refer to runtime variables as those variables that are prefaced with o3_ in the case of the normal overLIB code and prefaced with o for the mini version of overLIB. The default variables are those that are prefaced with ol_.
  3. During each invocation of an overLIB call, be able to easily set the runtime variables to the current value of the default variables. In addition, it must be easy to parse the overLIB command line for the appearance of these parameters, performing any necessary processing that may be required, and to continue with command line parsing after this processing is done. This command line parsing must be independent of any order that the parameters may appear.
  4. Be able to easily replace core routines with similar functioning routines that are needed to handle new parameters that are being added.
  5. Be able to call external routines, either at the very beginning or very end of normal core routine coding. This capability may be needed to do extra processing associated with the added parameters, either for setting variables associated with the added parameters or for cleaning up.
  6. In the case of the layer generation functions, be able to easily establish alternate pathways for processing. Currently there are at least three alternate pathways in overLIB -- simple popups, popups with captions, and popups that either specify full html code or have a background specification and three different cases to consider CSSOFF, CSSSTYLE, and CSSCLASS

2. Proposed Solution

The plug-in strategy that I propose here addresses each of these items as discussed here. Based on Erik's initial comments about the first release of this proposed plugin capability, I've made a few changes in its implementation to address some of his concerns.

The current version of overLIB assigns numerical values to all parameters, ranging from 1 to around 70 or 80. The only purpose that I can tell that this serves is to help in determining which parameter is specified on the command line during the parsing phase. However, it does have one practical benefit which was taken advantage of in the Beta releases of v3.51. All parameters occur with none or more additional associated parameter values. This feature was used to modify the start of parsing to eliminate the old requirement in overLIB that the very first argument in the call had to be either a text string or the parameter INARRAY so that any parameter can be specified as the first argument value. If you are supplying a string value, it must be the first argument. If you're not supplying a text string then any argument, including FUNCTION and INARRAY, can come first, but it is not required that these latter parameters must be first. This change is made possible by checking the typeof the argument and setting things up so that the following parsing block gets executed if that type is a 'number'.

I make mention of this because there have been some suggestions that this approach be scrapped in favor of assigning parameters string values that match their names. I don't recommend that this be done because for one thing the feature mentioned above would have to be modified (although not a big deal) and for another thing, I suggest letting javascript handle the numerical assignments in the following way:

  1. In each module, the parameters it will handle are passed as a comma delimited, lower-case string argument to the routine registerCommands(). This routine uses Javascript methods to generate numerical values associated with these parameters and to convert them to their capitalized form that one normally sees in overLIB. The global variable pmCnt (which stands for parameter count) is a running count of this numerical sequence, starting with the value of 1; the sequencing is simply continued when subsequent modules are loaded. I adopted this approach because:
    1. It shortens filesize.
    2. It is easier to type parameter names without worrying about whether the caps lock key is engaged or not. However, you can use capitals or mixed case in typing them if you wish. All of these will automatically be converted to an upper case form. This comment only pertains to the parameter description that is passed to the routine registerCommands; you won't be able to specify parameters on the overLIB command line, either as mixed case or lowercase, because its value won't be known and you'll get a javascript error. Only the capitalized names as used now in overLIB are known and won't cause any problems when used on the command line.
    3. You can easily add (or remove) additional parameters by just inserting (deleting) them in this command string.
    What this means is that any mini version of overLIB should not replace these parameters with their numerical values but should retain the capitalized parameters by name because their values can now change depending on the order the different plug-in modules are loaded.
  2. As an example, the core module uses the following code to define the commands that it will handle:
    
    var pmCnt = 1;
    var pMtr = new Array();
    coreCmds = 
     'inarray,caparray,sticky,background,noclose,caption,left,right,center,'+
     'offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,' +
     'border,status,autostatus,autostatuscap,height,closetext,snapx,snapy,' +
     'fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,' +
     'above,below,capicon,textfont,captionfont,closefont,textsize,' + 
     'captionsize,closesize,frame,timeout,function,delay,hauto,'+
     'vauto,closeclick,wrap,followmouse,'mouseoff,cssoff'; 
    registerCommands(coreCmds);
    

    where the function registerCommands is defined as

    function registerCommands(cmdStr) {
     if (typeof cmdStr != 'string') return;
     var pM = cmdStr.split(',');
     pMtr = pMtr.concat(pM);
     for (var i=0; i< pM.length; i++) 
      eval(pM[i].toUpperCase() + ' = ' + pmCnt++);
    }
    

    Because registerCommands is defined in the core module, subsequent modules can simply call this function with a string containing the commands it supports as it loads. As an example, the module which supports draggable popups has this as the first statement of the module: registerCommands('draggable,altcut,dragimg')

  3. The above code is what would be in the core library module which will have all of the capability that was found in v3.33 of overLIB, plus a few additional features that I feel should be in a core library module, such as mouseout/mouseoff, mousecapture capability with other scripts, and delay on mouseout, but none of the advanced features such as CSSSTYLE and CSSCLASS or a drop shadow effect. These would be incorporated into separate modules that could be loaded if the user requires that particular capability. By removing most of the comments, but not the fancy formatting that aids in understanding how the program logic works, I've managed to reduce the core file size to about 37K which is around the same size as v3.33, but with more functionality, and is only about 10K larger than v3.50 mini version. (If I perform the same formatting tricks that are used in the mini version, the file size saving is only around 3K for the core module and is certainly not worth the extra effort involved.)

    Most of the following modules would have coding similar to the above to continue the numerical values assigned to the parameters. As can be seen, this numbering will change with any change in the order of loading the modules or if more parameters are added and/or removed in a given module. However, by always referring to the parameters by their capitalized names there shouldn't be any problems since then one doesn't really care what their values are.

Nothing special is needed for item #2 listed above. This is already being done in overLIB now and the plug-in structure can easily continue with the same approach. A global variable is one that is defined outside any subroutine so that it is known to all subroutines. It makes no difference whether this definition comes at very beginning of the program, as it does now in overLIB, or if it is interspersed among the different plug-in modules just as long as the runtime and default variables are external to all subroutines. Note: Any variable defined within a subroutine without using var before it, also becomes a global variable. This feature is used in the registerCommands routine.

For items #3 - #6 above, I propose a registration type procedure. Based on the discussion of those items above, there are at least six different types of registrations that would be needed as outlined in the following table:
Types of function registrations
Typ Functionality Parameter
0 Replace core function FREPLACE
1 Run function before normal overLIB code is executed FBEFORE
2 Run function after normal overLIB code is executed FAFTER
3 Alternate pathway function FALTERNATE
* Functions which set runtime variables and handle command line parsing  
* Functions which are called after normal parsing is done for additional checking  

* No numbering is needed for these types of functions because the registration routines registerRunTimeFunction, registerCmdLineFunction, and registerPostParseFunction take care of these as explained below.

3. Registration Proceedure

The registration function is registerFunction(fnHookTo, fnRef, Typ, [optPm]) where

fnHookTo
name of the core module function to establish a hook to, a string value
fnRef
a reference to the function being applied. For Typ = 1 or 2, this can also be an array of function references.
Typ
a value from 0 through 3 associated with the functionality shown in the table above. The parameters given in the above table can be used to simplify remembering which one is which.
optPm
is an optional parameter whose value depends on the Typ of function being registered. When Typ is 3, this third argument will take one of the following values: CSSOFF, CSSCLASS, CSSSTYLE, or CSSW3C. Its purpose is to provide access to the particular alternate function being registered. When Typ is 1 or 2, the use of the third agrument is explained below. At present, this argument isn't used when Typ is 0.

The call to this function would be made at the very end of a plug-in module so that there won't be forward referencing of function names that may cause problems with the javascript interpreter. The following statements, which occur at the very end of the core module, illustrates how this function would be called:


registerFunction("ol_content_simple", ol_content_simple, FALTERNATE, CSSOFF);
registerFunction("ol_content_caption", ol_content_caption, FALTERNATE, CSSOFF);
registerFunction("ol_content_background", ol_content_background, FALTERNATE, CSSOFF);
		  

These calls are registering the basic layer-generation functions associated with the different types of popups. optPm is CSSOFF because this is the default for the core module.

When Typ is either 1 or 2, and there are several functions to be executed, these functions get run in the order in which they are registered. However, there may be situations where certain supporting routines must be run before others. In order to allow for modules to be called in any order, I've used the last variable optPm to indicate which functions the function being registered must come before in the execution chain. In this case, optPm can be either a single function reference or an array of function references (which doesn't include fnRef). The registration code re-arranges the order of the internal array which holds these function references so that fnRef comes before the function(s) specified by optPm, which are placed at the very end of this internal array. If optPm isn't specified (or is the null object), the function being registered just gets placed at the end of this internal array like it would normally. An example where order is important is the module which handles the DropShadow effect and the one that handles reference mark properties. For this case, a supporting routine in the DropShadow module must be executed before a particular function in the reference mark module. This is taken care of using the following code snippet at the end of the DropShadow module:


var before = (typeof rmrkPreface != 'undefined' ? rmrkPreface : null);
registerFunction("createPopup", generateShadow,FAFTER, before);
		  

Without the addition of this enhancement, popups were not positioned correctly if the Reference Mark module were loaded before the DropShadow module, because the Reference Mark routines were obtaining wrong information about the popup's width and height values.

4. The runTime and cmdLine arrays.
For item #3 above, I've defined two arrays, runTime and cmdLine, which hold function references to routines which will handle the tasks described there. Functions in the runTime array are called to set runtime variables to their associated default values, or possibly even initialize other global variables as needed. Functions in the cmdLine array handle parsing of parameter values on an overLIB command line. Functions are added to these arrays using either the registerRunTimeFunction or registerCmdLineFunction routines, respectively. Arguments to these two routines are either a function reference or an array of function references. The functions within these arrays are called from either setRunTimeVariables(), which occurs at the end of the initialization statements near the beginning of the overlib() routine, or from parseCmdLine(pf,i,ar) routine, which appears at the end of the series of checks within the parseTokens routine. This second function has three input arguments -- the first is the parsing prefix value, pf which is either ol_ or o3_ (since the routine must handle both parsing and setting of default values), the second argument is the index to which the input argument array has been parsed when the routine is called, and the last argument is the argument array to the overlib() routine. If there is a match, parseCmdLine should return the index where a match occurred, suitably incremented. If there is no match, it should just return the value -1.

A suggested format that can be used for the parsing routines is the following example, which is taken from the CSSSTYLE module:


function parseCSSStyleExtras(pf,i,ar) {
 var k = i;
 if (k < ar.length) {
  if (ar[k] == CSSSTYLE) { eval(pf + 'css = ' + ar[k]); return k; }
  if (ar[k] == FGCLASS) { eval(pf + 'fgclass = "' + ar[++k] + '"'); return k; }
  if (ar[k] == BGCLASS) { eval(pf + 'bgclass = "' + ar[++k] + '"'); return k; }
  if (ar[k] == TEXTFONTCLASS) { eval(pf + 'textfontclass = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CAPTIONFONTCLASS) { eval(pf + 'captionfontclass = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CLOSEFONTCLASS) { eval(pf + 'closefontclass = "' + ar[++k] + '"'); return k; }
  if (ar[k] == PADUNIT) { eval(pf + 'padunit = "' + ar[++k] + '"'); return k; }
  if (ar[k] == HEIGHTUNIT) { eval(pf + 'heightunit = "' + ar[++k] + '"'); return k; }
  if (ar[k] == WIDTHUNIT) { eval(pf + 'widthunit = "' + ar[++k] + '"'); return k; }
  if (ar[k] == TEXTSIZEUNIT) { eval(pf + 'textsizeunit = "' + ar[++k] + '"'); return k; }
  if (ar[k] == TEXTDECORATION) { eval(pf + 'textdecoration = "' + ar[++k] + '"'); return k; }
  if (ar[k] == TEXTSTYLE) { eval(pf + 'textstyle = "' + ar[++k] + '"'); return k; }
  if (ar[k] == TEXTWEIGHT) { eval(pf + 'textweight = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CAPTIONSIZEUNIT) { eval(pf + 'captionsizeunit = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CAPTIONDECORATION) { eval(pf + 'captiondecoration = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CAPTIONSTYLE) { eval(pf + 'captionstyle = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CAPTIONWEIGHT) { eval(pf + 'captionweight = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CLOSESIZEUNIT) { eval(pf + 'closesizeunit = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CLOSEDECORATION) { eval(pf + 'closedecoration = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CLOSESTYLE) { eval(pf + 'closestyle = "' + ar[++k] + '"'); return k; }
  if (ar[k] == CLOSEWEIGHT) { eval(pf + 'closeweight = "' + ar[++k] + '"'); return k; }
 }
 return -1;
}

I believe that when set up this way all parsing functions will be called, in sequence, to search for a match in the parameters supplied to the overLIB call. If you try to access some parameter that isn't defined in either the core module or one of the plug-in modules, you'll get a javascript error of some type. Also, coded in this manner, the routine will serve to both parse and set default variables. There are several examples of how this capability can be employed to toggle some behavior on or off in the Command References for the Core Module and the Reference Mark module.

Routines within the postParse array must be written so that they satisfy the following condition: if they execute without problems, return a true value, otherwise return false to signal an error and the overLIB call will be aborted at this point. The rationale for having this array is to make checks which can only be done after all of the command line has been parsed and do some further processing. An obvious use of this is in conjunction with the cross frame STICKY support contained in the overlib_crossframe.js module to set the appropriate value of the overLIB global variable fnRef. Functions are added to this array via the registerPostParseFunction routine, which takes either a single function reference or an array of function references. Like the other cases, this call should be placed near the end of a module to avoid forward referencing of function references. Functions in the postParse array are accessed through a call to the postParseChecks() function.

Here is an example of how the postParseChecks() is currently being used in the core module:


. . .
parseTokens('o3_', overlib.arguments);
if (!postParseChecks()) return false;
. . .
5. Calling Functions
Once a function has been registered, it is called using runHKFun(fnHookTo, Typ, other arguments required). The last argument in the above call are the arguments that would normally be supplied in a normal overLIB call. Depending on the call this argument may be absent. For example, the call to the overLIB function hideObject() from within the nd() function is done as follows:
if (over != null) runHKFun("hideObject",FREPLACE,over);

which replaces the normal overLIB call hideObject(over). If no functions have been registered for fnHookTo when Typ equals 0 or 3, then runHKFun() defaults to executing the core function whose name is fnHookTo with arguments given by the last argument in the call to runHKFun(). When Typ is 1 or 2, then runHKFun() just returns.

For all of this to work, appropriate calls to runHKFun() must be inserted at the appropriate places within the core module. Those core functions which can only be changed by overloading them (i.e., supplying functions which have the same name in subsequent modules) are:

  • olMouseMove - Formerly mouseMove
  • no_overlib
  • overlib
  • nd
  • set_background
  • cClick
  • compatibleframe
  • setOLParams
  • parseTokens
  • layerWrite
  • repositionTo
  • reorderMouseCapture - Function which switches the order of mouse capture execution.
  • opt_FRAME
  • opt_FUNCTION
  • opt_NOCLOSE
  • fnReference - Object constructor for registration proceedure
  • registerFunction - Main function registration routine
  • runHKFun - Main entry point for calling functions to be executed
  • argToString - Supporting routine used by registerHook
  • reorder - Another supporting routine used by registerHook
  • registerCommands - Routine that defines global variables for use by overLIB
  • registerRunTimeFunction - A function to add routines to the internal runTime array
  • registerCmdLineFunction - A function to add routines to the internal cmdLine array
  • registerPostParseFunction - A function which adds routines to the internal postParse array
  • isFunction - Checks that its arguments are function references. Used by the previous three registration functions. Returns true if its argument is a function reference otherwise it returns false.

These routines were not made part of the registration procedure because they are either external calls to overLIB or are not likely to be changed in any subsequent module add-in. If this changes in the future then some of them could probably be added to the registration procedure if needed. It highly recommended that you don't overload functions but work through the registration process so that some consistency can be maintained.

Core module routines which are affected by the registration process include:

  • olMain - Formerly was overlib3xx.
  • hideObject
  • ol_content_background
  • ol_content_simple
  • ol_content_caption
  • createPopup - A new function, which occurs in olMain, that was added to make the plug-in procedure easier to implement.
  • disp
  • placeLayer
  • showObject
  • cursorOff - Function which is needed for the mouseout/mouseoff feature

The layer generation functions can also be replaced if needed. However, if they are, those functions are automatically associated with the CSSOFF parameter, i.e, they will be called when the parameter CSSOFF is active.

6. Info Object

As a prelude to a possible future requirement that a module needs to have a certain minimum core level of support to operate correctly, I've added an Info object with the properties given in the table below. Authors of plugins may use this information as they see best. Please let me know if you think that some other information should also be included. If you do, then please also specify your reasons why that information should be included.

At present, the global variable olInfo holds this information. I'm certain that there will be changes made to this object as further development of a plugin strategy evolves.

The Info Object
Property Type Default Value
version number 4.00
simpleversion number 400
major number 4.0
minor number 0.0
prerelease boolean true
revision number 0
7. Modules

Using the approach outlined here, I have developed the modules listed in the table below. As far as I know, these can all be called in any order, although this hasn't been tested extensively and further testing may indicate that this isn't the case.

Module Module name(*) Functionality Command Reference
1 overlib.js Core module which supports all basic overLIB functionality1 Core Module Commands
2 overlib_dropscroll.js DropShadow and overLIB popup scrolling support Shadow commands
3 overlib_mark.js Reference Mark support Reference Mark Commands
4 overlib_mousecapture.js Swap order that mouse caputre functions get executed. Mouse Capture Command
5 overlib_cssclass.js CSSCLASS styling support CSSCLASS Styling Commands
6 overlib_cssstyle.js CSSSTYLE styling support CSSSTYLE Styling Commands
7 overlib_cssw3c.js Support for styling popups entirely through CSS Style Rules as reccommended by the W3C. CSSW3C Styling Commands
8 overlib_font.js Generates popup content using FONT tags that control the font face, color and size.1 FONT Style Commands
9 overlib_draggable.js Support for draggable popups Draggable Commands
10 overlib_crossframe.js Cross frame STICKYS support Cross Frame STICKY
11 overlib_debug.js2 Debug support for overlib Debug Operation
12 overlib_overtwo.js2 Popup-in-popup support Popup in Popup Commands
 

* Download a copy of all modules as a zip file

1In order to move closer towards standards compliance, the core module uses SPAN tags with inline style rules to control the look of a popup's content. The default text size unit is 'px'. Thus, the default variables for TEXTSIZE, CAPTIONSIZE, and CLOSESIZE are set to 11 rather than 1 as done in older versions of overLIB. For backward compatiblity, the FONT Style module has been introduced which will render popups according to older versions of overLIB.

2This module must be downloaded separately. It isn't included in the zip file that contains all of the modules.

 

 

Just a few comments with regard to these modules:

  • These modules all work in the new browser released by Opera v7 Final. The CrossFrame Sticky support module, overlib_crossframe.js, doesn't function in this browser if frames are nested. Non-nesting frames work without problems.
  • Use of CSSCLASS with a DropShadow effect doesn't display correctly in Netscape 4.x. If there is no DropShadow effect being applied, then CSSCLASS works fine. I believe this is a shortcoming in this browser. I didn't do anything to correct this deficiency because it wasn't worth the effort considering that the Netscape 4.x browser is being used less and less frequently, and one can get around the difficulty by using either CSSSTYLE or just a plain popup.
  • There are problems in the Netscape 4.x browser when you use popups that employ CSSSTYLE and CSSCLASS parameters on the same page. As soon as the popup which uses CSSSTYLE is shown, it will mess up the display of the popups which use CSSCLASS. If the page is manually reloaded, this problem clears up until the popup using CSSTYLE is shown again. I recommend that you avoid this situation entirely by using one or the other of these parameters for your popups. This problem doesn't seem to occur if normal popups are used with those having CSSSTYLE.
  • The definition of over for IE has been changed so that it doesn't contain the 'style' property in its definition, i.e. it refers to just the overDiv container object like it does for Netscape 4.x and Netscape 6+, which has necessitated the appropriate coding modifications to handle this. This change was made because in developing the above modules, the code snippet var ovObj = (olIe4 ? o3_frame.all['overDiv'] : over) kept popping up because a reference to the container object was frequently needed . This change has simplified coding somewhat.
  • The module overlib_cssw3c.js allows popups to be styled exclusively via CSS Style rules. It is designed to be used with more recent browsers that are CSS compliant. I specifically disable this capability in Netscape 4.x because of its numerous quirks in applying CSS Style rules that I didn't want to be bothered with trying to make it work in that browser. It employs a much simpler table structure for the popup than a normal overLIB popup, which is fully explained in the CSSW3C Command Reference.
  • There are major problems of overlib popups displaying correctly in IE5 on a Macintosh platform. Since my development platform is primarily a Windows PC, it is difficult for me to figure out how to overcome some of these obstacles. Hopefully, someone who works normally with a Mac will be willing to undertake some of these investigations.

As a final comment, it should be mentioned that any developer who wishes to develop a module for possible future inclusion in the overlib utility should strive to write that module so that it will work in any order that it is called. There are numerous examples how this can be done in the modules that have been developed thus far. The Reference Mark module has an example of a suggested coding style in the routine rmrk_placeLayer that replaces the core function placeLayer. This is just a recommendation; each developer is free to write modules in their own style of coding. If the module can't be loaded independently of other modules, then the precise order that is required should be clearly stated.

8. Examples using this approach

Examples using these modules together are given below where I also indicate the statements that would go in the HEAD section to include the modules.

  1. Reference Mark and DropShadow
    
    <SCRIPT TYPE="text/javascript" SRC="overlb.js"></SCRIPT>
    <SCRIPT TYPE="text/javascript" SRC="overlib_mark.js"></SCRIPT>
    <SCRIPT TYPE="text/javascript" SRC="overlib_dropscroll.js"></SCRIPT>
    		  
  2. DropShadow and Draggable
    
    <SCRIPT TYPE="text/javascript" SRC="overlib.js"></SCRIPT>
    <SCRIPT TYPE="text/javascript" SRC="overlib_dropscroll.js"></SCRIPT>
    <SCRIPT TYPE="text/javascript" SRC="overlib_draggable.js"></SCRIPT>
    
  3. W3C Styling of popups
    
    <SCRIPT TYPE="text/javascript" SRC="overlib.js"></SCRIPT>
    <SCRIPT TYPE="text/javascript" SRC="overlib_cssw3c.js"></SCRIPT>
    		  




On this page
Requirements
Proposed Solution
Registration
runTime and cmdLine Arrays
postParse Array
Calling Functions
Info Object
Modules
Examples


Command References Files
Core Commands
DropShadow Commands
Reference Mark Commands
Frame Support Commands
Mouse Capture Command
Draggable Commands
FONT Style
CSSCLASS Commands
CSSSTYLE Commands
CSSW3C Commands Debug Commands
Popup-in-popup Commands


Email links
Robert E. Bougnner


Status
Plug-in Proposal
Third revision:
01-17-2003
overLIB Logo Symbol
Copyright Erik Bosrup 1998-2002.
All rights reserved.