Lesson 2. Navigation menu and page structure

We finished the previous lesson with pointing out imperfections in the way our menu worked. Let's now fix them. So far, our menu has a spare link to the current page, which makes our site look rather clumsy. To avoid it, we should check if a section in the menu is the current page. If so, we shouldn't place a link. To indicate current section, we should change background color in current section cell.

Open file auto.p and replace its content with:

@navigation[]
$sections[^
table::load[/sections.cfg]]
<table width="100%" border="0" bgcolor="#000000" cellspacing="1">
   <tr  bgcolor="#FFFFFF">

   ^sections.
menu{
      ^navigation_cell[]
   }
   </tr>
</table>
<br />

@navigation_cell[]
$cell_width[^
eval(100\$sections)%]
^if($sections.
uri eq $request:uri){
   <td width="$cell_width" align="center" bgcolor="#A2D0F2"> 
   <nobr>
$sections.
name</nobr>
   </td>

}{
   <td width="$cell_width" align="center"> 
   <a href="
$sections.
uri"><nobr>$sections.name</nobr></a>
   </td>

}


What have we changed? Not much, seemingly. But our module has been significantly improved. We have added a new method-
navigation_cell-which is called from navigation method. As you have probably noticed, we introduce here a new structure:

^if(condition){code to execute if true}{code to execute if false}

What this piece does is not really hard to understand. The round brackets contain some condition and-depending on the value returned (TRUE or FALSE)-the code will follow different branches. If condition contains an expression which equals zero, the resulting value will be 'FALSE,' otherwise-'TRUE'. We use operator
if to check whether we need to place a link on the section or not. Let's now see how the whole piece of code with condition works. We will compare two strings, where the first is the URI-string contained in column uri in table sections and the other is the current URI ($request:uri returns string equal to the current URI). Here you may ask-and what strings can be equal? Of course those which are fully equal in length and characters contained in them.

To compare two strings, in Parser, we use the following operators:

eq - strings are equal (equal): parser eq parser
ne
- strings are not equal (not equal): parser ne parser3
lt
- number of characters in the first string is less than that in the second (less than): parser lt parser3
gt - number of characters in the first string is greater than that in the second (greater than): parser3 gt parser 
le
- number of characters in the first string is greater than or equal to that in the second (less or equal)
ge - number of characters in the first string is less than or equal to that in the second. (greater or equal)

Here is how it works: if
$sections.uri equals $request:uri a link shouldn't be placed (and the table cell will have different background color-we should always try to make surfing through our site as comfortable as possible), if not-place the link, then!

Another imperfection is that we have columns of varied width. That will do if you don't really care about the way your page looks, but is, frankly speaking, rather clumsy. The problem is quite easy to solve, though: we'll just take the width of the whole menu as 100% and divide it by the number of available sections (the amount of rows in table sections). In this case, we use operator
^eval() and the number of rows in our table (we can use object of class table in mathematical expressions-the numerical value of the table will then be the number of its rows). You should also remember that by using backslash instead of forward slash we use integer division.

Now, we should stop for a while to pay operator
^eval() more attention. This operator allows us to evaluate a mathematical expression without additional variables. We simply write:

^eval(expression)[format]

By using [format] we can specify in what format we expect the result of evaluation. By specifying format as [%d] we get our number without fractional part; [%.2f] returns number with two-figure long fractional part, while [%04d] returns number without fractional part, four-figure long, and-as we put zero in front of "4" while specifying format-the absent figures in the front will be padded with zeros on the left. Sometimes we do need formatted number (For example, 12.44 $ looks more sensible than 12.44373434501 $...).

We are through with our menu-it's now ready.

The first building block of our future site is now ready. Let's now proceed to page structure. Each page may be divided into three parts, which are
header (upper part of a page), body (main information including our navigation menu) and footer (the lower part of a page). This is a kind of general pattern for most sites.

