|
|
Introduction
Basically, we will build up a menu tag which uses labels and paths, from which we will return a typical textual menu-like table. Just like the one being used for the remark documentation itself.
We will use some api global values, we will rely on the persistent parsing, and will even return different html for each page, based on the current file!
The goal of this mini tutorial is to layout most of the concepts behind creating a new custom rtag, without going in too much details.
If anything here seems incomplete and you'd like to have more details, don't hesitate to browse the RTAG REFERENCE for a full description of any of the topics covered here.
Obviously, we expect you to have good understanding of REBOL itself. The goal of this crash-course is not to help non-REBOL coders to try out remark.
files
Creating and saving the rtag file:
First off, start by creating an ascii file within your favorite REBOL editor, saving the file as follows %REMARK-INSTALL-DIR%/docs/tags/my-menu.rtag
There should already be a file there called site.rtag.
Creating and saving the test html file:
To keep things simple, lets save this file within the remark documentation!
Just create and edit the following file: %REMARK-INSTALL-DIR%/docs/source/tests/my-menu.html
The process of parsing rtags
Obviously, before we begin, we've got to have a little clue about just what we are doing, so here are the broad lines of what will be needed for an rtag to function.
self-identification
Rtags are responsible for identifying themselves dynamically whenever a tag is found... this is because of the dynamic nature of remark. This allows us to create tags which react only under some circumstances, even sharing the same name!.
We can also use this dynamic name identification to create master tags which react to several tagnames and create different output based on what name was used to switch it. This is the case for all the basic html tags, which are parsed and generated by one core rtag.
global values
Remark shares several global values to the API which can use when you need.
Many of the globals are set for each file, and sometimes even as a result of some other rtag.
Unless noted otherwise it is illegal (and maybe even dangerous) to change the values of any api-shared global values, cause other tags might go awry.
Things like the site root, current file name, modification date, most recent file and others can be used within your rtag safely. The reference docs give an explicit list of all api global vars which you can use.
In the near future, the global vars will be a context supplied to the tag, in order to isolate tags within a safe sandbox.
string! vs block! parsing
Depending on the nature of your rtag, you have two options on how to get its content or data. Either the string of text which is included within, OR a loaded block of REBOL data.
In most rtags, we simply use the string data and give it a little bit more format.
But when more advanced tags are built, they will tend towards containing parameters, more than actual content.
In such situations, it is expected that you use block parsing. We must not give a confusing experience to the user. Furthermore, rebol's datatype engine is really interesting.
nesting
This is a simple to understand concept. But its VERY powerfull.
Basically, the remark engine will flush out innermost nested tags first.
This means that any content which is included within your tags will have been parsed before the engine gets to you.
The user can use nested rtags and leverage them within other tags, allowing the outermost tags to use processed values, as if they had been specified directly within the source file.
persistence
Persistence occurs whenever an rtag is found and after it is parsed.
The engine will automatically REPARSE (hence the name remark ;-) the result html again!
This allows your tag to return known rtags which will again, be parsed innermost tags first.
Thus basically, the source file AND rtag API can leverage other tags, and thus a powerfull nested dialecting effect occurs!
Ok, lets do it!
With the above in your head, you are now able to understand what we will be going on in the following quick step by step example.
create the rtag object!
We first choose what kind of rtag this is and because we will be expecting the user to supply menu item information, we will use the has-tag! base class.
we thus start our example with the following code:
;--------- ;- MY-MENU! ;--------- make has-rtag! [
Identify ourself!
We will use the default naming method which uses a property within the object and compares it with the current tag being parsed. Fast and easy to setup.
In more advanced tags you can redefine a method called is-rtag? instead and change the way you decide if the current tag is of a type you want to handle.
so we add the following to our previous code:
tag-id: "my-menu!"
We get and parse the source data!
Basically, all you have to do to define your rtag's functionality is overload one function within the base class and return the new html data it creates.
Notice the call to to-dialect, this will load the data and return a clean block of values.
Really, its THAT simple! here is the function definitions:
build-html: func [
tagdata
/local data menu-list item rdata
][
menu-list: to-dialect tagdata
Build the html links, and compare globals
This is a simple loop which will iterate over the block of menu items included in the menu definition.
We first start with a table and populate it. One cell per menu item.
If the menu item's destination file is the current file, make the cell a simple string of text, instead of a link.
rdata: copy {<table cellspacing=0 cellpadding=0 class="menu"><tr>}
foreach item menu-list [
label: select item 'label
link: select item 'link
; here we use the pseudo-relative paths using link! (rtag) to make the menu universal on all pages.
append rdata {<td class="menu-item"><p class="menu-item">}
append rdata reduce either ((to-string link) <> gbl-current-filepath) [[{<link! } link { } label {>}]][label]
append rdata {</p></td>}
]
append rdata copy { </tr></table>}
]
Here we now call a method within the rtag api (link). This method will link the rtag within the global list of available rtags for this or all sites depending where the rtag file is located.
Note that any tags which are set within the sites, overide those within the global config. So you can effectively replace tags to make them local to your site's functionality, while still keeping the standard name in between your sites.
This detail actually allows you to have the same site output in wildly different layouts without even changing one single line of site content. Go to the configuration docs for more details.
link
The whole thing!
When glued together, the above lines give the following complete rtag specification:
;---------
;- MY-MENU!
;---------
make has-rtag! [
tag-id: "my-menu!"
build-html: func [
tagdata
/local data menu-list item rdata outfile label link
][
menu-list: to-dialect tagdata
rdata: copy {<table cellspacing=0 cellpadding=0 class="menu"><tr>}
foreach item menu-list [
label: select item 'label
link: select item 'link
; here we use the pseudo-relative path using link! custom tag to make the menu universal on all pages.
append rdata {<td class="menu-item"><p class="menu-item">}
append rdata reduce either ((to-string link) <> gbl-current-filepath) [[{<link! } link { } label {>}]][label]
append rdata {</p></td>}
]
append rdata copy { </tr></table>}
]
link
]
This is so simple that it almost hurts ;-)
Try to get such leverage in any other page editing tool which allows you create custom tags.
Try out the rtag within an html file
here is an example using the previous my-menu! tag.
Just copy-paste the following code in your test file, save and run remark. press "update latest", browse and voila.
<H1>MY FIRST REMARK WEB PAGE</H1>
<subject! my first rtag test!!! Yippee!>
<p! THIS IS WHERE CONTENT WOULD GO!>
<hr>
<center! <my-menu!
[label "MY HOME" link %index.html ]
[label "MY configuration" link %configs.html ]
[label "Overview" link %remark-engine.html]
[label "rtags" link %core-tags/rtags.html ]
[label "Rtags crash course" link %custom-tags/rtags-crash-course.html]
[label "License" link %license.html ]
>>
Obviously, since you integrated yourself within the remark documentation site, you benefit from all the html template, which includes header and footer data.
last updated: 16-Feb-2006/22:01:38-5:00