Download Source Files
Main Files
Control Examples
Example CJEM Advanced Control
Introduction
This is a script I developed many years back, around 2002. It is an event manager for JavaScript that fixes many issues the browser wars created and makes developing controls with events on web pages, fun and easy. I couldn't come up with a catchy name for it, so I just called it (CJEM) Custom JavaScript Event Manager. I decided to release it to the public because development with JavaScript has been increasing especially over the past two years. Maybe someone will find this article beneficial for their web development. I hope you enjoy it.
Why Did I Create It?
I was tired of using the browser event manager, only to find out my code stopped working with different versions and browsers. The managers were also very buggy and did not implement everything that was reported in the online documentation. Lack of naming conventions between browser companies with objects in JavaScript, HTML, CSS and DOM has caused many developers to go crazy, writing cross compatible code. Is it so hard to stick to a standard naming structure?
Why Should You Use It?
It is a very lightweight, simple, highly organized and thought out script that has been in production for many years. It makes life easy when creating web page control events with JavaScript and DOM. I also tried to follow the standard documentation online and create what was missing or not uniform. Using this script can make you more organized with your JavaScript source files. The script also works in most if not all browsers and versions like Internet Explorer 5+, FireFox, Chrome, Opera, Safari, Konqueror and Netscape if you dare.
Class Properties and Methods
Title: Custom JavaScript Event Manager (CJEM) - Class |
Namespace: Global |
Description: The main event manager class for creating window, document and control events. |
Properties | Description | Return Value |
Events | This property variable contains an array collection of events, class names, control ids, event types, callbacks and other custom settings. The property is mostly used for internal information for the event manager, but has been left open to allow developers to extend it. | Array Collection |
Method(s) | Description | Return Value |
Add (ClassObject, ControlID, EventType, EventCallBack, TotalInstance, Wait, UserObject) | Adds a window, document or control event to the manager for monitoring. When the event fires, the manager will call the event callback method. The Add method also supports adding more than one EventCallBack by using the method again. | Nothing |
Parameters (Marked with * are required)
* ClassObject (string) - The name of window, document, class or variable that holds the method to call.
* ControlID (string) - The id for the window, document or control to attach the event to.
* EventType (string) - The event type name you want to monitor, onmousedown , onmouseup , onmousemove , onblur , etc.
* EventCallBack (function) - The function() to call back when the event occurs.
TotalInstance (integer) - The total times you want the event to occur. 0 = Complete, null or undefined is never ending.
Wait (integer) - The total milliseconds to wait before calling the EventCallBack method. Null or undefined is instant.
UserObject (object) - A custom parameter for adding anything you want that will be transfered to the EventCallBack .
|
|
Remove (ControlID, EventType, EventCallBack) | Removes a window, document or control event from the manager for monitoring. This will stop the event from being broadcasted to the EventCallBack. | Nothing |
Parameters (Marked with * is Required)
* ControlID (string) - The id for the window, document or control that the event was attach to.
* EventType (string) - The event type name onmousedown , onmouseup , onmousemove , onblur , etc., that you would like to stop monitoring.
EventCallBack (function) - The function() that was used for callback. If you specify a unique one, it will only remove that one. Null or undefined will result in all similar event types to be removed.
|
Implementation
To implement CJEM is rather easy, just include the external 'cjem.js
' file in a web page header. Then use the add or remove methods of the CJEM class to create or remove event handlers. CJEM allows for complete separation of JS from HTML. No more adding in-line JS to HTML tags to create DOM events. Everything is handled nice and easy in the JS file.
Example 1 - Capture Document Events
The first example captures the document onmousedown
event. Relatively simple example, but created in less than 10 seconds. When you click anywhere on the document, it will display an alert
message telling you what occurred.
function DocumentMouseDownHandler(src)
{
alert("You captured the '" + src.EventType +
"' from the control: '" + src.ControlID + "'");
}
$CJEM.Add('document','document', 'onmousedown', DocumentMouseDownHandler);
Example 2 - Capture Window Event + Control Event
This example captures the window load event only once. It then adds two events to the span
, onmousemove
and onmouseout
. When you mouse over the span
, it will change the innerHTML
of the span
, then it will change it back on mouse out. In order to capture a control event, the document window must be loaded first. Also the window load might fire more than once in different browsers, so the best thing to do is set the TotalInstance
to 1
. This makes sure it only fires once.
function WindowLoadHandler(src)
{
$CJEM.Add('document','example', 'onmousemove', DocumentExampleMouseMoveHandler);
$CJEM.Add('document','example', 'onmouseout', DocumentExampleMouseOutHandler);
}
function DocumentExampleMouseMoveHandler(src)
{
$O(src.ControlID).innerHTML = 'Mouse Over This! - Mouse is Over';
}
function DocumentExampleMouseOutHandler(src)
{
$O(src.ControlID).innerHTML = 'Mouse Over This!';
}
$CJEM.Add('window','window','onload', WindowLoadHandler, 1);
Example 3 - Event Manager Total Instances
I felt the need to add a total instance parameter to the add method. You may find the need to use it, like the previous window load method. In this example, we will create a span
that will onmousedown
only 3 times, then stop. It will display an alert
and tell you how many instances left.
function WindowLoadHandler(src)
{
$CJEM.Add('document','example', 'onmousedown', DocumentExampleMouseDownHandler, 3);
}
function DocumentExampleMouseDownHandler(src)
{
alert("You captured the '" + src.EventType + "' from the control: '" +
src.ControlID + "'. Total Instances Left: '" + src.TotalInstance + "'");
}
$CJEM.Add('window','window','onload', WindowLoadHandler, 1);
Example 4 - Event Manager Wait
I also felt the need to add a wait
parameter to the add
method. The wait
parameter allows you to specify an integer of milliseconds to wait until the event should fire the EventCallBack
method. This gives you the freedom to create some unique controls that fire later even though the event already occurred. With the example below, you can set the textbox
to how many milliseconds, then click on the span
to wait. Remember 1000 milliseconds is 1 second.
function WindowLoadHandler(src)
{
var msec = $O('mseconds').value;
$CJEM.Add('document','example', 'onmousedown',
DocumentExampleMouseDownHandler, null, msec);
}
function DocumentExampleMouseDownHandler(src)
{
alert("You captured the '" + src.EventType +
"' from the control: '" + src.ControlID + "'");
}
$CJEM.Add('window','window','onload', WindowLoadHandler, 1);
Example 5 - Attaching More EventCallBacks
You can also attach more than one EventCallBacks
to the same event. This allows the handler to call separate methods on one event, for example like below. When the span
is clicked, it will fire the DocumentMouseDownHandler1
and DocumentMouseDownHandler2
methods. The neat thing is you can set delays also like the previous example. So DocumentMouseDownHandler2
will fire 2 seconds after the first alert. This allows for major power, especially with AJAX.
function WindowLoadHandler(src)
{
$CJEM.Add('document','example', 'onmousedown', DocumentMouseDownHandler1);
$CJEM.Add('document','example', 'onmousedown', DocumentMouseDownHandler2, null, 2000);
}
function DocumentMouseDownHandler1(src)
{
alert("You captured the first '" + src.EventType +
"' from the control: '" + src.ControlID + "'");
}
function DocumentMouseDownHandler2(src)
{
alert("You captured the second '" + src.EventType +
"' from the control: '" + src.ControlID + "'");
}
$CJEM.Add('window','window','onload', WindowLoadHandler, 1);
Example 6 - Bubbling Events
When an event fires, it will bubble through all parent containers. This is a great feature implemented by most major browsers. The problem is browsers have different ways to handle it. Handling the scope and naming conventions of methods for cancellation can be a real pain. So I decided to fix these issues and make it simple and easy, the way it should have been done. To stop event bubbling, just 'return true
' in your EventCallBack
method. If you want event bubbling to occur, just return false
or don't add a return. This not only makes it easy to stop bubbling, but fixes the scope issues.
function WindowLoadHandler(src)
{
$CJEM.Add('document','document', 'onmousedown', DocumentMouseDownHandler);
$CJEM.Add('document','span1', 'onmousedown', Span1MouseDownHandler);
$CJEM.Add('document','span2', 'onmousedown', Span2MouseDownHandler);
}
function DocumentMouseDownHandler(src)
{
alert("You captured the '" + src.EventType +
"' from the control: '" + src.ControlID + "'");
}
function Span1MouseDownHandler(src)
{
alert("You captured the '" + src.EventType +
"' from the control: '" + src.ControlID + "'");
}
function Span2MouseDownHandler(src)
{
alert("You captured the '" + src.EventType +
"' from the control: '" + src.ControlID + "'");
return true;
}
$CJEM.Add('window','window','onload', WindowLoadHandler, 1);
Creating Your EventCallBack Method
Once you have created your EventCallBack
method, CJEM will pass your method one parameter object. It will contain the following:
ClassObject
- The name of window, document, class or variable that holds the method to call. ControlID
- The id for the window, document or control to attach the event to. EventType
- The event type name, onmousedown
, onmouseup
, onmousemove
, onblur
, etc. TotalInstance
- The total instances left before the event stops handling. Wait
- The total milliseconds to wait before calling your EventCallBack
method. UserObject
- A custom parameter for adding anything you want that will be transfered to the EventCallBack
. event
- This is the window event object.
The parameter object above will give you tons of information helping you to create remarkable controls. Scoping will no longer be an issue to access information like the class name, control id, parent id, event type, window event, etc.
Prevent Default Event Behavior
Someone requested me to show an example of how to prevent the default behavior of an element. Adding the code below to a callback handler will stop the event from firing its default behavior. The example shows a standard link element that will not work on single click or mouse down, but only on double click. Using the code below will enable this to work.
function WindowLoadHandler(src)
{
$CJEM.Add('document','link', 'onmousedown', mousedownhandler);
$CJEM.Add('document','link', 'onclick', mousedownhandler);
$CJEM.Add('document','link', 'ondblclick', doubleclickhandler);
}
function mousedownhandler(src)
{
if(src.event.preventDefault){ src.event.preventDefault()}
else{src.event.stop()};
src.event.returnValue = false;
src.event.stopPropagation();
return true;
}
function doubleclickhandler(src)
{
window.location = $O(src.ControlID).href;
}
$CJEM.Add('window','window','onload', WindowLoadHandler, 1);
Custom JavaScript Event Manager - Source Code
Below is the Custom JavaScript Event Manager (CJEM) source code. I will also upload a compressed version later for use on the web.
var $N={R:function(N){var o=window;var x=false;
for(var a=N.split('.');a.length>0;){var s=a.shift();
if(a.length==0){if(o[s]){x=true;}}if(!o[s]){o[s]={};}o=o[s];}if(x){return 1;}}};
function $O(S){return document.getElementById(S);}
function $NU(O){if(O==undefined||O==null){return true;}
else{if(typeof(O)=='string'&&O==''){return true;}else{return false;}}}
var $CJEM = {
Events: null,
Add: function(ClassObject, ControlID, EventType,
EventCallBack, TotalInstance, Wait, UserObject) {
if ($NU(this.Events)) { this.Events = new Array(); }
if ($NU(this.Events[ControlID])) { this.Events[ControlID] = {}; }
var EventItem = this.Events[ControlID];
if ($NU(EventItem[EventType])) { EventItem[EventType] = new Array(); }
var Handlers = EventItem[EventType];
Handlers.push({'ClassObject': ClassObject, 'ControlID': ControlID,
'EventType': EventType, 'EventCallBack': EventCallBack,
'TotalInstance': TotalInstance, 'Wait': Wait, 'UserObject':
UserObject, event: null});
$CJEM.Register(ControlID, EventType);
},
Remove: function(ControlID, EventType, EventCallBack) {
if ($NU(this.Events)) { return; }
var EventItem = this.Events[ControlID];
if ($NU(EventItem)) { return; }
var Handlers = EventItem[EventType];
if ($NU(Handlers)) { return; }
if(!$NU(EventCallBack))
{
for (var i = 0; i < Handlers.length; i++) {
if (EventCallBack == Handlers[i].EventCallBack)
{ Handlers[i] = null; Handlers.sort(); Handlers.pop(); }
}
}
else
{
Handlers = [];
}
if(Handlers.length==0)
{
Handlers = null;
EventItem[EventType] = null;
delete EventItem[EventType];
$CJEM.UnRegister(ControlID, EventType);
}
},
UnRegister: function(ControlID, EventType) {
switch (ControlID) {
case 'window': window[EventType] = null; break;
case 'document': document[EventType] = null; break;
default:
var control = $O(ControlID);
if($NU(control)){ return; }
control[EventType] = null; break;
}
},
Register: function(ControlID, EventType) {
switch (ControlID) {
case 'window': window[EventType] = function(e)
{ $CJEM.Caller(e, ControlID, EventType); }; break;
case 'document': document[EventType] =
function(e) { $CJEM.Caller(e, ControlID, EventType); }; break;
default:
var control = $O(ControlID);
if($NU(control)){ return; }
control[EventType] = function(e)
{ $CJEM.Caller(e, ControlID, EventType); }; break;
}
},
Caller: function(e, ControlID, EventType) {
if (!e) { e = window.event; }
var EventItem = this.Events[ControlID];
var Handlers = EventItem[EventType];
if($NU(Handlers)){ return; }
for (var i = 0; i < Handlers.length; i++) {
var EventObject = Handlers[i];
EventObject.event = e;
if(!$NU(EventObject.TotalInstance))
{
if(EventObject.TotalInstance>0)
{
EventObject.TotalInstance -= 1;
}
}
var handlerobject = {'ClassObject': Handlers[i].ClassObject,
'ControlID': Handlers[i].ControlID, 'EventType': Handlers[i].EventType,
'TotalInstance': Handlers[i].TotalInstance,
'Wait': Handlers[i].Wait, 'UserObject':
Handlers[i].UserObject, event: e};
if(!$NU(EventObject.Wait))
{
var t=setTimeout(function(){ if(EventObject.EventCallBack(handlerobject))
{ if (navigator.appVersion.indexOf('MSIE') != -1)
{ e.cancelBubble = true; } else { e.stopPropagation(); }}},
EventObject.Wait);
}
else
{
if (EventObject.EventCallBack(handlerobject)) {
if (navigator.appVersion.indexOf('MSIE') != -1)
{ e.cancelBubble = true; } else { e.stopPropagation(); }
}
}
if(EventObject.TotalInstance==0)
{
$CJEM.Remove(ControlID, EventType, EventObject.EventCallBack);
}
}
}
};
Compressed Version
I created a compressed version of CJEM. It weighs in at a whopping 1.9 KB. I stripped out the comments and long named variables and spacing. It doesn't change the output naming, so you can substitute it for the original.
i.e., It won't break your working code.
Control Examples
I will be adding many control examples through the months to this article. Also, if you have an example to share, please add it below and if it's good I will add it to the main article with your credits.
Tab Control
Drop Down Select Control
Checkbox Control
Conclusion
That concludes my article. If you find any bugs or want to suggest improvements, please give a comment below. Also just to be aware, there might be bugs from me changing everything to a long naming convention. I did that to improve readability and learning. I hope you all enjoyed my new article.
History
- August 3, 2011 - Creating a custom
Datagrid
- July 5, 2011 - Making a new version
- June 13, 2011 - Creating some new controls
- May 19, 2011 - Prevent default example upon request
- May 7, 2011 - Found a small issue with multi events and one instance
- Apr 28, 2011 - Movable item example created
- Apr 20, 2011 - Extending some code to include CSS class support
- Apr 12, 2011 - Building more advanced control examples
- Apr 8, 2011 - Checkbox example created
- Apr 3, 2011 - Drop down select control example created
- Mar 31, 2011 - Tab control example created
- Mar 30, 2011 - Creating some example control libraries
- Mar 10, 2011 - Created a compressed CJEM, file size 1.9 KB
- Mar 9, 2011 - Added date calendar textbox example
- Mar 6, 2011 - Released CJEM for General Public License (GPL3)