Footer will be the same for all pages, header will remain the same in style but with varying content (at least, page titles will vary) and body will always be different but of the same style, common for all pages (for example, it may consist of two information blocks-30% and 70% wide respectively). The menu will be included in body block.

Every page will have the following structure:


header

navigation

body_additional
(30%)




body_main
(70%)
footer


Each section will be stored in a separate method (function). Let's see how we do it:

To create our
footer we add the following piece of code to file auto.p:

@footer[]
<table width="100%" border="0" bgcolor="#000000" cellspacing="0">
   <tr>
      <td></td>
   </tr>
</table>
$now[^
date::now[]]
<font size="-3">
<center>Powered by Parser3<br />
1997-$now.
year</center>
</font>
</body>
</html>


There is nothing new here, except the piece where we use class
date. We create it with constructor now to get the current date and then take the value of field year. If you find it unclear, please get back to our first lesson where we described working with objects by the Example of objects of class table. In the present case, the process is just the same, except that we use another class, which is date.

Module
header is a little harder to make. On one hand, we must supply each page with unique title. On the other hand, we must stick to the same layout while generating unique content. What should we do? We are going to create, in auto.p file, a new function-header, from within which we will call another function-greeting. Function greeting, in its turn, will be defined in every page to provide unique greeting for it.

Let's add the following code to file
auto.p:

@header[]
<html>
<head>
<title>Test 
site in Parser3</title>
</head>
<body bgcolor="#FAEBD7">
<table width="100%" border="0" bgcolor="#000000" cellspacing="1">
   <tr  bgcolor="#FFFFFF" height="60">
      <td align="center">
         <font size="+2"> <b>
^greeting[]
</b></font>
      </td>
   </tr>
</table>
<br />


And now, the sweetest part: Parser allows us to play an amazing trick-we can once and for ever define uniform structure for all pages in
auto.p and then-by using functions like greeting contained in pages themselves-get unique content for all pages (still sticking to the same layout). How does it work?

To the very beginning of file
auto.p, we will place function @main[], which will always be automatically executed by Parser in the first place. From within it, we will call functions generating pages' parts.

In the beginning of
auto.p we thus write:

@main[]
^header[]
^body[]
^footer[]

…and provide unique title for a page by defining function
greeting, which will be called from function header:

…for the main page:

@greeting[]
Welcome!

…and for the guestbook:

@greeting[]
Leave your mark on history... 

and so on:

Now, as a page is loading, Parser will do the following:

1. Function
main defined in auto.p will automatically run first;
2. It will call function
header, which, in its turn, will call function greeting;
3. As function
greeting is defined in the page itself, function header will call this very greeting and not greeting defined in any other page or even in auto.p itself (function overriding takes place);
4. After finishing with
greeting and header, the Parser will trigger functions body and footer.

As a result, we will get a page having all necessary elements and unique greeting in its upper part. Overridable functions are also referred to as virtual. From within
auto.p, we call function which may be overridden and may thus vary from page to page. At the same time, we stick to the same structure and our pages remain intact in both logic and style.

It remains only to define body. As we have decided, it will consist of two parts to be generated by two separate functions, for instance,
body_main and body_additional. Since our navigation menu is logically related to the main part of the page, we call navigation from within body function. In this case, we should also use the mechanism of virtual functions. Thus, we should add to file auto.p:

@body[]
^navigation[]
<table width="100%" height="65%" border="0" bgcolor="#000000" cellspacing="1">
   <tr  bgcolor="#ffffff" height="100%">
      <td width="30%" valign="top" bgcolor="#EFEFEF">
         <b>
^body_additional[]
</b>
      </td>
      <td width="70%" valign="top">
         
^body_main[]
      </td>
   </tr>
</table>
<br />

Functions
body_main and body_additional should be defined in our page the same way we did with greeting:

@body_additional[]
This is main page

@body_main[]
This is main content

This text can be placed in index.html. Well done! Structure is now ready. We have defined all necessary modules in file auto.p, made up uniform structure, and prepared everything to generate pages. We no longer need to write the same HTML code for every page. A common page will now look like the following (the example is given for index.html, the main page):

@greeting[]
Welcome!

@body_additional[]
This is main page

@body_main[]
This is main content

Simple and clear, isn't it? Everything is in its place and ready to use. After processing a code like this, Parser will create HTML code with unique title, menu, main information block (sticking to the uniform layout and style), and footer, which will be the same for all pages. In fact, we have made up a site ready to be filled with information. This is how you can make up mini business site in a couple of minutes. This is by no means the only solution, but it perfectly puts everything in its place. Some mental workload put in structuring our site will give back easy support and enhancement. All common features are stored in auto.p and the rest-which must be unique for every page-will be stored in pages themselves.

You are free to improvise now. If you have to change the layout of your header you will just need to open
auto.p and change function header once. As you have done it, your every page will have new header design. If we dealt with pure HTML, we would have to rewrite every HTML page manually. This is just the same for all other modules. If you want to change the general layout (for example, to add some block) just add it as a new function and call it from within main in auto.p.

Such structure has yet another great advantage: imagine, one of your pages needs footer different from what you usually use (remember-in the beginning, we assumed that footer should be the same for all pages). All you should do is override existing
footer by placing new function footer in the page. For example, put this code into /contacts/index.html:

@greeting[]
Contact us

@body_additional[]
Here are our addresses

@body_main[]
:Page's content:

@footer[]
Here are our contacts

…and you will change
footer on this page for the one we have just given. That means, if Parser finds some function in the page, it will use it as a substitute for the function with the same name given in auto.p. If we don't specify footer in the page itself, Parser will use footer declared in auto.p.

To end with, let us give you some food for thought. We hope it will let you understand Parser better.

In our code, we used
$request:uri. It looks different from all we have dealt with so far. What is it, then? It resembles $object.property (value of an object's field, which we dealt with in (Lesson 1) , but instead of a dot, we use a colon. Actually, this is also a field's value, but this is not an object's field. This is a field of a class request. Parser doesn't provide any constructors to create objects of this class. Fields of the class are generated by Parser itself and we can directly access them. In technical terms, it is called static variable. There are also static methods, which we will get to know as soon as in the next lesson. Such methods can also be called directly, without first creating an object of the class with the help of a constructor. Remember: static fields and methods always need a colon to be used with them. Thus, when writing $class:field, we access a field of the class itself, and as we write ^class:method, we call a static method of the class. For example, we can look at class math which is designed for working with mathematical functions. It has only static methods and variables:

$math:PI-returns p. This is a static variable of class math.

^math:random(100)-returns a pseudorandom number from the range of 0-99. This is a static method of class math.

Ways of accessing methods and fields differ only in using dot/colon.

Let's sum it up:

What have we done?
We have fixed some problems in our navigation menu, which we started building in the previous lesson, and added new blocks: header, footer and body to determine the way our pages will look. Now we have an elegant technique, which can help us make a site to start with in a wink.

What have we learnt?
We have learnt code branching, putting results of mathematical calculations into our pages, comparing strings, and getting present URI. We have also learnt new methods of classes table and date and a powerful tool of Parser's virtual functions.

What should we remember?
We can place function main in auto.p, and it will be run automatically. We can call any function from within another function. All functions to be called from within function main must be declared either in auto.p or inside the page. If there are two functions with the same name, the latter overrides the former, which is, in this case, ignored (we call it virtual function).

What's next?
There is always a room for perfection. We start with simple things and go further to more complex ones, such as working with forms and databases, which we'll need to make our site genuinely interactive. At the same time, we're going to learn new opportunities provided by Parser for web-developers' easy living.


Copyright © 1997–2021 Art. Lebedev Studio | http://www.artlebedev.com Last updated: 21.07.2014