Lesson 3. First step-news section

During the previous two lessons we have made up the general structure of our site. It is now nothing but an empty box and we should fill it. Nearly every site has a news section and so will ours. As we start a new section, we should first make up a menu for it. Here, we will do just the same. Our menu for news section will look like a calendar-the thing all people are well accustomed to.

To create a calendar with pure HTML is not an easy task and the code will be rather huge, but as you will see, Parser will do it quite easy. Let's go.

All files related to news section we will locate in directory /news/-as we have previously indicated in sections.cfg. First, we will create there file auto.p. Surprised? Yes, we can create auto.p files in any directory. Still, we should remember that the functions we place into these files will be accessible only to the directory they are in (including subdirectories). The reason is that we shouldn't overload one auto.p file with ALL functions, so, we should relieve our main auto.p of section-dependent functions and keep there only those functions, which we will need for ALL directories (such functions as, probably, footer or header). The directory-dependent stuff we will place in auto.p files in relevant directories.

One more thing: if we redefine a function in a section's auto.p-thus overriding the function with the same name defined in root auto.p-root function will be ignored in favor of the section's function. The virtual functions mechanism described in the previous lesson will be triggered.

Let's get back to our codes. To
/news/auto.p we add the code:

@calendar[]
$calendar_locale[
   $.month_names[
         $.1[
January]
         $.2[
February]
         $.3[
March]
         $.4[
April]
         $.5[
May]
         $.6[
June]
         $.7[
July]
         $.8[
August]
         $.9[
September]
         $.10[
October]
         $.11[
November]
         $.12[
December]
   ]
   $.day_names[
         $.0[Sun]
         $.1[Mon]
         $.2[Tu]
         $.3[Wed]
         $.4[Thurs]
         $.5[Fri]
         $.6[Sat]
   ]
   $.day_colors[
         $.0[#000000]
         $.1[#000000]
         $.2[#000000]
         $.3[#000000]
         $.4[#000000]
         $.5[#800000]
         $.6[#800000]
   ]
]
$now[^
date::now[]]
$days[^
date:calendar[eng]($now.year;$now.month)]
<center>
<table bgcolor="#000000" cellspacing="1">
   <tr>
      <td bgcolor="#FFFFFF" colspan="7" align="center">
         <b>
$calendar_locale.month_names.[$now.
month]</b>
      </td>
   </tr>
   <tr>

   
   ^for[week_day](0;6){
         <td width="14%" align="center" bgcolor="#A2D0F2">
            <font color="
$calendar_locale.day_colors.$week_day
">
               $calendar_locale.day_names.$week_day
            </font>
         </td>
      }
   </tr>
^days.
menu{
   <tr>
      ^
for[week_day](0;6){
         ^if($days.$week_day){
            ^if($days.$week_day
==$now.day){
            <td align="center" bgcolor="#FFFF00">
               <font color="
$calendar_locale.day_colors.$week_day
">
               <b>
$days.$week_day
</b>
               </font>
            </td>

            }{         
            <td align="center" bgcolor="#FFFFFF">
               <font color="
$calendar_locale.day_colors.$week_day
">
               $days.$week_day
               </font>
            </td>
            }
         }{
            <td bgcolor="#DFDFDF">&nbsp</td>   
         }
      }
   </tr>
}
</table>
</center>

We have just defined function
calendar, which creates HTML-code of our calendar. At first, the code may seem unexpectedly big, but it's only because we are trying to handle a more complicated task. Let's now see what we've done:

The biggest piece of our code-that, which starts with
$calendar_locale-appears strange. Look at it closely: we seem to define some data for our calendar, and it resembles a table. The piece we define as $calendar_locale is called 'hash' or 'associative array.' Why do we need it? As you can see, we link the ordinal numbers of months and days of the week with their names in English, and link hexadecimal color values with certain numbers. Uh-huh! Now it's getting clearer. We need hash to link (associate) a name with an object. In our case, we link numerical values of months and days of the week with their names (strings). Parser uses object model, so a string is also an object. It's quite easy to get ordinal number of a month, but a calendar for "May" seems more sensible for a human eye than a calendar for "5," and names of the days given in calendar like 0, 1, or 2 instead of Sunday, Monday, or Tuesday will look completely crazy. That's why we create an associative array.

A general way of assigning variables-hashes is like this:

$name[
    $.key[value]
]

Such a construction allows further referring to a hash key by writing
$name.key and getting associated value. As you have probably noticed, fields of our hash are three other hashes.

After defining hash we see variable
now, which we use to store present date, but further, there is a completely strange construction:

$days[^date:calendar[eng]($date.year;$date.month)]

Its logic is similar to that of constructor, since variable
days now contains a table with a calendar for the current month of this year. Still, we see only one semicolon, whereas for constructor we use two. That shows us that calendar is one of static methods of class date. Static methods, like constructors, which we already know, can return objects. That is why we should assign created object to a variable. We have already touched upon static fields and methods in the end of the previous lesson. Such methods exist due to the fact that certain objects or their properties, such as page's URI or calendar for the current month, are unique. That is why such objects and fields comprise a separate group and can be accessed directly, without using constructors. If we call a static field, we get the value of the field of the class itself (but NOT of the object). Class math, which is designed for working with mathematical functions, can serve as an example. As p is unique, we refer to it by writing $math:PI and get the value of static field of class math itself.

As a result, variable
days will contain such table:
Table 1 (result of this code implemented on May 30, 2003)


0

1

2

3

4

5

6

week
year

 



01

02

03

04

18
2003

05

06

07

08

09

10

11

19
2003

12

13

14

15

16

17

18

20
2003

19

20

21

22

23

24

25

21
2003

26

27

28

29

30



22
2003


This is the table we will work with further on. We cannot retrieve the whole content stored in variable
days by simply writing

$days

If we do so, Parser won't understand what exactly we need-is it some row, the whole table or a value stored in some column? We also need    to elaborate the content of the table so it could be understandable for a human being. For this purpose we have created a hash with names of days and months. Further, we use HTML to create a table where the first row will contain the name of the current month. To get the name of the month we use data stored in our hash, where ordinal number of a month is associated with its name.

$calendar_locale.month_names.[$now.month]

Let's see how it works: we retrieve the value of field
month_names of hash calendar_locale with ordinal of the current month identified as $now.month. This construction will result in name of the month in English (in our case) or any other language (it depends on what language you use when specifying associated strings).

In calendar's next row, we will output names of days of the week using hash data. Let's see precisely what we're after: we will go through the numbers of days of the week (from 0 to 6) step by step and output strings which we have previously associated with these numbers (that is retrieve them from the field
day_names of hash calendar_locale). The best way to do it is to use a loop, i.e. a succession of actions to be executed a certain number of times. We will use loop for. The syntax for this loop is:

^for[counter](counter values' range, for example 0;6){succession of counter' values}

One of the best things provided by loops is that we can use values of the counter within the loop, referring to it as to a variable. That's what we'll do:

^for[week_day](0;6){
   <td width="14%" align="center" bgcolor="#A2D0F2">
      <font color="
$calendar_locale.day_colors.$week_day
">
         $calendar_locale.day_names.$week_day
      </font>
   </td>
}

It is simple if you know what a loop is: sequentially changing the value of
week_day, starting with 0 and ending with 6 (where week_day is loop counter), we get seven values:

$calendar_locale.day_colors.$week_day   -font color
$calendar_locale.day_names.$week_day   -name of day of the week.

The idea behind this is just the same as that we used to get months' names, but here we use different hash keys.

You would most probably ask, 'why is there
day_colors key?' The answer is 'fine feathers make fine birds.' If we want our calendar to look very much like real, we should make weekdays different from rest-days.

The next block needs special attention. Let's examine the task carefully. We will:

1. go through the rows of table days (Table 1) step by step;
2. in each row, go through the columns step by step, outputting the values (which are days of the month);
3. correctly indicate empty cells in our calendar (that is to check if there are blanks in the first and the last weeks of the month)
4. Indicate current date (output it in different color and make it bold).

How will we do it? The first step is easy to make with the help of familiar method
menu of class table:

^days.menu{...}

To go through the columns in each row, we'll use the loop
for, which we have recently learnt:

^for[week_day](0;6){...}

To check whether we should output empty cells we will use operator
if. In fact, any check can be done with this operator:

^if($days.$week_day){
   …
}{
   
<td bgcolor="#DFDFDF">&nbsp</td>
}

Note: in our condition we do not compare
$days.$week_day with anything. Thus we perform zero-check.
Parser understands this construction like the following:

"If
$days.$week_day exists (not empty), then do {...} otherwise output an empty grey table cell."

Most of the work is complete. Now we should only highlight current date. We can do it with another if, where we shall compare present value in table days with current date (
$days.$week_day==$now.day):

^if($days.$week_day==$now.day){
   
<td align="center" bgcolor="#FFFF00">
      <font color="
$calendar_locale.day_colors.$week_day
">
         <b>
$days.$week_day
</b>
      </font>
   </td>
}{         
   
<td align="center" bgcolor="#FFFFFF">
      <font color="
$calendar_locale.day_colors.$week_day
">
      $days.$week_day
   
   </font>
   </td>
}

Note: to compare numerical values we use
== operator, while to compare strings we use eq operator.

Let's look back at the general structure we use to form the calendar:

# going through the table with calendar

^days.menu{

# going through columns in each row

   ^for[week_day](0;6){
      ^if($days.week_day){
         ^if($month.$week_day==$date.day){
            different cell background, boldface font
         }{
            simple cell
         }
      }{
         empty grey cell
      }
   }
}


This is not a simple block-here we use nested constructions. Still, it helps us understand the possibility to combine different means to handle a specific task. A construction could be more graceful if we united checking and coloring into a separate function to be called from within the loop. A similar solution was used in Lesson 2. By doing so, we could make our code simpler and easier to read, but our main purpose here is to show you how to combine several logical structures. You can improve the code on your own. Let it be your home assignment.

If you want to be sure that the code works, you can create file
test.html in directory /news/ and put there a single line:

^calendar[]

Now open this page in your browser and enjoy yourself!

Let's sum it up,

What have we done?
We defined function making up calendar for the current month.

What have we learnt?
·file auto.p may be placed not only in root directory, but also in any other directory (but in this case, functions contained in it will be accessible only within the directory it is in);  
·variable-hash is an array used to associate some objects with other ones. In our case, objects were strings;  
·static method calendar creates a table with calendar for the current month;  
·loop for allows repeating some actions specified number of times.  

What should we remember?
·along with methods of objects created with constructors of a class, there exist static methods. You can access these methods directly without first creating an object;  
·within loop for, we can refer to the counter as to a variable with specified name and get its current value.  

As our code grows bigger, we should place comments for the code to be clearly understood. In Parser, every line starting with
# is regarded as a comment. So far, we didn't use comments, but as we step further and further, placing comments becomes nearly vital. The following line is an example of a comment:

# all this text will be ignored-this is a comment !!!

We urge that you place comments in your code! Ideally, your code should be self-descriptive for anyone who reads it to understand the logic of the code and succession of actions. If you neglect it, you yourself may be unable to read it after a while. Remember it!

What's next?
In the next lesson, we will teach our calendar to place links on dates and-what is most important-we will learn how to work with forms and databases to create a full-blown news section.


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