Customizing Squirrel Mail Login Page
For those of you who are using SquirrelMail
(link opens in a new window), you might have noticed that it looks
a bit well, let's just say amateurish :-) That doesn't go to say it isn't a good package! (I personally
love it and I think it does a pretty good job -- hence my additions to this software.) However,
as every open-source package in its early stages, there is still a lot more to be done to get it
to a stage where it works beautifully and looks just as good! If you have been using it for a while
chances are you have already installed some of the plugins
(link opens in a new window) and configured them to your needs. Some of
these plugins as you know allows certain visual customizations to SquirrelMail to make it look
more pleasant to the eye.
It is one of these plugins that captured my attention, as I figured out straight away it will allow
me to customize the login page! And here's how:
First of all download the Login Notes
plugin (link opens in a new window). This plugin allows you to add
your HTML code at the top and bottom of the login page. (Some of you might see already where this is going
I guess, but for the others, I will go into details about how to use this.) Follow the plugin installation
instructions (provided in the tar gzipped file) and enable the plugin.
For obvious reasons, I will use throughout this article the paths that I have used
to configure and install SquirrelMail on my machine, but the same notes should apply for any other
configurations as long as you replace the paths with the ones you have used in your configuration.
I am using a Debian Linux distribution, so my SquirrelMail plugins are installed under /usr/share/squirrelmail/plugins/
and the Login Notes plugin gets installed therefore under /usr/share/squirrelmail/plugins/login_notes -- your
configuration might be different but the only path we are really interested in is the plugin directory. (You
might also want to take a note of the images directory if you want to use images to customize
your SquirrelMail login page -- in my case, they rely under /usr/share/squirrelmail/images/, but
you might use a different path.) In order to avoid using the complete paths throughout this article,
I will be referring to /usr/share/squirrelmail/images as the images directory and
to /usr/share/squirrelmail/plugins as the plugins directory. Also, the
/usr/share/squirrelmail/plugins/login_notes becomes the Login Notes directory.
So, you've installed the plugin, and enabled it in your SquirrelMail configuration (use squirrelmail-configure
on Debian systems). Next, if you visit your SquirrelMail login page, you will notice a simple "Welcome" note
at the top of the login page and a Tux image at the bottom of the page. You might think straight-away that even so
the login page still doesn't look that much more appealing. Don't panic -- these are just the default
HTML tags that the plugin creator has put in! We're going to change these to make the login page
look prettier.
If you go to the Login Notes directory, you will notice that there is a config.php file and
a few other files, but we're only going to use this particular file to customize the login page. Simply
open it in a text editor, and you will find the following 2 variables: topText and bottomText.
You don't have to be a PHP programmer to spot these, as the file itself contains very few lines:
one line that declares these 2 variables as global variables and then 2 more sections/lines which assign
values to these variables. It is exactly the assignment sections we are going to change.
As you can imagine, the topText variable stores the HTML code that will be inserted in
the login page before the login controls; while the bottomText variable stores the
HTML code that will be inserted after the login controls. So, let's start with the top one:
Typically, at the top of the page you would want to put some branding for your server, in order to
remind the user the server s/he is logging into. Also, ISPs would probably want to add some self-promotion
banners or some sort of "offer of the day", which the user might click on in order to get access to
more services for their hostings. Also, this is probably the place to put any banners that might
instruct the user that the server will be unavailable for a certain period due to hardware upgrades
and such. Remember that any images you refer in this HTML code have to be present in your images
directory, otherwise the browser will show them as broken links/images! In my case for instance, I have
chosen to show just a simple stylish keyboard with the server name embossed on top of that, so the code
looks like this:
$topText = "<center><table border='0' width='100%'>"
. "<tr><td width='100%' align='center'><img src='/images/keyboard.jpg'></td></tr>"
. "</table></center>";
(remember that the dot in PHP is used for string concatenation.)Of course, you can have
anything else that takes your fancy here.
Let's now look at the bottom HTML part. Remember that this HTML code is pretty much placed in the page
right before we're closing the </body> tag. Which means that by the time these
tags are written onto the page most of the DOM has been built and the page has been rendered. While
this might not sound as much, if you think about it though, it's a really important detail: if the DOM
has been built and the page rendered it means we can execute a piece of JavaScript to modify
the DOM and apply/change styling!
You would wonder why not do this via CSS in the top of the page? Well for starters, the top of
the page is written after we have opened the <body> tag, and W3C says
that the styling should be applied in the <head> element; however, most of
browsers are tolerant to this and we can still try to apply CSS in that segment of HTML. Unfortuantelly,
it will get overriden by whatever template SquirrelMail uses! :-( (well, most of it anyway, you might
be lucky to have a few elements or attributes which are not overriden, but it's not worth digging for
this) However, using a piece of JavaScript, we can traverse the DOM and apply inline styling on
the fly which will then override any styling defined in the SquirrelMail CSS!
For instance, if you want to apply a background color to your page and change the default font,
all you need is a script like this one:
$bottomText = "<script type='text/javascript'>"
. "var bd = document.getElementsByTagName( 'body' )[0];"
. "bd.style.background = 'url(\"/images/splash_screen.jpg\")';"
. "bd.style.font = 'normal 12px Verdana';"
. "</script>";
(again bear in mind that any image referrenced here should be copied in your images
directory; either that or change the path /images/ to reflect where you have
placed the image file). Simply, all this function does is retrieves the first <body>
element (there has to be one single such element in the DOM!) and applies on-the-fly styling in
terms of background and default text. You will notice now that if you reload the page, the tables
used to align the login controls will still have the (default) white background. This can be changed
again in the same script like this:
$bottomText = "<script type='text/javascript'>"
. "var tbls = document.getElementsByTagName( 'table' );"
. "for( var i=0; i< tbls.length; i++ ) tbls[i].style.background = 'transparent';"
. "</script>";
Or if you want to customize the Login button, you can do something like this:
$bottomText = "<script type='text/javascript'>"
. "var btns=document.getElementsByTagName('input');"
. "for( var i = 0; i < btns.length; i++ ){"
. "if( btns[i].value == 'Login' ){"
. "btns[i].style.cssText = 'font:bold 12px Tahoma;color:white;border:1px solid white;background-color:navy;';"
. "}"
. "</script>";
I guess the bottom line is that really the possibilities are endless here and you can take customizing
the login page to any level you want following these guidelines -- the basic idea was to apply styling
on the fly to the whole document after it was loaded, and the combination of Login Notes
and JavaScript does it brilliantly!
|
Implementing Squirrel Mail Autocomplete Plugin under Mozilla Firefox
For the heavy SquirrelMail users, you are without a doubt using your address book a lot! (Unless
you have a really good memory and can remember by heart any email address in your address book! Personally
I can't! :)
And if you do, you might have contemplated using the Autocomplete Plugin for
SquirrelMail (link opens in a new window), which does autocompletion
of email addresses based on nicknames or first name + surname (or both!). I must admit, I love this
little plugin as it saves me a lot of time and it's quite easy to use. Unfortunatelly it only works
with Internet Explorer! :-( Well, this is at the time I'm writing this (2/Dec/06) -- future versions
of this plugin will probably include the fix that I've submitted for Firefox, however, if you don't want
to wait until the next release of the plugin, here's how you can change it to work with Firefox or
any other Mozilla browser.
For obvious reasons, I will use throughout this article the paths that I have used
to configure and install SquirrelMail on my machine, but the same notes should apply for any other
configurations as long as you replace the paths with the ones you have used in your configuration.
I am using a Debian Linux distribution, so my SquirrelMail plugins are installed under /usr/share/squirrelmail/plugins/
and the Autcomplete plugin gets installed therefore under /usr/share/squirrelmail/plugins/autcomplete -- your
configuration might be different but the only path we are really interested in is the plugin directory. In order to
avoid using the complete paths throughout this article, I will be referring to /usr/share/squirrelmail/plugins
as the plugins directory. Also, the /usr/share/squirrelmail/plugins/autcomplete becomes the Autocomplete directory.
So, you've installed the plugin, and enabled it in your SquirrelMail configuration (use squirrelmail-configure
on Debian systems). Next, log into the system using MSIE and make sure the autcomplete plugin works fine.
(Try the same with a Firefox browser and you will notice a whole lot of errors in your JavaScript Console!)
This is because the JavaScript provided with the plugin makes usage of some special features present only in
Internet Explorer (so it's not cross-browser). We're going to change this JavaScript in order to support
both IE (no point in breaking the compatibility with IE just for the sake of supporting Firefox only!) and Firefox
as well.
To do so, go to your Autocomplete directory and look inside the folder. The file we are really
interested in is functions.php. If you edit this function using a text editor, you will
notice a line containing the following comment:
// Spit out javascript
Following this line there is a biiig echo call which (as the comment describes it)
spits the needed JavaScript to the browser. So our task is to change this echo call
such that the JavaScript produced is cross-browser. For the impatient users, scroll down to the download
section and download this file, replacing the existing version (make sure you make a backup of it first!);
those of you who want to rather modify their local copy, here's how:
The first JavaScript function being output is called autocomplete_find (function autocomplete_find (str) {) --
we are not going to change this file, so scroll in the code right after the closing brace for this
function. Next we're going to introduce 2 new functions: selectRange and typeAhead as
follows:
/*
* TheLiv at liviutudor.com : This is our selection function
*/
function selectRange( src, start, len ) {
if( src.createTextRange ) {
var oRange = src.createTextRange();
oRange.moveStart( "character", start );
oRange.moveEnd( "character", len - src.value.length );
oRange.select();
} else if( src.setSelectionRange ) {
src.setSelectionRange( start, len );
}
}
/*
* TheLiv at liviutudor.com : And this is our magincal type ahead/suggestion function that does it!
*/
function typeAhead( src, suggestion ) {
if( src.createTextRange || src.setSelectionRange ) {
var iLen = src.value.length;
src.value = suggestion;
selectRange( src, iLen, suggestion.length );
}
}
Next, change the autocomplete_core (function autocomplete_core (src) {) function,
the autocomplete_work function (function autocomplete_work (event) {) and the
autocomplete_scroll function (function autocomplete_scroll(event) {) as follows:
function autocomplete_core (src) {
// kinda support multiple addresses
var Str = src.value;
var StartPos = 0;
var newSP = Str.lastIndexOf(", ");
if (newSP >= StartPos) {
StartPos = newSP + 2;
}
// do not search for nothing
if (Str.length - StartPos <= 0)
return;
// If we can find something in our lookup list
newValue = autocomplete_find(Str.substr(StartPos, Str.length));
if (newValue == "" || newValue == Str.substr(StartPos, Str.length))
return;
newValue = Str.substr(0, StartPos) + newValue;
var pos = Str.length;
typeAhead( src, newValue );
document.acMatch = Str;
}
function autocomplete_work (event) {
var src = event.srcElement ? event.srcElement : event.target;
if (! src.createTextRange && !src.setSelectionRange)
return;
// Ignore cursor keys, shift, alt, etc
// look only for A-Z, 0-9, etc.
if (event.keyCode < 48 || (event.keyCode > 57 && event.keyCode < 65) ||
(event.keyCode > 90 && event.keyCode < 96) || event.keyCode == 108 ||
(event.keyCode > 111 && event.keyCode < 186) ||
(event.keyCode > 192 && event.keyCode < 219) || event.keyCode > 222)
return;
// If there is no change in the field, ignore
if (src.value == src._value)
return;
autocomplete_core(src);
}
function autocomplete_scroll(event) {
var src = event.srcElement ? event.srcElement : event.target;
if (isNaN(document.acOffset))
document.acOffset = 0;
if (event.keyCode == 38 || event.keyCode == 40) {
if (document.acMatch != "") {
if (event.keyCode == 40) {
++document.acOffset;
} else if (document.acOffset > 0) {
--document.acOffset;
}
src.value = document.acMatch;
autocomplete_core(src);
} else {
document.acOffset = 0;
}
event.returnValue = false;
} else {
document.acOffset = 0;
document.acMatch = "";
}
}
Next we introduce 2 new functions (getNamedEl and assignHandlers):
/*
* TheLiv at liviutudor.com: Function used to find an element by name.
*/
function getNamedEl(name) {
var el = document.getElementsByName(name);
if( !el ) return;
if( el.length <= 0 ) return;
return el[0];
}
/*
* TheLiv at liviutudor.com: Function used to assign dynamically our handlers.
* Note that we only do this if we have found our send_to text control!
*/
function assignHandlers(send_to) {
if( !send_to ) return;
var isIE = (navigator.appVersion.indexOf("MSIE") >= 0) || (navigator.appVersion.indexOf("Internet Explorer") >= 0);
if( isIE ) { // Internet Explorer :-(
send_to.onkeydown = new Function( "autocomplete_scroll(event);" );
send_to.onkeyup = new Function( "autocomplete_work(event);" );
} else { // The almighty Firefox :-)
send_to.onkeydown = new Function( "event", "autocomplete_scroll(event);" );
send_to.onkeyup = new Function( "event", "autocomplete_work(event);" );
}
}
And finally we set up our newly introduced JavaScript handlers for the To:, Cc: and
Bcc: text boxes on the Compose page:
/*
* TheLiv at liviutudor.com: Cross-browser compatibility.
* OK, so we are now doing stuff the DOM way which should work on all browsers.
*/
assignHandlers( getNamedEl("send_to") );
assignHandlers( getNamedEl("send_to_cc") );
assignHandlers( getNamedEl("send_to_bcc") );
Note that this last line of code is now followed by the closing </script> tag.
Also, the original file has a few other <script> tags after this code -- you will
need to remove those lines as they are no longer needed.
Having made the above changes, empty your browser cache and log back into SquirrelMail using Firefox,
then go to the Compose screen, and you will notice that the autcomplete facility now works under Firefox
too -- hooray!
Download the complete functions.php file
to replace your local version (make sure you make a backup copy first!)
Read our download disclaimer.
|