PDA

View Full Version : Tips on creating self encapsulating scripts



WA
06-19-2002, 02:27 AM
I thought we might use this thread to share some tips on creating self encapsulating scripts when coding, so to minimize the chances of conflicts occurring between our script and others on the same page. I'm sure Alex (mod of XML forum) will have something to say here heh.

Tip on avoiding variable conflicts:

One of the most common conflicts with scripts occurs with identical variable names. This is the result of coders picking common names as variables, such as x, y etc. One way to minimize this problem from occurring is to define variables as properties of a custom object:



var glidescript=new Object()
glidescript.x=50
glidescript.y=150
glidescript.text="welcome to my homepage!"

This way, we only have to worry about "glidescript" being unique on the page, and not any of its properties such as x, y, speed etc.

Please add your tips here.

jkd
06-19-2002, 02:53 AM
Once there is a significant amount of replies, you should make this thread sticky.

Anyway, for DHTML effects I highly recommend looking into IE's element/ViewLink behaviors (not too complicated to learn at all), and Gecko's XBL (definitely a little tougher - but you have a resident expert frequenting these forums ;)).

You can then assign elements their effect through CSS, instead of hardcoding references, which means infinite code reuse on the same page, and exactly 0 conflicts with other scripts (unless they also use a behavior/binding, which is when you'll need to look into the addBehavior() and addBinding() methods).

RoyW
06-19-2002, 04:41 AM
WA,
A good idea but what if you want 2 glidescripts on the same page?

I find the best idea is to use the fact you can use OO methods in JavaScript


function glider(text, sx, sy)
{
this.startX = sx;
this.startY = sy;
this.text = text;
}
glider.prototype.glideTo = function(x,y)
{
this.endX = x;
this.endY = y;
alert("Start at " + this.startX + ":" + this.startY);
alert("Move to " + this.endX + ":" + this.endY)
}

and then you can create multiple gliders



myGlider1 = new glider("Hello World", -100, -100);
myGlider2 = new glider("Welcome", -100, 0);
myGlider3 = new glider("Some More Text", 0, -100);

myGlider1.glideTo(100,100);
myGlider2.glideTo(100,200);
myGlider3.glideTo(100,300);


OO JavaScript is a little harder to learn but it is possible to turn a conventional procedural JavaScript into an Object so it won't interfere with other scripts or itself.

It is just a pity that there seem to be very few public scripts that use OO methods to learn from.

I have some links somewhere to how to create OO scripts. I'll post them when I find them.

P.S.
Here is an example Multiple xeyes (http://www.javascript-fx.com/post/ozone/the5k/eyes/index.html).

WA
06-19-2002, 05:35 AM
Good tips guys. I think we also need to take into account rapid deployment though. For example, creating an object class is quite a bit more work than merely creating an object on the fly, and in many situations, the later alone will do nicely.

How about another potential conflict that has to do with two scripts both accessing the same event handler? For example:



window.onload=dothis //first script
window.onload=dothat //second script

Any tips on invoking an event handler while leaving it open to other scripts? Not sure if it's even possible.

RoyW
06-19-2002, 03:13 PM
NOTE: I have put javascript code examples between [ php ] vbCode as it color codes the syntax (but it really is JavaScript).


For example, creating an object class is quite a bit more work than merely creating an object on the fly, and in many situations, the later alone will do nicely.

I agree. It should make converting existing scripts a lot easier.

As for the "onload" one method you could use is


//Save a reference to the existing onload handler
var oldOnload = window.onload;
function gliderStart()
{
//If there was an old onload handler, execute it
if(oldOnload) oldOnload();

//Code to initialize glider script
}
//point the window.onload to my handler
window.onload=gliderStart;


This relies on your script being inserted last in the document. If another script simply assigns the onload handler :-
window.onload=anotherFunc;
then it will wipe out your handler.

RoyW
06-19-2002, 03:26 PM
A better solution to the onload problem would be if the window object had an "addOnloadHandler()" method so you could add your init method to a chain of onload handlers without wiping out existing onload handlers. We can implement this ourselves with the following code.


/**** Start onload Code ****/
var initFuncs = new Array();
function addOnloadHandler(func)
{
initFuncs[ initFuncs.length ] = func;
}
function initAll()
{
for(var i=0 ; i<initFuncs.length ; i++)
initFuncs[i]();
}
window.onload=initAll;
/**** End - onload code ***/

This code could be put into the head of all your documents
You could also place it in an external ".js" file and include it into all documents that require an onload handler.
You would then replace all
"window.onload=myFunc"
with
"window.addOnloadHandler(myFunc);

For example


function myStart()
{
alert("My Start");
}

function initMenus()
{
alert("Init Menus");
}

function startGlider()
{
alert("Start Glider");
}

window.addOnloadHandler(myStart);
window.addOnloadHandler(initMenus);
window.addOnloadHandler(startGlider);

RoyW
06-19-2002, 04:11 PM
This is similar to the tip for variables but it allows you to include methods as well. Consider
Script 1


function moveTo(x,y)
{
glidescript.x = x;
glidescript.y = y;
}

Script 2


function moveTo(x,y)
{
myDiv.style.x = x;
myDiv.style.y = y;
}

You could prepend each with some text, e.g...
function glider_moveTo(x, y)
but a better solution is to add the functions to your custom object


glidescript.moveTo = function(x, y)
{
glidescript.x = x;
glidescript.y = y;
}
glidescript.moveTo(10,10);

RoyW
06-19-2002, 04:25 PM
Tired of typing long variable names of your custom object. E.g...


glidescript.x = glidescript.x + glidescript.speed;
glidescript.y = glidescript.y + glidescript.speed;
glidescript.moveTo(glidescript.x, glidescript.y);

Then use the "with" keyword to get a shortcut


with(glidescript)
{
x = x + speed;
y = y + speed;
moveTo(x, y);
}

(this is why it is better to add functions to your objects rather than just prepend some text)

RoyW
06-19-2002, 04:28 PM
Here are some links. I will edit to add more when I find them
Coding for portability
---------------------------
http://www.13thparallel.org/?issue=2002.03&title=portability_one
http://www.13thparallel.org/?issue=2002.04&title=portability_two

OO Programing in JavaScript
-----------------------------------
http://www.webreference.com/js/column79/
http://www.webreference.com/js/column80/

jkd
06-19-2002, 07:31 PM
Don't want to destroy event handlers?

Use the DOM2 Events standard addEventListener for Gecko, and IE's proprietary attachEvent:



function MyMouseMove(event) {
// do stuff
}

if (typeof document.attachEvent != 'undefined')
document.attachEvent('onmousemove', MyMouseMove);
else if (typeof document.addEventListener != 'undefined')
document.addEventListener('mousemove', MyMouseMove, false);


Voila, you didn't remove anything that may have been assigned to document.onmousemove, but added an event to it nonetheless.

TrueLies
06-19-2002, 08:51 PM
It may sound arcane but be indulgent: my solution to this riddle was to make an object name so much shared as possible: write once, borrow everywhere.

In Java, each class has its methods, at most you can have an interface (those strongly data typed languages really cause a significant waste of code with the strong call for overloaded methods: we have javas in a nutshell which exhibits for each class at times hundreds of functions that include the very same code and just a couple of commas different to accomodate different input data type). Each class incapsulates its methods.

In my approach, each method is lent to each class, without implementing the interface.

Basically was developed on layers for Dhtml:
var foo= new layerManager("foo");

now you have a method which is cognizant of how that constructor works
function moveEllipse(){
this...
this...
if(!this...){this...=...}
}

then you can borrow to each manager the method by using a second constructor:
foo.moveEllipse=new managerMethod("moveEllipse")

each layerManager can therefore hold methods with an identical name without this causing any conflict and with the method wrtitten only once and not thousand of times to accomodate differnent combinations of layers.

foo.moveEllipse.execute() triggers the method on foo.

I think it may be a curiosity to add to this thread for it is an attempt, partially successful, to solve the problem of shared names by pioneering exactly in the direction one wouldn't have ventured to. I called it ULMA (Universal Layer Management APPROACH), maybe it can give an interesting outlook for further developements on the thread issue.

Just my two cents.

Alex Vincent
06-20-2002, 12:53 AM
RoyW beat me to it. :cool: