Category “internet”

Introducing the Proton Template Engine (part 3)

Thursday, 29 January, 2009

Templates are usually made up of other templates, especially if you want to re-use page/document components. Proton supports an include function to embed one template inside another.

For example, a fragment of a template (include2.xhtml) containing 2 paragraphs of text…

<div>
    <p eid="para1">PARA 1 TEXT</p>
    <p eid="para2">PARA 2 TEXT</p>
</div>

…can be embedded in another template (include1.xhtml)…

<body>
    <h1 eid="title">PAGE TITLE GOES HERE</h1>

    <div eid="includedcontent">
    INCLUDED CONTENT GOES HERE
    </div>
</body>

…and then populated with data, using the following snippet of code:


tmp = self.templates['include1.xhtml']
tmp.setelement('title', 'Page Title')
tmp.include('includedcontent', 'include2.xhtml')
tmp.setelement('para1', 'First paragraph of text')
tmp.setelement('para2', 'Second paragraph of text')

 

On the ‘syntactic sugar front’, as an alternative to the more explicit repeat function (for repeating elements in the output), Proton supports setting lists of values rather than single-values. Consider the template:

<ul>
    <li rid="list-item" eid="list-item">LIST ITEMS</li>
</ul>

The list can be populated without having to explicitly call repeat, using the following code snippet:


lst = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g' ]
tmp.setelement('list-item', lst)

If your objects are decorated with properties (@property), then Proton also supports automatically setting the values in the page, using the convention of id followed by colon followed by property. For example, using the following template:

<dl>
    <dt>X Value</dt>
    <dd eid="prop:x">prop x here</dd>
    <dt>Y Value</dt>
    <dd eid="prop:y">prop y here</dd>
</dl>

A class Temp, with properties x and y can be set in the template, with the name prop and the values will be automatically populated.


class Temp(object):
    def __init__(self, x, y):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

t = Temp('100', '500')
tmp.setelement('prop', t)

Introducing the Proton Template Engine (part 2)

Tuesday, 27 January, 2009

In a typical template engine, there will be some form of conditional logic, for changing the display of a section of a document. This will generally be an if-statement wrapping one or more elements, perhaps enabling or disabling sections based on access rights, showing more detail based on data, and so on.

Proton supports this logic with the facility to hide an element (marked with the eid attribute). For example, in this excerpt of a navigation menu:

<ul class="menu">
    <li eid="accounts"><a href="/accounts">Account Summary</a></li>
    <li eid="transactions"><a href="/transactions">View / Download Transactions</a></li>
    <li eid="transfer"><a href="/transfer">Transfer Funds</a></li>
    <li eid="bills"><a href="/bills">Bill Payments</a></li>
    <li eid="autopayments"><a href="/autopayments">Automatic Payments</a></li>
    <li eid="exchange"><a href="/exchange">Foreign Exchange</a></li>
</ul>

The following code will switch off the “transactions”, “autopayments” and “exchange” elements:


tmp.hide('autopayments')
tmp.hide('exchange')
tmp.hide('transactions')

Resulting in output of:

<ul class="menu">
    <li><a href="/accounts">Account Summary</a></li>
    <li><a href="/transfer">Transfer Funds</a></li>
    <li><a href="/bills">Bill Payments</a></li>
</ul>

You can see this example in action in the test hiding.py.

Another, less common but equally useful, feature of template engines is the facility to translate text (in other words, i18n or the internationalisation of output). Proton supports translation by setting a translation function on a template. For example, consider the following template:

<html>
<head>
<title>Page Title</title>
</head>
<body>
    <h1>Page Title</h1>

    <p id="para1">Some translated text</p>
    <p id="para2">Not translated text</p>
</body>
</html>

In this case, translation doesn’t rely on the 3 attributes (eid, aid, rid) — rather a default set of named (xhtml) elements are translated (the set can, of course, be overridden). The following code demonstrates translation in action:


