improvements to docs

pull/27/head
Matthew Butterick 10 years ago
parent 5656801fe1
commit bfa552e357

@ -231,15 +231,15 @@ Pollen + Markdown
As before, go to the @link["http://localhost:8080/index.ptree"]{dashboard} for the project server. This time, click the link for @link["http://localhost:8080/downtown.html"]{@tt{downtown.html}}. You'll see something like this:
@nested[#:style 'code-inset]{
@bold{@larger{Pollen + Markdown}}
@nested[#:style 'inset]{@itemlist[
@browser{
@bold{@larger{Pollen + Markdown}}
@item{You @bold{wanted} it — you @italic{got} it.}
       • You @bold{wanted} it — you @italic{got} it.
       • @link["https://google.com/search?q=racket"]{search for Racket}
}
@item{@link["https://google.com/search?q=racket"]{search for Racket}}
]}}
As usual, you're welcome to edit @tt{downtown.html.pmd} and then refresh the web browser to see the changes.
@ -260,15 +260,14 @@ Pollen + ◊metal
Refresh @link["http://localhost:8080/downtown.html"]{@tt{downtown.html}} in the browser:
@nested[#:style 'code-inset]{
@bold{@larger{Pollen + Plutonium}}
@browser{
@bold{@larger{Pollen + Plutonium}}
@nested[#:style 'inset]{@itemlist[
       • You @bold{wanted} Plutonium — you @italic{got} it.
@item{You @bold{wanted} Plutonium — you @italic{got} it.}
       • @link["https://google.com/search?q=Plutonium"]{search for Plutonium}
}
@item{@link["https://google.com/search?q=Plutonium"]{search for Plutonium}}
]}}
Pollen is handling two tasks here: interpreting the commands in the source, and then converting the Markdown to HTML. But what if you wanted to use Pollen as a preprocessor that outputs a Markdown file? No problem — just change the source name from @tt{downtown.html.pmd} to @tt{downtown.md.pp}. Changing the extension from @tt{.pmd} to @tt{.pp} switches Pollen from Markdown mode back to preprocessor mode. And changing the base name from @tt{downtown.html} to @tt{downtown.md} updates the name of the output file.
@ -298,8 +297,9 @@ Let's convert our Markdown example into Pollen markup. Marking up content is sim
Go to the @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/uptown.html"]{@tt{uptown.html}}. You'll see something like this:
@nested[#:style 'code-inset]{
Pollen markup You @bold{wanted} it — you @italic{got} it. https://google.com/search?q=racketsearch for Racket}
@browser{
Pollen markup You @bold{wanted} it — you @italic{got} it. https://google.com/search?q=racketsearch for Racket
}
That's not right. What happened?
@ -321,15 +321,13 @@ For that, we'll make a special file called @tt{directory-require.rkt}. This is a
Return to the @link["http://localhost:8080/index.ptree"]{project dashboard} and click on @link["http://localhost:8080/uptown.html"]{@tt{uptown.html}}. Now you'll get the right result:
@nested[#:style 'code-inset]{
@bold{@larger{Pollen markup}}
@nested[#:style 'inset]{@itemlist[
@browser{
@bold{@larger{Pollen markup}}
@item{You @bold{wanted} it — you @italic{got} it.}
       • You @bold{wanted} it — you @italic{got} it.
@item{@link["https://google.com/search?q=racket"]{search for Racket}}
]}}
       • @link["https://google.com/search?q=racket"]{search for Racket}
}
Markup mode takes a little more effort to set up. But it also allows you more flexibility. If you want to do semantic markup, or convert your source into multiple output formats, or handle complex page layouts — it's the way to go.

