Difference between revisions of "BML"
(mention template file) |
(BML documentation.) |
||
Line 1: | Line 1: | ||
BML stands for Brad's Better Markup language. | BML stands for Brad's Better Markup language. | ||
− | == | + | == Basic Introduction == |
− | + | BML is essentially a templating system, which is used on LJ mainly to provide the backend support for the siteschemes. It's kind of a bastard hybrid of [http://search.cpan.org/~samtregar/HTML-Template-2.9/Template.pm HTML::Template] and [http://search.cpan.org/~drolsky/HTML-Mason-1.40/lib/HTML/Mason.pm HTML::Mason], except it was developed completely independently by Brad, and in fact, was developed long before either of those distributions released on CPAN. | |
− | ** [http://www. | + | |
− | + | BML has been described as "''the bastard shambling horror of the deep''" by those who have had to work with it. Most of what it's used for could be replaced by CSS nowadays. (It's somewhat telling that one of the siteschemes on LiveJournal is "Lynx", which is designed for text browsers such as [http://lynx.isc.org/ Lynx], hence the name.) | |
+ | |||
+ | == Files == | ||
+ | |||
+ | BML is composed of two types of files - '''*.bml''' files and '''*.look''' files. The former can be considered standard HTML files, except that before they're passed to a browser, the BML engine parses it for special tags beginning with '''<?''' and ending with '''?>''', and does things with them according to the '''.look''' file that's being used. | ||
+ | |||
+ | It's worth noting that older versions of BML used '''(=''' and '''=)''' instead of '''<?''' and '''?>'''. Those versions are dead and buried, and are not used in either LiveJournal or Dreamwidth. Trust me, this is a good thing. | ||
+ | |||
+ | == Single-line Blocks == | ||
+ | |||
+ | The '''.look''' file being used will define ''blocks'' that define how these tags are replaced. Each block has a name and a value. For example, a simple block might be defined as: | ||
+ | |||
+ | sitename=>Dreamwidth | ||
+ | |||
+ | The name of this block is "sitename", and its value is "Dreamwidth". The '''=>''' means that the following text, up to the end of the line, should be considered to be the block value. Then, you could use the following code in a BML file: | ||
+ | |||
+ | Welcome to <?sitename?>! | ||
+ | |||
+ | and when you combine the '''.look''' file and the '''.bml''' file together, the end-result is: | ||
+ | |||
+ | Welcome to Dreamwidth! | ||
+ | |||
+ | == Multi-line Blocks == | ||
+ | |||
+ | A block can span more than one line, but to do this you need to define the start and end points. To do this, you reverse the '''=>''' part to become '''<=''' to define the start point: | ||
+ | |||
+ | introduction<= | ||
+ | |||
+ | and for the end point, you do the line again, but this time putting the block name after the symbols: | ||
+ | |||
+ | <=introduction | ||
+ | |||
+ | A good mnemonic is to think of the <= as pointing first to the name of the block, then to the value. A complete multi-line block might look like: | ||
+ | |||
+ | introduction<= | ||
+ | <nowiki><p>Welcome to Dreamwidth!</p></nowiki> | ||
+ | <nowiki><p>We hope you enjoy your time here.</p></nowiki> | ||
+ | <=introduction | ||
+ | |||
+ | As before, this could then be used in a normal BML page just by doing something like: | ||
+ | |||
+ | <nowiki><h1>Introduction</h1></nowiki> | ||
+ | <?introduction?> | ||
+ | |||
+ | Which would be parsed out to: | ||
+ | |||
+ | <nowiki><h1>Introduction</h1></nowiki> | ||
+ | <nowiki><p>Welcome to Dreamwidth!</p></nowiki> | ||
+ | <nowiki><p>We hope you enjoy your time here.</p></nowiki> | ||
+ | |||
+ | == Passing data == | ||
+ | |||
+ | It's possible to pass data into a block depending on what's needed. For example, let's say you wanted to make a simple error page. Without passing data, you might define such an error page like this in the '''.look''' file: | ||
+ | |||
+ | errorpage<= | ||
+ | <nowiki><h1>Error</h1></nowiki> | ||
+ | <nowiki><p>An error has occurred.</p></nowiki> | ||
+ | <=errorpage | ||
+ | |||
+ | However, this is very generic. It would be nice to have a way to pass in the specific error. | ||
+ | |||
+ | Fortunately, this is easily done: | ||
+ | |||
+ | errorpage<= | ||
+ | <nowiki><h1>Error</h1></nowiki> | ||
+ | <nowiki><p>An error has occurred: %%DATA%%</p></nowiki> | ||
+ | <=errorpage | ||
+ | |||
+ | The name '''%%DATA%%''' is defined to mean everything that's in the BML tag by default. In order to use this, you can use this type of tag: | ||
+ | |||
+ | <?errorpage Invalid login. errorpage?> | ||
+ | |||
+ | This will pass "Invalid login." to the block as '''%%DATA%%''', resulting in the following when parsed: | ||
+ | |||
+ | <nowiki><h1>Error</h1></nowiki> | ||
+ | <nowiki><p>An error has occurred: Invalid login.</p></nowiki> | ||
+ | |||
+ | == Passing multiple pieces of data == | ||
+ | |||
+ | Sometimes you want to pass more than one piece of data. For example, you may want to define a generic "page" tag to spit out a complete HTML document with one tag, defining the title and the body in the BML file. To do this, you have to define a block as "Full". To do this, you put the text '''{F}''' directly at the beginning of the definition. Once you've done this, you can name the data that gets passed in. | ||
+ | |||
+ | An example definition might look like: | ||
+ | |||
+ | page<= | ||
+ | {F} | ||
+ | <nowiki><html></nowiki> | ||
+ | <nowiki><head></nowiki> | ||
+ | <nowiki><title>%%TITLE%%</title></nowiki> | ||
+ | <nowiki></head></nowiki> | ||
+ | <nowiki><body></nowiki> | ||
+ | <nowiki>%%BODY%%</nowiki> | ||
+ | <nowiki></body></nowiki> | ||
+ | <nowiki></html></nowiki> | ||
+ | <=page | ||
+ | |||
+ | In this example you have two pieces of data - '''%%TITLE%%''' and '''%%BODY%%'''. | ||
+ | |||
+ | Now, since the '''.look''' files already define bits of data by name (in this case, blocks), Brad decided to reuse that syntax for passing these named pieces of data into a block. In this case, you might do something like: | ||
+ | |||
+ | <?page | ||
+ | TITLE=>Homepage | ||
+ | BODY<= | ||
+ | <nowiki><p>Welcome to Dreamwidth!</p></nowiki> | ||
+ | <nowiki><p>We hope you enjoy your time here.</p></nowiki> | ||
+ | <=BODY | ||
+ | page?> | ||
+ | |||
+ | '''Don't be fooled into thinking these are defining blocks you can use later as tags''' - they're not, and you can't use <?TITLE?> or <?BODY?> to put them elsewhere in your BML file too. These are ''only'' used to pass data to the block that you're using, and the only BML-specific tags that are valid on the page are those defined in the '''.look''' file. | ||
+ | |||
+ | (well, okay, as you'd expect with something called the shambling horror of the deep, there's an exception to this. But it's fairly easyish to understand, and in any case we're not going to go near that just yet, so don't panic.) | ||
+ | |||
+ | In this case, combining the '''.look''' file and the '''.bml''' file above would give: | ||
+ | |||
+ | <nowiki><html></nowiki> | ||
+ | <nowiki><head></nowiki> | ||
+ | <nowiki><title>Homepage</title></nowiki> | ||
+ | <nowiki></head></nowiki> | ||
+ | <nowiki><body></nowiki> | ||
+ | <nowiki><p>Welcome to Dreamwidth!</p></nowiki> | ||
+ | <nowiki><p>We hope you enjoy your time here.</p></nowiki> | ||
+ | <nowiki></body></nowiki> | ||
+ | <nowiki></html></nowiki> | ||
+ | |||
+ | By the way, if you thought that last example was eerily familiar, that's because this is the basic format used by the Dreamwidth BML files. Most of them simply have a 'page' tag with 'title' and 'body' data. The 'page' tag defined in the '''.look''' file being used for your current sitescheme then puts it all together into a coherent page. | ||
+ | |||
+ | The only real difference is that the Dreamwidth BML/look files use lower-case names like '''%%title%%''' rather than upper-case names like '''%%TITLE%%'''. This is sad, because upper-case names are easier to pick out, and using upper-case names for data also means you don't get them confused with blocks. Oh well, c'est la vie. | ||
+ | |||
+ | == Blocks within blocks within blocks... == | ||
+ | |||
+ | Of course, Brad being who he is, it's possible to combine these in lots of weird and wonderful ways. For example, here's a relatively simple '''.look''' file that contains a definition for a block named 'heading', that encloses its data in h1 HTML tags, and another block named 'para', that encloses its data in paragraph HTML tags: | ||
+ | |||
+ | <nowiki>heading=><h1>%%DATA%%</h1></nowiki> | ||
+ | <nowiki>para=><p>%%DATA%%</p></nowiki> | ||
+ | |||
+ | Hey, now we can modify the "errorpage" example above to use these blocks: | ||
+ | |||
+ | <nowiki>heading=><h1>%%DATA%%</h1></nowiki> | ||
+ | <nowiki>para=><p>%%DATA%%</p></nowiki> | ||
+ | |||
+ | errorpage<= | ||
+ | <nowiki><?heading Error heading?></nowiki> | ||
+ | <nowiki><?para An error has occurred: %%DATA%% para?></nowiki> | ||
+ | <=errorpage | ||
+ | |||
+ | Let's then say that actually, what we want to do is combine it with our "page" block above too. So we might end up with: | ||
+ | |||
+ | <nowiki>heading=><h1>%%DATA%%</h1></nowiki> | ||
+ | <nowiki>para=><p>%%DATA%%</p></nowiki> | ||
+ | |||
+ | page<= | ||
+ | {F} | ||
+ | <nowiki><html></nowiki> | ||
+ | <nowiki><head></nowiki> | ||
+ | <nowiki><title>%%TITLE%%</title></nowiki> | ||
+ | <nowiki></head></nowiki> | ||
+ | <nowiki><body></nowiki> | ||
+ | <nowiki>%%BODY%%</nowiki> | ||
+ | <nowiki></body></nowiki> | ||
+ | <nowiki></html></nowiki> | ||
+ | <=page | ||
+ | |||
+ | errorpage<= | ||
+ | <?page | ||
+ | TITLE=>Error | ||
+ | BODY<= | ||
+ | <nowiki><?heading Error heading?></nowiki> | ||
+ | <nowiki><?para An error has occurred: %%DATA%% para?></nowiki> | ||
+ | <=BODY | ||
+ | page?> | ||
+ | <=errorpage | ||
+ | |||
+ | As you can see, it can get convoluted ''very'' quickly if you're not careful. | ||
+ | |||
+ | You can also use tags within tags. For example, given the following '''.look''' file: | ||
+ | |||
+ | sitename=>Dreamwidth | ||
+ | <nowiki>heading=><h1>%%DATA%%</h1></nowiki> | ||
+ | |||
+ | You can produce this BML snippet: | ||
+ | |||
+ | <nowiki><?heading Welcome to <?sitename?>! heading?></nowiki> | ||
+ | |||
+ | which would produce the following output: | ||
+ | |||
+ | <nowiki><h1>Welcome to Dreamwidth!</h1></nowiki> | ||
+ | |||
+ | So, now we've covered how ugly BML can (and ''does'') get, let's return to some saner things. | ||
+ | |||
+ | == Special blocks == | ||
+ | |||
+ | Some blocks are predefined in BML. To distinguish them, their names always begin with an underscore. The most common of these blocks are presented here. | ||
+ | |||
+ | === _code === | ||
+ | |||
+ | The most obvious of these special blocks is '''_code''', and you'll see this in pretty much every BML file. In fact, it's not uncommon to find that the whole 'body' data of the 'page' tag is in fact one giant '''_code''' tag. | ||
+ | |||
+ | A '''_code''' tag contains Perl code. Obviously, it's beyond the scope of this page to teach Perl, but one important thing is that the value of a '''_code''' tag is whatever the Perl code inside returns. For example, if you have a BML snippet as follows: | ||
+ | |||
+ | <nowiki><p><?_code return 5 + 5; _code?></p></nowiki> | ||
+ | |||
+ | it would be output as: | ||
+ | |||
+ | <nowiki><p>10</p></nowiki> | ||
+ | |||
+ | In short, this is your Perl equivalent to PHP, but instead of using <nowiki><?php php?></nowiki> and writing in PHP code, you use <nowiki><?_code _code?></nowiki> and write in Perl code. | ||
+ | |||
+ | === _ml === | ||
+ | |||
+ | The "ml" in '''_ml''' stands for '''M'''ulti-'''L'''anguage, and it's BML's way of allowing for multiple translations. Instead of storing English text in a BML file, you instead include the text in an external file, and use this tag to include the text on the page. The process of moving English text to an external file in this way is referred to as ''English-stripping'' a page. | ||
+ | |||
+ | Because English-stripping and the translation system is a whole subject unto itself, I'm not going to cover it here. Ask somebody who knows about it, or wait for somebody to produce a page on this wiki about it. | ||
+ | |||
+ | === _info === | ||
+ | |||
+ | This block contains various miscellaneous data, none of which we care about here, except for one important one: '''localblocks'''. | ||
+ | |||
+ | Remember that I said above that the only BML-specific tags you can use on a BML page are those defined in the '''.look''' file? I also said that there was an exception. This is that exception. | ||
+ | |||
+ | The '''localblocks''' data value essentially defines a mini-'''.look''' file that you can only use on the same page as the one it appears on. | ||
+ | |||
+ | For example, you might have: | ||
+ | |||
+ | <nowiki><?_info</nowiki> | ||
+ | <nowiki>localblocks<=</nowiki> | ||
+ | <nowiki>heading=><h1>%%DATA</h1></nowiki> | ||
+ | <nowiki>para=><p>%%DATA</p></nowiki> | ||
+ | <nowiki><=localblocks</nowiki> | ||
+ | <nowiki>_info?></nowiki> | ||
+ | |||
+ | If this appears confusing to you, don't worry, it is. Basically, this allows you to then use <?heading?> and <?para?> tags as normal in the same page as the place this was defined, but not in any other page. You'll occasionally see these floating about in the code. | ||
+ | |||
+ | === _c === | ||
+ | |||
+ | I decided to finish with an easy one. This defines a comment, and everything within a '''_c''' tag is ignored completely. For example: | ||
+ | |||
+ | <?_c This code sucks. Don't blame me, I didn't write it. _c?> | ||
+ | |||
+ | These comments aren't output at all, unlike standard HTML comments (that is, <nowiki><!-- comments like this --></nowiki>). You'll sometimes see them at the bottom of Dreamwidth BML pages with some sort of <nowiki><LJDEP></LJDEP></nowiki> tag in them. I don't know what this is for, so chances are you don't need to. My guess is that it was for a ljcom-specific site management system. In any case, BML ignores these, so I do too. | ||
+ | |||
+ | === The others === | ||
+ | |||
+ | There are other special blocks, but they're hardly ever used. You can find more info about them at [http://www.livejournal.com/doc/server/bml.core.html the Core BML Blocks page on LJ]. | ||
+ | |||
+ | == End == | ||
+ | |||
+ | And that's about it for this BML wiki documentation project. If you really want to know more, LJ hosts the [http://www.livejournal.com/doc/server/bml.index.html BML Guide]. | ||
+ | |||
+ | == Resources == | ||
* [http://bugs.dwscoalition.org/show_bug.cgi?id=202 Template file] | * [http://bugs.dwscoalition.org/show_bug.cgi?id=202 Template file] | ||
[[Category: BML]] | [[Category: BML]] |
Revision as of 23:13, 17 February 2009
BML stands for Brad's Better Markup language.
Contents
Basic Introduction
BML is essentially a templating system, which is used on LJ mainly to provide the backend support for the siteschemes. It's kind of a bastard hybrid of HTML::Template and HTML::Mason, except it was developed completely independently by Brad, and in fact, was developed long before either of those distributions released on CPAN.
BML has been described as "the bastard shambling horror of the deep" by those who have had to work with it. Most of what it's used for could be replaced by CSS nowadays. (It's somewhat telling that one of the siteschemes on LiveJournal is "Lynx", which is designed for text browsers such as Lynx, hence the name.)
Files
BML is composed of two types of files - *.bml files and *.look files. The former can be considered standard HTML files, except that before they're passed to a browser, the BML engine parses it for special tags beginning with <? and ending with ?>, and does things with them according to the .look file that's being used.
It's worth noting that older versions of BML used (= and =) instead of <? and ?>. Those versions are dead and buried, and are not used in either LiveJournal or Dreamwidth. Trust me, this is a good thing.
Single-line Blocks
The .look file being used will define blocks that define how these tags are replaced. Each block has a name and a value. For example, a simple block might be defined as:
sitename=>Dreamwidth
The name of this block is "sitename", and its value is "Dreamwidth". The => means that the following text, up to the end of the line, should be considered to be the block value. Then, you could use the following code in a BML file:
Welcome to <?sitename?>!
and when you combine the .look file and the .bml file together, the end-result is:
Welcome to Dreamwidth!
Multi-line Blocks
A block can span more than one line, but to do this you need to define the start and end points. To do this, you reverse the => part to become <= to define the start point:
introduction<=
and for the end point, you do the line again, but this time putting the block name after the symbols:
<=introduction
A good mnemonic is to think of the <= as pointing first to the name of the block, then to the value. A complete multi-line block might look like:
introduction<= <p>Welcome to Dreamwidth!</p> <p>We hope you enjoy your time here.</p> <=introduction
As before, this could then be used in a normal BML page just by doing something like:
<h1>Introduction</h1> <?introduction?>
Which would be parsed out to:
<h1>Introduction</h1> <p>Welcome to Dreamwidth!</p> <p>We hope you enjoy your time here.</p>
Passing data
It's possible to pass data into a block depending on what's needed. For example, let's say you wanted to make a simple error page. Without passing data, you might define such an error page like this in the .look file:
errorpage<= <h1>Error</h1> <p>An error has occurred.</p> <=errorpage
However, this is very generic. It would be nice to have a way to pass in the specific error.
Fortunately, this is easily done:
errorpage<= <h1>Error</h1> <p>An error has occurred: %%DATA%%</p> <=errorpage
The name %%DATA%% is defined to mean everything that's in the BML tag by default. In order to use this, you can use this type of tag:
<?errorpage Invalid login. errorpage?>
This will pass "Invalid login." to the block as %%DATA%%, resulting in the following when parsed:
<h1>Error</h1> <p>An error has occurred: Invalid login.</p>
Passing multiple pieces of data
Sometimes you want to pass more than one piece of data. For example, you may want to define a generic "page" tag to spit out a complete HTML document with one tag, defining the title and the body in the BML file. To do this, you have to define a block as "Full". To do this, you put the text {F} directly at the beginning of the definition. Once you've done this, you can name the data that gets passed in.
An example definition might look like:
page<= {F} <html> <head> <title>%%TITLE%%</title> </head> <body> %%BODY%% </body> </html> <=page
In this example you have two pieces of data - %%TITLE%% and %%BODY%%.
Now, since the .look files already define bits of data by name (in this case, blocks), Brad decided to reuse that syntax for passing these named pieces of data into a block. In this case, you might do something like:
<?page TITLE=>Homepage BODY<= <p>Welcome to Dreamwidth!</p> <p>We hope you enjoy your time here.</p> <=BODY page?>
Don't be fooled into thinking these are defining blocks you can use later as tags - they're not, and you can't use <?TITLE?> or <?BODY?> to put them elsewhere in your BML file too. These are only used to pass data to the block that you're using, and the only BML-specific tags that are valid on the page are those defined in the .look file.
(well, okay, as you'd expect with something called the shambling horror of the deep, there's an exception to this. But it's fairly easyish to understand, and in any case we're not going to go near that just yet, so don't panic.)
In this case, combining the .look file and the .bml file above would give:
<html> <head> <title>Homepage</title> </head> <body> <p>Welcome to Dreamwidth!</p> <p>We hope you enjoy your time here.</p> </body> </html>
By the way, if you thought that last example was eerily familiar, that's because this is the basic format used by the Dreamwidth BML files. Most of them simply have a 'page' tag with 'title' and 'body' data. The 'page' tag defined in the .look file being used for your current sitescheme then puts it all together into a coherent page.
The only real difference is that the Dreamwidth BML/look files use lower-case names like %%title%% rather than upper-case names like %%TITLE%%. This is sad, because upper-case names are easier to pick out, and using upper-case names for data also means you don't get them confused with blocks. Oh well, c'est la vie.
Blocks within blocks within blocks...
Of course, Brad being who he is, it's possible to combine these in lots of weird and wonderful ways. For example, here's a relatively simple .look file that contains a definition for a block named 'heading', that encloses its data in h1 HTML tags, and another block named 'para', that encloses its data in paragraph HTML tags:
heading=><h1>%%DATA%%</h1> para=><p>%%DATA%%</p>
Hey, now we can modify the "errorpage" example above to use these blocks:
heading=><h1>%%DATA%%</h1> para=><p>%%DATA%%</p> errorpage<= <?heading Error heading?> <?para An error has occurred: %%DATA%% para?> <=errorpage
Let's then say that actually, what we want to do is combine it with our "page" block above too. So we might end up with:
heading=><h1>%%DATA%%</h1> para=><p>%%DATA%%</p> page<= {F} <html> <head> <title>%%TITLE%%</title> </head> <body> %%BODY%% </body> </html> <=page errorpage<= <?page TITLE=>Error BODY<= <?heading Error heading?> <?para An error has occurred: %%DATA%% para?> <=BODY page?> <=errorpage
As you can see, it can get convoluted very quickly if you're not careful.
You can also use tags within tags. For example, given the following .look file:
sitename=>Dreamwidth heading=><h1>%%DATA%%</h1>
You can produce this BML snippet:
<?heading Welcome to <?sitename?>! heading?>
which would produce the following output:
<h1>Welcome to Dreamwidth!</h1>
So, now we've covered how ugly BML can (and does) get, let's return to some saner things.
Special blocks
Some blocks are predefined in BML. To distinguish them, their names always begin with an underscore. The most common of these blocks are presented here.
_code
The most obvious of these special blocks is _code, and you'll see this in pretty much every BML file. In fact, it's not uncommon to find that the whole 'body' data of the 'page' tag is in fact one giant _code tag.
A _code tag contains Perl code. Obviously, it's beyond the scope of this page to teach Perl, but one important thing is that the value of a _code tag is whatever the Perl code inside returns. For example, if you have a BML snippet as follows:
<p><?_code return 5 + 5; _code?></p>
it would be output as:
<p>10</p>
In short, this is your Perl equivalent to PHP, but instead of using <?php php?> and writing in PHP code, you use <?_code _code?> and write in Perl code.
_ml
The "ml" in _ml stands for Multi-Language, and it's BML's way of allowing for multiple translations. Instead of storing English text in a BML file, you instead include the text in an external file, and use this tag to include the text on the page. The process of moving English text to an external file in this way is referred to as English-stripping a page.
Because English-stripping and the translation system is a whole subject unto itself, I'm not going to cover it here. Ask somebody who knows about it, or wait for somebody to produce a page on this wiki about it.
_info
This block contains various miscellaneous data, none of which we care about here, except for one important one: localblocks.
Remember that I said above that the only BML-specific tags you can use on a BML page are those defined in the .look file? I also said that there was an exception. This is that exception.
The localblocks data value essentially defines a mini-.look file that you can only use on the same page as the one it appears on.
For example, you might have:
<?_info localblocks<= heading=><h1>%%DATA</h1> para=><p>%%DATA</p> <=localblocks _info?>
If this appears confusing to you, don't worry, it is. Basically, this allows you to then use <?heading?> and <?para?> tags as normal in the same page as the place this was defined, but not in any other page. You'll occasionally see these floating about in the code.
_c
I decided to finish with an easy one. This defines a comment, and everything within a _c tag is ignored completely. For example:
<?_c This code sucks. Don't blame me, I didn't write it. _c?>
These comments aren't output at all, unlike standard HTML comments (that is, <!-- comments like this -->). You'll sometimes see them at the bottom of Dreamwidth BML pages with some sort of <LJDEP></LJDEP> tag in them. I don't know what this is for, so chances are you don't need to. My guess is that it was for a ljcom-specific site management system. In any case, BML ignores these, so I do too.
The others
There are other special blocks, but they're hardly ever used. You can find more info about them at the Core BML Blocks page on LJ.
End
And that's about it for this BML wiki documentation project. If you really want to know more, LJ hosts the BML Guide.