SCRIPTING:

Salma Hayek and the rainbow pumpkins
UNIVERSAL LAYER MANAGEMENT APPROACH - ULMA
Implementing a Dhtml setting with constructors such that each layer you define can take in a whole thread of actions simultaneously, if needed, and such that by the very same templates you can simultaneously animate more layers without crossing into interferences. «That's Smashing, baby!».
February 2002
{ @ }

The model above is Salma Hayek
LOADS OF SALMA HAYEK ON THE NET


OVERVIEW ON THE MOST POWERFUL & COMPREHENSIVE DHTML APPROACH AVAILABLE ONLINE
What is ULMA composed by? What this new DOM (Document Object Model) detection method and its subroutines properly accomplish?

ULMA is composed by (click links):
ULMADefaulter, at bottom of this file, is optional.
Wherever present in the code, please keep this website commented url to use quite safely.
ULMA whole working set including ULMADefaulter weights 21 KB, namely like a normal jpg portrait!
 
If by chance you found a typo you can email me.

ULMA methods are categorised as follows: on the whole we have three types of methods:
BUILT IN methods: those methods that are resident within the ULMA constructors (alike in Java each class has a set of owned methods). The two ULMA constructors are:
  • layerManager()
  • managerMethod()
Therefore the built in methods included in these "classes", as you will see, need not to append a call to execute() or to run() in order to be triggered.
Instance on the built-in method named abilitate:
  • AlayerManager.abilitate.execute() //wrong!
  • AlayerManager.abilitate.run() //wrong!
  • AlayerManager.abilitate() //right!
IN BUNDLE methods: those methods that are not resident inside within the ULMA constructors but none the less are provided along with ULMA as its basic external methods and therefore do need a call either to execute() or to run(): these methods can therefore be either executed one time or are suitable to be recursively executed (run).

The need to establish such a difference is why every non built-in ULMA method has been devised to be triggered not directly but appending a call to one of the two auxiliary -actually: built in!- execute/run methods).
Note that two of such bundled methods have been initialized in within the DOM detection set-up actually: writeText() and readText() for they heavily relied upon a dom detection.

Remember that the main error you can make with ULMA is to call a bundled or borrowed (external) method forgetting to append either run or execute:

  • AlayerManager.externalMethod() //wrong!
  • AlayerManager.externalMethod.execute() //correct!
  • AlayerManager.externalMethod.run() //correct!

For completeness' sake, another main error with ULMA, as you are to understand, is exactly to forget abilitating a variable previously initialized as a new layerManager:
 
var foo;
foo=new layerManager("foo", "layerID");
foo.abilitate();

 
In fact, abilitation is the ULMA built-in method which enables for the newly produced layerManager all the subroutines which are bundled with ULMA.
 
If you're using the most recent version of ULMA (the present one, that is, and not some version you copied earlier before mid december 2002), you can even remove some or all of the bundled methods and ULMA won't complain although you won't be able any longer, obviously enough, to use the bundled methods you deleted. This because of a "smarter" definition of the abilitate built in method, that now firstly checks if the bundled method is defined and only if so it activates the defined in bundle method on the given layerManager upon your call to abilitate.
BORROWED (or EXTERNAL) methods: those methods that are not bundled or built in with ULMA but that are crafted by you (or provided, like it happens, on this very same website); they need the calls to execute or run as well in order to be triggered.
With this approach, you can write one method that is shared by all the managers, and which can be provided also as a standard for other ULMA users!

Note this characteristic of ULMA: it's the opposite of Java: in Java each class has its own methods (to the degree that given the strongly data typed approach, which I always considered a sheer waste of code, the very same method has to be rewritten dozens of times to allow different data type inputs); unlike Java, in ULMA once you've defined a method one single time, you borrow it to each constructor (which is an emulation of a class)!
This is why ULMA (out of dhtml: UMA: Universal Management Approach, like for instance ACTION MANAGERS are) is quite interesting an approach which deserves attention.

Note: it is finally available on this website the file which explains and gives suggestions on how you can craft your own external ULMA valid methods to borrow them to your layerManager instances.
Such file can be located clicking the following link:
HOW TO CRAFT YOUR OWN ULMA METHODS
It is obviously advisable that you first perused at least this current file before accessing the one mentioned above.

DRAMATIS PERSONAE: INCIPIT
«(...) and the reward of which is earthly rebirth.»
[The Bhagavad Gita]

«Understand the code at all times, and resist those foul urges to just change it until it works.»
[Jon Bentley]

«When everything else fails, sleep.»
 
«Never speculate. And if you can't avoid it, be sure you do it only in order to include, never to exclude possibilities.»
[... me]

Elvira pledges allegiance
«Last thing I remember,
I was running for the door
I had to find the passage back
to the place I was before.
"Relax", said the night man:

"We are programmed to receive:
You can check out at any time you like
but you (just) can never leave

[Eagles, Hotel California]

At times you just come across one of those blessing approaches about to simplify your life and about which, once mastered, you'd say:

«Since I learned it, I don't want to know about any alternative any longer, so obvious natural and good it is! I wonder how comes they didn't think of it earlier!»

What about a Dynamic Html approach that may be going to elicit from you such an eureka! sentence after you have dedicated to it a couple of days to grab its logics?
So, basically, I don't know what idea of an advice of mine you might have got, but if your idea is that this website is handling over a few interesting scripts («Best and brightest, come away!» wrote once Shelley, and that's funny a verse! Looks like Louis XIV -the so called Sun King- motto: «Nec Pluribus Impar»: not inferior to a few, a slogan that gives a shiver if you know who Louis XIV was and you ponder over it a bit...) and must not be the byproduct of an incompetent, well I'd be glad then to run out of my little credit with you by simply stating this: this is official ULMA documentation and I can't make an already long document unduly longer adding reasons to technicalities, but let me summarize those reasons I could not include in order to save some bandwidth in one tip-like sentence (call it your «tip on the dead jockey» if you prefer...): if you're dealing with Dhtml, do learn how to use ULMA and then use it, for absolutely nothing is more powerful as far as the many Dhtml approaches we see popping around are concerned: I spend in this statement all the little credibility I may have before your eyes (without which you weren't still here arguably. And if I never had it, well it just can't backfire).


Ernest Hemingway once said that the quality of the good bull was "to grow braver and braver under punishment" (Death in the Afternoon); without any real claim to live up either to this expectation or (God forbid) up to Ernest Hemingway's exquisite sensitiveness (for he's an author unfairly regarded as a tough guy: he was an artist, in the purest crystal-clear sense of the term), we can say that the purpose I had in mind when setting up these Dhtml procedures was to arrange a method that would allow you to address a single layer with a whole host of contemporary or consecutive actions as a more and more, increasingly demanding request set issued on that single layer or even on a host of layers (if needed: for nothing would prevent you from using these subroutines just to achieve the more simple and mainstream, traditional, one-shot hit) without having to set up one single function for each involved layer (one of the main consequences of what is used to perform animations, namely timeouts, is you can't actually pass arguments to them to assign to them given layers, and thenceforth you'd arrange a specific function for each specific layer even if what the function does is... exactly the same on both layers) and/or without having to conceive basically brand new functions from scratch just in order to implement a combination of animations on a Layer.
That's the games I'm chasing after here.

Therefore, I presume that the most enticing appeal these scripts conjure up, is whenever you've got to implement timed out animations and you feel indeed that even too much familiar & eerie, biting sensation you just snapped up in those situations whereas while eagerly intent up to your ass in alligators, you've got zero time to drain the bloody swamp.

