Every TurboGears project tends to be a complete and self-sufficient site. This way, when we want to add a HTML page to our site, even if it is a static page, we should do it the TurboGears way.
The pages must be written in XML, in a grammar that Kid template engine understands and translates to HTML 4.01 transitional, HTML 4.01 strict, or XHTML, accordingly to project configurations.
When you opened the page http://localhost:8080, the contents are product of two source files: the ajaxfin/templates/welcome.kid template, and a method in the ajaxfin/controllers.py source file.
Take a look at the Root class, automatically created along with the project:
class Root(controllers.RootController):
@expose(template="ajaxfin.templates.welcome")
def index(self):
import time
log.debug("Happy TurboGears Controller Responding For Duty")
return dict(now=time.ctime())
The @expose decorator is the 'glue' that binds Root.index method to the welcome.kid template. Also note that the template path is separated with dots, not slashes (to keep portability).
Now try to create yourself a new page. Copy the ajaxfin/templates/welcome.kid template to the new file ajaxfin/templates/fincalc.kid. If you have time, change something in this new template, so you can check that this is "your" page. Next, open the ajaxfin/controllers.py file and add one method to the Root class:
@expose(template="ajaxfin.templates.fincalc")
def fincalc(self):
import time
log.debug("Happy TurboGears Controller Responding For Duty")
return dict(now=time.ctime())
As soon as you save controllers.py, TurboGears (as long as it is running, of course!) detects the file change and reloads tha class. Now, open the http://localhost:8080/fincalc link (should work).
Well, we want to make a Web calculator, not a static page. We need to create a template that "draws" a calculator. There may be better layouts, but my version (based on tables) is this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
<title>AJAX Calculator (proof of concept)</title>
<SCRIPT SRC="/static/javascript/fincalc.js" TYPE="text/javascript"></SCRIPT>
<link rel="STYLESHEET" href="/static/css/fincalc.css" type="text/css"></link>
</head>
<body>
<hr/>
<form name="calc" onSubmit="return false">
<fieldset>
<legend>AJAX calculator (proof of concept)</legend>
<table>
<tr>
<td>
<input type="text" name="n" value="0" size="12"/>
</td>
<td>
<input type="button" name="Button_n" value="n" onClick="fincalc('n')" class="mybutton"/>
</td>
<td>
<input type="button" name="Button_pot" value="x^y" onClick="fincalc('pow')" class="mybutton"/>
</td>
<td>
<input type="button" name="Button_root" value="1/y" onClick="fincalc('inv')" class="mybutton"/>
</td>
</tr>
<tr>
<td>
<input type="text" name="i" value="0.00" size="12"/>
</td>
<td>
<input type="button" name="Button_i" value="i" onClick="fincalc('i')" class="mybutton"/>
</td>
<td>
<input type="button" name="Button_div" value="÷" onClick="fincalc('/')" class="mybutton"/>
</td>
<td>
<input type="button" name="Button_begin" value="Begin" onClick="begin_toogle()" class="mybutton_0"/>
<input type="hidden" name="begin" value="0"/>
</td>
</tr>
<tr>
<td>
<input type="text" name="PV" class="yellowform" value="0.00" size="12"/>
</td>
<td>
<input type="button" name="Button_PV" value="PV" onClick="fincalc('PV')" class="mybutton"/>
</td>
<td>
<input type="button" name="Button_times" value="×" onClick="fincalc('*')" class="mybutton"/>
</td>
<td>
<input type="button" name="Button_stoeex" value="CFP" onClick="stoeex_toogle()" class="mybutton_1"/>
<input type="hidden" name="stoeex" value="1"/>
</td>
</tr>
<tr>
<td>
<input type="text" name="PMT" class="yellowform" value="0.00" size="12"/>
</td>
<td>
<input type="button" name="Button_PMT" value="PMT" onClick="fincalc('PMT')" class="mybutton"/>
</td>
<td>
<input type="button" name="Button_minus" value="-" onClick="fincalc('-')" class="mybutton"/>
</td>
<td>
</td>
</tr>
<tr>
<td>
<input type="text" name="FV" class="blueform" value="0.00" size="12"/>
</td>
<td>
<input type="button" name="Button_FV" value="FV" onClick="fincalc('FV')" class="mybutton"/>
</td>
<td>
<input type="button" name="Button_plus" value="+" onClick="fincalc('+')" class="mybutton"/>
</td>
<td class="alignright">
<input type="text" name="decimals" value="2" maxlength="1" size="1"/>
</td>
</tr>
</table>
</fieldset>
</form>
<hr/>
</body>
</html>
The XML grammar of this template file is XHTML, with an additional namespace (py:). The py: parameters are Python/Kid code; there lies the Kid active tricks. Being still a valid XML, the template can be directly loaded by a XHTML browser. In this respect, Kid is very different from, say, PHP.
In this example, the only Kid-specific parameter is py:extends="'master.kid'", which means that our template is a "subclass" of ajaxfin/templates/master.kid, and inherits header and footer elements from that parent class.
If you prefer, you can download the project and copy the ready-made file to your own project. Once loaded in the browser, this page should look like this:
It doesn't look incredibly pretty, but we can add a CSS stylesheet to improve a bit. Since the CSS file is completely static (it is not even translated from XML), it should be in the <project>/static/css folder.
We create the fincalc/static/css/fincalc.css file with the following suggested contents:
table
{
border: 0;
cell-padding: 2;
}
fieldset
{
border: 1px solid #781351;
width: 25em
}
legend
{
color: #fff;
background: #ffa20c;
border: 1px solid #781351;
padding: 2px 6px
}
input
{
text-align: right;
border: 3px double #999999;
border-top-color: #CCCCCC;
border-left-color: #CCCCCC;
padding: 0.25em;
background-color: #FFFFFF;
color: #333333;
font-size: 75%;
font-weight: bold;
font-family: Verdana, Helvetica, Arial, sans-serif;
}
.mybutton {
width: 5em;
}
.mybutton_0 {
width: 5em;
background-color: #F0F0F0;
}
.mybutton_1 {
width: 5em;
background-color: #FFFF00;
}
.blueform
{
background-color: #B0FFFF;
}
.yellowform
{
background-color: #FFFFC0;
}
.alignright
{
text-align: right;
}
I guess the page looks has improved a lot with the CSS in place:
At this point, the calculator skeleton is done but it still does not do nothing useful.
Next: the Javascript functions >>>