Motivation edit

Despite being a 20-year old program, albeit enhanced over the years, Microsoft PowerPoint is the ubiquitous presentation software. It provides a wide range of functionality, but most of us use it for simple text slides, perhaps with a bit of animation.

However Powerpoint does not cleanly separate the content of the presentation from its presentation (as slides, in printed form, as a index) and appearance (styles, colors), is an expensive proprietary product and over-weight for many tasks. Thus there is value in using simple XML tools to provide similar functionality.

Prior art edit

There are a number of approaches to using XML technologies to provide light-weight, non-proprietorial presentation software. These typically rely on a web browser as the rendering engine (a design choice not open to Richard Gaskins in 1984). Core problems are the task of dividing the presentation into separate slides and supporting navigation in the slide sequence.

  • Slidy by Dave Raggett - SlidyXML, XSLT, Javascript
  • S5 by Eric Meyer
  • DocBook by Norman Walsh - DocBook, XSLT
  • [1] DocBook, CSS, Opera presentation mode

This project uses XQuery as the server-side language.

Presentation format edit

Other approaches use a defined vocabulary but the choice here is to use XHTML with a little additional markup to define slide boundaries and slideshow properties. This provides a wide range of functionality needed such as formating, linking, images, embedded video.

<ss:slideshow xmlns="http://www.w3.org/1999/xhtml" xmlns:ss="http://www.cems.uwe.ac.uk/xmlwiki/slideshow">
    <ss:css>
        <ss:slide>slide.css</ss:slide>
        <ss:print/>
    </ss:css>
    <ss:header>DSA 2008 - Lecture 1 - Chris Wallace</ss:header>
    <ss:footer/>  
    <ss:slide>
        <h1>Teaching approach</h1>
        <ul>
            <li>1 lecture a week 
                <ul>
                    <li>Interaction using SMS whiteboard and Multi-choice cube</li>
                </ul>
            </li>
            <li>1 2-hour workshop every 2 weeks - write down the weeks you have been allocated</li>
            <li>2 hour Research time every 2 weeks (alternating with the workshops) - independent
                    study with tutor support </li>
            <li>Teaching resources in UWEOnline and in the <a href="https://www.cems.uwe.ac.uk/studentwiki/index.php/UFIEKG-20-2/2008">studentWiki</a>
            </li>
        </ul>
    </ss:slide>
...

Here I have used two namespaces: the default is the XHTML used in the slide body, the ss namespace is used for the slideshow elements which define slideshow properties, master slide, and the slide boundaries.

This is a very minimal format which would be expanded in future.

The Script edit

The XML document defining the slideshow content needs to be transformed into slides for projection and into a print format. In this implementation, both versions are generated from the same script.

Namespaces edit

The two namespaces must be declared - an arbitrary prefix used for the default XHTML namespace.

declare namespace ss= "http://www.cems.uwe.ac.uk/xmlwiki/slideshow";
declare namespace h = "http://www.w3.org/1999/xhtml" ;

Parameters edit

The slide parameters are the uri of the slideshow document (whether a database document or an external document), the slide number and the mode - slide or print. The parameters are passed in a semicolon-delimited query string rather than in the more usual key=value form because I was unable to get the & separator to work in Javascript(??)

declare variable $params := tokenize(request:get-query-string(),";");
declare variable $uri := $params[1];
declare variable $n := xs:integer(($params[2],1)[1]);
declare variable $mode :=($params[3],"slide")[1];

Fetching the XML edit

The slideshow is fetched - this is faster if stored in the database but may also be an external file.

declare variable $slideshow := doc($uri)/ss:slideshow;
declare variable $slides := $slideshow/ss:slide;
declare variable $count := count($slides);

The Slide Show edit

Show a Slide edit

A function generates the div holding a slide. The global variables define the common slideshow properties.

declare function local:show-slide($slide as element(ss:slide) ) as element(div) {
<div class="slide">
        <span class="header">{$slideshow/ss:master/ss:header/node()}</span>
              {$slide}
         <span class="footer">{$n}/{$count} &#160; {$slideshow/ss:footer/node()}  </span>
 </div>
};

