In part one of this two part series, I explained the reason behind Leaflink and gave an overview of the different technologies used in creating it. In this next part, I will explain in detail just about every feature that was put into Leaflink.
The first aspect of Leaflink that I want to talk about is the "Dashboard". The Dashboard came about as an afterthought to Leaflink. I thought to myself, why have these very useful links only appear on the Leaflink site. Why not put a handy little toolbar or dashboard on top of EVERY internal page?! And so I created the Dashboard, which is simply a nicer representation of the links added to Leaflink, arranged by icon (sort of like the thumbnail or icon view in windows explorer.)
The idea was to have the Dashboard sit on top of every one of our internal pages. This way we could easily jump from one page to another. This works better than using bookmarks because links can change, pages can be removed or new ones can be added at any time.
Simply put, the Dashboard is nothing more than a DIV that fades in and out when the user clicks on the top black bar on the page. In this example, you will see that when you click on the Dashboard bar on top, the Dashboard fades into view as the background fades out. The background doesn't fade out completely though.
The default behavior of the Prototype Effects are to be automatically run whenever you instantiate them. So if you create a new fade effect and pass it the id of the element you want to fade, it will run the fade effect right away. This is not what I wanted, as I needed to modify a few attributes before I ran the fade effect. To accomplish this, I had to modify the Prototype library just a bit. Only a one line change:
// node snippet. around lines 595 - 605
Effect.Fade = Class.create();
Effect.Fade.prototype = {
initialize: function(element) {
this.element = $(element);
this.speed = 10; // new accessor added to control fade speed
this.timeout = 50; // new accessor added to control fade speed
this.start = 100;
this.finish = 0;
this.current = this.start;
/* comment out this line to stop the fade effect
from automatically running when instantiated.
The same line of code should also be commented
out in the Effect.Appear function. */
//this.fade();
},
.....
This takes care of Prototype. The next step is to create our own Dashboard object in javascript. The reason I did this was mainly to allow me to use this Dashboard effect on multiple DIVs easily. I was also inspired by Prototype's object oriented coding style.
The code for the Dashboard object is a little lengthy and there are some confusing references to variables with strange names (wrapper, glass). I will explain them both shortly:
var Dashboard = new Object();
Dashboard = Class.create();
Dashboard.prototype = {
initialize: function(element, wrapper) {
this.element = $(element);
this.wrapper = $(wrapper);
this.dbEffect = null;
this.wrapperEffect = null;
this.wrapperOpacity = 25;
this.fadeSpeed = 25;
this.timeout = 50;
this.glass = this.createGlass();
},
createGlass: function() {
g = document.createElement('DIV');
g.id = 'glass-' + new Date();
g.className = 'glass';
g.style.display = 'none';
g.style.height = document.body.offsetHeight;
g.style.width = document.body.offsetWidth;
return g;
},
isOpen: function() {
return this.element.style.display == 'block' ? true: false;
},
show: function() {
if (this.isOpen() || !this.element) return;
if(!this.glass) {
this.glass = this.createGlass();
} else {
this.wrapper.appendChild(this.glass);
}
this.dbEffect = new Effect.Appear(this.element);
this.wrapperEffect = new Effect.Fade(this.wrapper);
this.wrapperEffect.finish = this.wrapperOpacity;
this.dbEffect.speed = this.wrapperEffect.speed = this.fadeSpeed;
this.dbEffect.timeout = this.wrapperEffect.timeout = this.timeout;
this.dbEffect.fade();
this.wrapperEffect.fade();
this.glass.style.display = 'block';
},
hide: function() {
if (!this.element) return;
this.dbEffect = new Effect.Fade(this.element);
this.wrapperEffect = new Effect.Appear(this.wrapper);
this.wrapperEffect.current = this.wrapperOpacity;
this.dbEffect.speed = this.wrapperEffect.speed = this.fadeSpeed;
this.dbEffect.timeout = this.wrapperEffect.timeout = this.timeout;
this.dbEffect.fade();
this.wrapperEffect.fade();
this.glass.style.display = 'none';
if(this.glass) {
this.wrapper.removeChild(this.glass);
//this.glass = null;
}
}
}
Let's go through this step by step. To keep in stride with the Prototype coding style, I create and instantiate my object the same way. Here, element refers to the element we are declaring as our Dashboard object. wrapper refers to the area (most likely a DIV) that will be fading out when our Dashboard is fading in. I usually label my outer DIV (which holds the content of my page) #wrapper, and that just happens to be the element I am fading out, so I just called this variable "wrapper".
The next two variables are dbEffect and wrapperEffect. These variables will be used to assigned the effects to be applied to our Dashboard and Wrapper objects, repectively. I chose to use the Fade and Appear effects, but any effect that accepts an element or ID would work (for example, Scale, Squish, etc. from the Prototype library.)
The next few variables are just to control the opacity and speed at which the Dashboard fades in and out. They are pretty much self explanatory. You can play around with them to get the desired opacity and speed for your Dashboard. These are simply default values and can be overridden.
The next important variable is the glass variable. The glass variable holds the element created by the createGlass function. What this does is create an empty DIV with a transparent background image tiled across it. Every time the Dashboard appears, this glass element is put on top of everything else behind the Dashboard. In other words, there is an invisible glass layer that sits in between the wrapper and the dashboard. The width and height of this glass layer is set to the width and height of our content. This allows us to do two things.
- Stop the user from interacting with the rest of the page while the DB is open.
- Assign event handlers to the glass to control the showing and hiding of the DB (explained blow)
The first usage of the glass layer is simple enough to understand. The second usage was an added extra feature that I added to enhance the "oooh, ahhh" effect of the DB. Since we have a reference to this glass layer when we create our DB, we can easily attach event handlers to it. When I first created my DB object, I added a onmouseover event handler to the glass layer. When the user would mouse over the glass layer, the Dashboard would hide and the wrapper would come back into focus. This became a little annoying as sometimes the user would accidentally move their mouse around, but did not want the DB to hide. All I did was change the onmouseover to on click and the problem was solved. Now when the user tries to click anywhere outside of the DB, the DB will hide and the background will fade back into focus (optionally, there is also a close button which does the same exact thing.)
The rest of the code in our DB object is to control the hiding and appearing effects of both the DB as well as the wrapper. Also note that I give the glass layer a unique ID every time it is created. This was done to allow for multiple DB objects on the same page, each with its own glass layer.
Here is the code to instantiate the DB object and add the event handler to the glass layer:
/* 'db' is the ID of the DIV which holds the contents of our dashboard.
'wrapper' is the ID of the outer DIV that holds the content of our page.
note: the DB DIV cannot be inside the wrapper DIV, otherwise it would
also fade out with the wrapper
*/
var db = new Dashboard('db', 'wrapper');
db.glass.onclick = function() {
db.hide();
}
I hope I was able to fully explain how the Dashboard works. Feel free to visit the example page and play around with it. I would recommend looking through the source code to get a better understanding of it. I haven't really commented my code too much, as most of it is pretty self explanatory. If you have any questions, feel free to contact me.
Oh yeah. You can download the code and do with it as you please. I just ask that you let me know of any improvements that you make to it and also a link to different applications of it would be nice as well.
That's it for part 2a. In part 2b, I will be going over the techniques required to save the current scroll position of a site on a form submittal. I'm sure you've been to pages where you are at the bottom of a form, you click on a link or a button to perform an action which submits a form. The page returns and you are all the way at the top again. However whatever you were doing is at the bottom, so now you got to scroll back down again. Very annoying.
Note: I am going to be away on vacation this weekend and won't be returning until next week, so part 2b may not be written until some time next week. Until then, play with the Dashboard and make your own versions of it :-)
