Portable Dynamic HTML Elements with the DynEl Class
/*
* File: DynEl.js
* Include with: <SCRIPT SRC="DynEl.js"></SCRIPT>
*
* This file defines the DynEl class, which provides a portable API
* to many Dynamic HTML features.
*/
/*
* This is the constructor function for DynEl objects.
* The arguments are the following:
* window: The Window object in which the dynamic element is to appear
* id: The HTML ID for the dynamic element. Must be unique.
* body: HTML text that constitutes the body of the dynamic element
* left: The optional initial X-coordinate of the element
* top: The optional initial Y-coordinate of the element
* width: The optional width of the element
*
* This constructor outputs a style sheet into the current document.
* This means that it can only be called from the <HEAD> of the document
* before any text has been output for display.
*/
function DynEl(window, id, body, left, top, width) {
// Remember some arguments for later.
this.window = window;
this.id = id;
this.body = body;
// Output a CSS-P style sheet for this element.
var d = window.document;
d.writeln('<STYLE TYPE="text/css">');
d.write('#' + id + ' {position:absolute;');
if (left) d.write('left:' + left + ';');
if (top) d.write('top:' + top + ';');
if (width) d.write('width:' + width + ';');
d.writeln('}');
d.writeln('</STYLE>');
}
/*
* Now we define a bunch of methods for the DynEl class.
* We define one set of methods if we are running in Navigator, and
* another set of methods if we are running in Internet Explorer.
* Note that the APIs of the methods are the same in both cases; it
* is only the method bodies that change. In this way, we define
* a portable API to the common DHTML functionality of the two browsers.
*/
// First, define the Navigator methods.
if (navigator.appName.indexOf("Netscape") != -1) {
/*
* This function outputs the dynamic element itself into the document.
* It must be called before any other methods of the DynEl object can
* be used.
*/
DynEl.prototype.output = function() {
var d = this.window.document; // Shortcut variable: saves typing
// Output the element within a <DIV> tag. Specify the element id.
d.writeln('<DIV ID="' + this.id + '">');
d.writeln(this.body);
d.writeln("</DIV>");
// Now, for convenience, save a reference to the Layer object
// created by this dynamic element.
this.layer = d[this.id];
}
// Here are methods for moving, hiding, stacking, and otherwise
// manipulating the dynamic element.
DynEl.prototype.moveTo = function(x,y) { this.layer.moveTo(x,y); }
DynEl.prototype.moveBy = function(x,y) { this.layer.moveBy(x,y); }
DynEl.prototype.show = function() { this.layer.visibility = "show"; }
DynEl.prototype.hide = function() { this.layer.visibility = "hide"; }
DynEl.prototype.setStackingOrder = function(z) { this.layer.zIndex = z; }
DynEl.prototype.setBgColor = function(color) {
this.layer.bgColor = color;
}
DynEl.prototype.setBgImage = function(image) {
this.layer.background.src = image;
}
// These methods query the position, size, and other properties
// of the dynamic element.
DynEl.prototype.getX = function() { return this.layer.left; }
DynEl.prototype.getY = function() { return this.layer.right; }
DynEl.prototype.getWidth = function() { return this.layer.width; }
DynEl.prototype.getHeight = function() { return this.layer.height; }
DynEl.prototype.getStackingOrder = function() { return this.layer.zIndex; }
DynEl.prototype.isVisible = function() {
return this.layer.visibility == "show";
}
/*
* This method allows us to dynamically change the contents of
* the dynamic element. The argument or arguments should be HTML
* strings which become the new body of the element.
*/
DynEl.prototype.setBody = function() {
for(var i = 0; i < arguments.length; i++)
this.layer.document.writeln(arguments[i]);
this.layer.document.close();
}
/*
* This method registers a handler for the named event on the
* element. The event name argument should be the name of an
* event handler property, such as "onmousedown" or "onkeypress".
* The handler is a function that takes whatever action is necessary.
* Because Navigator and IE do not have compatible Event objects,
* all event details are passed as arguments to the handler function.
* When invoked, the handler will be passed the following nine arguments:
* 1) A reference to the DynEl object
* 2) A string containing the event type
* 3) The X-coordinate of the mouse, relative to the DynEl
* 4) The Y-coordinate of the mouse.
* 5) The mouse button that was clicked (if any)
* 6) The Unicode code of the key that was pressed (if any)
* 7) A boolean specifying whether the Shift key was down
* 8) A boolean specifying whether the Control key was down
* 9) A boolean specifying whether the Alt key was down
* Event handlers that are not interested in all these arguments do
* not have to declare them all in their argument lists, of course.
*/
DynEl.prototype.addEventHandler = function(eventname, handler) {
// Arrange to capture events on this layer.
this.layer.captureEvents(DynEl._eventmasks[eventname]);
var dynel = this; // Current DynEl for use in the nested function.
// Define an event handler that will invoke the specified handler,
// and pass it the nine arguments specified above.
this.layer[eventname] = function(event) {
return handler(dynel, event.type, event.x, event.y,
event.which, event.which,
((event.modifiers & Event.SHIFT_MASK) != 0),
((event.modifiers & Event.CTRL_MASK) != 0),
((event.modifiers & Event.ALT_MASK) != 0));
}
}
/*
* This method unregisters the named event handler. It should be
* called with a single string argument such as "onmouseover".
*/
DynEl.prototype.removeEventHandler = function(eventname) {
this.layer.releaseEvents(DynEl._eventmasks[eventname]);
delete this.layer[eventname];
}
/*
* This array is used internally by the two methods above to map
* from event name to event type.
*/
DynEl._eventmasks = {
onabort:Event.ABORT, onblur:Event.BLUR, onchange:Event.CHANGE,
onclick:Event.CLICK, ondblclick:Event.DBLCLICK,
ondragdrop:Event.DRAGDROP, onerror:Event.ERROR,
onfocus:Event.FOCUS, onkeydown:Event.KEYDOWN,
onkeypress:Event.KEYPRESS, onkeyup:Event.KEYUP, onload:Event.LOAD,
onmousedown:Event.MOUSEDOWN, onmousemove:Event.MOUSEMOVE,
onmouseout:Event.MOUSEOUT, onmouseover:Event.MOUSEOVER,
onmouseup:Event.MOUSEUP, onmove:Event.MOVE, onreset:Event.RESET,
onresize:Event.RESIZE, onselect:Event.SELECT, onsubmit:Event.SUBMIT,
onunload:Event.UNLOAD
};
}
/*
* Now define methods for Internet Explorer.
* These methods have identical APIs to the ones defined for Netscape
* above. Therefore, we will not repeat all the comments above.
*/
if (navigator.appName.indexOf("Microsoft") != -1) {
// The all-important output() method
DynEl.prototype.output = function() {
var d = this.window.document; // Shortcut variable: saves typing
// Output the element within a <DIV> tag. Specify the element id.
d.writeln('<DIV ID="' + this.id + '">');
d.writeln(this.body);
d.writeln("</DIV>");
// Now, for convenience, save references to the <DIV> element
// we've created, and to its associated Style element.
// These will be used throughout the methods that follow.
this.element = d.all[this.id];
this.style = this.element.style;
}
// Methods to move the dynamic object
DynEl.prototype.moveTo = function(x,y) {
this.style.pixelLeft = x;
this.style.pixelTop = y;
}
DynEl.prototype.moveBy = function(x,y) {
this.style.pixelLeft += x;
this.style.pixelTop += y;
}
// Methods to set other attributes of the dynamic object
DynEl.prototype.show = function() { this.style.visibility = "visible"; }
DynEl.prototype.hide = function() { this.style.visibility = "hidden"; }
DynEl.prototype.setStackingOrder = function(z) { this.style.zIndex = z; }
DynEl.prototype.setBgColor = function(color) {
this.style.backgroundColor = color;
}
DynEl.prototype.setBgImage = function(image) {
this.style.backgroundImage = image;
}
// Methods to query the dynamic object
DynEl.prototype.getX = function() { return this.style.pixelLeft; }
DynEl.prototype.getY = function() { return this.style.pixelRight; }
DynEl.prototype.getWidth = function() { return this.style.width; }
DynEl.prototype.getHeight = function() { return this.style.height; }
DynEl.prototype.getStackingOrder = function() { return this.style.zIndex; }
DynEl.prototype.isVisible = function() {
return this.style.visibility == "visible";
}
// Change the contents of the dynamic element.
DynEl.prototype.setBody = function() {
var body = "";
for(var i = 0; i < arguments.length; i++) {
body += arguments[i] + "\n";
}
this.element.innerHTML = body;
}
// Define an event handler.
DynEl.prototype.addEventHandler = function(eventname, handler) {
var dynel = this; // Current DynEl for use in the nested function
// Set an IE4 event handler that invokes the specified handler
// with the appropriate nine arguments.
this.element[eventname] = function() {
var e = dynel.window.event;
e.cancelBubble = true;
return handler(dynel, e.type, e.x, e.y,
e.button, e.keyCode,
e.shiftKey, e.ctrlKey, e.altKey);
}
}
// Remove an event handler.
DynEl.prototype.removeEventHandler = function(eventname) {
delete this.element[eventname];
}
}