Previous Page
Next Page

Hack 11. Generate a Styled User Message on the Fly

Dynamically define and assign CSS styles to web page content.

JavaScript and DOM programming allow you to define CSS style attributes and apply them to page elements from scratch. An example of where you may want to implement these methods is a Wiki page that permits users to develop their own page designs and styles.

In most cases, separating the style definitions from the JavaScript code is the way to go. Separating application concerns or tiers in this manner allows each element to evolve independently and makes web development less complex and more efficient.


This hack, like the one before it, dynamically displays server information based on the user's choice of style categories. Unlike the previous hack, this one formulates the styles in code, then applies the chosen style to an HTML element. Here is the code, with the style information highlighted:

var request;
var urlFragment="http://localhost:8080/";
var st;

function getAllHeaders(url,styl){
    if(url){
        st=styl;
        httpRequest("GET",url,true);
    }
}

/*  Set one or more CSS style attributes on a DOM element 
CSS2Properties Object.
 Parameters:
  stType stands for a style name, as in 'plain,''fancy,''loud,' or 'cosmo'.
  stylObj is the HTML element's style property, as in div.style. */

function setStyle(stType,stylObj){
    switch(stType){
        case 'plain' : 
            stylObj.maxWidth="80%";
            stylObj.border="thin solid black"; 
            stylObj.padding="5%";
            stylObj.textShadow="none";
            stylObj.fontFamily="Arial, serif";
            stylObj.fontSize="0.9em";
            stylObj.backgroundColor="yellow"; break;
        case 'loud' : 
            stylObj.maxWidth="80%";
            stylObj.border="thin solid black"; 
            stylObj.padding="5%";
            stylObj.fontFamily="Impact, serif";
            stylObj.fontSize="1.4em";
            stylObj.textShadow="0 0 2.0em black";
            stylObj.backgroundColor="rgb(181,77,79)"; break;
        case 'fancy' :
            stylObj.maxWidth="80%";
            stylObj.border="thin solid black"; 
            stylObj.padding="5%";
            stylObj.fontFamily="Herculanum, Verdana, serif";
            stylObj.fontSize="1.2em";
            stylObj.fontStyle="oblique";
            stylObj.textShadow="0.2em 0.2em grey";
            stylObj.color="rgb(21,49,110)";
            stylObj.backgroundColor="rgb(234,197,49)"; break;
        case 'cosmo' :
            stylObj.maxWidth="80%";
            stylObj.border="thin solid black"; 
            stylObj.padding="1%";
            stylObj.fontFamily="Papyrus, serif";
            stylObj.fontSize="0.9em";
            stylObj.textShadow="0 0 0.5em black";
            stylObj.color="aqua";
            stylObj.backgroundColor="teal"; break;
        default : 
            alert('default');
       
    }
}

//event handler for XMLHttpRequest
function handleResponse(  ){
    try{
        if(request.readyState == 4){
            if(request.status == 200){
                /* All headers received as a single string */
                var headers = request.getAllResponseHeaders(  );
                var div = document.getElementById("msgDisplay");
                if(st){
                    setStyle(st,div.style);
                } else {
                    setStyle("plain",div.style);
                }
                div.innerHTML="<pre>"+headers+"</pre>";
            } else {
                //request.status is 503 if the application isn't available; 
                //500 if the application has a bug
                alert(request.status);
                alert("A problem occurred with communicating between "+
                      "the XMLHttpRequest object and the server program.");
            }
        }//end outer if
    } catch (err) {
        alert("It does not appear that the server is available for "
              "this application. Please"+
              " try again very soon. \\nError: "+err.message);

    }
}

/* Initialize a request object that is already constructed */
function initReq(reqType,url,bool){
    try{
        /* Specify the function that will handle the HTTP response */
        request.onreadystatechange=handleResponse;
        request.open(reqType,url,bool);
        request.send(null);
    } catch (errv) {

        alert(
                "The application cannot contact the server at the moment. "+
                "Please try again in a few seconds." );
    }
}