The whole system may appear complex only as long as you don't realize that once it has been cached in the browser's memory, it won't just load without delay at each subsequent page which invokes the same external javaScript file holding these scripts (in fact no doubt the best way to use these scripts is to paste them all in a single external js file and then keep loading it in each page requiring the dhtml animations) but it would let you device and implement complex animations triggering them with two line long statements and without any need to concoct a new function just in order to jumble, for instance, a dynamic moving of the layer and a clipping of the same layer at the same time, while other layers undergo more animations.

Let me stress soon one thing: all these scripts must be loaded after (after: for failing doing so and complaining nothing works, is one thing!) the <BODY> tag, and presumably I'd even suggest to you, in order to keep you clear from possible mischief, to actually paste them not just after the BODY tag but also after you've defined your layers; therefore you'd use these scripts as follows:


an ULMA TAXONOMY OVERVIEW
  • You define your starting body tag.
  • You define your layers.
  • You now load the scripts, either as a script pasted in the page or as a mere call to an external javascript file (extension is, as you should know, dot js: "yourFileName.js")
  • You can now initialize your animations or trigger Dhtml tasks, in the following order:
    1. You always declare all of your layer managers (to know what they are see further on):
      • prior to everything else
      • and as global variables.
      This means: initialize first, and no initializations of layer managers in within functions: in within functions you can manipulate a layer manager, but you can't expect a layer manager asset to survive out of a function scope if you initialize it in there!
      The lifespan of a layer manager must arguably be perennial in the page lifetime, you see.
      So, being foo a placeholder for whatever variable name, you do declare as your very first step:
      var foo;
      So: no such declaration in within functions, or your layerManager won't have a global scope. And failing declaring such a Java-like initialization would make your script fail as well.
    2. You then initialize all of your layer managers (to know what they are see further on) by:
      foo=new layerManager('foo','layerID');
      And no, do not initialize directly your variable as a new layerManager, first initialize it as described in point 1.
      • Rule of thumb: don't do as above (foo different name than layerID): instead do give to your layer manager(s) and the layer ID it(they) manage(s) the same names (manager/layerID: same name, that is; to know what's this about see further on, here I just summarize an ULMA procedure taxonomy): this would provide you with the greatest flexibility to loop the ULMAObjects hash table by a
        for(i in ULMAObjects){}
        cycle (again, see further on).
    3. You abilitate all of your layer managers (to know what it is see further on) by:
      foo.abilitate()
    4. The three points above must be executed prior to everything in order to keep you away from whatever possible attempt to make a layer manager communicate with another layer manager which... has not been initalized or abilitated yet.
Example: define first your layers soon after the <BODY> tag:
1:
<div id="fooLayer" style="position:absolute;top:0;left:0; z-index:1; visibility: visible; layer-background-color:#00ff00; background-color:#00ff00;"> </div>

Remember that to accomodate crazy behaviors by NS4 all your layers must be defined soon after the body tag (beware: nothing else between the <body> tag and your layers definitions or NS4 would do any sort of strange things) and have a full set of css properties: position, top, left, z-index, visibility, and the NS4 layer-background-color too preferably, or NS4 might "assert", in unpredicatble ways, the layer doesn't exist (that is: position top and left might not suffice).


2:
Now you load either as an external js file or as inline statements in within a set of <script> </script> tags, all the ULMA components.

3:
Then in another set of <script> </script> tags:


  1. var fooLayer;
  2. fooLayer=new layerManager("fooLayer", "fooLayer");
  3. fooLayer.abilitate();

That's all: you've a layer ready to use all the (ULMA) Dhtml of the world: step 3 accomplished with the only 3 lines of code you really had to write yourself!

