Overview
The Web Style Guide calls for the Login dialog to appear at the top of each page, just to the right of the IAC logo. The Search dialog is to be vertically aligned with the Login dialog, positioned at the right edge of the window. In addition, these dialogs' various input fields (email address, password, and search text) are to have light gray prompts embedded within them, which disappear when the user starts typing.
While conceptually simple, these features required new CSS, "hooking" the Drupal login form, and injecting some JavaScript. Nothing to it!!! <eye roll>
User Login Dialog
CSS
I added rules to css/local.css file to accomplish the following:
- Moved the entire login block to the desired location
- Set the background color for all sub-elements to "transparent" so that they wouldn't cover any other backgrounds
- Suppressed the display of the block's H2 title element
- For all div elements within the block, set a five-pixel left margin and set them to line up horizontally using float:left
- The form has two inputs: email address and password. Each of those inputs is wrapped in a div, which also contains the field prompts. Each of those divs was set to position:relative, part of the magic of placing the prompts atop the input areas.
- Suppressed the display of the red asterisk that denotes that each field is required because it was visually distracting. (I assume that pretty much every web user knows that they must supply both their user ID and password if they want to log in.)
- For the label elements (prompts), we specified an absolute position (again part of the disappearing prompt magic), and gray italic font. A little margin adjustment is thrown in for aesthetic reasons.
Here's a copy of the CSS in question, located in $D7/sites/www.iac.org/themes/iac/css/local.css. Note that while we could use the section#block-user-login selector for almost all of the elements within the dialog box, some code in a different CSS file was taking precedence when it came to the label fields. Hence the .region-header selector in the last rule.
/********** User Login Block **********/ section#block-user-login { position: absolute; top: -25px; left: 65px; } section#block-user-login * { background-color: transparent; } section#block-user-login h2 { display: none; } section#block-user-login div { margin-left: 7px; float: left; } section#block-user-login div.form-item-name { position: relative; } section#block-user-login div.form-item-pass { position: relative; } section#block-user-login span.form-required { display: none; } .region-header #block-user-login label { position:absolute; top:0; left:0; font-style: italic; color: #aaa; margin: 0.2em 0 0 0.3em; }
Hooking the Form
Drupal provides many code injection points, known as hooks, that allow the developer to customize the platform's behavior. In addition to the requirements listed at the top of this article, I also wanted to change the sizes of the input fields so as to make the best use of the available space on the screen, change some of the wording, and force the form's Submit button to appear between the password field and the Lost password? link. The hook is also a handy place to instruct Drupal to inject the JavaScript files that complete the magic with the prompts. Last but not least, I disabled browser autocompletion for the form because it interferes with the magic prompts.
Here's a copy of the code, found in $D7/sites/www.iac.org/themes/iac/template.php:
function iac_form_user_login_block_alter(&$form, &$form_state, $form_id) { /* Change display sizes of the login & password text boxes */ $form['name']['#size'] = 20; $form['pass']['#size'] = 12; /* Change text of various labels */ $form['name']['#title'] = "Email address"; $form['actions']['submit']['#value'] = " Go "; $form['links']['#markup'] = str_replace("Request new password", "Lost password?", $form['links']['#markup']); /* Make the "Lost password?" link appear last */ $form['actions']['#weight'] = 5; $form['links']['#weight'] = 10; /* Turn off autocomplete, coz it screws up the background colors */ $form['#attributes']['autocomplete'] = 'off'; /* Callback to insert JS for background prompts */ $form['#after_build'] = array('_iac_insert_prompts_js'); }
/* Insert the JavaScript that will diddle the background prompts */ function _iac_insert_prompts_js($element) { drupal_add_js(drupal_get_path('theme', 'iac') . '/js/jquery.infieldlabel.min.js'); drupal_add_js(drupal_get_path('theme', 'iac') . '/js/pop-labels.js'); return($element); }
JavaScript
Here's where the magic happens. In a nutshell, the drupal_add_js calls (see the above hook) tell Drupal to insert JavaScript code from files in the $D7/sites/www.iac.org/themes/iac/js directory.
The first JS file contains logic to display the prompts initially, dim them when the user clicks on the field, and hide them altogether when the user starts typing. This nifty little script comes in the form of a jQuery plugin, authored by Doug Neiner, and available here. Note: I had to enhance the script so that it would edit <input type="search"> HTML tags.
The second JS file, authored by yours truly, simply triggers the first script once the user's browser has fully digested and displayed the web page.
Search Dialog
This works in much the same way as the Login dialog. Here's the CSS:
/********** Search Form Block **********/
form#search-block-form { position: absolute; top: -25px; right: 0px; min-width: 100px; } form#search-block-form * { background-color: transparent; } form#search-block-form div.form-item-search-block-form { position: relative; } form#search-block-form div.form-item-search-block-form label { position: absolute; top: -2px; left: 0; width: 45px; font-style: italic; color: #aaa; margin: 0.2em 0 0 0.3em; /* IE7 */ clip:rect(auto); clip: auto; } form#search-block-form input.form-submit { display: none; }
The form hook for the Search dialog turns off autocomplete to avoid interfering with the magic prompts. It also triggers the JS insertion if the user is already logged in. This is is necessary because a) this should only be done once, b) it has to happen after the last form with magic prompts is built, and c) if the user isn't logged in then the Login form is the last one to be built, otherwise the Search form is the last. Here's the code:
/* Customize the Search dialog */ function iac_form_search_block_form_alter(&$form, &$form_state, $form_id) { global $user; /* Turn off autocomplete, coz it screws up the background colors */ $form['#attributes']['autocomplete'] = 'off'; /* * If the user is logged in, login form alter function above won't have fired, * so we need to provide the #after_build directive here. */ if ($user->uid > 0) { $form['#after_build'] = array('_iac_insert_prompts_js'); } }
JavaScript
Same as for the Login dialog above.