fr = {
    'Page Title' : 'Titre de la page',
    'Some translated text' : 'Certains textes traduits'
}

def translate(text):
    if text in fr:
        return fr[text]
    else:
        return text

tmp = self.templates['tests/i18n.xhtml']
tmp.translate = translate

And the resulting output:

<html>
<head>
<title>Titre de la page</title>
</head>
<body>
    <h1>Titre de la page</h1>

    <p id="para1">Certains textes traduits</p>
    <p id="para2">Not translated text</p>
</body>
</html>

Introducing the Proton Template Engine

Tuesday, 20 January, 2009

I haven’t come across many (any?) templating engines for Python 3, so it seemed like a good idea to update my own attempt, and then release as an open source (LGPL) project.

Proton is a simple, “code-less” engine for xml/xhtml templates. Code-less, because it uses 3 types of ID (attribute) in a template file, rather than snippets of code — this moves the complexity out of the template and into the application (where I think it belongs).

The following template demonstrates basic use of the 3 IDs:

<html>
<head>
<title eid="title">PAGE TITLE</title>
</head>
<body>
    <h1 eid="title">PAGE TITLE</h1>

    <p><a eid="link" aid="link" href="">LINK ITEM</a></p>

    <ul>
        <li rid="list-item" eid="list-item">LIST ITEMS</li>
    </ul>
</body>
</html>

The attribute “eid” is used to change the value of an element, or hide the element. “aid” is used to change the value of an attribute, and “rid” is used for repeating elements. This might seem a bit simplistic, but it covers the fundamentals of most templating tasks.

The following code demonstrates the use of the template:


tmp = Templates()['test.xhtml']

tmp.setelement('title', 'An Xhtml Page', '*')
tmp.setelement('link', 'This is a link to Google')
tmp.setattribute('link', 'href', 'http://www.google.com')

tmp.repeat('list-item', 5)
for x in range(0, 5):
    tmp.setelement('list-item', 'test%s' % x, x)

print(str(tmp))

I used an earlier version of Proton for my own (rather ill-fated) project; a web-based system for timesheet and invoice management, so it has been tested in some relatively complicated scenarios — however, I am keen to hear where it falls down. i.e. complex pages where using 3 attributes just doesn’t cut it.

RESTful resources

Sunday, 16 December, 2007

A recent release of Do My Invoice was a minor update to add more documentation for the various resources used in the application. DMI is a REST application — well, at the very least, that was the initial design goal — so there are some basic access points for most system resources.

For example, you may call GET to request your user profile:



http://www.domyinvoice.com/resources/[username]/profile


Using CURL the request:


curl -X GET -u joebloggs:password http://www.domyinvoice.com/resources/joebloggs/profile

…will return something like…



    joebloggs
	joe@bloggs.com
	Joe
	Bloggs


Resources in DMI are self-describing, thus with the addition of a single parameter, you can view the documentation for that resource. Thus the url…



http://www.domyinvoice.com/resources/joebloggs/profile?help


…returns a list of the HTTP verbs accepted by the resource, basic description and more detailed information about each verb. If you don’t have an account (it’s free for the first month, by the way), you can see a static version of this help information here.

Another example, is the clients resource. You can GET a list of clients:


curl -X GET -u joebloggs:password http://www.domyinvoice.com/resources/joebloggs/clients



	
		test company
address line 1
address line 2
		London
sa1 sa2
		United Kingdom
	


A client can be added with the use of an HTTP PUT:


curl -X PUT -u joebloggs:password http://www.domyinvoice.com/resources/joebloggs/clients/test+company+2 -d @-

address_1=23+Wrights+Lane&address_2=Kensington&city=London&postcode=W8+6TA&country=GB&currency_symbol=£&currency_format=1&sales_tax_label=VAT&sales_tax=0.175

Which also returns the created client (assuming nothing went wrong):



	
		test+company+2
23 Wrights Lane
Kensington
		London
W8 6TA
		United Kingdom
	