Now you can proceed with whatever animation or dhtml task, remembering that (see further on: you probably are to come back to these points once you've read it all, I bet!) run() animates (triggers repeating tasks, that is), whereas execute() or its aliases just execute once (trigger a task only once). I am now to introduce you to the easiest part, the build up of a set of variable names meant to hold valid syntax references (either direct or as string equivalents meant to undergo an eval() lately on, which is a conversion of a string in its equivalent "executable" syntax keyword, provided the stringed version of the word is obviously identical to the executable keyword) accordingly to the 3 different Document Object Models we're dealing with currently: IE4, NS4, and the generation 5 browsers: therefore the compatibility is absolute as far as NS4, NS6 and above, IE4 and above, Mozilla, Gecko flavours are concerned: I have no clue what they're up to with the Opera Browsers or other fuzzy brands, whose very likely weird or unexpected behaviours are not something I'm accountable for but (quite candidly) you're accountable for: for once you put yourself out of the trial of the big toil (Explorer, Netscape, Mozilla, Gecko) you're on a minefield I did not put you into, and rebellion makes sense only as long as the cause you rebel for badly wants you (and no doubt it does: for it's not men who need God, but God Who needs men isn't it?) or as long as you choose your rebellion path final destination and you devotedly pursue it: White Fang or The Call of the Wild?

There is one remarkable advantage with such an approach: the differentiate DOMs we're bound to deal with compel every scripter to perform DOM detection at runtime of a function (inline inside the functions, that is): with a build up of reference table made prior to everything else and once for all, you can:

  1. Skip whatever conditional statements checking at runtime, which upon animations can be a surefire time saver.
    Yes, processors are quite powerful, even old ones: but if you're dealing with many animations, the sparing of time cumulates and avoids possible buffering of the tasks for quickier animations: if you move and clip and flash a layer at the same time you might have to repeat at least 4 conditionals in each function each 50 milliseconds: computers do that, but if you have one chance to work it around, then do it: optimization is not a totem: it's just one more thing you do only if possible: otpimizing for the sake of optimizing is the hallmark of the naive scripter: computers are powerful, a script length is an issue only for him who has not clear when optimizing. It's not a matter that:
    «3 seconds is a nanocentury»
    It's a matter that you do what is necessary when it is necessary not what is necessary when it is not necessary: do the latter and your code would be the worst, not the best: optimizing when it's not necessary might be an endless spring of problems. Please, do meditate on this Jon Bentley excerpt [taken from: Programming Pearls] and you may see by the agency of by far better words what I mean:

    «(...) why hasn't the Brooklyn Bridge torn itself apart like [the] Galloping Gertio [bridge did]? It's because John Roebling had sense enough to know what he did not know. His notes and letters on the design of the Brooklyn Bridge still exist, and they are a fascinating example of a good engineer recognizing the limits of his knowledge (...) he designed the stiffness of the truss on the Brooklyn Bridge roadway to be six times what a normal calculation based on known static and dynamic loads would have called for.»

    Now, what if Roebling would have committed himself to optimization as a totem without any real understanding of what optimization is for? For men, not vice versa.
    Optimize when optimization is called for, and do not lecture those who write longer codes on the virtue of gratuitous optimization: it crashes bridges.
  2. You can make references to Dhtml properties inside a function making a call always to the same names (instance: inner width with ULMA is always innerW no matter which your browser is...).

I will use for the detection of a layer width and heigh on browsers 5 generation a syntax keyword named offsetWidth, offsetHeight for it appears that even Mozilla and NS6 adopted it although it was originally an IE thing, so to say: thus, it appeared to me the most logical solution, the smoother and the more consistent.

We have one drawback anyway: listen to what Danny Goodman says (probably by far the best javaScript Author I ever read, although the book I'm drawing the following excerpts from is by no means his best achievement) in the O'Reilly (nothing to share with fox news) Dynamic HTML Definitive Reference on these properties and its family:


(...) as an example of the mess that has developed (...) consider [that] the developer documentation asserts that these properties measure the element content only, exclusive of margins borders or padding tacked onto the element.
(...) this assertion holds true for margins and borders but not padding. Padding is not only added (...) but the padding size is doubled in the calculation (...)

The offset properties are supposedly measured within the context of the next outermost container. (...) but if margins, borders, or padding are involved (...) the calculations go astray (and they go completely wild in IE 4 for the Macintosh).


Morale: do not (not) set padding or margin properties in the style declarations (css) of your layers, and thenceforth you a safe dude.
Of course, seems that you can set at least margins (by css declarations) to a layer in a reasonably confident way, if you reason IE4 on macintosh is not going to be a big audience hit by now (and shouldn't be at all), provided that when (for instance) moving or repositioning the layer you add to its newest top and left coordinates the amount of the margins you set in pixels.

Anyway, if you badly need to get margins padding and borders in your layer, given mr. Goodman's excerpt above, consider doing that by a table, either border less or not, setting its cellspacing and cellpadding properties until they empirically fit your need (such a move would surely fit as far as width is concerned, for there is no way to give a defined height to a table and apply possible padding to the bottom border: the height property of a table, in fact, does nothing on most browsers and a table height, by and large, just shrinks and stretches to fit its actual contents).

Eventually, and last but not least, while attempting to abide by the rules so many developers divulged and champion (to the degree of qualifying the most remarkable authors as "crap" for they did not follow such advice, and assuming they weren't because of blunt negligence) and namely to stick to DOM detection and not to browser sniffing, I stumbled into this: Netscape 4, which normally and by any means recognizes its own DOM syntax by document.layers can none the less be at times utterly un capable to spot it, to the bewildering degree that if you nest an alert immediatly after an expression like


if(document.layers){alert("It's Netsie 4")}
Netscape 4 can be quite able, in some circumstances I'm detailing below, to ignore the alert thoroughly and without remorse (in javaScript alerts, or even better confirm-boxes set to return false in functions or function loops, are the traditional print like debugger): just never triggers it.
I stumbled into this while loading a DOM detection by document.layers on NS4.51 which was written in an external javaScript file: the file was called in soon after the body tag, and Netscape 4.51 was utterly and stubbornly unable to read (and therefore trigger the debug-purpose tailored alert box) the statement held by the condition if(document.layers) until a (also mild) reload occurs: for after one single reload, the problem did not occur any longer and Netscape 4.51 went back to do what it was supposed to do since the beginning: recognize if(document.layers) like its hallmark and trigger the goddam alert.

Therefore there we go, after 2 DOM detections for document.getElementById (syntax for generation 5 browsers) and document.all (syntax for IE4), I was forced to use, in order to be cautious, a traditional browser sniffing for the last browser left: Netscape 4.
Also, in some cases browser's sniffing (is your browser's name Netscape? is its name Explorer? those questions are called browser's sniffing and regarded un elegant for they cut off all browsers whose name is not taken into account) may be the only way out, although I do my best to avodi this: in fact a few differences in the implementation of some syntaxes are still in place whereas the W3C has not set a reccommended syntax in order to detect a few particular properties; cases in point to date:

  1. Width and height of the inner window (different from screen size for the screen size takes into account also the chromes of a browser's window, while Dhtml deals with the document width and heights, and should never presume the full screen).
  2. Page offsets (that is: the coordinates of topleft corner of your browser's window adding to such coordinates the scrolling level the users has currently positioned its scrolling bar at)
  3. Most remarkably: event top/left coordinates detection, namely reading the mouse pointer coordinates upon document clicking or upon mouse movements.
Nobody knows if such properties will be subject to a recommendation, but if so that would not solve the problem for we should still go on sniffing the browsers to accommodate previous versions: really, the W3C should release its recommendations only when its drafts are the most complete as possible trading off the risk of being pedant with the unconvenience of releasing standards which are constantly never fully met.

DOM DETECTION SETUP



DELVING DEEPER
A few basic subroutines which would traditionally go with the data collected by the DOM detection build up exposed above.

Elvira
Scripts below not, in themselves, a big deal yet: you will learn how to execute them in the next section, but I prefer to describe now what they do and how their arguments are crafted for these methods belong to the pool of default methods that every layer manager (see further on) will own.
They are just an implementation, consistent with the DOM detection featured above, whose purpose is to provide you with built in the 7 or 8 main facilities that every Dhtml environment must arguably have when managing a layer: that is, setting the:

1) Resizing of a layer. Pass as arguments the dimensions you want the layer to be resized as width/height: resizer(100, 300) (Experienced Scripter? You may be wondering where's the reference to the layer to manipualte, aren't you? it's OOP plus pointers -in javaScript!- applied to Dhtml: just go on reading and follow the tide). If no arguments are passed, the function returns the current layer dimensions as an array whose first entry is the width, and whose second entry is the height: so resizer()[0] is... the width of the layer!

2) Positioning of a layer. [Note: this is the official ULMA documentation, so it's fully comprehensive: skip sections you judge of no actual or immediate interest - not yet, at least]
Just keep in mind that the function named dispatcher, which moves layers, returns the layer top and left coordinates without therefore moving the layer if no top and left coordinates are passed upon calling it. Since also number zero is read as an undefined property, if you do want to move a layer to either top or left coordinate zero, pass zero not like a number but like a string ('0' in between apex, that is: arguments order may therefore look like: dispatcher('100', '200').
This applies particularly in case of coordinate=zero meant not as false or undefined argument but as actual zero position coordinate): the function will work it out you mean to move to zero coords if you pass it in between strings.
So, especially upon animations, when a coord crosses or attains zero, if such zero gets passed as a number the function could wrongly argue it's equivalent to false: passing therefore numbers as strings may be prudentially mandatory (which can also be attained by simply adding to your number an empty set of two apex num+"") and would solve the issue: it is a trade off to have one function that makes three things: returns, assigns, and and can assign a position also if an argument is missing.
Please discriminate about the two ways dispatcher behaves when

  • Setting the layer position
  • Reading the layer position
Dispatcher always returns the current layer position top and left coordinates as an array of two entries whose first entry is the top, whose second entry is the left coordinate: so
  • dispatcher()[0] would return the top.
  • dispatcher()[1] would return the left.
Dispatcher returns these coordinates anyway, and by default it returns them subtracting the page offsets: this means that you get as the returned value (you keep in mind this only if you wanna read/retrieve/get the position coords) the coordinates calculated as absolute regardless of the page level the user is currently positioned at.
Therefore what happens upon reading/setting the positions entirely depends on wether you pass or not the noOffsets argument as number 1:
  • NO-OFFSETS == 0: template: dispatcher(num, num)
    1. Setting position: it adds the current page offsets to the passed numbers: dispatcher(""+0, ""+0) moves to top 0 and left 0 adding the offsets: the user would see the layer (if position is 0 and offsets is 3000, moves to 3000).
    2. Reading position: it gives the current top/left set subtracting the current offsets (reading positions without setting the noOffsets argument as 1 is, therefore, a practice of no real utility): dispatcher(0, 0) or dispatcher(): reads subtracting the offsets (if position is 0 and offsets 3000, returns -3000, so to say).
      dispatcher()[0] is the top, [1] is the left.
  • NO-OFFSETS == 1: template: dispatcher(num, num, 1)
    1. Setting position: it does not add the current page offsets to the passed numbers: dispatcher(""+0, ""+0, 1) is top 0 and left 0 without adding offsets: so if the user scrolled, maybe won't see the repositioned layer.
    2. Reading position: it gives the current and actual top/left position, without meddling at all with current offsets. Period. dispatcher(0, 0, 1): reads (if top position is,say, 150 and current offsets the user is at would be say 3000, would return 150 as top coordinates. The real position, indeed);
      dispatcher(0,0,1)[0] reads top coordinate, [1] reads left coordinate.

Why this strange criss-crossed settings with this branching that at one time returns the position without the offsets, at another time it doesn't?
It accomodates in one subroutine a plurality of capabilities: you are to see how powerful this approach is when you will see the way it can relocate a whole animation to the focus keeping track of the current page level.

In fact, if I positon a layer at, say, top 200 and then I want to bring it to the surfer focus after he/she has scrolled at, say, the top offset of page whose pixel amount is 2000, I can certainly move the layer to 200+2000: but what after this? The offsets and the current position are forever merged and if the user scrolls back upward and after a while I need to bring the layer to the focus again, here's your quiz man: how would you work out what values to subtract? You have 2200 and say current offset is now 1300: if you subtract 2200-1300 you get 900: this is not the same as what 200+1300 would yield, and which would be the current amount to move at in order to bring the layer to the new focus coordinate preserving its top/left original ratio... Well, ULMA can work that out given the way dispatcher works.


3) Visibility toggling (visible/hidden) of a layer.
We feature a second argument called onlyReturn: if set to something above zero, the function just checks and returns (as a string carrying either "visible" or "hidden" words) the current visibility status without changing it: possible instance: shower(0, 1): the first argument won't be parsed at all if the third is set.
If shower is passed without arguments, it automatically toggles!

4) Clipping (must the layer be cropped and therefore partially visible? that is): gets the four arguments necessary to clip from bottom right top left.

5) Z-Index: stack order of the layer on other layers: if no arguments, returns the current zIndex.

6) Reloading the whole of the page if the window gets resized: in fact a resize of the window would cause a shrinking or expansion of the document width and height, and therefore without a reload a few variables built on startup would still hold outdated values referring to the old document size settings.
Therefore upon a user performed window resizing, the document must be reloaded to allow a refreshing of the values to fit the newly generated environment conditions: such occurrence is not likely to happen, but you have to take it into account and trade off a possible termination of currently engaged animations (unavoidable consequence of a reload) with the chance of (skipping such a reload) seeing your layers moving to the wrong directions (overstepping them if the resizing shrinks the window, downstepping if the resizing enlarges the window).
If you do not want the automatic resizing to occur, just delete the last string in this section of the scripts (flagged by a comment, although I, and with me every other web scripter, would highly recommend you not to do so).
Also, NS4.08 and lower versions are are unable to deal with such command so in our script it has been disabled on Netscape Navigator versions lower or equal to 4.08 - and no, that's not an issue revolving around capturing events (Netscape 4 has a procedure called event capturing, which is not mandatory as far as window resizing is involved): NS4.08 just keeps reloading the page forever when it meets a window onresize event, no matter whether it's captured or not. On the other hand, communicator can deal with the command smoothly even without the event capture.

7) Perhaps the WHProportion function is the most original, considering that it would give to you, out of one number passed as argument named amount and a layer reference passed as other argument, an array whose entries will be two numbers derived by the amount argument: the first suited to pursue a clipping by the given amount on the longer size of the layer (which can't be known beforehand, at times: is the layer's longer size its width or its height? Henceforth the interesting utility of such a function) and of a second proportioned amount, drawn and calculated to suit the smaller side of the given layer.
Therefore, calling in WHProportion tantamount to mean or to be about to resort to such a tailoring of a clipping amount, although in the functions that I have devised and that implement Dhtml animations, WHProportion, when called in, would also grant a way to escape its services, in case you just want to clip by the specified amount argument without any background automatic resizing of such amount to the layer's proportions.
You in reasonably safe, caring hands!

8) I also include a subroutine to read/set the background color of a layer: if no arguments passed, returns the current bg color.

