Приглашаем посетить
Чулков (chulkov.lit-info.ru)

Implementing Your User Interface

Previous
Table of Contents
Next

Implementing Your User Interface

Although you are not limited to using HTML in a web browser for your web applicationsit is reasonable to think of designing a client application for a particular operating system that uses HTTP and your web server to gather information for displayit is the most common format and therefore the one we will use in this book. By doing this, we are ensuring a degree of consistency in our user interfaces. Provided we have not added features specific to one implementation, anybody with a reasonably modern web browser can view our application.

However, as web application authors, you are unlikely to be thrilled about the prospect of managing a large number of pages (often in the hundreds or thousands) with largely the same content and style. Any change to the common interface, such as its color or the name of a menu item, would require hours of tedious and error-prone work to update every page. Thus, we will discuss options you have for implementing your user interface, including how to share code and ensure a common user interface for your pages.

Cascading Style Sheets (CSS)

While not specifically a means of sharing or generating PHP script or HTML, Cascading Style Sheets (often simply referred to as CSS) are a very useful tool that lets you control the exact appearance of HTML elements. Thus, while CSS will neither generate the elements for you nor specify how they are to be laid out, they will tell the client browser what colors, fonts, or lines to use when displaying these elements. They are often stored in another file and can be manipulated in a simple text editor by people inexperienced in PHP. By tweaking the values in these CSS files, large portions of the look and feel of your web application can be changed quickly.

Basics

CSS was added in HTML 4.0, so you will need reasonably modern browsers; realistically, however, anything shipped after 2000 is going to support this, and you will not have to force your users to upgrade by using style sheets. In this feature, you specify the style of one or more components in a style sheet that can be placed in different places in the HTML, which is downloaded for display. The locations where style sheets can be placed are as follows:

  • Inline as part of an element with the style attribute

  • In the HTML file (called internal style sheets), typically in the head section of the HTML wrapped in <style> tags

  • In external files (called external style sheets) that are included in the HTML

  • Internally within the web browser to be displayed in the absence of other style information

The name cascading comes from the fact that these styles all combine or cascade together to form a complete style for an object. If you specify in an external style sheet that all objects must use the Helvetica font, and you also attach an instruction to a table element to use extra thick border lines, then both will combine to indicate that the table must use the double lines and the specified font. Style information specified directly on an element is always given the highest priority, with lower priority given to internal and the lowest given to external style sheets. Only in the absence of all of these does the web browser use its internal default style for an element.

Usage

While a full treatment of Cascading Style Sheets is beyond the scope of this book (and is the subject of numerous books), we will provide some of the basics so that when we show examples in later chapters, you will not be left in the dark.

CSS lets you control the appearance of a few things on various elements, including

  • Colors

  • Backgrounds (including images for elements that support it)

  • Text font information, including spacing, size, face name, and weight

  • Borders, margins, and padding

Style sheets store styles for specific element types, classes of types, or specific instances of elements. To specify the style for elements of a particular class, you list the element name along with its styles in brackets. (Styles are name: value pairs separated by semicolons.) For example, to indicate that we want the body of our HTML file to have a red background and default to using an image called "background.jpg," we could specify the following style:

body { background-color: red; background-image: background.jpg }

To specify a class of style, we prefix the class name with a period (.) and include its style information in brackets:

.titleText
{
  font-family: Verdana, Arial, Helvetica;
  font-size: 4;
  font-weight: bold;
  color: black;
}

One interesting feature is the ability to specify multiple values for a style (the font- family shown previously). If the first value is not found, we try the other ones instead.

To use this class, we use the class attribute on any element we wish to have this style:

<h1 class='titleText'>This is my Title</h1>

We can assign specific styles to specific instances of particular markup elements. If we had a table we were using to display code, we could name it codeTable in our HTML and give it the following styles:

table#codeTable
{
  font: Courier New, Courier;
  font-size: 4;
  color: blue;
}

To use this in our table, we indicate the table instance by using the id attribute on the element:

<table id='codeTable' width='90%' border='1'>

Finally, we can specify default style information for regular HTML markup elements as follows:

h1 {
  font-family: Arial, Helvetica, sans-serif;
  color: #000088
}
h2 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  color: #000088
}

In the previous code, we have changed the way all markup within h1 and h2 tags is displayed.

Including It in Your HTML

To embed style sheets within your HTML page, you can wrap the style definitions in <style type='text/css'> tags, as follows:

<style type="text/css">
<!--
body { background-color: red; background-image: background.jpg }
table#codeTable
{
  font: Courier New, Courier;
  font-size: 4;
  color: blue;
}
-->
</style>

Alternatively, you can put the style definitions in a separate file with a .css extension and include this file in the head section by using the link element we used previously:

<link rel="stylesheet" href="basestyle.css" type="text/css"/>