Said client could then be deleted with the use of the DELETE verb:


curl -X DELETE -u joebloggs:password http://www.domyinvoice.com/resources/joebloggs/clients/test+company+2

The obvious advantage of using RESTful resources internally is that I’m effectively providing an external API for free — in other words, without requiring any additional development effort.

Dodgy ISPs

Monday, 24 September, 2007

Is it just me, or do ISPs in New Zealand tend to operate on the south-side of the “moral tracks”? At the moment, I’m trying to decide whether it’s worth having an argument with Orcon over the advertising for their “Zero Shock” plan (see “The Yogurt Container Broadband Plan“) — supposedly, this plan is “traffic managed” to keep email and web access fast, and the speed of P2P applications are reduced as a consequence (by accepting this, you get the piece of mind that if you go over your datacap, you won’t get charged extra… as long as you don’t keep going over every month). For me, traffic management actually meant I had the average speed of a 28K modem most evenings for any site out of the country. Of course, if you look at their Terms & Conditions, there’s just enough caveats there to make them liable for nothing. Legally they’re fine. I quibble, however, on the dubious morals that allow a company to sell a “broadband” plan that they know barely meets the definition at the best of times.

To be honest, I really have no argument with Orcon otherwise. It just seems like false advertising to call something “Zero Shock”, when I find myself damn shocked at how slow it is.

The other ISP I have experience with is IHUG, who, if they reduce their prices for some reason, will keep quiet about it… “it’s your responsibility to check our website”. I’ve experienced this and so, more recently, has my father. Seems you should focus on keeping your current customers happy, rather than just attracting new ones.

That’s two of NZ’s larger ISPs, and I know the largest (Xtra) has had problems in the past.

I wonder if the issue is industry wide?

The Yogurt Container Broadband Plan

Thursday, 20 September, 2007

It’s an impressive feat.

When my daughter was about 2 and a half years old, we got a long piece of string, poked it through holes in a pair of yogurt containers, pulled the string tight and used it as a telephone. It was difficult to get the concept across to a 2 year old; of talking into the container, then listening for the response. It was also difficult keep the string taut enough, so that sound waves were transmitted properly.

Somehow, Orcon have managed not only to keep a piece of string tight over thousands of kilometres, they have also managed to connect the yogurt container to the local internet loop. An extremely impressive piece of engineering. Even if it does mean my international traffic is slower than a 28K modem. Just think of the science!

* * *

So it’s now almost a month since I first noticed the problem, and over 3 weeks since I reported it — and there is still no resolution in sight. At least a couple of emails have gone unanswered in the last few weeks, although the initial response from their support department (instructions on how to provide all the data their technicians would need) was positive. Last night I finally gave up waiting and decided to sit on hold for 10 minutes or so. Their helpdesk, while nice enough (and local), were unable to shed any light and would need to pass on the details to technicians. But…

“…we have had reports from other customers of similar problems… it may have something to do with the traffic shaping…”

Yes. I’m blimmin’ well aware that it’s traffic shaping. I could’ve told you that a month ago.

“…a quick fix might be to upgrade your plan…”

Where’s the sound of screeching tyres when you want it?

Upgrade my plan?

I must remember that if I ever get a complaint about software I’ve developed…

“I’m sorry you’re having problems sir. Other people have also experienced problems with that version of our software. I invite you to upgrade to a more expensive version, in which we have fixed that issue.”

PS. Unsurprisingly, still no response from technical support.

Painful IE6 event handling

Monday, 2 July, 2007

If you want to preload images before displaying them in the browser, a convenient way to do so is to use image.onload.

For example, the following code shows the onload in action:


img = new Image();

var onloadFunc = function() {
    alert("got here... you really should do something now");
};

img.onload = onloadFunc;
img.src = url;
if (img.complete) {
    onloadFunc();
}

That works in most situations, but I’ve just discovered IE6 is seriously buggy (so what’s new?) in its onload event handling. The specific problem is preloading an image from the body’s onload event (or any other method that fires after the page has loaded, such as a script at the bottom of the page, etc).