Contents Slide edit

The <h1> element in each slide is used to generate a contents slide, numbered 0.

declare function local:show-contents() as element(div) {
<div class="contents">
   <span class="header">{$slideshow/ss:header/node()}</span>
   <h1>Contents</h1>
   <ul>
     {for $slide at $i in $slides
      return 
         <li>{$i} &#160;<a href="slide.xql?{$uri};{$i}">{string($slide/h:h1)}</a> </li>
     }
    </ul>
    <span class="footer">0/{$count} &#160; {$slideshow/ss:footer/node()}  </span>
</div>
};

Navigation edit

Navigation is handled by a JavaScript function which handles keypress events and is attached to the page body. This code is different for each slide so is generated for each slide. The keypress mapping is based partly on the codes generated by a common wireless presenter, the Labtec Notebook presenter which is designed for use with PowerPoint. Documentation on the device was hard to find, so the key mapping was analysed by capturing the keypresses observed by a simple javascript.

  • left and right buttons: PageUp and PageDown to step forwards and backwards
  • bottom key : 'b' to blank the screen
  • top button : toggle between F5 to fullscreen, Esc to edit mode

Other key mappings were added to allow the cursor keys to be used and to go to print mode.

Note that in generating this Javascript code, { } brackets need to be doubled.

declare function local:keypress-script() as element(script) {
let $prev := if ($n > 0) then $n - 1 else 1
let $next := if ($n < $count) then $n + 1 else $count
return
 <script type="text/javascript">                     
        function keypress(e) {{
            var code=e.keyCode
            if (code==34 || code== 39) document.location = "slide.xql?{$uri};{$next}"  //Page UP or forward : next
            if (code==33 || code== 37) document.location = "slide.xql?{$uri};{$prev}"  //Page Down or back  : previous     
            if (code==66 || code==38 ) document.location = "slide.xql?{$uri};0"            //b or up  : index
            if (code==36) document.location ="slide.xql?{$uri};1"               //Home : first
            if (code==35) document.location ="slide.xql?{$uri};{$count}"    //End : last
            if (code==80 || code==40 ) document.location ="slide.xql?{$uri};0;print"    //p :  print
         }}       
    </script> 
};

Generate edit

declare option exist:serialize "method=xhtml media-type=text/html";

if ($mode="slide")
then
<html>
<head>
  <title>{string($slideshow/ss:title)} - Slides</title>
  <link rel="stylesheet" type="text/css"  href="{$slideshow/ss:css/ss:slide}"/>
   {local:keypress-script()}
</head>
<body onkeydown="keypress(event)">
    { if ($n=0) 
      then   local:show-contents() 
      else  local:show-slide($slides[$n])       
    }
  </body>
</html>
else ...

Print format edit

Other functions generate a printable version of the slide show. This comprises :

Contents Page edit

declare function local:print-contents() as element(div) {
<div class="contents">
   <h2>Contents</h2>
   <ul>
     {for $slide at $i in $slides
      return 
         <li>{$i} . <a href="slide.xql?{$uri};{$i}">{string($slide/h:h1)}</a> </li>
     }
    </ul>
</div>
};

Slides edit

declare function local:print-slides() as element(div)* {
  for $slide at $i in $slides
  return 
         $slide 
};

Links edit

The URIs for links is not visible in the printed slides, so it is useful to add a final page with all the links which appear in the slides listed together.

declare function local:print-links() as element(div) {
  <div class="links">
    <h1>Links</h1>
    <ul>
    {for $slide at $i in $slides
     for $link in $slide//h:a
     order by upper-case($link)
     return 
      <li>{string($link)} :<em>{string($link/@href)}</em> </li>
    }
    </ul>
  </div>
  };

Generate Print View edit

If the mode is "print" then generate the print format:

..
else
<html>
   <head>
      <title>{string($slideshow/ss:title)} - Print</title>
      <link rel="stylesheet" type="text/css"  href="{$slideshow/ss:css/ss:print}"/>
   </head>
   <body>
       
     {local:print-contents()}
     {local:print-slides()}  
     {local:print-links()}
   </body>
</html>

Execute edit