URL Handling
In a previous post on TiddlyWebPages, I mentioned URL handling functionality, and promised a later post detailing how to use it. Well, since then, I've done a considerable amount of extra work on it, simplifying the way URL's are stored, and adding a couple of extra features, which I'll detail here.
First, and most importantly though, it's no longer part of TiddlyWebPages. Instead, it has been packaged up as tiddlywebplugins.urls and can be installed by doing
Then you'll need to put 'tiddlywebplugins.urls' into both the 'server_plugins' and 'twanager_plugins' sections of tiddlywebconfig.py.
Once you've done that, you'll be able to add URLs with twanager. For example, loading up the "default" recipe as a TiddlyWiki at /mywiki, you'd write:
Where /mywiki is the url path you want to use, and /recipes/default/tiddlers.wiki is what you want to appear there.
If you wanted to load up any recipe as a wiki, and serve them up at /wikis/<recipe_name> then you could write:
In this example, {recipe:segment} specifies a variable within the URL called "recipe". The {{ recipe }} then get's replaced with whatever URL you eventually go to. You could then arrive at the /mywiki example above by pointing your browser at /wikis/default.
You can find further instructions about syntax for the URL path you are adding at http://lukearno.com/projects/selector/ though note that any variables are always embedded within the destination URL with double braces (eg - /recipes/{{ recipe }}/tiddlers.wiki).
tiddlywebplugins.urls also supports URL redirection. This can be used either internally to your site, or with any external link instead.
To use internally, just add --redirect to the twanager command (eg - twanager url --redirect /s3Rw /bags/common/tiddlers/MyTiddler would redirect anyone going to /s3Rw to /bags/common/tiddlers/MyTiddler).
To use with external sites, you just need to use the full URL. For example, you could redirect to Google with:
These URLs are all stored in the TiddlyWeb store with the Title being the URL you want to create, and the text being the URL you want to map/redirect to. The redirect option in the twanager command, relates directly to tagging the tiddler "redirect".
By default, this will be stored in a bag called urls, with a strict policy to stop other users modifying your URLs. This means that, with sufficient permissions, you could manage all your URLs from within TiddlyWebWiki itself.
Just one final note to finish off with, Currently, this only supports GET requests. This means that you cannot send PUT, POST or DELETE requests to these URLs. Saying that though, TiddlyWebWiki should still work regardless, just bear in mind that you should currently be PUTting to the standard set of URLs if you're writing any custom Javascript yourself.
Source code: http://github.com/bengillies/tiddlywebplugins.urls
Package: http://pypi.python.org/pypi/tiddlywebplugins.urls
Guide to Selector: http://lukearno.com/projects/selector/
First, and most importantly though, it's no longer part of TiddlyWebPages. Instead, it has been packaged up as tiddlywebplugins.urls and can be installed by doing
pip install -U tiddlywebplugins.urls
Then you'll need to put 'tiddlywebplugins.urls' into both the 'server_plugins' and 'twanager_plugins' sections of tiddlywebconfig.py.
Once you've done that, you'll be able to add URLs with twanager. For example, loading up the "default" recipe as a TiddlyWiki at /mywiki, you'd write:
twanager url /mywiki /recipes/default/tiddlers.wiki
Where /mywiki is the url path you want to use, and /recipes/default/tiddlers.wiki is what you want to appear there.
If you wanted to load up any recipe as a wiki, and serve them up at /wikis/<recipe_name> then you could write:
twanager url /wikis/{recipe:segment} "/recipes/{{ recipe }}/tiddlers.wiki"
In this example, {recipe:segment} specifies a variable within the URL called "recipe". The {{ recipe }} then get's replaced with whatever URL you eventually go to. You could then arrive at the /mywiki example above by pointing your browser at /wikis/default.
You can find further instructions about syntax for the URL path you are adding at http://lukearno.com/projects/selector/ though note that any variables are always embedded within the destination URL with double braces (eg - /recipes/{{ recipe }}/tiddlers.wiki).
Redirection
tiddlywebplugins.urls also supports URL redirection. This can be used either internally to your site, or with any external link instead.
To use internally, just add --redirect to the twanager command (eg - twanager url --redirect /s3Rw /bags/common/tiddlers/MyTiddler would redirect anyone going to /s3Rw to /bags/common/tiddlers/MyTiddler).
To use with external sites, you just need to use the full URL. For example, you could redirect to Google with:
twanager url /google http://www.google.com
URL storage and Modification
These URLs are all stored in the TiddlyWeb store with the Title being the URL you want to create, and the text being the URL you want to map/redirect to. The redirect option in the twanager command, relates directly to tagging the tiddler "redirect".
By default, this will be stored in a bag called urls, with a strict policy to stop other users modifying your URLs. This means that, with sufficient permissions, you could manage all your URLs from within TiddlyWebWiki itself.
Just one final note to finish off with, Currently, this only supports GET requests. This means that you cannot send PUT, POST or DELETE requests to these URLs. Saying that though, TiddlyWebWiki should still work regardless, just bear in mind that you should currently be PUTting to the standard set of URLs if you're writing any custom Javascript yourself.
Useful Links
Source code: http://github.com/bengillies/tiddlywebplugins.urls
Package: http://pypi.python.org/pypi/tiddlywebplugins.urls
Guide to Selector: http://lukearno.com/projects/selector/
Comments
Validating Comments with reCAPTCHA
Since I enabled comments on my site, I've been getting quite a lot of spam. Now, this is a problem that's existed all over the web now for quite a long time. What's more, it's been solved quite often before, usually requiring log in, or some sort of CAPTCHA validation to ensure that whoever is posting a comment is actually a human being.
While TiddlyWeb supports log in off the bat, I'm not a huge fan of requiring it just to post a comment, as logging in seems, to me at least, a bit unnecessary when all you want to do is leave one comment on a site.
With that in mind, I've gone down the CAPTCHA route, and implemented a validator that supports the popular reCAPTCHA validator that you've probably seen all over the rest of the web.
To use it, you'll need to grab it from my GitHub repository here. Then you can add it to system_plugins in your tiddlywebconfig.py file. As its an external service, you'll then need to sign up to it at http://recaptcha.net/api/getkey in order to get the requisite private and public keys.
Once you've signed up, add your private key to the tiddlywebconfig.py file like so:
Then, wherever you need to use it, add the following HTML:
Making sure to substitute <your_public_key> for the public key you got when you signed up (its in there twice).
Finally, it's a validator, so don't forget to set your accept policy.
While TiddlyWeb supports log in off the bat, I'm not a huge fan of requiring it just to post a comment, as logging in seems, to me at least, a bit unnecessary when all you want to do is leave one comment on a site.
With that in mind, I've gone down the CAPTCHA route, and implemented a validator that supports the popular reCAPTCHA validator that you've probably seen all over the rest of the web.
To use it, you'll need to grab it from my GitHub repository here. Then you can add it to system_plugins in your tiddlywebconfig.py file. As its an external service, you'll then need to sign up to it at http://recaptcha.net/api/getkey in order to get the requisite private and public keys.
Once you've signed up, add your private key to the tiddlywebconfig.py file like so:
'recaptcha_private_key': '<private_key>'
Then, wherever you need to use it, add the following HTML:
<script type="text/javascript"
src="http://api.recaptcha.net/challenge?k=<your_public_key>">
</script>
<noscript>
<iframe src="http://api.recaptcha.net/noscript?k=<your_public_key>"
height="300" width="500" frameborder="0"></iframe><br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40">
</textarea>
<input type="hidden" name="recaptcha_response_field"
value="manual_challenge">
</noscript>
src="http://api.recaptcha.net/challenge?k=<your_public_key>">
</script>
<noscript>
<iframe src="http://api.recaptcha.net/noscript?k=<your_public_key>"
height="300" width="500" frameborder="0"></iframe><br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40">
</textarea>
<input type="hidden" name="recaptcha_response_field"
value="manual_challenge">
</noscript>
Making sure to substitute <your_public_key> for the public key you got when you signed up (its in there twice).
Finally, it's a validator, so don't forget to set your accept policy.
How to make a Template in TiddlyWebPages
Since I announced TiddlyWebPages, I've been meaning to write a quick tutorial explaining how to make templates and define custom URLs for use on your site. In this post, I'll just cover templates and save URLs for another day. So let's start off at the point where you've installed TiddlyWeb, you have some content in your store, and you've installed TiddlyWebPages.
Right, the first step is to create a bag called templates and a bag called urls. Within the templates bag, you'll need to create a "wrapper" template. This will be the wrapper for all your content, so you can add links to your CSS definitions and Javascript files (or anything else) here without needing to include such things in every template. It needs to be called "Default" as it's the first one (and you need some sort of default right?) and while you can add other wrappers, we're not going into that quite yet. For now though, get the Default tiddler in the TiddlyWebPages GitHub directory at http://github.com/bengillies/TiddlyWeb-Plugins/raw/master/tw_pages/Default.tid and put it into your templates bag. You'll notice a couple of extra fields. list_tiddlers lets you specify the default template to use with a list of tiddlers (be it a bag, recipe or search results) while single_tiddlers does the same thing but for displaying a single tiddler only.
Now that's done, you can start adding templates. Now, as templates are all tiddlers themselves, you may want to just copy some from somebody else (my templates for example), but as this post is entitled "How to make a template", we'll assume you want to start from scratch.
Create a tiddler in the templates bag entitled "List". This will simply list all tiddlers in the bag/recipe that you are in, showing both the title, and the text. Next, enter the following information into the body of the tiddler:
Let's take a look at that line by line shall we?
This line starts a loop over all tiddlers, giving each tiddler in the list (called base, short for "base tiddlers") a name that you can refer to it with of "tiddler". "base" is a value that TiddlyWebPages provides you with to access the base set of tiddlers in the bag/recipe.
You can add other tiddlers, pre-formatted with another template, by specifying the template/recipe combination as a field in the template you want to include it in. For example, let's say you have created a "Header" template already and want to include it in your "List" template. Let's say that the tiddler that defines your header, is returned by the "my_header" recipe. To do that, you'd add a field to the "List" template specifying the "Header" template and the "my_header" recipe:
In this definition, "Header" is the title of the field, and specifies the template you want to use, while "my_recipe" specifies the recipe that you want to use. Anything after the question mark is run as a filter on the recipe. In this case, we are selecting the ListHeading tiddler from the recipe. The ability to filter recipes is especially useful for sorting tiddlers, as recipes cannot sort by default.
Adding this Header into the template, would produce a result as follows:
Notice the new variable called "extra". This contains the HTML for any extra templates you have specified in the tiddler's "fields" (as above). This gives two main variables that you can use: base; and extra. Other variables are: prefix - any server prefix you have defined in tiddlywebconfig.py; query - a key/value list of all items in the query string of the url; root_vars - a key/value list of any patterns that you have specified in your URL (by default, this will contain the tiddler name, in root_vars['tiddler'], the recipe name in root_vars['recipe'] and the bag name in root_vars['bag']).
You can put HTML wherever you like, which can form the basis of your template. The tiddler.title is enclosed in double braces - this tells TiddlyWebPages (actually the Jinja2 templating engine) that tiddler.title is a variable and you want to write its value into the page. The {% ... %} pattern tells Jinja2 that you want to run something without writing the output to the page. In the example above, this would be the for loop.
These lines just output the text of the tiddler and close the for loop. Optionally, you can choose to wikify the text by passing it through a filter and specifying a recipe name to use when creating links. If you did this with the recipe "sitecontent" (the recipe on my site that contains all my tiddlers) then you'd end up with the following:
In addition to all the standard Jinja filters and the wikifier, there is another filter called "shorten" that you can use to safely shorten HTML without worrying about cutting off closing tags.
Now that you've done that, you'll want to test it. So go to the tiddlers in one of your bags, and append ".List" to the end of tiddlers to see the result. You can try this on my site by going to http://bengillies.net/.a/recipes/blog/tiddlers.ContentList (my template is a bit more complicated though).
Finally, please read through the Jinja2 documentation to get a better idea of what you can accomplish. You can find it at http://jinja.pocoo.org/2/documentation/templates
You can also view my Templates at http://bengillies.net/.a/bags/templates/tiddlers If you want to use any of them yourself.
Right, the first step is to create a bag called templates and a bag called urls. Within the templates bag, you'll need to create a "wrapper" template. This will be the wrapper for all your content, so you can add links to your CSS definitions and Javascript files (or anything else) here without needing to include such things in every template. It needs to be called "Default" as it's the first one (and you need some sort of default right?) and while you can add other wrappers, we're not going into that quite yet. For now though, get the Default tiddler in the TiddlyWebPages GitHub directory at http://github.com/bengillies/TiddlyWeb-Plugins/raw/master/tw_pages/Default.tid and put it into your templates bag. You'll notice a couple of extra fields. list_tiddlers lets you specify the default template to use with a list of tiddlers (be it a bag, recipe or search results) while single_tiddlers does the same thing but for displaying a single tiddler only.
Your First Template
Now that's done, you can start adding templates. Now, as templates are all tiddlers themselves, you may want to just copy some from somebody else (my templates for example), but as this post is entitled "How to make a template", we'll assume you want to start from scratch.
Create a tiddler in the templates bag entitled "List". This will simply list all tiddlers in the bag/recipe that you are in, showing both the title, and the text. Next, enter the following information into the body of the tiddler:
{% for tiddler in base %}
<h1>{{tiddler.title}}</h1>
{{tiddler.text}}
{% endfor %}
<h1>{{tiddler.title}}</h1>
{{tiddler.text}}
{% endfor %}
Let's take a look at that line by line shall we?
{% for tiddler in base %}
This line starts a loop over all tiddlers, giving each tiddler in the list (called base, short for "base tiddlers") a name that you can refer to it with of "tiddler". "base" is a value that TiddlyWebPages provides you with to access the base set of tiddlers in the bag/recipe.
You can add other tiddlers, pre-formatted with another template, by specifying the template/recipe combination as a field in the template you want to include it in. For example, let's say you have created a "Header" template already and want to include it in your "List" template. Let's say that the tiddler that defines your header, is returned by the "my_header" recipe. To do that, you'd add a field to the "List" template specifying the "Header" template and the "my_header" recipe:
Header: my_recipe?select=title:ListHeading
In this definition, "Header" is the title of the field, and specifies the template you want to use, while "my_recipe" specifies the recipe that you want to use. Anything after the question mark is run as a filter on the recipe. In this case, we are selecting the ListHeading tiddler from the recipe. The ability to filter recipes is especially useful for sorting tiddlers, as recipes cannot sort by default.
Adding this Header into the template, would produce a result as follows:
{{extra['Header']}}
{% for tiddler in base %}
<h1>{{tiddler.title}}</h1>
{{tiddler.text}}
{% endfor %}
{% for tiddler in base %}
<h1>{{tiddler.title}}</h1>
{{tiddler.text}}
{% endfor %}
Notice the new variable called "extra". This contains the HTML for any extra templates you have specified in the tiddler's "fields" (as above). This gives two main variables that you can use: base; and extra. Other variables are: prefix - any server prefix you have defined in tiddlywebconfig.py; query - a key/value list of all items in the query string of the url; root_vars - a key/value list of any patterns that you have specified in your URL (by default, this will contain the tiddler name, in root_vars['tiddler'], the recipe name in root_vars['recipe'] and the bag name in root_vars['bag']).
<h1>{{tiddler.title}}</h1>
You can put HTML wherever you like, which can form the basis of your template. The tiddler.title is enclosed in double braces - this tells TiddlyWebPages (actually the Jinja2 templating engine) that tiddler.title is a variable and you want to write its value into the page. The {% ... %} pattern tells Jinja2 that you want to run something without writing the output to the page. In the example above, this would be the for loop.
{{tiddler.text}}
{% endfor %}
{% endfor %}
These lines just output the text of the tiddler and close the for loop. Optionally, you can choose to wikify the text by passing it through a filter and specifying a recipe name to use when creating links. If you did this with the recipe "sitecontent" (the recipe on my site that contains all my tiddlers) then you'd end up with the following:
{{tiddler.text|wikifier('sitecontent')}}
In addition to all the standard Jinja filters and the wikifier, there is another filter called "shorten" that you can use to safely shorten HTML without worrying about cutting off closing tags.
Now that you've done that, you'll want to test it. So go to the tiddlers in one of your bags, and append ".List" to the end of tiddlers to see the result. You can try this on my site by going to http://bengillies.net/.a/recipes/blog/tiddlers.ContentList (my template is a bit more complicated though).
Finally, please read through the Jinja2 documentation to get a better idea of what you can accomplish. You can find it at http://jinja.pocoo.org/2/documentation/templates
You can also view my Templates at http://bengillies.net/.a/bags/templates/tiddlers If you want to use any of them yourself.