9) Writing / Reading to/from a layer: actually the functions that accomplish this task were initialized upon DOM detection build up (for they were performing a branching between browsers using innerHTML and NS4 using document.write, and that whole section was about branching actually as well as about strings meant to undergo an eval like, actually, the function initalized overe there with keyword new is), but we explain them here for they do belong to the set of the traditional actions a layer can undergo. We have here a very interesting approach: you can:

  1. READ from whatever layer (even on NS4!) by invoking:
    myVar=readText()
    This expression is a function built up at DOM detection start up which returns the text stored in a layer. If you read and assign to this function to a variable like, in our example, myVar, then myVar would store the returned text of the given layer.
  2. WRITE onto whatever layer by invoking:
    writeText('hallo or a variable')
    In such case you still pass as argument either the text to write in between apex, or a variable which holds the text (in such case the variable must be passed without apex or would be interpreted not like a reference to a variable but like a text to write: in other words if you have a variable which is like coolText="cool game!", you can then do:
    writeText(coolText)
  3. APPEND text to a layer. In fact when you write to a layer, normally all text gets erased in order to accommodate only the new one; this is one of the very first approaches that let you at least append text; to accomplish this we store the data already written to all your layers in a hash like table (for hash like table do see at bottom of this file) and we retrieve the texts from there: this trick accomodates Netscape4 which is otherwise unable to read a layer contents!
    To append just use the same syntax used to read, but add as a second argument number 1:
    writeText('hallo or a variable',1)
  4. Be warned on a few Netscape 4 issues: first, do not set Css style declarations about the layer width or height: this might make Netscape go wild (yeah: seems that you can resize a layer in NS4 but not to assign safely enough and directly to it a height or a width by Css).

    Also, on NS4 padding and margins disappear after a resizing of a layer if they've been set by Css.

    Then do not write to your layer tables whose align property is set to "center" (even better: do not set a table align property at all) although you can quite safely set as such the align property in the <TD> cells of the table: if you set an align property to the table tag, you may see NS4 doing things like writing to the layer but being unable to... position it!

    Then, when reached the width limits of a layer upon writing (or appending) to it, NS4 is absolutely unable to understand the limit has been reached and would go on writing on some (apparently) non visible layer sector (even better: non existent; and fuck ya you damned Netscape 4! I spend 60% of my time to accommodate just you, sweetheart) and would show the appended text only after a while, accordingly, basically, to its own whims. Workaround: when appending text, be sure to introduce html line breaks by <BR> tags here and there... give a call to the Netscape guys if you find this unacceptable, don't blame me!

    Also, when reached the bottom of the layer, NS4 is utterly unable to provide you with scrolling bars or to stretch the layer in order to arrange the overflowing contents.

    All of this, obviously doesn't make the possibility to write to a layer hopelessly useless: rest assured: not at all!. It just constraints it into contents which can surely fit the given layer width and height, thanks to NS4.


Wanna test it?
Morgan Fairchild
TEST UNIVERSAL LAYER WRITING
Morgan Fairchild
WRITE:
APPEND:
READ:

Always set a layer-background-color property in a style declaration for a layer, or NS4, for mysterious reasons, in some cases cannot resize it dynamically (maybe it was transparent, but I really stumbled in some strange things with NS4 on this).
So that is the deal: each style declaration should bring, if you want to be safe with NS4:
layer-background-color: #ffffff; background-color: #ffffff
whereas:
  1. #ffffff is an hexadecimal value that you can change at your wish
  2. and the
    layer-background-color
    accomodates the background color rendering for NS4
  3. while the simpler
    background-color
    statement accomodates -abiding by the standards, actually- all the rest as far as an object's background hue may be concerned.

IN BUNDLE METHODS


THE HARD STUFF
Building Universal Layer Objects

Elvira
Welcome to the hard part, ya know: when the play gets tough the tough get playing: although if you do not want to bother with some explanations I've added for not experienced scripters, you can just skip to the section after the code.

It's a function, whose purpose is to operate like a constructor: a constructor is a function shaped in a particular way such that you should invoke it as an assignment (=) to a variable name of your choice. Of course, if a function is meant to return a value (by keyword return somewhere, usually at the end, of its body) after it has performed all its calculations, you can assign to a variable of your choice like, say, foo=100 the function itself instead of a stark value like 100.
This provided (as said) the function returns a value:
function myFunction(){var something=5+2; return something}
foo=myFunction()

which would result in assigning to the variable named foo the returned value, in our case 7.

But there is a second way you can assign a function to a variable name, and in this case even if it doesn't return a value: precisely, if the function is a constructor.
A constructor is a function meant to bestow a variable name not just one single (returned) value, but a full set of properties that will belong to that variable as its properties: in such fashion, your chosen variable will hold a whole set of values, and not just one, all of them accessible if you address them in the proper way. Some call this (namely a variable name that holds a lot of different values, and none the less isn't an array) an object: actually, I prefer to call this data structure, for that it is indeed: structured data.

In order to let a function perform like a constructor you cannot anyway just do foo=myFunction(), but you have to pre pone the keyword new:
foo=new myFunction()

This grants you that whatever variable name you initialize as a new yourFunction "object" would draw a brand new template form the given function, and each newly generated "object" will be able to perform on its own keeping itself distinguished by whatever other variable name initialized as another new yourFunction: keyword new, therefore, allows you to use a function like a template and use it to construct a whole host of objects all entirely independent from each other although all busy doing the same calculations: define once, borrow everywhere.

What independent means?
Well, a constructor implies that the function builds in its body a set of inner variables to which is pre poned most of the time the keyword this: each of these variable names would then become a property of the object foo (or whatever other name it may have) which gets assigned the function, so:

  1. if the function would be something like
    function myFunction(){this.someName=300}
  2. And your initialized variable name is foo (or even foo and foo2, for you can initialize as many variables as you prefer, with the names you prefer)
  3. and provided you have initialized them like:
    foo=new myFunction()
    foo2=new myFunction()

a subsequent invocation of something like:
foo.someName or foo2.somename would yield the value of 300 (and, as you may already guess, values can be not just read but set too). You may now understand better what the keyword this stands for: a placeholder for what is meant to be pre poned to the property name, which would be foo in our case.

Now, if you change the somename value of foo2 (which accounts for 300) by a statement like:
foo2.somename="hallo"
you will realize immediately what being fully independent meant: in fact, now:
foo2.somename equals "hallo", but
foo.somename still equals 300
The objects drawn by the template are all independent, although they all share the same somename property!
In blue, are highlighted the names given to the property set: each newly initialized layerManager can invoke (set, read, change) its own instance of the given property!


CHECK IF A PROPERTY NAME
is available
This snippet checks if a property name for your own crafted ULMA object properties is available. Checks on layerManager constructor and on managerMethod constructor, so you can avoid conflicting names.
It is Case SeNsItIvE.

[ NO case sensitive? » ]


LAYER MANAGER

You could now certainly initialize a Dhtml object like:
foo=new layerManager ()
None the less, you have to pass some arguments:
  1. The managerName and layer arguments must be strings (in between single -preferably; otherwise double- apex quotes, that is) which will carry the former the very same name of the variable which is going to be initialized as a layer manager (foo itself in our case) and the latter is the id assigned to a layer (each layer to be manipulated must have: an id and a style, the latter of which must include a position:absolute statement and a top and left position on the page at least, as well as the background color after the recommendation I've made to you halfway of this file and regarding NS4); so, say:
    foo=new layerManager ('foo', 'layerName')
    This means that upon building a new layerManager, you first declare what the name of this manager is going to be and then you declare what is the name of the layer it is going to manage: makes sense, doesn't it?
  2. The originalWidth and originalHeight arguments are actually optional, but if you pass them the layer will be resized, upon abilitation of its manager (see below), to their values by the agency of an invocation to the resizer() function.
    This means that, given in our DOM set up building the values of innerW and innerH are shaped to hold the width and height of the document, if you just do:
    foo=new layerManager ('foo', 'layerName', innerW, innerH)
    this would immediately generate, upon abilitation of the layer manager, a layer whose width and height are those of the visible document. Of course, you could pass just numbers.
    If you don't pass them, they will be generated anyway and hold the current dimensions of the layer (read using once again resizer but this time passing to it no arguments, which would cause the resizer function to return an array whose first entry is the width of the layer and whose second entry is the height of the layer, without performing any actual resizing on the layer but limiting itself to read from it).
  3. The top and left arguments are still optional: if you pass them (one or both) the layer would be immediately repositioned, upon abilitation of its manager, accordingly. Just keep in mind that if you pass zero, this would not move the layer to coordinate zero, but leaves it still and unaffected at the coordinates where you put it originally (unless you pass zero as a string in between quotes: '0').
    The dispatching performed here forcibly counts in page offsets (scrolling level of the page): we assume when you abilitate a layer you want it to be within the surfer sight scope, in case he/she has scrolled somewhere else; if you want to exclude the page offsets (and I do not think so), this time you have to pass the values such that offsets are already subtracted (which might mean to pass negative numbers): this would certainly neutralize the forcibly added offsets.
  4. Also the url argument is optional. I added it in case you're triggering the action by an anchor with an onClick event or other event handler and you're postponing the redirection to the given url to the end of the animation. If in a link you put an:
    <a href="http://www.bho.com" onClick="foo=new layerManager ('foo', 'layerName', widthvalue,heightValue, topPos, leftPos, this.href) ; return false">
    The return false set as the last statement of the event would make the redirection impossible, while the this.href would pass as an url argument the href value (in our case http://www.bho.com) so that it can be later retrieved as: foo.url and assigned to the location at a second time, in order to redirect to the given page only if/when the animation is over.
    Only setback with this argument, if you want to set it you're forced to set all the preceding ones too, at least as zero if you want to leave the width/height and top/left settings of your layer unaffected:
    foo= new layerManager('foo','layerName', 0,0,0,0,'http://www.cool.xyz')
Actually, the originalWidth and originalHeight arguments at point 2 are generated anyway upon abilitation for they are sort of necessary: in fact if you clip an object, be warned you won't be able to know any longer its original width and height values unless you've stored that data somewhere prior to clipping: this is another reason a call to this constructor may be critical for the portability and success of your Dynamic Html, for it automatically stores such values even if you do not pass them.

As I said in point 2, you could stretch a layer to fit the document (say window) dimensions: upon doing this, I came across an unbelievable behaviour by NS6 and Mozilla at least up to date (NS 6.2): if the layer was stretching to the full page, upon clipping such layer, NS6 and Mozilla did not show anything of the page contents behind the layer (I was clipping it little by little to unveil the background) or just show a blank background: if you just take a nick from that, it works.
No other solution I attempted was successful, so this constructor tads off 0.1 pixels in case the width and height of the layer is the same as the window.
None the less, the 0.1 thing works, but not always: at times it isn't just enough, other times also even if it works and shows the background with all its contents, you can't interact with the links though.
So, if that doesn't work you have to do two things to address this so much self evident and quite serious bug of NS6/Mozilla:

  1. Reduce the size (height and width) of the layer if one of its dimensions stretches to the whole window width or height until the background is no longer blank when appearing
  2. To reabilitate the links (and also in order to avoid that upon scrolling the layers would reappear as flashing items or ghost prints - oh yes, NS6 could do that too), always remember, upon finishing the clipping of a window width or height size layer, to:
    • hide the layer
    • do reset its width and height to a very small size, that is: much inferior to the window width/height
    • These two tasks must be accomodated in order to happen at the conclusion of your animations (do not start an animation and then call a hide of the layer, for this would hide the animation itself).
As a consequence of this great stuff of the more modern versions of the Mozilla family (something that really annoys you when you've to bring home some bread: not beacuse it's a bug, but beacuse Nestcape has by now fairly too long a story of bugs dating from the earliest version 4 up to all its 4 subversions, and we're all jobbing folks here... we'd like to devote our time to fix Netscape bugs limiting it to a reasonable amount of time, this is properly what I mean), you should also never rely upon dynamism whose purpose is to build layers whose width exceeds the innerW and whose height exceeds the innerH variable values (complain with the Netscape guys for this, although I see no reason why you should make a layer which exceeds what can be seen and therefore is already invisible - by the way the solution for a layer that covers a whole page even to its bottom which is out of the window, is a layer whose height amounts to the innerH and which scrolls up and down upon scrolling! this, as you will learn with a future file I will upload, can be accomplished with a watermark).

Also, Mozilla exhibits a very strange behaviour in one more case at least: if you clip a layer so that it shrinks, and then you do not set it to invisible, Mozilla behaves as whether the layer would still stretch upon its original width although it is correctly clipped by Mozilla: the implication of this conundrum is that whatever object would have been beneath the layer margins and that is now visible for those margins shrunk, would still go on behaving as if a layer were overlapping upon it - and therefore buttons could not be clicked if they were that object in case...
Do set to invisible a layer after you've clipped it into contraction, for even if it is invisible since it has been clipped, Mozilla can insist behaving as if it were still visibile although... it correctly doesn't show its clipped margins. I call this stuff cool: when you meet them you can work them out overnight if you don't sleep.

A few other properties initialized in within this object cannot be clear yet to you, but let me stress that you need also a global variable named ULMAObjects to be defined somewhere in your document (I put it before this function code as you may have noted).
Upon constructing a new object by layerManager , the ULMAObjects array is added one object, the newly generated object itself:
ULMAObjects[layer]=this
This may appear puzzling: I am passing to it as an index the layer argument you passed to the layerManager function itself upon construction of a new object.
Well, this means that that array is an hashed array, namely an array whose indexes are not numbers but literals, and if you have no clue what it is and how to deal/loop them, I do urge you to read the file on hashed arrays with special reference to the bottom section and the input given by Danny Goodman which is un valuable for everyone committed to dedicated scripting: it can be found clicking here.

I use such an array to store global data on active layers, since each entry (property more correctly: for hash like arrays have no entries and length, but properties) is a layer name: and since each layer can have but one single layerManager, whatever data stored for that layer such as:
ULMAObjects[layer]=this
would let you inspect by a [for-in] loop all the prioperties of each manager of each layer, allowing you thus check, for instance, if a layer is still undergoing some action or, by and large, whatever else property you know belongs or has been assigned to the layerManager of that layer, such as:
ULMAObjects[layer].someProperty
You may wonder why I used the layer name as an index instead of the name of the layer Manager: but a layer name and a layerManager name, although different in names (although I do guess you could give a layerManager the same name of its layer to make your codex crystal-clear), are the same thing, in ULMA!
Anyway, my personal suggestion is: give to your layer managers the same name than the layer ID they manage: it's optional, of course; but such a move would give to you the greater flexibility when scanning ULMAObjects, for you can pass as parameters whatever best suits your needs. Also, it would make your coding more intuitive: when calling in a layer manager knowing it holds the same name of a layer, you can immediately understand whose manager it is.

Also, keep in mind that you may want to hide a layer before resizing it so to make it visible only when undergoing an animation: to hide a layer just use the function foo.shower.execute(0) passing to it a zero to flag you want to hide it.

Critical note: I have dealt so far with the bundled methods of your layerManagers as if they were already there and as if they could be invoked in the way you saw: actually it is not like that: I featured the explanations that way for they were more crafted by the traditional approach. ULMA is not too traditional anyway.
So remembert this: after you have initialized your layerManager, you have to abilitate its pool of default methods: it gets achieved just by:
foo.abilitate()
It is upon this call to abilitation that your layer gets also resized/dispatched and so on accordingly to the arguments you have passed upon constructing the new layerManager!
Now all your built in metods listed above belong to this layerManager and it can use them!
To run one of its built in methods:
foo.shower.execute(1)
That is, the keyword execute() triggers the built in method appended before it, and you pass to execute the arguments exactly as if they were inside the function appended before it:
it will propagate to the named function, which will propagate to the layerManager, which will propagate to the layer!
Also: do not confound a call to execute() with a call to run(): the former triggers a direct action, the latter triggers an animation: if you'd attempt to trigger an animation by calling in execute() the animation would display only its first step, and then would not go on, for only a call to run() involves a timeout (which is a built in repetetive call to execute itself until some conditions which stop this repetetive call are met). So, when you call run on your method the syntax is like foo.myMethod.run()
 
You may have noticed that both the layerManager constructor and the managerMethod constructor have been devised like a new type of class, for they hold many default properties (a necessary step, for every scripting environment must set a starting lot of objects, attributes, properties, although you could have populated those constructor shells with properties of your fantasy) and methods.
Obviously, nothing prevents your from adding or appending new properties in case you need so. With an approach which, by the way, is really consistent with the W3C DOM1 specifications for Dhtml, you can surely add your properties to the layerManager foo by declaring:
foo.NewProperty="Hi"
and provided you've initialized the method as a new managerMethod, you can append properties to each enabled method as well:
foo.MyMethod.myNEWproperty="Hi from method"
Anyway, I've provided you with a built in method which works on the layer manager itself and on each of its initialized methods as well, and whose name in both cases is:
setAttributes.
It works as follows:

  • Pass two arguments: assumes first argument is the name of the newly generated property (and this first argument must always be a string and therefore be passed in between quotes), second argument the value to assign to it (can be whatever data type, even if in the examples I use strings in both cases).
    Use it on:
    1. layerManager:
      foo.setAttributes("newPropName", "whatever value type")
    2. a managerMethod:
      foo.aManagerMethod.setAttributes("newPropName", "whatever value type")
  • Pass more than two arguments: assumes they are a list of elements whose odd numbers are property names to be initialized holding as correspondent values the subsequent argument:
    Use it on:
    1. layerManager:
      foo.setAttributes("newPropName1", "whatever value type 1", "newPropName2", "whatever value type 2", "newPropName3", "whatever value type 3")
    2. a managerMethod:
      foo.aManagerMethod.setAttributes("newPropName1", "whatever value type 1", "newPropName2", "whatever value type 2", "newPropName3", "whatever value type 3")
  • Last but not least, if the arguments is only one and it's an array, it can detect it and would scan the array for matching properties/value pairs.

Bonus Function
Let's imagine you want to assign to a whole lot of attributes the same value, and pass this either to setAttributes or to setDefaults (see further on for this mere variation on setAttributes). It would certainly be boring to keep writing, say:
foo.setAttributes("prop1", 1, "prop2", 1, "prop3", 1, "prop4", 1) //etc etc...
for as you see the value is always 1.
Well, in such case here a bonus snippet function that, if you pass as its first parameter the value you want to share among the properties and as a second parameter an array (numerical array) whose each entry carries as a string the name of the property, would return as its output an array where each entry of the argument array is alternated with the provided value, so you can save some significant time (namely, with such an output, you can just pass to either setAttributes or setDefaults one argument: the array produced as output by this following code):

function alternateValues(value, array){
var output=new Array(0);
for(var i=0; i<array.length; i++){
output[++output.length-1]=array[i];
output[++output.length-1]=value;
}
return output; }

Alternatively, I've just thought it may be a good idea to add to the layerManager such a function as a built in one. So you can also call foo.alternateValues(value, array); this built in method is more powerful than the static snippet featured just above, for not only it is an internal built in method, but it can also accept that you pass as first parameter still the value as usual, and as subsequent parameters the name of the properties such value has to be assigned to either as a subsequent traditional list of arguments (without necessarily resorting to an Array as second argument, that is), or as an array in the same fashion outlined for the snippet above.

setAttributes has two aliases: one is setAttribute, namely without the ending "s" to forestall some common typos, and the second is a shorthand: set.
The remarkable utility of this method, working both on layer managers and its methods, is that it can really save you lot of typing (and typos) when you have to add many properties to a custom method or when you have to... change their values! In fact setAttributes can certainly add attributes which are not there yet, but can also just change the values of the existing ones. Definitely useful.
 
As far as arguments are concerned in run(), we have some issues: in fact run is the method that triggers the timeout and passing arguments to timeouts can be a problem. But as you might guess, the method I just described above and named setAttributes is a a great way to set the properties either of a layer manager or of some of its enabled methods. By and large, in an ULMA or just a DHTML environment, arguments appsed to a function are either the name of the layers (an overrun necessity in ULMA, for by the agency of layerManager constructors such necessity results completely overturned and overhwlemed) or values that should affect their performance. Since in ULMA all such values are set as properties either of the layer manager or of its enabled methods, passing arguments to a Dhtml or ULMA function tantamounts to the intention to set property/values pairs.
There we go: you don't actually need to pass arguments:
  1. First use a call to setAttributes - either on your layer manager
    foo.setAttributes("att1", "value1");
    or on one of its method
    foo.anEnabledFooMethod.setAttributes("att1", "value1");
  2. The just run (or execute) the method:
    foo.anEnabledFooMethod.run();
    without therefore any need to pass arguments at all, but just pre-poning a call to setAttributes.
Anyway I deviced a way to let you even pass some arguments to run() - just skip this section if you're not interesetd in these developer's technicalties, this is ULMA advanced stuff. Moreover, ULMA relies on layerManagers, so you should not be intereseted in passing arguments to a managerMethod at all, since you can manipulate argument equivalents by simply appending to your layerManager a new property at your custom method start up (foo.newProperty='hallo world'). Anyway I strived to let you a way to even pass arguments.
  • ADVANCED SECTION: do skip if not interested in advanced techincalties.
    run() can accept one argument, provided in the definition of your myMethod such argument is set (it's in between the round brackets in your custom method definition, that is): so, say the definition of a silly myMethod might be:
    function mySillyMethod(arg){alert(1+arg)}
    if mySillyMethod is initialized to be a new managerMethod of the foo layerManager, you can pass arg upon calling run as:
    foo.mySillyMethod.run(10) //which triggers an alert carrying 11 (1+arg), obviously.

    You may wonder what if you need to pass to run() more arguments: pass them as an array, they will be unfold as a subsequent set of arguments (a variation on a trick by a language known as Perl).
    So say you have a custom method defined as follows:
    function mySillyMethod(yourName, yourSurname){
    alert(yourName+' '+yourSurname);
    }

    You need to pass 2 arguments but run accepts only one: pass this only one as a new Array, so say:
    var dumb=new Array("John","Smith");
    If you call run passing array as:
    foo.mySillyMethod.run( dumb )
    this would unfold, when propagating to mySillyMethod, as:
    mySillyMethod(john, smith)
    So far so good, you got how it works. But you also got a serious drawback we stumble in when attempting to pass strings to a timeout method: string arguments get read without quotes, therefore as variable names: as long as what you want to pass are numbers or indeed variable names with a global scope, very good: but if you want to pass strings, Houston we have a problem.
    The solution out is to pass strings nesting in it escaped single apex:
    var dumb=new Array("\'John\'", "\'Smith\'")
    foo.mySillyMethod=new managerMethod("foo", "mySillyMethod");
    foo.mySillyMethod.run( dumb );

    Morale: do not pass arguments to run, actually you don't need it: append properties to the layerManager or to the managerMethod. If by chance and for reasons I can't spot you badly need it, refer back to this advanced section.
    ADVANCED SECTION OVER

So, here is your lot whereas foo is still the placeholder for whatever variable name you may want to assign to it:

var foo;
foo=new layerManager('foo','layerName'); /*other arguments are optional*/
foo.abilitate() //pool abilitated! + layer moved/resized...!
/*to execute some method of the newly abilitated foo pool, like dispatching it somewhere else:*/

foo.dispatcher.execute(50,200); /*it does dispacthes the layer named layerName to top 50, left 200!*/


The keyword execute( ) accepts as many as 6 aliases:
  1. exec( )
  2. exe( )
  3. ex( )
  4. x( )   //it's a lowercase x
  5. X( )   //it's an Uppercase x, for fashionable guys!
  6. e( )
Therefore expressions like:
     foo.backgrounder.execute('#ffffff');
     foo.backgrounder.X('#ffffff');
are quite equivalent.
By the way the expression above sets to white -'#ffffff'- the background of the layer whose manager is foo.
To add a method:
 
foo.aMethod=new managerMethod('foo', 'aMethod');
 
to run it:
 
foo.aMethod.run();
 
or if aMethod needs arguments prior to being run:
 
foo.aMethod.setArguments("arg1", "val1", "arg2", "val2");
//and then:
foo.aMethod.run();
 
or if aMethod itself is crafted to get arguments:
 
foo.aMethod.run( yourArgumentOrArray );

run() has no aliases.


ASSIGNING NEW METHODS
How to assign new customed methods to the pool of those already abilitated for the given layerManager

Now, more code: another constructor (the last one) that when launched on your variable objects (such as foo) is about to trigger whatever type of animation (you may have noticed an inconsistency in the names: layerManager vs managerMethod instead of methodManager: when I realized this small thing, ULMA was already online with many features, so I suppose we just have to bear our triflesome exceptions in every language or approach we deal with):
MANAGER METHOD

As you see the constructor has many arguments although as you can guess you do not need set all of them. I want you to focus solely on the first 2:
  1. managerName is a stringed version, namely in between single (preferably; otherwise double) apex, of the variable name you assigned upon constructing a new layerManager (in our cases foo and foo2): so in the case of foo=new layerManager() , what managerName argument would be here would be exactly... 'foo': managerMethod ('foo')
    In my system each method must be invested with the characteristic to borrow a copy of itself to whatever given object (variable) is going to own such a copy, generating a copy from the managerMethod constructor template: in order to let such a thing happen each copy from the template must be able to build, upon assignement to a variable (object), a path that enables it to make a direct reference to this object (variable) itself to which this copy of the template is going to be assigned, or there would be no actual dependency: and no such path could be established if I do not pass at this stage the name of the variable (object) that holds this newly generated copy of the method; and therefore you pass such name to allow the new method copy argue from it which its owner is (what variable name, that is). This is performed by the statements:
    1. this.variable=eval(managerName)
    2. this.execute=eval(methodName);
    In this way each method can be used on more layerManagers, and each layerManager can hold more methods, wrtiting just one single istance of each method which will be valid to all layerManagers instead of writing brand new methods for each layer or new task!
    This is why we first build a new layerManager and later we assign to it new managerMethods: to allow one new layerManager object to own more than one method, which couldn't happen without separating the two generations, the generation of the object from the generation of all its possible methods.
    Therefore, the former expression (1) grants that a copy of the method is assigned to another layerManager, the latter (2) grants that each layerManager can execute its copy of whatever method is assigned to it.
  2. methodName this is the funny part!
    This last constructor mostly works presuming you have a whole library of functions (that you may actually build for yourself although I am providing several over time on this very same web site) to perform actions, so imagine you have a particularly shaped function named myAction: you do as follows: you pass as a methodName argument the stringed version (its name in between single -preferably; otherwise double- apex, that is) of your myAction itself:
    foo2=new layerManager ('foo2', 'layerName')
    foo2.myAction=new managerMethod ('foo2', 'myAction')

    Such a move would instantaneously add your function as a new property of the foo2 object; for foo2 does is an "object" -structured data- indeed given you have initialized it with the layerManager constructor in the first place, and therefore can accept for sure you add to it another property by concatenating the foo2 variable name with the name of your function by a dot.
    If you now initialize this latest lot (foo2.myFunction, that is: foo2 plus its newly added property) as another new object, this would ramificate and propagate a data structure not only able to arrange independent objects by the agency of the former layerManager constructor, but also a full set of methods that by the agency of the latter managerMethod constructor can now be invoked by these objects as independent calls, allowing thus to arrange one single function and to use it at the same time and moment on a (theorycally) infinite amount of layers, for each layer can cast its own template out of it.
    Pass as 2nd argument of managerMethod the very name of this function, the script will work it all out for itself, provided that the given function (myAction, in this case) is defined somewhere in the document (an invocation of a function not defined would obviously cause an error) and provided it is shaped with some knowledge and awareness of the way it is going to be used (taking avail of keyword this and of the names of the properties as defined in layerManager, this is what awareness properly means here. In the future I'm going to issue an example file on this).
  3. The speed argument defaults to 1000 (milliseconds) and is the timeout timing: in fact as soon as you construct a new managerMethod , it may trigger a timeout that repeatedly invokes itself until it works out there is nothing else that can be manipulated on the given layer: therefore the speed for such timeout must be invoked (a setInterval, actually, not a setTimeout).
    If you don't pass it, you can still set it at a second time by:
    foo.myMethod.speed=250 //or whatever value
  4. The amount argument is the amount you want to use for (for instance) clipping a layer. It works in two ways:
    • Pass a number: the function will run WHProprotion() on that amount and yield an array of two amounts, one for the longer side of the layer and one for the shorter one.
    • Pass an array such as:
      foo2=new layerManager ('foo2', 'layerName')
      foo2.myAction=new managerMethod ('foo2', 'myAction',0, new Array(50,38))

      and the function will abide by those numbers without daring any proportion on them and applying them to... well to what?
      It depends on whether in your myAction function you have instructed to be processed first (for instance in a clipping process) the top margins and later the bottom margins (or vice versa; in any case first A, then B): in this case the number held by the first array entry will apply to the first property defined in your myAction function (top margins, or A) while the number held by the second array entry will apply to the second defined property (bottom margins, or B).
      Since it may give to you a headache and you may be wondering how you do if you want to invert those values, well you could certainly invert them manually and just pass new Array(38, 50), but I have added a small trick: if you pass an array whose length is above 2 entries, it swaps the first two entries by itself.
      If on the other hand you face some need to perform this swap on the very same numbers generated by WHProportion (that is: you need both : the proprotion, and to swap the numbers yielded by the proportion itself - for WHProportion returns an array and, being invoked in within managerMethod, generates such array from within: passing it like an argument means to generate an array, which would skip the WHProportion generated in within by... generating it oustide), well you have then to perform the proportion outside the method and assign the outcome to a variable (let's say named swapped), and add this variable an entry, passing such latest result as the argument:
      var swapped=WHProportion('layerName', myAmount)//myAmount or a number, like 50...
      swapped.length++
      foo.myMethod=new managerMethod('foo', 'myMethod', speedValue, swapped)

      You may wonder why I provide you with these ways to swap the entries if you want: better safe than sorry.
      If you are to change the amount argument to accomodate, for instance, newly generated environment conditions or layer communications, do as:
      foo.myMethod.setAmount(100) //100, or whatever.
      If you don't pass it, you can still set it at a second time by:
      foo.myMethod.setAmount(100) //100, or whatever value
  5. All the arguments after amount would be detailed when I feature dynamic functions, anyway they are meant to set, basically, either starting and ending coordinates for a positioning process (defaulting the end to [0,0] coordinates) or for clipping processes (defaulting the end to [0,0] attained limits)
    As far as positioning functions are concerned, the goal of the arguments named startTop, startLeft, endTop, endLeft should be clear and self evident by their names themselves.
    If you don't pass them upon invoking the constructor, you can still set them at a second time by:
    foo.myMethod.startTop=250 //or whatever value, whatever property
    Conversely, for clipping functions, you have a whole set of properties for starting and stopping the clipping processes from top/bottm/left/right directions: the functions (you can find them clicking here) are able to assign to such properties the correct default (and therefore most likely) values: none the less if you want to clip, you can change these properties on the fly before running your functions (see below on how to run).
    So, to change one of these properties for a, say, myClippingMethod named method that would take avail (manipulate, that is) such property, the syntax would be:
    foo.myClippingMethod.stopClipTop=300 (or whatever other assignements best fits your customized method).
  6. Note that each method holds, along with the execute() method, another built in method named run(): this applies to animations, that is: when you do not want to execute the method just once, but repeatedly; it therefore allows you to determine when to run your animation:
    1. You first initalize a new layerManager
    2. you then add to it its methods initalizing for that layerManager as many new managerMethods as you want
    3. Passing parameters to both constructors above you can determine a whole host of properties.
    4. When you feel like running your animation (your custom method on your layer) you just do:
      foo.myMethod.run()

      NOTE:
      Such call to run will also update a managerMethod property named communicatEnd to 0, in order to flag to other possible "lurking" methods that a process has activated the foo.someMethod method on this layer (the foo.someMethod.communicateEnd property returns zero as soon as run() gets called on the method: it therefore flags the method has not reached an end yet, that is. As you are to see, a call to stop() would immediately flag the opposite); you see, it can be important to let other methods know that no call to stop() (a built in method which conversely would update the communicateEnd to 1) has been performed yet as far as some specific managerMethod of your interest on the given layerManager is concrned. There are actually several items that attempt to communicate the status of a method of a layerManager:
        1. foo.myMethod.isRunning from methods
        2. foo.layerEngaged from the layerManager
        are properties available to inspection, but if you want them to change their values in order to flag something from within your custom methods, you have to program your custom method to do so on either or both.
      • On the other hand
        1. foo.myMethod.communicateEnd from methods
          1. 1= inactive (ended; default value)
          2. 0= active (no end)
        2. foo.animationCoords['myMethod'][0] which is a component of the layerManager
          1. if no animationCoords['myMethod'], don't even check further: myMethod has never been triggered before! A good way to inspect even this, in case you may need...
            But conversely if animationCoords['myMethod'] is a property which exists, well it is an array of two entries then, and so check if:
          2. animationCoords['myMethod'][0]=0= inactive (default value)
          3. animationCoords['myMethod'][0]=1= active
        These latest two properties (communicateEnd and the animationCoords['myMethod'] object, that is) get updated automatically and therefore you can inspect them whenever in order to know whether a method is still running. The reason I had to device two different flags is not only to provide two properties (one in each managerMethod, another in the layerManagers), but is also due to the fact that communicateEnd is, for instance, a bit faster: at times the execution of a "lurking" method that has to check the status of another method to assess what to do, is so quick that before the former method updates a value, the latter method that inspects it has already deduced the method has stopped since the former couldn't update the check value quickly enough in a span of