spiffy-utils

  1. spiffy-utils
    1. Description
    2. Author
    3. Requirements
    4. Documentation
    5. Variable helpers
      1. Example
    6. Pagination
      1. Parameters
      2. Tags
        1. Tags below 'entries'
      3. Procedures
    7. Shortcut rules
      1. Example
    8. Miscellaneous
    9. Changelog
    10. License

Description

Author

Peter Bex

Requirements

Documentation

Utility library for spiffy to make advanced webprogramming more comfortable. Features include:

Variable helpers

[procedure] (link-to url variable-alist)

Construct an URL string that links to url. and has an association list of variable/value pairs.

These pairs can be extracted from the request arguments using get-var. Both the name and the value objects of the alist are converted to strings using ->string.

[procedure] (get-var varname [string->type] [default])

Returns the value for the named variable from the GET argument list, or default if it could not be found. (#f if not specified). The returned value is a string which can optionally be converted to the desired type by supplying a string->type argument.

[procedure] (post-var varname [string->type] [default])

Same as get-var, but for http POST request variables instead.

[procedure] (cookie-var varname [string->type] [default])

Same as get-var, but for cookie variables instead. Cookies automatically get sent by the user agent on each request, both GET and POST, so they're always available.

[procedure] (string->bool b)

Convenience function to convert the string value b to a <boolean> value. (useful in combination with get-var, post-var and cookie-var).

[procedure] (string->boolean b)

An alias for string->bool.

[procedure] (string->number! n)

Just like string->number, but guaranteed to return a number. It defaults to 0 instead of #f.

[procedure] (write-cookie name value [comment] [max-age] [domain] [path] [secure])

Instruct Spiffy to write a cookie header in the current reply. Cookies are name / value pairs of strings (but any value is ok; ->string is automatically called on the two values). A cookie has an optional comment string for the user if he has a client which allows him to view the cookies. Cookies will expire when the session ends (usually when the browser closes) unless the max-age is supplied, which is an integer argument declaring the maximum time the cookie can be stored on the client side, in seconds. The domain string specifies for which domain the cookie is. The cookie will only be returned on subsequent requests to that domain. By default, the domain is the domain from which the cookie originates. The path string specifies the topmost path from which this cookie is active.

If there are multiple cookies with the same name, the value from the cookie with the least generic ("deepest") path will be passed to the server. Finally, the boolean secure can be set to #t if the cookie should be treated as confidential information. If the user wishes to set one parameter, but not any other optional parameters, the value #f can be used. These parameters will be ignored.

[procedure] (delete-cookie name [domain] [path])

Instruct Spiffy to write a cookie header constructed in such a way that the cookie with the supplied name (also converted to a string with ->string) will be deleted. The two optional parameters behave as with write-cookie. (See above).

Example

;; A simple webpage which allows you to play with three different
;; types of variables, which are submitted to the page itself via HTTP GET.
(use spiffy-utils sxml-transforms srfi-1 regex doctype)
(define vars `((integer . ,(get-var 'integer string->number 0))
	       (boolean . ,(get-var 'boolean string->bool))
	       (string . ,(get-var 'string identity ""))))

(define (addfoo var)
  (string-append var "foo "))

(define (delfoo var)
  (string-substitute "foo " "" var))

(define (alist-replace var func)
  (alist-cons var (func (alist-ref var vars))
	      (alist-delete var vars)))

(define my-conversion-rules
  `((doctype . ,(lambda (doctype) doctype:xhtml-1.0-strict))
    ,@universal-conversion-rules))

(define document
 `((doctype)
   (html
    (head
     (title "GET-var and typing showcase"))
    (body
     (dl
      (dt "Integer:")
      (dd (url ,(link-to "test.ssp" (alist-replace 'integer sub1)) "sub1")
	  " " ,(alist-ref 'integer vars) " "
	  (url ,(link-to "test.ssp" (alist-replace 'integer add1)) "add1"))
      (dt "Boolean:")
      (dd ,(->string (alist-ref 'boolean vars)) " "
	  (url ,(link-to "test.ssp" (alist-replace 'boolean not)) "Toggle"))
      (dt "String:")
      (dd (url ,(link-to "test.ssp" (alist-replace 'string delfoo)) "Delete foo")
	  " " ,(alist-ref 'string vars)
	  (url ,(link-to "test.ssp" (alist-replace 'string addfoo)) "Add foo")))))))

(output-html document shortcut-rules my-conversion-rules)

Pagination

Pagination can performed by a combination of parameters, functions and sxml tag-rules. The collection of these rules is available as pagination-rules. Using these rules requires threading the result through shortcut-rules or rules with similar names and arity. When trying to get a big picture of how these work together, take a look at the examples listed at the end of this document.

Parameters

These parameters can be utilised to get multiple pages on one HTML page (by calling pre-post-order more than once) or getting different defaults.

[parameter] (page-size [number])

The size of a page/the number of entries on a page. Defaults to: 20

[parameter] (page-var [symbol])

The GET variable to use for this page. Defaults to: 'page

Tags

  Tag: (paginate-list sxml-code list)
  

By far the easiest pagination tag to use. This just paginates all entries in the list using the sxml-code as template. See also entries. The example should be clarifying.

  Tag: (paginate sxml-code entries entries-length)

Basic pagination. This automates only the templating, it requires you to pass it only the entries on the current page and the total number of entries on all pages. See also entries. This tag is especially useful if generating every entry on every call is too expensive (ie, grabbing entries from a database). Use the functions first-entry and last-entry to get the current entries to use.

  Tag: (entries sxml-code)

This tag delimits the part of the template that is to be repeated for every entry that is displayed on the page.

Tags below 'entries'

These tags are available only as descendents of an entries tag.

  Tag: (pagination-links)

Shows links to the first, previous, next, last and all page numbers in between.

  Tag: (current-page)

The number of the page that's currently being viewed. See also the function current-page.

  Tag: (first-entry)

The first entry on the page that's currently being viewed. See also the function first-entry.

  Tag: (last-entry)

The last entry on the page that's currently being viewed. See also the function last-entry.

  Tag: (page-count)

The total number of pages required to fit all the entries on. See also the function page-count.

Procedures

All these procedures assume the parameters listed above are correctly set (ie, match the value when calling pre-post-order on the tags.

[procedure] (current-page num-entries)

Returns the number of the page currently being viewed. The total number of entries on all pages is required.

[procedure] (page-count num-entries)

Returns the total number of pages. The total number of entries on all pages is required.

[procedure] (first-entry num-entries)

Returns the position of the first entry on the page currently being viewed.

[procedure] (last-entry num-entries)

Returns the position of the last entry on the page currently being viewed.

Shortcut rules

[constant] shortcut-rules

These are some convenience functions that simplify common tags, described below.

  Tag: (url href . code)

Short for `(a (@ (href ,href)) ,code...).

  Tag: (pic src alt [title] . rest)

Short for `(img (@ (src ,src) (alt ,alt) (title ,title) ,@rest)).

If title is not provided, it is equal to alt.

  Tag: (movie src title . rest)

Short for:

`(object (@ (type "video/quicktime"))
   (param (@ (name "src") (value ,src)))
   (param (@ (name "controller") (value "true")))
   ,@rest
   (url ,src ,title))

That is, it shows the movie pointed to by src embedded in the browser. If the browser does not support it, an url with the description title is provided.

Example

;; A quick example of how to use pagination-rules
(use spiffy-utils sxml-transforms doctype srfi-1)

(define my-conversion-rules
  `((doctype . ,(lambda (doctype) doctype:xhtml-1.0-strict))
    ,@universal-conversion-rules))

(define content
  `((doctype)
    (html
     (head
      (title "Showing page" ,(current-page 109) " of " ,(page-count 109)))
     (body
      (paginate-list
       (div (@ (class "paginated-stuff"))
	    (p "Click on a number to flip to the corresponding page:")
	    (pagination-links)
	    (p "Below we see something that is shown only once per page "
	       "(the UL), which has subentries that are shown many times "
	       "per page, ie the entries on the page (the LIs):")
	    (ul
	     (entries
	      (li (entry))))
	    (p "As we can see, every part of the page that has to be "
	       "for every entry is enclosed by the (entries) 'tag'."
	       "We can also show the same entries twice or more:")
	    (ol
	     (entries
	      (li (entry))))
	    (p "Showing entry" (first-entry) " through " (last-entry) " on "
	       "page " (current-page) " of " (page-count) "."))
       ,(iota 109))
      (p "We are showing entry " ,(first-entry 109) " through "
	 ,(last-entry 109) ".")
      (p "Note that it is necessary to pass the total number of entries "
	 "to every pagination function, but not the actual tags within "
	 "(pagination).  This is because the paginator has no way of "
	 "determining this outside of the (paginate-list) 'tag'.")))))

(output-html content pagination-rules shortcut-rules my-conversion-rules)

Miscellaneous

[procedure] (sxml-apply-rules content rule1 rule2 ...)

Calls pre-post-order on content sequentially using the given rulesets. Ie, it calls pre-post-order on the the first ruleset, then calls pre-post-orderon the result of that with the second ruleset etc.

[procedure] (output-html content rule1 rule2 ...)

Simple convenience function which calls SRV:send-reply on the result of (sxml-apply-rules content rule1 rule2 ...).

Changelog

License

 Copyright (c) 2004-2006, Peter Bex
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
 met:
 
 Redistributions of source code must retain the above copyright
 notice, this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright
 notice, this list of conditions and the following disclaimer in the
 documentation and/or other materials provided with the distribution.
 
 Neither the name of the author nor the names of its contributors may
 be used to endorse or promote products derived from this software
 without specific prior written permission.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 OF THE POSSIBILITY OF SUCH DAMAGE.