A morning of googling failed to find a solution, so for future-me‘s reference, basically the best way to ensure images are preloaded at the end of a pageload is something like the following:


var timer = null;
var images = new Array(); 

// trigger this from the body's onload
function onPageLoad() {
	images[0] = new Image();
	images[0].src = 'url to some image';
	images[1] = new Image();
	images[1].src = 'url to another image';
	timer = window.setInterval("onPageCheck()", 250);
} 

function onPageCheck() {
	for(var i = 0; i < images.length; i++) {
		if (!images[i].complete) {
			return;
		}
	}

	window.clearInterval(timer);
	images = null;

	// now use the images
	...
}

Basically, create an array of images (where the .src property triggers the preload), then use a timeout to check if the load is completed.

This appears to get around the problem. Note that the onload seems to work fine when triggered outside of the page onload (a button click and so on).

logproxy project

Monday, 11 June, 2007

One of my earliest posts (back when I was using blogger.com), was regarding a reverse logging proxy — a simple Python script to transparently log requests between a client and a server. Very useful for debugging web service calls, to see what exactly what is being sent back and forth.

I’ve just added logproxy.py to my projects page, after updating it to handle virtual hosts (in other words, when using Apache to serve more than one domain).

This is not quite as impressive a change as it might sound. It basically means correctly setting the Host HTTP header, rather than defaulting to localhost…

Anyway, a few people appear to have found it useful, judging from my access logs, so this update might help someone else (it certainly helped me figure out why my wsgi app was failing to properly handle multipart form content).

Digest, basic…. IE7?

Saturday, 12 May, 2007

I’ve just discovered that my implementation of a Digest Authentication middleware for WSGI, which had been working perfectly with Firefox, fails miserably when I try it with IE.

A bit of googling finds the following…

http://www.eweek.com/article2/0%2C1895%2C1500432%2C00.asp
http://www.extremetech.com/article2/0,1697,20373,00.asp

…making me think that I’m basically stuffed, despite the fact that I followed the RFC. Excellent work Microsoft! (Sarcasm alert!)

Should’ve done some reading first I think.

So now a decision. Persevere with digest auth and upgrade (irreversibly?) to IE7 in the vain hope that it works, or roll back to Basic auth which will obviously support more browsers.

Much as I’d like to stick with digest (and see if my implementation works in IE7), I think Basic auth is the safer option (at least coupled with SSL), particularly when you look at browser market share.

Basic CSS Popups

Friday, 6 April, 2007

Every time I have a requirement for a basic CSS popup box of some kind, I end up going through the same process. Hunt through old code looking for straightforward examples, then trawl through the googleweb trying to find something that isn’t an example of a CSS popup menu.

I’m sure pure CSS popup menus are all well and good, but it’s painful picking out the useful bits.

So, more for my own future reference, a simple CSS popup can be accomplished using the following CSS:


a span {
	display: none;
	text-decoration: none;
}

a:hover {
/** fix for IE6 popup bug.  nice one Microsoft! */
	overflow: hidden;
	text-decoration: none;
}

a:hover span {
	display: inline;
	border: 1px solid black;
	position: absolute;
	background-color: white;
	padding: 5px;
	margin-left: 5px;
	overflow: hidden;
}

The first reference hides the popup, the second redisplays, using margin-left to move the popup a little to the right of the href it’s linked from.

Then create HTML as follows:


<p>this is a test this is a test this is a test this is a test this is a test this is a test this is a test
this is a test this is a test this is a test this is a test this is a test this is a test this is a test
<a href="#">popup<span>test message 1<br />test message 2</span></a>
this is a test this is a test this is a test this is a test this is a test this is a test this is a test this is a test
this is a test this is a test this is a test this is a test this is a test this is a test this is a test this is a test
this is a test this is a test this is a test this is a test this is a test this is a test</p>

Check this link for an example.