/* Wrapper function for constructing a request object.
 Parameters:
  reqType: The HTTP request type such as GET or POST.
  url: The URL of the server program.
  asynch: Whether to send the request asynchronously or not. */
function httpRequest(reqType,url,asynch){
    //Mozilla-based browsers
    if(window.XMLHttpRequest){
        request = new XMLHttpRequest(  );
    } else if (window.ActiveXObject){
        request=new ActiveXObject("Msxml2.XMLHTTP");
        if (! request){
            request=new ActiveXObject("Microsoft.XMLHTTP");
        }
    }
    //the request could still be null if neither ActiveXObject
    //initialization succeeded
    if(request){
        initReq(reqType,url,asynch);
    }  else {
        alert("Your browser does not permit the use of all "+
              "of this application's features!");
    }
}

Nudging Aside the Stylesheet

Each HTML element on a web page has a style property, if its host browser supports CSS stylesheets. For example, a div element has a property called div.style that allows a JavaScript writer to set inline style attributes for that div (as in div.style.fontFamily="Arial"). This is how the setStyle( ) function works in the prior code. The two function parameters are a style name such as "Fancy" (chosen from a predefined list) and the style property of a specific div element. The function then sets the appearance of the HTML div element on the web page.

The information that appears on the page (a bunch of response headers) is derived from the server using the request object. As in the previous hack, the user completes a URL, then clicks outside the text field or presses the Tab key, thus firing an onblur event handler that sets the request object and CSS styling in motion. The HTML for the page is not much different from that in "Generate a Styled Message with a CSS File" [Hack #10], but it omits the link to a stylesheet. All the styling for this hack is defined by the imported JavaScript file, hack10.js. Here's the code:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">
<html>
<head>
    <script type="text/javascript" src="/parkerriver/js/hack10.js"></script>
    <script type="text/javascript">
    function setSpan(  ){
        document.getElementById("instr").onmouseover=function(  ){
            this.style.backgroundColor='yellow';};
        document.getElementById("instr").onmouseout=function(  ){
            this.style.backgroundColor='white';};
    }
    </script>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>view response headers</title>
</head>
<body onLoad="document.forms[0].url.value=urlFragment;setSpan(  )">
<h3>Find out the HTTP response headers when you "GET" a Web page</h3>
<h4>Choose the style for your message</h4>
<form action="javascript:void%200">
    <p>
        <select name="_style">
            <option label="Loud" value="loud" selected>Loud</option>
            <option label="Fancy" value="fancy">Fancy</option>
            <option label="Cosmopolitan" value="cosmo">Cosmopolitan</option>
            <option label="Plain" value="plain">Plain</option>
        </select>
    </p>
    <p>Enter a URL: <input type="text" name="url" size="20" onblur=
            "getAllHeaders(this.value,this.form._style.value)"> 
            <span id="instr" class="message">&#171;press tab or 
            click outside the field when finished editing&#187;
            </span></p>
    <div id="msgDisplay"></div>
</form>
</body>
</html>

The getAllHeaders( ) function, an event handler for onblur, passes in to the application the name of the style the user has chosen from a select list (such as "cosmo"), as well as the URL of the server component. The only purpose of the server component is to provide a value for display. We're mainly interested in dynamically generating styles for any type of server information your applications could acquire via Ajax and the request object.

The purpose of the setSpan( ) function defined within the web page's script tags is to give some instructions ("press tab or click outside the field when finished editing") a yellow background when the user passes the mouse pointer over them.


Figure 1-18 shows what the page looks like in a web browser prior to the sending of the HTTP request.

Figure 1-18. Choose a style for dynamic generation


Figure 1-19 depicts what the page looks like when the user optionally selects a style name, completes the URL in the text field, and presses Tab.

Figure 1-19. Styled server data


None of these web page changes involves waiting for the server to deliver a new page. The request object fetches the data from the server in the background, and the client-side JavaScript styles the displayed information. Voil\x88 , Ajax!


Previous Page
Next Page