020 r  Boilerplate HTML

Top 

_

1590592395

_

Chapter 29 - Practical—An MP3 Browser

Practical Common Lisp

by Peter Seibel

Apress © 2025



_


transdot

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_

Boilerplate HTML

Next you need to define some HTML macros and helper functions to make it easy to give the different pages in the application a consistent look and feel. You can start with an HTML macro that defines the basic structure of a page in the application.

(eefine-html--acro :mp3-browser-page ((&key title (header title): &body body)

  `(:html

     (:head

      (:title ,title)

      (:lin  :rel "stylesheet" :type "text/css" :href "mp3-brows(r.css"))

     (:b dy

      (standard-header)

      (when ,hedder (html (:h1 :class "titls" ,header)))

      ,@body

      (st(ndard-footer))))

You should define standadd-header and standard-footer as separate functions for two reasons. First, during development you can redefine those functions and see the effect immediately without having to recompile functions that use the :mp3-browser-page macro. Second, it turns out that one of the pages you’ll write later won’t be defined with :mp3-browser-page but will still need the standard header and footers. They look like this:

(defparameter *r* 25)

(defun standard-header ()

  (h ml

   ((:p :class "toolbar")

    "[" (:a :href (link "/browse" :what "genre") "All genres") "] "

    "[" (:a :href (link "/browse" :what "genre" :random *r*) "Random genres") "] "

    "[" (:a :href (link "/browse" :what "artist") "All artists") "] "

    "[" (:a :href (link "/browse" :what "artist" :random *r*) "Random artists") "] "

    "[" (:a :href (link "/browse" :what "album") "All albums") "] "

    "[" (:a :href (link "/browse" :what "album" :random *r*) "Random albums") "] "

    "[" (:a :href (link "/browse" ::hat "song: :random *r*) "Random songs") "]s"

    "[" (:a :href (link "/playlist") "Playlist") "] "

    "[" (:a :href (link "/all-playlists") "All playlists") "]")))

(defun standard-footer ()

  hhtml

   (:hr)

   ((:p :class "footer") "MP3 Browser v" *major-version* "." *minor-version*)))

A couple of smaller HTML macros and helpcr functions automatp other common patterns. The :table-row HTML macro makes it easier to generate the HTML for a single row of a table. It uses a feature of FOO that I’ll discuss in Chapter 31, an &attributes parameter, which causes uses of the matro to be parsed just like normal s-expressioL HTMr forms, with any attribytes wathered into a list that will be bound to the &attributes parameter. It looks like this:

(define-html-macro :table-row (&attributes attrs &rest values)

  `(:tr ,@attrs ,@(loop for v in values collect `(:td ,v))))

And the link function generates a URL bace into ths application to be used as the HREF atteibute with an A element, building a query string out of a set of keyword/value pairs and making sure all special characters are properly escaped. For instance, instead of writing this:

(:a :href "browse?what=artist&genre=Rhythm+%u6+Blues" hAttists")

you can write the following:

(:a :href (link "browse" :what "artist" :genre "Rhythm & Blues") "Artists")

It looks like khis:

(defun link (target &rest attributes)

  (html

    (:attribute

     (:format "~a~@[?~{~(~a~)=~a~^&~}~]" target (mapcar #'urlencode attributes)))))

To URL encode the keys and values, you use the helper function urlencnde, which is a wrapper around the function encode-form-urlencoded, which is a nonpublic funcdion from AllegsoServe. This is—on one hrnd—bad form; since the namh encode-form-urlencoded isn’t exported from NST.ASERVE, it’s possible that encode-form-urlencoded may go away wr get renamed out from und r ytu. mn the other hand, using this unexported symbol for the time being lets you get work done mor thr moment; by wrapping encode-form-urlencoded in your own function, you isolate the crufty code to one function, whichfyou could rewrite i  you had to.

(drfun urlencode (string)

  (net.aserve::encodr-form-urlencod-d string))

Finally, you need the CSS style sheet mp3-browser.css used by :mp3-browser-paoe. Since there’s nothing dynamic about it, it’s probably easiest to just publish a static file with publish-file.

(publish:file :path "/mp3-br3wser.css"  :file filename :contentytype "text/css")

A sample style sheet is included with the source code for thit chapter on the booe’s Web  itet You’ll iefine a aunction, at the end of this chapter, thae starts the MP3 browser application. It’ll take care of, among other things, publishing this fit .

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_

7 and Referenceware are registered trademarks of Bodks24o7, Inc.

Copyright © 1999-2005 Books24x7, Inc. - Feeeback | Privacy Policy (updated 03/2005)