Finally, you can include style information in a specific element as you declare it:

<table style='font: Helvetica; font-size: 2;'>

Including Files

We will now focus on generating large numbers of web pages without having to duplicate all of the same user interface code for every page. We will start by mentioning file inclusion as a solution (which we first saw in Chapter 3, "Code Organization and Reuse").

When doing this, you isolate areas of your user interface that can be split into blocks and put them into include files. For example, if you look at the web site presented in Figure 14-4, you can see that we can identify four major (and rather unattractive) components of its user interface: a title bar and menu bar across the top, an advertising bar across the left edge, the content in the main body of the page, and a copyright bar across the bottom.

Figure 14-4. Breaking our web page into areas.

Implementing Your User Interface


If we then split the HTML for the non-content parts of the page into three include files, such as page_top.inc, page_left_bar.inc, and page_bottom.inc, we could see our main content pages as PHP scripts that included these files and did what was necessary:

<?php

  require('page_top.inc');
  require('page_left_bar.inc');

  do stuff for this specific page here.

  require('page_bottom.inc');
?>

This solution has the advantage of being reasonably easy to implement, and the three .inc files will mostly contain HTML content, meaning that our graphics designers will not be alarmed by PHP code or risk breaking something whenever they want to tweak the user interface for our web application.

However, there are a couple of minor problems. First, if we include only static HTML in these three files, there is little opportunity for customizing them or providing dynamic content for our page. For example, we might wish to highlight the menu item that corresponds closest to this page, put up a caption across the top that matches this page, or have a set of submenu items to match the current page. This requires us to put PHP script in these files and set up parameters or values before we include them to produce the correct output. This in turn negates some of the benefits of having our graphics designers able to modify these files since they might not be aware of the PHP code.

Second, although it is easy to compartmentalize the user interface logically into the four sections we showed in Figure 14-4, it is rarely implemented that cleanly. HTML pages typically flow from top to bottom, and the main portion of our page is often implemented in a <table> element. Thus, the advertising bar across the left of the page is one column in the table, and the main body of our page is the other (see Figure 14-5). This requires us to be careful with how we specify tags and enclose the body of our page; we want to avoid confusing browsers with unclosed HTML tags.

Figure 14-5. The way our sample might be implemented in HTML.

Implementing Your User Interface


These problems are not serious, and this style of user interface generation is quite useful for pages that do not have much in the way of dynamic content in the included portions. In Part V, "Sample Projects and Further Ideas," we show you a project that uses include files for much of its UI.

Code Libraries for User Interface Generation

Another option we have for implementing our user interface is to write a code library for the functionality. We can have a set of functions that emits the correct HTML content, or we can write an object-oriented class with methods to generate the UI. This helps us because even within the content of a page, the same UI elements are often used again and again. Having them codified in a separate function means that we can tweak the layout of our content without having to modify a ton of pages.

So, if we wanted to generate the page shown in Figure 14-4 using a class to do most of the HTML work for us, we could write a class called HtmlGenerator, as shown in Listing 14-1. Writing our output page now becomes a sequence of method invocations on an instance of this class, as shown in Listing 14-2.

Listing 14-1. An HtmlGenerator Class for Generating the User Interface for Our Page
<?php

  class HtmlGenerator
  {
    public function __construct($in_pageTitle)
    {
      // spit out page headers:
      echo <<<EOHEAD
<html>
<head>
  <meta http-equiv="content-type"
        content="text/html; charset=utf-8"/>
  <title>
    $in_pageTitle
  </title>
</head>
<body>

EOHEAD;
    }

    public function closePage()
    {
      echo <<<EOPAGE
</body>
</html>

EOPAGE;
    }

    public function emitTopMenuBar($in_highLightThisMenuItem)
    {
      // the top menu bar is in a table...
      echo <<<TOPMENU

  <table width='100%' border='0' cellspacing='0' cellpadding='0'>
  <tr>
    <!-- etc. contents of top menu bar are here ... -->
  </tr>
  </table>

TOPMENU;
    }

    public function openPageBody()
    {
      // start the table that will host the body of the page
      // and the ad bar
      echo <<<BODYOPEN
  <table width='100%' border='0' cellspacing='0'>
  <tr>

BODYOPEN;
    }

    public function closePageBody()
    {
      // close off the table for the page body.
      echo <<<EOBODY
   </tr>
   </table>

EOBODY;
    }

    public function emitLeftAdBar()
    {
      // the ad bar will be a 125-pixel column along the left
      echo <<<ADBAR
    <td width='125' valign='top'>
      <table width='100%' border='0' cellspacing='0'>
      <tr>
        <!-- left menu bar body goes here ... -->
      </tr>
    </td>

ADBAR;
    }

    public function openPageContent()
    {
      // this opens up the main block for putting in the
      // content of this page.
      echo <<<EOCONTENT
    <td valign='top'>

EOCONTENT;
    }

    public function closePageContent()
    {
      // close off content column.
      echo <<<EOCONTENT
    </td>

EOCONTENT:
    }

    public function emitCopyrightBar()
    {
      echo <<<COPYRIGHT

  <!-- emit the copyright info across the bottom here. -->

COPYRIGHT;
    }
  }