@ -1,6 +1,6 @@
#lang scribble/manual
@(require (for-label pollen/world) racket/runtime-path "mb-tools.rkt")
@(require (for-label pollen/world) "mb-tools.rkt")
@title[#:tag "first-tutorial"]{First tutorial}
@ -70,13 +70,13 @@ Language: racket; memory limit: 1000 MB.
If you don't see the interactions window, select @menuitem["View"
"Show Interactions"] from the menu.
@subsection{Setting the @racketfont{#lang} line}
@subsection{Setting the @tt{#lang} line}
The first line of every Racket source file, and every Pollen source file, is called the @italic{@racketfont{#lang} line}. The @racketfont{#lang} line identifies the language used to interpret the rest of the file.
The first line of every Racket source file, and every Pollen source file, is called the @italic{@tt{#lang} line}. The @tt{#lang} line identifies the language used to interpret the rest of the file.
@margin-note{For more about the @racketfont{#lang} line, see @secref["hash-languages" #:doc '(lib "scribblings/guide/guide.scrbl")]. BTW, it's pronounced @italic{hash lang}.}
@margin-note{For more about the @tt{#lang} line, see @secref["hash-languages" #:doc '(lib "scribblings/guide/guide.scrbl")]. BTW, it's pronounced @italic{hash lang}.}
When you start a new Pollen source file in DrRacket, you'll need to change the @racketfont{#lang} line to the Pollen language. The simplest way is to change the first line to this:
When you start a new Pollen source file in DrRacket, you'll need to change the @tt{#lang} line to the Pollen language. The simplest way is to change the first line to this:
@codeblock{
#lang pollen
@ -90,7 +90,7 @@ Language: pollen; memory limit: 1000 MB.
>
}
Notice that the language is now reported as @racketfont{pollen}. If you like, change the @racketfont{#lang} line to this:
Notice that the language is now reported as @tt{pollen}. If you like, change the @tt{#lang} line to this:
@nested[#:style 'code-inset]{@verbatim{
#lang pollenxyz}}
@ -100,7 +100,7 @@ Then click @onscreen["Run"] again. DrRacket will print an error:
@errorblock{Module Language: invalid module text
standard-module-name-resolver: collection not found ...}
Why? Because there's no language called @racketfont{pollenxyz}. Switch it back to @racketfont{pollen} and let's move on.
Why? Because there's no language called @tt{pollenxyz}. Switch it back to @tt{pollen} and let's move on.
@subsection{Putting in the text of the poem}
@ -113,7 +113,7 @@ The padding is 15em.
The border is too.
}
Paste the text of this poem into your DrRacket editing window, below the @racketfont{#lang} line, so it looks like this:
Paste the text of this poem into your DrRacket editing window, below the @tt{#lang} line, so it looks like this:
@codeblock{
#lang pollen
@ -131,7 +131,7 @@ The border is blue.
The padding is 2em.
The border is too.}
This shows you something important: by default, any plain text in a Pollen source file is simply printed as written when you @onscreen["Run"] the file (minus the @racketfont{#lang} line, which is just for Racket's benefit). If you like, edit the text of the poem and click @onscreen["Run"] again. You'll see the updated text printed in the interactions window.
This shows you something important: by default, any plain text in a Pollen source file is simply printed as written when you @onscreen["Run"] the file (minus the @tt{#lang} line, which is just for Racket's benefit). If you like, edit the text of the poem and click @onscreen["Run"] again. You'll see the updated text printed in the interactions window.
@subsection{Saving & naming your source file}
@ -139,19 +139,19 @@ This shows you something important: by default, any plain text in a Pollen sourc
File naming in Pollen is consequential.
Ultimately, every Pollen source file in your project will be @italic{rendered} into an output file. Each Pollen source file corresponds to one output file. @bold{The name of this output file will be the name of the source file minus the Pollen source extension.} So a source file called @racketfont{file.txt.pp} will become @racketfont{file.txt}.
Ultimately, every Pollen source file in your project will be @italic{rendered} into an output file. Each Pollen source file corresponds to one output file. @bold{The name of this output file will be the name of the source file minus the Pollen source extension.} So a source file called @tt{file.txt.pp} will become @tt{file.txt}.
Thus, to build the name of a source file, we take the name we want for the output file and add the appropriate Pollen file extension. Different Pollen source files use different extensions — but more about that later. For now, the extension you'll use for your source is @racketfont{.pp}.
Thus, to build the name of a source file, we take the name we want for the output file and add the appropriate Pollen file extension. Different Pollen source files use different extensions — but more about that later. For now, the extension you'll use for your source is @tt{.pp}.
In this case, let's say we want to end up with a file called @racketfont{poem.html}. Therefore, the name of our source file needs to be:
In this case, let's say we want to end up with a file called @tt{poem.html}. Therefore, the name of our source file needs to be:
the output name @racketfont{poem.html} + the source extension @racketfont{.pp} = @racketfont{poem.html.pp}
the output name @tt{poem.html} + the source extension @tt{.pp} = @tt{poem.html.pp}
(If you want to name the file @racketfont{something-else.html.pp}, be my guest. There's no magic associated with the prefix.)
(If you want to name the file @tt{something-else.html.pp}, be my guest. There's no magic associated with the prefix.)
@margin-note{You're welcome to change the name of your source files from the desktop. On Mac OS X and Windows, however, the desktop interface often hides file extensions, so check the properties of the file afterward to make sure you got the name you expected.}
In a convenient location (e.g., your home directory or the desktop) create a new directory for your project called @racketfont{tutorial}. In this new directory, save your DrRacket file as @racketfont{poem.html.pp}.
In a convenient location (e.g., your home directory or the desktop) create a new directory for your project called @tt{tutorial}. In this new directory, save your DrRacket file as @tt{poem.html.pp}.
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
@ -177,24 +177,24 @@ A note about security. The project server isn't intended for real-world use, but
@subsection{Starting the project server with @racketfont{raco pollen}}
@subsection{Starting the project server with @tt{raco pollen}}
Before we start the project server, a word about the @racketfont{raco pollen} command.
Before we start the project server, a word about the @tt{raco pollen} command.
When you installed Racket, Racket installed a utility program called @racketfont{raco}. This name is short for @bold{Ra}cket @bold{co}mmand, and @racketfont{raco} acts as a hub for — you guessed it — Racket commands. You used it when you first installed Pollen:
When you installed Racket, Racket installed a utility program called @tt{raco}. This name is short for @bold{Ra}cket @bold{co}mmand, and @tt{raco} acts as a hub for — you guessed it — Racket commands. You used it when you first installed Pollen:
@terminal{
> raco pkg install pollen
}
The first argument after @racketfont{raco} is the subcommand. For instance, @racketfont{raco pkg ...} lets you install, update, and remove packages like so:
The first argument after @tt{raco} is the subcommand. For instance, @tt{raco pkg ...} lets you install, update, and remove packages like so:
@terminal{
> raco pkg update pollen
> raco pkg remove pollen
}
Likewise, @racketfont{raco pollen} lets you issue commands relevant to Pollen, like starting the project server. (See @secref["raco-pollen"] for a full description of available commands.)
Likewise, @tt{raco pollen} lets you issue commands relevant to Pollen, like starting the project server. (See @secref["raco-pollen"] for a full description of available commands.)
Now we'll start the project server. Go to your command line and enter the following:
@ -202,7 +202,7 @@ Now we'll start the project server. Go to your command line and enter the follow
> cd /path/to/tutorial
> raco pollen start}
@margin-note{Windows users, I'll trust you to convert @racketfont{raco} into the appropriate command for your system — assuming defaults, it's likely to be @racketfont{"C:\Program Files\Racket\raco"} (include the surrounding quotes in the command).}
@margin-note{Windows users, I'll trust you to convert @tt{raco} into the appropriate command for your system — assuming defaults, it's likely to be @tt{"C:\Program Files\Racket\raco"} (include the surrounding quotes in the command).}
After a moment, you'll see a startup message like this:
@ -213,19 +213,19 @@ Project server is http://localhost:8080 (Ctrl-C to exit)
Project dashboard is http://localhost:8080/index.ptree
Ready to rock}
@italic{Project root} means the directory that the project server was started in, and which it's treating as its root directory. Any absolute URLs (i.e., those beginning with @litchar{/}) will resolve into this directory. So a URL like @racketfont{/styles.css} will impliedly become @racketfont{/path/to/tutorial/styles.css}.
@italic{Project root} means the directory that the project server was started in, and which it's treating as its root directory. Any absolute URLs (i.e., those beginning with @litchar{/}) will resolve into this directory. So a URL like @tt{/styles.css} will impliedly become @tt{/path/to/tutorial/styles.css}.
If you use the bare command @racketfont{raco pollen start}, the project server will start in the current directory. But if you want to start the project server elsewhere, you can add that directory as an argument like this:
If you use the bare command @tt{raco pollen start}, the project server will start in the current directory. But if you want to start the project server elsewhere, you can add that directory as an argument like this:
@terminal{
> raco pollen start /some/other/path
}
The next line of the startup message tells you that the web address of the project server is @racketfont{http://localhost:8080}. This is the address you put into your web browser to test your project. If you're unfamiliar with this style of URL, @racketfont{localhost} refers to your own machine, and @racketfont{8080} is the network port where the project server will respond to browser requests.
The next line of the startup message tells you that the web address of the project server is @tt{http://localhost:8080}. This is the address you put into your web browser to test your project. If you're unfamiliar with this style of URL, @tt{localhost} refers to your own machine, and @tt{8080} is the network port where the project server will respond to browser requests.
If you want to access the project server from a different machine, you can't use @racketfont{localhost}. But you can use the IP address of the machine running the project server (e.g., @racketfont{http://192.168.1.10:8080}) or any name for that machine available through local DNS (e.g., @racketfont{http://mb-laptop:8080}).
If you want to access the project server from a different machine, you can't use @tt{localhost}. But you can use the IP address of the machine running the project server (e.g., @tt{http://192.168.1.10:8080}) or any name for that machine available through local DNS (e.g., @tt{http://mb-laptop:8080}).
Though port @racketfont{8080} is the default, you can start the project server on any port you like by adding it as an argument to @racketfont{raco pollen start}:
Though port @tt{8080} is the default, you can start the project server on any port you like by adding it as an argument to @tt{raco pollen start}:
@terminal{
> raco pollen start /path/to/tutorial
@ -253,11 +253,11 @@ Your terminal window will report status and error messages from the project serv
For each directory in your project, starting at the top, the project server displays a @italic{dashboard} in your web browser. The dashboard gives you an overview of the files in the directory, and links to view them.
The address of the top-level dashboard is @racketfont{http://localhost:8080/index.ptree}. Other dashboards follow the same pattern (e.g., @racketfont{http://localhost:8080/path/to/dir/index.ptree}.)
The address of the top-level dashboard is @tt{http://localhost:8080/index.ptree}. Other dashboards follow the same pattern (e.g., @tt{http://localhost:8080/path/to/dir/index.ptree}.)
Note that the dashboard is @bold{not} at @racketfont{http://localhost:8080/} or its equivalent, @racketfont{http://localhost:8080/index.html}. Why? So it doesnt interfere with any @racketfont{index.html} that you may want to put in your project.
Note that the dashboard is @bold{not} at @tt{http://localhost:8080/} or its equivalent, @tt{http://localhost:8080/index.html}. Why? So it doesnt interfere with any @tt{index.html} that you may want to put in your project.
Thus, @racketfont{index.ptree}. The @racketfont{.ptree} extension is short for @italic{pagetree}. In Pollen, a pagetree is a hierarchical list of pages. We'll do more with pagetrees in a later tutorial. For now, just be aware that to generate the dashboard, the project server will first look for an actual @racketfont{index.ptree} file in each directory. If it doesn't find one, it will generate a pagetree from a listing of files in the directory.
Thus, @tt{index.ptree}. The @tt{.ptree} extension is short for @italic{pagetree}. In Pollen, a pagetree is a hierarchical list of pages. We'll do more with pagetrees in a later tutorial. For now, just be aware that to generate the dashboard, the project server will first look for an actual @tt{index.ptree} file in each directory. If it doesn't find one, it will generate a pagetree from a listing of files in the directory.
Let's look at the root-level dashboard for our project. First, make sure your project server is running:
@ -266,31 +266,31 @@ Let's look at the root-level dashboard for our project. First, make sure your pr
> raco pollen start
}
Then, in your web browser, visit @link["http://localhost:8080/index.ptree"]{@racketfont{http://localhost:8080/index.ptree}}.
Then, in your web browser, visit @link["http://localhost:8080/index.ptree"]{@tt{http://localhost:8080/index.ptree}}.
You should see something like this:
@image/rp["dashboard.png"]
The top line tells us that we're in the root directory of the project. We didn't make an explicit @racketfont{index.ptree} file, so the project server just shows us a directory listing.
The top line tells us that we're in the root directory of the project. We didn't make an explicit @tt{index.ptree} file, so the project server just shows us a directory listing.
@subsection{Source files in the dashboard}
We see the only file, @racketfont{poem.html.pp}. Note that the @racketfont{.pp} extension is grayed out. The dashboard automatically consolidates references to source and output files into a single entry. What this entry says is ``The directory contains a source file in @racketfont{.pp} format for the output file @racketfont{poem.html}.''
We see the only file, @tt{poem.html.pp}. Note that the @tt{.pp} extension is grayed out. The dashboard automatically consolidates references to source and output files into a single entry. What this entry says is ``The directory contains a source file in @tt{.pp} format for the output file @tt{poem.html}.''
Every source-file entry in the dashboard has three links. The first link is attached to the filename itself, and takes you to a preview of the output file. If the output file doesn't yet exist — as is the case here — it will be dynamically rendered. (This is true whether you click its name in the dashboard, or link to it from another page.) So click the filename. You'll see in your web browser:
@browser{
The margin is 42em. The border is red. The padding is 15em. The border is too.}
Granted, this is a boring web page. The main point here is that you're seeing the @italic{output} from your source file, which didn't exist before. Notice that the address bar says @racketfont{http://localhost:8080/poem.html}, not @racketfont{poem.html.pp}. And if you look in your @racketfont{tutorial} directory, you'll see a new file called @racketfont{poem.html}.
Granted, this is a boring web page. The main point here is that you're seeing the @italic{output} from your source file, which didn't exist before. Notice that the address bar says @tt{http://localhost:8080/poem.html}, not @tt{poem.html.pp}. And if you look in your @tt{tutorial} directory, you'll see a new file called @tt{poem.html}.
In other words, when you clicked on the filename link in the dashboard, Pollen rendered the output file from your source file and saved it in your project directory. As promised earlier, the name of the output file (@racketfont{poem.html}) is the name of the source file (@racketfont{poem.html.pp}) minus the Pollen extension (@racketfont{.pp}).
In other words, when you clicked on the filename link in the dashboard, Pollen rendered the output file from your source file and saved it in your project directory. As promised earlier, the name of the output file (@tt{poem.html}) is the name of the source file (@tt{poem.html.pp}) minus the Pollen extension (@tt{.pp}).
If you go back to the dashboard and click on the filename link again, you'll see the same output file. If the source file hasn't changed, Pollen will just show you the output file that's already been rendered.
But if you like, open your @racketfont{poem.html.pp} source file in DrRacket, edit the first two lines, and save the file:
But if you like, open your @tt{poem.html.pp} source file in DrRacket, edit the first two lines, and save the file:
@codeblock{
#lang pollen
@ -308,9 +308,9 @@ The cave is pitch black. Look out for the grue. The padding is 15em. The border
Here, Pollen notices that the source file has changed, so it refreshes the output file. This makes it convenient to work between DrRacket and your web browser, editing source and then reloading to see the changes.
The other two links in the dashboard are labeled @racketfont{in} and @racketfont{out}.
The other two links in the dashboard are labeled @tt{in} and @tt{out}.
The link labeled @racketfont{in} will display the contents of the source file:
The link labeled @tt{in} will display the contents of the source file:
@codeblock{
#lang pollen
@ -321,7 +321,7 @@ The padding is 15em.
The border is too.
}
The link labeled @racketfont{out} will display the contents of the output file (just like the ``view source'' option in your web browser):
The link labeled @tt{out} will display the contents of the output file (just like the ``view source'' option in your web browser):
@terminal{
The cave is pitch black.
@ -329,22 +329,22 @@ Look out for the grue.
The padding is 15em.
The border is too.}
For now, the files are identical except for the @racketfont{#lang} line. But let's change that.
For now, the files are identical except for the @tt{#lang} line. But let's change that.
@section{Working with the preprocessor}
Pollen can operate in several processing modes. One of these is @italic{preprocessor} mode. A preprocessor is a tool for making systematic, automated changes to a file, often in contemplation of further processing (hence the @italic{pre-}). You can use the Pollen preprocessor this way. Or you can just use it on its own, and leave your files in a finished state.
That's how we'll use it in this tutorial. We'll build out our @racketfont{poem.html.pp} source file so that it exits the preprocessor as a legit HTML file.
That's how we'll use it in this tutorial. We'll build out our @tt{poem.html.pp} source file so that it exits the preprocessor as a legit HTML file.
@subsection{Setting up a preprocessor source file}
The file extension of a Pollen source file tells Pollen what kind of processing to apply to it. The ``@racketfont{.pp}'' file extension stands for ``Pollen preprocessor.'' You can use the preprocessor with any text-based file by:
The file extension of a Pollen source file tells Pollen what kind of processing to apply to it. The ``@tt{.pp}'' file extension stands for ``Pollen preprocessor.'' You can use the preprocessor with any text-based file by:
@itemlist[
@item{inserting @racketfont{#lang pollen} as the first line,}
@item{inserting @tt{#lang pollen} as the first line,}
@item{adding the @racketfont{.pp} file extension,}
@item{adding the @tt{.pp} file extension,}
@item{running it through Pollen.}
]
@ -376,7 +376,7 @@ The padding is 15em.
The border is too.
}]
This file has @racketfont{#lang pollen} as the first line, and @racketfont{.pp} as the file extension, so it meets the minimum requirements for the preprocessor.
This file has @tt{#lang pollen} as the first line, and @tt{.pp} as the file extension, so it meets the minimum requirements for the preprocessor.
@subsection{Creating valid HTML output}
@ -402,7 +402,7 @@ Return to the project server and view @link["http://localhost:8080/poem.html" "h
The margin is 42em. The border is red. The padding is 15em. The border is too.}
But now, because of the @racketfont{<pre>} tag, the poem will appear in a monospaced font, and the line breaks will be preserved:
But now, because of the @tt{<pre>} tag, the poem will appear in a monospaced font, and the line breaks will be preserved:
@terminal{
The margin is 42em.
@ -410,7 +410,7 @@ The border is red.
The padding is 15em.
The border is too.}
As before, because the source has changed, Pollen refreshes the output file. From the dashboard, you can use the @racketfont{in} and @racketfont{out} links to inspect the source and output.
As before, because the source has changed, Pollen refreshes the output file. From the dashboard, you can use the @tt{in} and @tt{out} links to inspect the source and output.
This is now a valid HTML page.
@ -449,11 +449,11 @@ How to type a lozenge:
@itemlist[#:style 'ordered
@item{The core building block of Racket is the @italic{expression}. An expression can be a value (like @racket[2] or @racket{blue}), a variable (like @racketfont{edge}), or a function call (like @racket[(* inner 4)]).}
@item{The core building block of Racket is the @italic{expression}. An expression can be a value (like @racket[2] or @racket{blue}), a variable (like @tt{edge}), or a function call (like @racket[(* inner 4)]).}
@item{Every expression is @italic{evaluated} to produce a value.}
@item{A variable evaluates to whatever value it holds (so @racketfont{inner} would become @racket[2]). A function call evaluates to its return value (so @racket[(+ 1 1)] would become @racket[2]).}
@item{A variable evaluates to whatever value it holds (so @tt{inner} would become @racket[2]). A function call evaluates to its return value (so @racket[(+ 1 1)] would become @racket[2]).}
@item{Function calls go between parentheses. Unlike most languages, the function name comes @italic{first}, followed by its arguments (so it's @racket[(* inner 4)], not @racket[(inner * 4)]). This is called @italic{prefix notation}.}
@ -480,7 +480,7 @@ To learn more about Racket syntax, consider a detour through the excellent @othe
@subsection{Defining variables with commands}
Let's use commands to define variables that will hold some values for our page. First, add a @racketfont{<head>} tag to your source file, and three commmands to define three variables:
Let's use commands to define variables that will hold some values for our page. First, add a @tt{<head>} tag to your source file, and three commmands to define three variables:
@fileblock["/path/to/tutorial/poem.html.pp" @codeblock{
#lang pollen
@ -522,7 +522,7 @@ The border is too.
</body>
</html>}
What's with the blank lines? Don't panic — our @racketfont{◊(define ...)} commands define variables, so they don't evaluate to any value. Instead, we get blank lines. So far, so good.
What's with the blank lines? Don't panic — our @tt{◊(define ...)} commands define variables, so they don't evaluate to any value. Instead, we get blank lines. So far, so good.
@subsection{Inserting values from variables}
@ -548,7 +548,7 @@ The border is too.
</body>
</html>}]
Here, we're replacing three values in the poem with the variables containing those values — @racketfont{◊|edge|}, @racketfont{◊|color|}, and @racketfont{◊|inner|}. @link["http://localhost:8080/poem.html"]{Reload the file} in the project server, and you'll see:
Here, we're replacing three values in the poem with the variables containing those values — @tt{◊|edge|}, @tt{◊|color|}, and @tt{◊|inner|}. @link["http://localhost:8080/poem.html"]{Reload the file} in the project server, and you'll see:
@terminal{
The margin is 8em.
@ -558,13 +558,13 @@ The border is too.}
Hey, look at that — the text of the poem changed. Now it even rhymes.
If you like, in the source file, edit the variable definitions with different values and reload the page in the project server. The page will be rendered afresh with the new values. In particular, if you update @racketfont{inner}, you'll also see @racketfont{edge} change, since its value depends on @racketfont{inner}.
If you like, in the source file, edit the variable definitions with different values and reload the page in the project server. The page will be rendered afresh with the new values. In particular, if you update @tt{inner}, you'll also see @tt{edge} change, since its value depends on @tt{inner}.
@subsection{Inserting variables within CSS}
Our poem makes claims about the @racketfont{margin}, @racketfont{border}, and @racketfont{padding} of the page that aren't yet true. To fix this, we'll rely on the same basic technique of inserting variables into our HTML file. But instead of putting them in the @racketfont{<body>} of the page, we'll put them in a CSS @racketfont{<style>} tag.
Our poem makes claims about the @tt{margin}, @tt{border}, and @tt{padding} of the page that aren't yet true. To fix this, we'll rely on the same basic technique of inserting variables into our HTML file. But instead of putting them in the @tt{<body>} of the page, we'll put them in a CSS @tt{<style>} tag.
Update the @racketfont{<head>} section of the page with a new @racketfont{<style>} tag that defines a style for @racketfont{pre} like so, using our variables for the relevant values:
Update the @tt{<head>} section of the page with a new @tt{<style>} tag that defines a style for @tt{pre} like so, using our variables for the relevant values:
@fileblock["/path/to/tutorial/poem.html.pp"
@ -598,7 +598,7 @@ The border is too.
Notice that we're using the same @litchar{◊|}@italic{variable-name}@litchar{|} pattern as before to insert the variable values.
What do we expect to see? We expect that the @racketfont{padding} and @racketfont{border} will be 2em wide, because @racketfont{inner} is 2. We expect the @racketfont{margin} to be 8em, because it's equal to @racketfont{edge}, which is @racketfont{inner} multiplied by 4. And we expect the color of the border to be @racket["blue"], because that's the value of the variable @racketfont{color}.
What do we expect to see? We expect that the @tt{padding} and @tt{border} will be 2em wide, because @tt{inner} is 2. We expect the @tt{margin} to be 8em, because it's equal to @tt{edge}, which is @tt{inner} multiplied by 4. And we expect the color of the border to be @racket["blue"], because that's the value of the variable @tt{color}.
And indeed, when you @link["http://localhost:8080/poem.html"]{reload the file} in the project server, you'll see exactly that:

@ -72,7 +72,7 @@ My name is _Brennan_, and I enjoy:
You'll be able to see this file in the project server, but for now, it's just a static file. Pollen isn't doing anything to it.
Let's change that. Consistent with the usual preprocessor practice, we add @racketfont{#lang pollen} as the first line, and append the @racketfont{.pp} file extension, so our new preprocessor-ready file looks like this:
Let's change that. Consistent with the usual preprocessor practice, we add @tt{#lang pollen} as the first line, and append the @tt{.pp} file extension, so our new preprocessor-ready file looks like this:
@fileblock["brennan.md.pp"
@codeblock{
@ -85,7 +85,7 @@ My name is _Brennan_, and I enjoy:
+ 24 fish nuggets
}]
Go back to the project server and you'll see the new filename. When you click on it, Pollen will render a new @racketfont{markdown.md} file, but it will look the same as the one you had before.
Go back to the project server and you'll see the new filename. When you click on it, Pollen will render a new @tt{markdown.md} file, but it will look the same as the one you had before.
Now we'll change some of the values using Pollen commands:
@ -104,7 +104,7 @@ My name is _Brennan_, and I enjoy:
+ ◊nugget-quantity ◊nugget-type nuggets
}]
When you reload this file in the project server, @racketfont{brennan.md} will be regenerated, and will now look like this:
When you reload this file in the project server, @tt{brennan.md} will be regenerated, and will now look like this:
@terminal{
My name is _Brennan_, and I enjoy:
@ -156,7 +156,7 @@ However, this creates ambiguity between the name of the tag and the content. So
@terminal{(body (h1 "Hello world") (p class="first" "Nice to" (i "see") "you."))}
As for the @racketfont{class} attribute, we need to distinguish it from both the markup tags and the content, so we'll move it between double parentheses:
As for the @tt{class} attribute, we need to distinguish it from both the markup tags and the content, so we'll move it between double parentheses:
@terminal{(body (h1 "Hello world") (p ((class "first")) "Nice to" (i "see") "you."))}
@ -189,7 +189,7 @@ In Pollen's authoring modes, your source file is parsed into an X-expression, wh
Let's start putting together our article. For simplicity, I'm going to use unrealistically short sample texts. But you can use whatever Markdown content you want.
We want to use Markdown authoring mode to make a file that will ultimately be HTML. So consistent with Pollen file-naming conventions (see @secref["Saving___naming_your_source_file" #:doc '(lib "pollen/scribblings/pollen.scrbl")]), we'll start with our desired output filename, @racketfont{article.html}, and then append the Markdown authoring suffix, @racketfont{.pmd}. So in DrRacket, start a new file called @racketfont{article.html.pmd} and put some Markdown in it:
We want to use Markdown authoring mode to make a file that will ultimately be HTML. So consistent with Pollen file-naming conventions (see @secref["Saving___naming_your_source_file" #:doc '(lib "pollen/scribblings/pollen.scrbl")]), we'll start with our desired output filename, @tt{article.html}, and then append the Markdown authoring suffix, @tt{.pmd}. So in DrRacket, start a new file called @tt{article.html.pmd} and put some Markdown in it:
@fileblock["article.html.pmd"
@codeblock{
@ -215,9 +215,9 @@ From what you learned in the last section, it should be evident that this X-expr
@repl-output{<root><h1 id="my-article">Deep Thought</h1><p>I am @(linebreak)<strong>so</strong> happy to be writing this.</p></root>}
``But what's this @racketfont{root} tag? That's not HTML.'' An X-expression must have a root tag, so in the spirit of obviousness, every X-expression produced by a source file in authoring mode will start with @racketfont{root}. If you don't need it, you can discard it. But it also creates a useful hook for further processing, as we'll see later.
``But what's this @tt{root} tag? That's not HTML.'' An X-expression must have a root tag, so in the spirit of obviousness, every X-expression produced by a source file in authoring mode will start with @tt{root}. If you don't need it, you can discard it. But it also creates a useful hook for further processing, as we'll see later.
By the way, as review, let's remind ourselves how this is different from preprocessor mode. Let's take the same Markdown content, but this time put it into a preprocessor source file called @racketfont{article.md.pp}.
By the way, as review, let's remind ourselves how this is different from preprocessor mode. Let's take the same Markdown content, but this time put it into a preprocessor source file called @tt{article.md.pp}.
@fileblock["article.md.pp"
@codeblock{
@ -266,10 +266,10 @@ I am **so** happy to be writing this.
Last time, I had you run this file in DrRacket to see the X-expression it produced. This time, load it in the project server. You'll see something like this:
@terminal{
@bold{@larger{@larger{Deep Thought}}}
@browser{
@bold{@larger{Deep Thought}}
@larger{@smaller{I am @bold{so} happy to be writing this.}}
I am @bold{so} happy to be writing this.
}
Here, you're seeing the X-expression from your source combined with an HTML template, which adds the necessary boilerplate for the finished HTML:
@ -285,7 +285,7 @@ But wait — where did the template come from? When you view an authoring-mode s
But we can learn a few things from the fallback template about how to make an HTML template.
@subsection{The @racketfont{->html} function and the @racketfont{doc} variable}
@subsection{The @tt{->html} function and the @tt{doc} variable}
This is the fallback template that Pollen uses.
@ -315,22 +315,22 @@ But within a template, we need to explicitly convert from X-expression to HTML.
◊(->html (html (head (meta 'charset: "UTF-8")) (body)))
}
Third, we need to include the content from our source file. We do this by putting the variable @racketfont{doc} inside the @racketfont{body} tag.
Third, we need to include the content from our source file. We do this by putting the variable @tt{doc} inside the @tt{body} tag.
@codeblock[#:keep-lang-line? #f]{
#lang pollen
◊(->html (html (head (meta 'charset: "UTF-8")) (body doc)))
}
By convention, every Pollen source file makes its output available through the variable @racketfont{doc}. A source file in preprocessor mode puts its text result in @racketfont{doc}. And a source file in authoring mode puts its X-expression result in @racketfont{doc}.
By convention, every Pollen source file makes its output available through the variable @tt{doc}. A source file in preprocessor mode puts its text result in @tt{doc}. And a source file in authoring mode puts its X-expression result in @tt{doc}.
@margin-note{You can change the name to something other than @racketfont{doc} by changing @racket[world:main-pollen-export].}
@margin-note{You can change the name to something other than @tt{doc} by changing @racket[world:main-pollen-export].}
Under the hood, a template is just a partial program that relies on a set of variables defined by another source file (fancy name: @italic{lexical context}). So if you ran this template on its own, nothing would happen, because @racketfont{doc} isn't defined. But when you run it in the context of another source file, it picks up the @racketfont{doc} that's defined by that file.
Under the hood, a template is just a partial program that relies on a set of variables defined by another source file (fancy name: @italic{lexical context}). So if you ran this template on its own, nothing would happen, because @tt{doc} isn't defined. But when you run it in the context of another source file, it picks up the @tt{doc} that's defined by that file.
Caution — despite the name, a Pollen template is not necessarily a file of the type suggested by its extension. For instance, @racketfont{fallback.html} is a file that ultimately produces HTML, but it's not actually written in HTML.
Caution — despite the name, a Pollen template is not necessarily a file of the type suggested by its extension. For instance, @tt{fallback.html} is a file that ultimately produces HTML, but it's not actually written in HTML.
It could be, however. Here's an equivalent way of writing @racketfont{fallback.html} that inserts @racketfont{doc} into actual HTML, rather than making the whole thing an X-expression.
It could be, however. Here's an equivalent way of writing @tt{fallback.html} that inserts @tt{doc} into actual HTML, rather than making the whole thing an X-expression.
@codeblock[#:keep-lang-line? #f]{
#lang pollen
@ -338,20 +338,20 @@ It could be, however. Here's an equivalent way of writing @racketfont{fallback.h
<body>◊(->html doc)</body></html>
}
Notice that we still need to use the @racket[->html] function, but this time, instead of surrounding a larger X-expression, it just goes around @racketfont{doc}.
Notice that we still need to use the @racket[->html] function, but this time, instead of surrounding a larger X-expression, it just goes around @tt{doc}.
Truly, there is no difference between these two methods. Use whichever works best for you. I often prefer the second method because I like to build & test HTML layouts by hand using placeholder content to make sure all the fiddly bits work. Then it's easy to replace the placeholder content with @racket[(->html doc)], and it becomes a template.
@subsection{Making a custom template}
We'll use these three ingredients to make our own template for @racketfont{article.html.pmd}.
We'll use these three ingredients to make our own template for @tt{article.html.pmd}.
In general, template files can have any name you want. But by default, Pollen will first look for a file in your project directory called @racketfont{template.ext}, where @racketfont{ext} matches the output-file extension of the source file. So if your source file is @racketfont{database.xml.pmd}, Pollen will look for @racketfont{template.xml}. And for @racketfont{article.html.pmd}, Pollen will look for @racketfont{template.html}.
In general, template files can have any name you want. But by default, Pollen will first look for a file in your project directory called @tt{template.ext}, where @tt{ext} matches the output-file extension of the source file. So if your source file is @tt{database.xml.pmd}, Pollen will look for @tt{template.xml}. And for @tt{article.html.pmd}, Pollen will look for @tt{template.html}.
Therefore, to set up a custom template, all we need to do is create a file called @racketfont{template.html} in our project directory, and make sure it has the three key ingredients we saw in the fallback template. Pollen will automatically apply it to @racketfont{article.html.pmd} when we view it in the project server.
Therefore, to set up a custom template, all we need to do is create a file called @tt{template.html} in our project directory, and make sure it has the three key ingredients we saw in the fallback template. Pollen will automatically apply it to @tt{article.html.pmd} when we view it in the project server.
But don't take my word for it. In your project directory, create a new file called @racketfont{template.html}:
But don't take my word for it. In your project directory, create a new file called @tt{template.html}:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -363,9 +363,9 @@ But don't take my word for it. In your project directory, create a new file call
</html>
}]
Recall from the last section that this is the same as the fallback template, but written out in HTML, and with a @racketfont{title} element added. In fact, you can now refresh @racketfont{article.html} in the project server. Does it look different? No — it won't, because the resulting template is the same. You should notice, however, that the title of the browser window is now ``Custom template,'' because Pollen is relying on your new template file, rather than the fallback template.
Recall from the last section that this is the same as the fallback template, but written out in HTML, and with a @tt{title} element added. In fact, you can now refresh @tt{article.html} in the project server. Does it look different? No — it won't, because the resulting template is the same. You should notice, however, that the title of the browser window is now ``Custom template,'' because Pollen is relying on your new template file, rather than the fallback template.
Let's change our custom template by adding a @racketfont{style} block:
Let's change our custom template by adding a @tt{style} block:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -381,19 +381,19 @@ strong {color: red;}
<body>◊(->html doc)</body>
</html>}]
When you refresh @racketfont{article.html} in the project server, you'll see that the heading now has a gray background, and one word in the text is red.
When you refresh @tt{article.html} in the project server, you'll see that the heading now has a gray background, and one word in the text is red.
Feel free to add other settings to @racketfont{template.html}, or update the text in @racketfont{article.html}, and see how the page changes. As you'd expect, the project server keeps an eye on both your source files and your template files, and if one changes, it will refresh the output file automatically.
Feel free to add other settings to @tt{template.html}, or update the text in @tt{article.html}, and see how the page changes. As you'd expect, the project server keeps an eye on both your source files and your template files, and if one changes, it will refresh the output file automatically.
@subsection{Inserting specific source data into templates}
In the last example, we used @racketfont{doc} to insert the entire content of the source file — as an X-expression — into the template.
In the last example, we used @tt{doc} to insert the entire content of the source file — as an X-expression — into the template.
But what if you want to only insert part of your source file into the template? For instance, you'll look like a dork if the title on each page is ``Custom template.'' So let's fix that.
When you're working in a template, Pollen provides a @racket[select] function that lets you extract the content of a specific tag, like so: @racketfont{◊(select '@racketvarfont{tag-name} doc)}, which means ``get the content of @racketvarfont{tag-name} out of @racketfont{doc} and put it here.''
When you're working in a template, Pollen provides a @racket[select] function that lets you extract the content of a specific tag, like so: @tt{◊(select '@racketvarfont{tag-name} doc)}, which means ``get the content of @racketvarfont{tag-name} out of @tt{doc} and put it here.''
Let's suppose that we'd rather use the name of the article — @italic{Deep Thought} — as the page title. We're going to put a @racketfont{◊(select ...)} command inside the @racketfont{<title>} tag.
Let's suppose that we'd rather use the name of the article — @italic{Deep Thought} — as the page title. We're going to put a @tt{◊(select ...)} command inside the @tt{<title>} tag.
Beyond that, we just need to know the tag name that contains the title. If we have a little Markdown expertise, we might already know that this part of our Markdown source:
@ -404,14 +404,14 @@ Deep Thought
============
}
is going to produce a tag named @racketfont{h1}.
is going to produce a tag named @tt{h1}.
What if we don't have all the Markdown conversions memorized? No problem. We can still figure out the tag name by running the @racketfont{article.html.pmd} source file in DrRacket and looking at the X-expression that results:
What if we don't have all the Markdown conversions memorized? No problem. We can still figure out the tag name by running the @tt{article.html.pmd} source file in DrRacket and looking at the X-expression that results:
@repl-output{'(root (h1 ((id "my-article")) "Deep Thought") (p () "I am "
(strong () "so") " happy to be writing this."))}
Either way, now we know that the text @italic{Deep Thought} lives in the @racketfont{h1} tag. So we update our template accordingly (for brevity, I'm going to omit the @racketfont{style} tag in these examples, but it's fine to leave it in):
Either way, now we know that the text @italic{Deep Thought} lives in the @tt{h1} tag. So we update our template accordingly (for brevity, I'm going to omit the @tt{style} tag in these examples, but it's fine to leave it in):
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
@ -451,7 +451,7 @@ A couple notes on command syntax. We inserted the @racket[select] and @racket[->
This is exactly equivalent to the previous example. Skeptics are welcome to confirm this by checking the result in the project server.
Finally, notice that in the @racket[select] command, the tag name @racket['h1] is written with a quote mark, whereas @racketfont{doc} is not. This is an easy place to get tripped up, but the rule is simple: you don't use a quote mark when you're referring to the name of an existing function or variable (like @racket[select] or @racketfont{doc}). But you do need a quote mark when you're using the text as a literal value.
Finally, notice that in the @racket[select] command, the tag name @racket['h1] is written with a quote mark, whereas @tt{doc} is not. This is an easy place to get tripped up, but the rule is simple: you don't use a quote mark when you're referring to the name of an existing function or variable (like @racket[select] or @tt{doc}). But you do need a quote mark when you're using the text as a literal value.
@margin-note{Racket (and hence Pollen) makes a distinction between @secref["symbols" #:doc '(lib "scribblings/guide/guide.scrbl")] (e.g. @racket['h1]) and @secref["strings" #:doc '(lib "scribblings/reference/reference.scrbl")] (e.g. @racket["h1"]). Without getting into the weeds, just note for now that the tag of an X-expression is always a symbol, not a string. But if you write @racketfont*{◊(@racket[select] "h1" doc)}, the command will still work, because Pollen will treat it as @racketfont*{◊(@racket[select] 'h1 doc)}, consistent with a general policy of not being persnickety about input types when the intention is clear.}
@ -459,26 +459,28 @@ Finally, notice that in the @racket[select] command, the tag name @racket['h1] i
@subsection{Linking to an external CSS file}
If you're a super web hotshot, you probably don't put your CSS selectors in the @racketfont{<head>} tag. Instead, you link to an external CSS file. So it will not surprise you that in Pollen, you can do this by adding the usual @racketfont{<link>} tag to your HTML template, in this case a file called @racketfont{styles.css}:
If you're a super web hotshot, you probably don't put your CSS selectors in the @tt{<head>} tag. Instead, you link to an external CSS file. So it will not surprise you that in Pollen, you can do this by adding the usual @tt{<link>} tag to your HTML template, in this case a file called @tt{styles.css}:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<head>
<meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
</head>
<body>◊->html[doc]</body>
</html>
}]
Fans of hand-coded CSS, I trust you to take it from here: make your @racketfont{styles.css} file, and enjoy the results.
Fans of hand-coded CSS, I trust you to take it from here: make your @tt{styles.css} file, and enjoy the results.
But folks who paid attention during the @secref["first-tutorial"] might be wondering ``Can we link to a dynamically generated @racketfont{styles.css.pp} file?''
But folks who paid attention during the @secref["first-tutorial"] might be wondering ``Can we link to a dynamically generated @tt{styles.css.pp} file?''
Yes, of course. Here's the rule of thumb: when you're making links between files — whether CSS, or HTML, or anything else — Pollen doesn't care whether the file is static or dynamic. You just refer to it by its ultimate name, in this case @racketfont{styles.css}. If a static @racketfont{styles.css} file exists, Pollen will use that. If it doesn't, Pollen will look for a source file it can use to make @racketfont{styles.css}, and generate it on the spot. (You can also start with a static file, and change it to be dynamic later, and Pollen will do the right thing.)
Yes, of course. Here's the rule of thumb: when you're making links between files — whether CSS, or HTML, or anything else — Pollen doesn't care whether the file is static or dynamic. You just refer to it by its ultimate name, in this case @tt{styles.css}. If a static @tt{styles.css} file exists, Pollen will use that. If it doesn't, Pollen will look for a source file it can use to make @tt{styles.css}, and generate it on the spot. (You can also start with a static file, and change it to be dynamic later, and Pollen will do the right thing.)
So to use a dynamic CSS file, we don't need to make any changes to @racketfont{template.html}. We just need to add @racketfont{styles.css.pp} to the project directory:
So to use a dynamic CSS file, we don't need to make any changes to @tt{template.html}. We just need to add @tt{styles.css.pp} to the project directory:
@fileblock["styles.css.pp"
@codeblock{
@ -492,7 +494,7 @@ h1 {background: ◊|h1-color|; color: white;}
strong {color: ◊|strong-color|;}
}]
Now, when you refresh @racketfont{article.html} in the project server, Pollen will generate the @racketfont{styles.css} file it needs, and you'll see the new colors in the page. As before, if you update @racketfont{styles.css.pp}, Pollen will notice and regenerate the CSS file when you refresh the page.
Now, when you refresh @tt{article.html} in the project server, Pollen will generate the @tt{styles.css} file it needs, and you'll see the new colors in the page. As before, if you update @tt{styles.css.pp}, Pollen will notice and regenerate the CSS file when you refresh the page.
Can you add multiple dynamic style sheets? Yes.
@(linebreak)Can you mix dynamic and static style sheets? Yes.
@ -518,11 +520,11 @@ Pagetrees are used in various ways throughout Pollen. But the most obvious use f
@subsection{Using the automatic pagetree}
You've actually already been exposed to pagetrees (though I didn't tell you about it at the time). Recall that the dashboard of the project server is located at @racketfont{http://localhost:8080/index.ptree}. The list of files you see in the dashboard is a pagetree that Pollen creates by reading the files in the current directory and arranging them in alphabetical order.
You've actually already been exposed to pagetrees (though I didn't tell you about it at the time). Recall that the dashboard of the project server is located at @tt{http://localhost:8080/index.ptree}. The list of files you see in the dashboard is a pagetree that Pollen creates by reading the files in the current directory and arranging them in alphabetical order.
If the multiple pages in your project are already ordered by filename, then you can rely on this automatic pagetree.
From earlier in the tutorial, you have a Markdown source file called @racketfont{article.html.pmd} that looks like this:
From earlier in the tutorial, you have a Markdown source file called @tt{article.html.pmd} that looks like this:
@fileblock["article.html.pmd"
@codeblock{
@ -556,45 +558,47 @@ Carticle Title
The terrific third part.
}]
As before, you can fill these source files with any sample Markdown content you like. Moreover, you don't have to use the filenames @racketfont{barticle.html.pmd} and @racketfont{carticle.html.pmd} — the point is that the intended sequence needs to match the alphabetic sorting of the filenames.
As before, you can fill these source files with any sample Markdown content you like. Moreover, you don't have to use the filenames @tt{barticle.html.pmd} and @tt{carticle.html.pmd} — the point is that the intended sequence needs to match the alphabetic sorting of the filenames.
We'll reuse the @racketfont{template.html} and @racketfont{styles.css} files from earlier in the tutorial. Move or delete the other tutorial files so that your dashboard in the project server shows only these five files:
We'll reuse the @tt{template.html} and @tt{styles.css} files from earlier in the tutorial. Move or delete the other tutorial files so that your dashboard in the project server shows only these five files:
@itemlist[
@item{@racketfont{article.html.pmd}}
@item{@racketfont{barticle.html.pmd}}
@item{@racketfont{carticle.html.pmd}}
@item{@racketfont{styles.css} (or @racketfont{styles.css.pp})}
@item{@racketfont{template.html}}
@item{@tt{article.html.pmd}}
@item{@tt{barticle.html.pmd}}
@item{@tt{carticle.html.pmd}}
@item{@tt{styles.css} (or @tt{styles.css.pp})}
@item{@tt{template.html}}
]
If you click on any of the three Markdown sources, you will see it converted into HTML using @racketfont{template.html}, with styles appiled from @racketfont{styles.css}.
If you click on any of the three Markdown sources, you will see it converted into HTML using @tt{template.html}, with styles appiled from @tt{styles.css}.
The automatic pagetree for this project is exactly what you see in the dashboard: a list of the three article files, followed by @racketfont{styles.css} and @racketfont{template.html}.
The automatic pagetree for this project is exactly what you see in the dashboard: a list of the three article files, followed by @tt{styles.css} and @tt{template.html}.
@subsection{Adding navigation links to the template with @racketfont{here}}
@subsection{Adding navigation links to the template with @tt{here}}
Recall from earlier in the tutorial that the content of your source file is made available in the template through the special variable @racketfont{doc}. Likewise, the name of the current source file is made available through the special variable @racketfont{here}.
Recall from earlier in the tutorial that the content of your source file is made available in the template through the special variable @tt{doc}. Likewise, the name of the current source file is made available through the special variable @tt{here}.
To make any navigation link — up, down, sideways — the general idea is that we use @racketfont{here} as input to a pagetree-navigation function, which then looks up the answer in the current pagetree.
To make any navigation link — up, down, sideways — the general idea is that we use @tt{here} as input to a pagetree-navigation function, which then looks up the answer in the current pagetree.
First, let's just see @racketfont{here} on its own. Update your template as follows:
First, let's just see @tt{here} on its own. Update your template as follows:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<head>
<meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
</head>
<body>◊->html[doc]
The current page is called ◊|here|.
</body>
</html>
}]
If you refresh @racketfont{article.html}, you will now see the line ``The current page is called article.html.'' Switch to @racketfont{barticle.html}, and you'll see ``The current page is called barticle.html.'' Makes sense, right?
If you refresh @tt{article.html}, you will now see the line ``The current page is called article.html.'' Switch to @tt{barticle.html}, and you'll see ``The current page is called barticle.html.'' Makes sense, right?
Now let's use pagetree functions to show the names of the previous and next pages. Consistent with the usual policy of obviousness, these functions are called @racket[previous] and @racket[next]:
@ -602,9 +606,11 @@ Now let's use pagetree functions to show the names of the previous and next page
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<head>
<meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
</head>
<body>◊->html[doc]
The current page is called ◊|here|.
The previous is ◊|(previous here)|.
@ -613,7 +619,7 @@ The next is ◊|(next here)|.
</html>
}]
Refresh @racketfont{barticle.html}. You'll now see that ``The current page is called barticle.html. The previous is article.html. The next is carticle.html.'' So far, so good: we're correctly deriving the previous and next pages from the automatic pagetree.
Refresh @tt{barticle.html}. You'll now see that ``The current page is called barticle.html. The previous is article.html. The next is carticle.html.'' So far, so good: we're correctly deriving the previous and next pages from the automatic pagetree.
All that's left is to add hyperlinks, which is easy:
@ -621,9 +627,11 @@ All that's left is to add hyperlinks, which is easy:
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<head>
<meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
</head>
<body>◊->html[doc]
The current page is called ◊|here|.
The previous is <a href="◊|(previous here)|">◊|(previous here)|</a>.
@ -632,27 +640,29 @@ The next is <a href="◊|(next here)|">◊|(next here)|</a>.
</html>
}]
Refresh @racketfont{barticle.html}, and you'll see that the names of the previous and next pages are now hyperlinks to those pages. Click through and convince yourself that it works.
Refresh @tt{barticle.html}, and you'll see that the names of the previous and next pages are now hyperlinks to those pages. Click through and convince yourself that it works.
@margin-note{The documentation for pagetree @secref["Navigation" #:doc '(lib "pollen/scribblings/pollen.scrbl")] will tell you about the other functions available for generating navigation links.}
@subsection{Handling navigation boundaries with conditionals}
If you clicked through to @racketfont{article.html} or @racketfont{carticle.html}, you might've noticed a couple problems. Because @racketfont{article.html} is the first page in the automatic pagetree, it doesn't have any previous page it can link to. And the next-page link for @racketfont{carticle.html} is @racketfont{styles.css}, which is strictly correct — it is, in fact, the next file in the automatic pagetree — but it's not part of our article, so we'd rather stop the navigation there.
If you clicked through to @tt{article.html} or @tt{carticle.html}, you might've noticed a couple problems. Because @tt{article.html} is the first page in the automatic pagetree, it doesn't have any previous page it can link to. And the next-page link for @tt{carticle.html} is @tt{styles.css}, which is strictly correct — it is, in fact, the next file in the automatic pagetree — but it's not part of our article, so we'd rather stop the navigation there.
One way to fix the problem would be to have three separate template files — the standard one with both previous- and next-page links, one with only a next-page link, and one with only a previous-page link.
But since we have a whole programming language available in Pollen, that's a dull-witted way to solve the problem. The better way is to add @italic{conditionals} to the template to selectively change the navigation. That keeps things simple, because we'll still have only one @racketfont{template.html} to deal with.
But since we have a whole programming language available in Pollen, that's a dull-witted way to solve the problem. The better way is to add @italic{conditionals} to the template to selectively change the navigation. That keeps things simple, because we'll still have only one @tt{template.html} to deal with.
To handle @racketfont{article.html}, we want to hide the previous-page navigation link when there's no previous page. As it turns out, if the @racket[previous] function can't find a previous page, it will return false. So we just need to wrap our previous-page navigation in the @racket[when/block] command like so:
To handle @tt{article.html}, we want to hide the previous-page navigation link when there's no previous page. As it turns out, if the @racket[previous] function can't find a previous page, it will return false. So we just need to wrap our previous-page navigation in the @racket[when/block] command like so:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<head>
<meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
</head>
<body>◊->html[doc]
The current page is called ◊|here|.
◊when/block[(previous here)]{The previous is
@ -662,7 +672,7 @@ The next is <a href="◊|(next here)|">◊|(next here)|</a>.
</html>
}]
The basic structure of @racket[when/block] is @racketfont{◊when/block[@racketvarfont{condition}]{@racketvarfont{insert-this-text}}.} Note the square braces around the @racketvarfont{condition}, and the curly braces around the @racketvarfont{text}. Using @racket[(previous here)] as the condition is shorthand for ``when @racket{(previous here)} does not return false...''
The basic structure of @racket[when/block] is @tt{◊when/block[@racketvarfont{condition}]{@racketvarfont{insert-this-text}}.} Note the square braces around the @racketvarfont{condition}, and the curly braces around the @racketvarfont{text}. Using @racket[(previous here)] as the condition is shorthand for ``when @racket{(previous here)} does not return false...''
Programmers in the audience might be getting anxious about the repeated use of @racket[(previous here)] — you're welcome to store that value in a variable, and everything will work the same way:
@ -670,9 +680,11 @@ Programmers in the audience might be getting anxious about the repeated use of @
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<head>
<meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
</head>
<body>◊->html[doc]
The current page is called ◊|here|.
◊(define prev-page (previous here))
@ -685,15 +697,17 @@ The next is <a href="◊|(next here)|">◊|(next here)|</a>.
We need a different technique for handling the end of the next-page navigation, because we're not reaching the actual end of the pagetree. We're just reaching the end of the pages we care about navigating through.
What condition will help us detect this? Here, we can notice that the names of our article pages all contain the string @racketfont{article}. While you'd probably want a more robust condition for a real project, in this tutorial, what we'll do is hide the next-page navigation if the name of the next page doesn't contain ``@racketfont{article}''. As we did before, we wrap our navigation line in the @racket[when/block] function:
What condition will help us detect this? Here, we can notice that the names of our article pages all contain the string @tt{article}. While you'd probably want a more robust condition for a real project, in this tutorial, what we'll do is hide the next-page navigation if the name of the next page doesn't contain ``@tt{article}''. As we did before, we wrap our navigation line in the @racket[when/block] function:
@fileblock["template.html"
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<head>
<meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
</head>
<body>◊->html[doc]
The current page is called ◊|here|.
◊(define prev-page (previous here))
@ -707,15 +721,15 @@ The next is <a href="◊|(next here)|">◊|(next here)|</a>.}
This time, the condition is @racket[(regexp-match "article" (->string (next here)))]. How were you supposed to know this? You weren't. That's why this is a tutorial. Without going on a lengthy detour, the @racket[regexp-match] function returns true if the first string (in this case, @racket["article"]) is found inside the second string (in this case, we convert @racket[(next here)] to a string by wrapping it in @racket[->string]).
In any case, even if some of the programmy bits went over your head just now, relax and paste the code into your template. What you'll see when you refresh @racketfont{carticle.html} is that the next-page link is gone. So now our template lets us navigate among the pages of our article, and the conditionals handle the end pages correctly.
In any case, even if some of the programmy bits went over your head just now, relax and paste the code into your template. What you'll see when you refresh @tt{carticle.html} is that the next-page link is gone. So now our template lets us navigate among the pages of our article, and the conditionals handle the end pages correctly.
@subsection{Making a pagetree file}
I didn't want to dwell on programming complications in the last conditional. Why? The extra programming was necessary only because we made life somewhat difficult for ourselves by relying on the automatic pagetree. A better way to solve the problem is to avoid it altogether by making a pagetree file.
Pagetree source files have a different syntax and status than other Pollen source files, so they are parsed using their own Pollen dialect. To invoke this dialect, you just start the file with @racketfont{#lang pollen} and name the file with the @racketfont{ptree} extension, for instance @racketfont{my-project.ptree}. While you can have as many pagetrees in your project as you want, Pollen will accord primary status to the one named @racketfont{index.ptree}.
Pagetree source files have a different syntax and status than other Pollen source files, so they are parsed using their own Pollen dialect. To invoke this dialect, you just start the file with @tt{#lang pollen} and name the file with the @tt{ptree} extension, for instance @tt{my-project.ptree}. While you can have as many pagetrees in your project as you want, Pollen will accord primary status to the one named @tt{index.ptree}.
So let's make an @racketfont{index.ptree} file. At its simplest, a pagetree file can just be a list of files in the intended order. In DrRacket, create a new file in your project directory as follows:
So let's make an @tt{index.ptree} file. At its simplest, a pagetree file can just be a list of files in the intended order. In DrRacket, create a new file in your project directory as follows:
@fileblock["index.ptree"
@codeblock{
@ -743,13 +757,13 @@ article.html.pmd
barticle.html.pmd
}]
You also probably noticed that the files are in a different order than they were in the automatic pagetree: @racketfont{carticle.html} is first, followed by @racketfont{article.html} and then @racketfont{barticle.html}. This too is deliberate, so we can see what happens with a differently ordered pagetree.
You also probably noticed that the files are in a different order than they were in the automatic pagetree: @tt{carticle.html} is first, followed by @tt{article.html} and then @tt{barticle.html}. This too is deliberate, so we can see what happens with a differently ordered pagetree.
Pagetrees don't change nearly as often as other source files, so as a performance optimization, the project server does @italic{not} dynamically reflect changes to pagetrees. To see the effect of this new pagetree on our project, you'll need to go to your terminal window and stop the project server with ctrl+C, and then restart it. Which will take all of three seconds.
Now refresh @racketfont{carticle.html}. You'll notice that the navigation links are different. You won't see a previous-page link — because @racketfont{carticle.html} is now the first page in the pagetree — and the next page will show up as @racketfont{article.html}. Click through to @racketfont{article.html}, and you'll see the navigation likewise updated. Click through to @racketfont{barticle.html}, and you'll see ...
Now refresh @tt{carticle.html}. You'll notice that the navigation links are different. You won't see a previous-page link — because @tt{carticle.html} is now the first page in the pagetree — and the next page will show up as @tt{article.html}. Click through to @tt{article.html}, and you'll see the navigation likewise updated. Click through to @tt{barticle.html}, and you'll see ...
BAM! An error page with a yellow box that says @racketfont{Cant convert #f to string}. What happened? We switched to using our own pagetree file but we didn't update our template conditionals. Once you reach @racketfont{barticle.html}, the value of @racket[(next here)] is false, which means the @racket[(->string (next here))] command in the template conditional is trying to convert false into a string. Hence the error.
BAM! An error page with a yellow box that says @tt{Cant convert #f to string}. What happened? We switched to using our own pagetree file but we didn't update our template conditionals. Once you reach @tt{barticle.html}, the value of @racket[(next here)] is false, which means the @racket[(->string (next here))] command in the template conditional is trying to convert false into a string. Hence the error.
So let's go back and fix that. Because we don't have extraneous files in our pagetree anymore, we can change the second conditional in the template to work the same way as the first:
@ -757,9 +771,11 @@ BAM! An error page with a yellow box that says @racketfont{Cant convert #f to
@codeblock[#:keep-lang-line? #f]{
#lang pollen
<html>
<head><meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title></head>
<head>
<meta charset="UTF-8">
<title>◊select['h1 doc], by MB</title>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
</head>
<body>◊->html[doc]
The current page is called ◊|here|.
◊(define prev-page (previous here))
@ -772,13 +788,13 @@ The next is <a href="◊|next-page|">◊|next-page|</a>.}
</html>
}]
Refresh @racketfont{barticle.html} — because you're updating the template, you don't need to restart the project server — and you'll see the right result. The previous-page link goes to @racketfont{article.html}, and the next-page link is hidden.
Refresh @tt{barticle.html} — because you're updating the template, you don't need to restart the project server — and you'll see the right result. The previous-page link goes to @tt{article.html}, and the next-page link is hidden.
@subsection{@racketfont{index.ptree} & the project server}
@subsection{@tt{index.ptree} & the project server}
One more thing to show you before we wrap up this tutorial. Remember that the dashboard of the project server is at @racketfont{http://localhost:8080/index.ptree}? By default, the project server will synthesize a pagetree from an alphbetical directory listing.
One more thing to show you before we wrap up this tutorial. Remember that the dashboard of the project server is at @tt{http://localhost:8080/index.ptree}? By default, the project server will synthesize a pagetree from an alphbetical directory listing.
But if you put your own @racketfont{index.ptree} file in the directory, the project server will use that for the dashboard instead. In fact, visit @racketfont{http://localhost:8080/index.ptree} now and you'll see what I mean. Consistent with the @racketfont{index.ptree} you made, you'll now see @racketfont{carticle.html}, @racketfont{article.html}, and @racketfont{barticle.html}, but not @racketfont{template.html} nor @racketfont{styles.css} (even though they're still in the project directory).
But if you put your own @tt{index.ptree} file in the directory, the project server will use that for the dashboard instead. In fact, visit @tt{http://localhost:8080/index.ptree} now and you'll see what I mean. Consistent with the @tt{index.ptree} you made, you'll now see @tt{carticle.html}, @tt{article.html}, and @tt{barticle.html}, but not @tt{template.html} nor @tt{styles.css} (even though they're still in the project directory).
@section{Second tutorial complete}

Loading…
Cancel
Save