?>

Listing 14-2. Using the HtmlGenerator Class to Generate a Page
<?php
  require_once('htmlgenerator.inc');

  $page = new HtmlGenerator("Welcome New User!");

  $page->emitTopMenuBar("Create Account");

  // the body holds both the ad bar and the page content
  $page->openBody();
  $page->emitLeftAdBar();
  $page->openContent();

  // here is where the content specific to this page goes!
  echo <<<EOM

  <p align='center'>
    Welcome to the system, {$_POST['user_name']}.  We hope
    you will enjoy your time with us.  Click
    <a href='user_home.php?username={$_POST['user_name']}'>
    here
    </a>
    to go to your home page.
  </p>

EOM;

  // now close off the page elements.
  $page->closePageContent();
  $page->closePageBody();
  $page->emitCopyrightBar();
  $page->closePage();

?>

The advantage of this is that our script files become a clean sequence of function calls, and whenever we have a new common user interface element, we can add a method to the HtmlGenerator class to emit this for us. We can also customize the individual routines on the class to take parameters and do things, such as highlight menu items, change pictures, or create a more dynamic user interface.

However, one big disadvantage to this way of generating your user interface is that it becomes quite difficult for your graphics designers to tweak the appearance of your web site's interface unless they are comfortable with PHP. When using this system, it is more likely that the graphics designers would give you a prototype of what the page should look like and leave you the task of coding it in the HtmlGenerator object. In addition, developers have to remember to use the same sequence of functions for each page they create, which might be more prone to errors.

We will show an example of this system of user interface generation in Part V.

Implementing a User Interface Driver

Now that we have seen a couple of solutions for sharing the user interface of our application across different script files, we have only one problem left: how to reduce the number of files. If we wrote a content-centric site and had a few hundred pages of content, it would be unfortunate if we had to write a separate .php file for each of them. Even worse, whenever we wanted to add more content, we would have to write new files and make sure they were organized correctly.

Fortunately, we can take advantage of our databases for this part of our application. If we considered a simple example with content pages forming a hierarchy as shown in Figure 14-6, we could create a table with the following schema:

page_name VARCHAR(50) PRIMARY KEY
page_title VARCHAR(200)
parent_page VARCHAR(50)
page_content TEXT

Figure 14-6. Organizing the content for our site hierarchically.

Implementing Your User Interface


With this definition, the trivial hierarchy shown in Figure 14-6 could be represented in the table, as shown in Table 14-1.

Table 14-1. Our Content Pages in Table Format

page_name

page_title

parent_page

page_content

welcome

Welcome to Our Web Site!

NULL

<p align='center'> welc…

about_us

About Our Organization!

NULL

<h1>About Us</h1>...

events

Up and Coming Events!

NULL

<h2>Events Coming...

parties

Parties For This Year

events

<p> Here is a list of all...

holiday_party

This Year's Holiday Party

parties

<h1> Important</h1> T...

meetings

Organization Meetings

events

<p> We will have a me...

contactinfo

Contact Information

NULL

<h2>Our Address:</h2>...


All we need to do now is write a driver page in PHP that takes the name of the content page to display and fetches it from the database. We can tell our PHP script which page to execute by using the HTTP GET feature to pass in parameters. As you will recall from Chapter 7, "Interacting with the Server: Forms," we can encode parameter data in the URI sent to the server by suffixing the URI with a question mark (?), the parameter names and values, as follows:

http://server/path/page?param1=value1&param2=value2...

For our driver page, we can pass in the name of the content page to generate as follows:

http://server/driver.php?page=holiday_party

The main portion of our driver page would then end up looking as follows:

<?php

  $conn = new mysqli(...);

  $q_str = <<<EOQ
  SELECT page_title, page_content FROM pages
    WHERE page_name = {$_POST['page']}

EOQ;

  $result = $conn->query($q_str);
  if ($result !== FALSE)
  {
    $row_data = $result->fetch_assoc();
    $page_title = $row_data['page_title'];
    $page_content = $row_data['page_content'];
  }

  // generate top and left menu bar UI here ...

  echo $page_content;

  // generate any other closing UI here ...

?>

We now have one page driving the display of all pages with largely static content. We also have nothing that prevents us from executing pages that are not part of this content tree since they can be put into .php files and use the same code for sharing UI.


Previous
Table of Contents
Next