meyerweb.com

Skip to: site navigation/presentation
Skip to: Thoughts From Eric

Slide Show Beta 2

Thanks to the help of several contributors, the simple standards-based slide show system I put into public beta status, and which I may well end up calling S5, is almost ready to go final.  At its core, it seems to work consistently in Internet Explorer (both platforms), Firefox 0.9, and Safari 1.2.  I’ve also scripted things so that the system works in Opera 6 and up, basically allowing those browsers to fall back to using Opera Show.  This allows the slide show’s behavior to be consistent with what Opera Show users already expect, which seems like a good thing.

There are two things that don’t work as I’d hoped.  The first is the “click anywhere to advance a slide” feature, which is broken in IE/Win.  It throws a JavaScript error about the target that doesn’t make sense to me.  The second is the show/hide of the menu in IE/Mac, which I just cannot get to work.  If anyone can figure out how to make those work, let us know in the comments; otherwise I’ll just prevent IE from running that code in the final version, which will of course mean a reduced feature set in those browsers.  I’m not going to lose a lot of sleep if that happens, but I’d rather have the system be feature-consistent across browsers if possible.

(Update: if you downloaded the archive between 1421 EDT and 1504EDT, grab it again.  I initially forgot to update it with the new files.  Sorry!  It’s fixed now.)

74 Responses»

    • #1
    • Pingback
    • Sun 3 Oct 2004
    • 2244
    Received from solitude.dk | OperaShow Manager

    […] started when Eric Meyer started to create a cross-browser Slide Show. the comments in his second post has the creator of the OperaShow Format participating. With a […]

    • #2
    • Pingback
    • Wed 6 Oct 2004
    • 2330
    Received from snapping links » mostly work

    […] web dev – general haven’t finished reading home and garden projects to try Eric Meyer’s slide show intranet trends to watch for MS ce […]

    • #3
    • Comment
    • Sat 2 Oct 2004
    • 1522
    Henryk Pl wrote in to say...

    Moin,

    Your IE problem is due to the idiotic way IE is handling event handlers. Instead of passing the event object as an parameter to the handler it is something like a global variable.

    Inserting the following line as the first line of your clicker() function should fix it:
    if(window.event) e = window.event;

    Well, maybe you need to work around other differences in the IE event model. I currently do not have an IE to test with.


    Henryk Pl

    • #4
    • Comment
    • Sat 2 Oct 2004
    • 1540
    Eric wrote in to say...

    Henryk: I tried that but it didn’t seem to help. The error I get, either with or without the line you suggested, is:

    ‘target.href’ is null or not an object

    • #5
    • Comment
    • Sat 2 Oct 2004
    • 1545
    christian wrote in to say...

    i have reworked a bit your code, so that it does work in the same way in opera, firefox and ie. ( page up and down for next and back, up and down arrow to open the quick-jumper window, left to jump, right to close). perhaps you can use something from it.

    you can check it out here

    • #6
    • Comment
    • Sat 2 Oct 2004
    • 1546
    Arjan wrote in to say...

    function clicker(e) {
    if (window.event.srcElement != “[object]”) return true;
    go(1);
    }

    This function seems to do the trick in IE, but breaks the slide down in firefox, but that is easy to overcome I guess..

    • #7
    • Comment
    • Sat 2 Oct 2004
    • 1556
    Eric wrote in to say...

    Arjan: thanks for the code, but having it break other browsers isn’t acceptable. Unfortunately, I’m not skilled with JavaScript, so overcoming the breakage in non-IE browsers is not easy for me; I tried and wasn’t successful. But at least this proves it can be done in IE/Win!

    • #8
    • Comment
    • Sat 2 Oct 2004
    • 1559
    Arjan wrote in to say...

    Well, you can just add another if () statement..

    This is all it takes:

    function clicker(e) {
    if (isIE) {
    if (window.event.srcElement != “[object]”) return true;
    go(1);
    }
    else {
    if (e.target.href != null || isParentOrSelf(e.target, ‘controls’)) return true;
    if (e.which == 1) go(1);
    }
    }

    • #9
    • Comment
    • Sat 2 Oct 2004
    • 1602
    Henryk Pl wrote in to say...

    Moin,

    Uh, you’re right, Eric. There are more differences that I forgot about. The first, as Arjan mentioned, is that ‘target’ is called ‘srcElement’ in IE-speak. The second is that there is no ‘which’ in the event object. (Well, there is a ‘button’ but that only applies to mouse{down,up,move} events.)

    So, the following does the trick for me:
    function clicker(e) {
    var target;
    if(window.event) {
    target = window.event.srcElement;
    e = window.event;
    } else {
    target = e.target;
    }
    if (target.href || isParentOrSelf(target, "controls")) return true;
    if (!e.which || e.which == 1) go(1);
    }

    See the Microsoft DHTML reference on event for more information.


    Henryk Pl

    • #10
    • Comment
    • Sat 2 Oct 2004
    • 1609
    Arjan wrote in to say...

    A couple of other (little) things:

    1. de accesskeys x / z doesn’t seem te work in IE
    2. If you press “return” when de “next” or “previous” button is selected, the slide show slides twice (try to pronounce that 10 times in a row)

    • #11
    • Comment
    • Sat 2 Oct 2004
    • 1612
    Eric wrote in to say...

    That’s got it, Henryk, and it seems to play better with the whole “don’t pay attention to clicker() if the click happens in the controls area”, so it’s in the code now.

    Now all we need is a fix for the navigation menu show/hide problem in IE/Mac, and I think we’ll be all set.

    • #12
    • Comment
    • Sat 2 Oct 2004
    • 1615
    Gabriel Mihalache wrote in to say...

    Give me Safari or give me… uh… Firefox! :-)
    Now, seriously, Safari is important.

    • #13
    • Comment
    • Sat 2 Oct 2004
    • 1635
    Henryk Pl wrote in to say...

    Moin,

    A fix for problem 2 of comment 8: Insert the following two lines in keys() between the line “case 32:” and the line “case 39:” (Yes, that’s bad coding style):
    if(window.event && isParentOrSelf(window.event.srcElement, "controls")) return;
    if(key.target && isParentOrSelf(key.target, "controls")) return;

    That will disable the return, enter and spacebar keys for elements in the control area.


    Henryk Pl

    • #14
    • Comment
    • Sat 2 Oct 2004
    • 1648
    Arjan wrote in to say...

    Why disable the space bar? Now the spacebar doesn’t do anything when pressed and a button is selected..

    Put the code above one line higher, and it works perfectly :)

    • #15
    • Comment
    • Sat 2 Oct 2004
    • 1651
    Henryk Pl wrote in to say...

    Moin,

    Ok ok, you’re right. Somehow I believed the space bar would trigger the link, too. It doesn’t, so put it a line above.


    Henryk Pl

    • #16
    • Comment
    • Sat 2 Oct 2004
    • 1700
    Eric wrote in to say...

    Out of curiosity, what would be good coding style in this circumstance? I’d rather use good style than bad. (Of course!)

    • #17
    • Comment
    • Sat 2 Oct 2004
    • 1724
    K Scott wrote in to say...

    Bug report that I haven’t seen any one else mention so far: when the style is toggled off, clicking anywhere still executes the advance slide code, resulting in strange behaviour.

    The toggle() call should disable that (by setting a flag or something that can be checked?).

    If the user tells the browser to disable styles some other way, the problem will still remain, though, and I don’t know of any way in javascript to test for what stylesheet the browser is using. I could be wrong, though; might that be in the DOM?

    • #18
    • Comment
    • Sat 2 Oct 2004
    • 1737
    Henryk Pl wrote in to say...

    Moin,

    That’s the way I would write it and I find it pretty elegant. However, I’m aware that a lot of people don’t like having code executed and then fall through more cases. I guess these people would prefer something like
    switch(...) {
        case 10: /* fall-through */
        case 13: if(! (... || ...)) go(1);
                 break;
        case 32: /* fall-through */
        case 39: /* fall-through */
        case 40: go(1);
                 break;
        case 37: /* fall-through */
        case 38: go(-1);
                 break;
    ....
    }


    Henryk Pl

    • #19
    • Comment
    • Sat 2 Oct 2004
    • 1747
    Olivier wrote in to say...

    In addition to K Scott’s comment, when style is toggled off, scrolling with the arrow keys exhibits the same strange behaviour that the different sections are hidden one after the other until only one if left.

    Anyway, I love it.

    • #20
    • Comment
    • Sat 2 Oct 2004
    • 1753
    Henryk Pl wrote in to say...

    Moin,

    Ok, insert the following line as the first line in go():
    if(document.getElementById && document.getElementById("slideProj").disabled) return;

    That disables go() when the projection style is disabled, either by toggle() or the browser. At least it works for me in Gecko and IE.


    Henryk Pl

    • #21
    • Comment
    • Sat 2 Oct 2004
    • 1956
    Bruce D'Arcus wrote in to say...

    This is nice! What would really be a cool is an XSLT to convert Apple Keynote presentations to this format.

    • #22
    • Comment
    • Sat 2 Oct 2004
    • 2138
    Jos wrote in to say...

    In the fragment of code

    var newopt = document.createElement(‘option’);
    var opttext = document.createTextNode(n+’ : ‘+otext);
    // newopt.setAttribute(‘value’,n);
    // list.appendChild(newopt).appendChild(opttext);
    list.options[list.length] = new Option(n+’ : ‘+otext,n,false,false);
    you are not using the opttext and the newopt vars. I think you should comment the first two lines

    • #23
    • Comment
    • Sun 3 Oct 2004
    • 0239
    K Scott wrote in to say...

    Henryk, that fix is working for me, too. Modularity is wonderful.

    • #24
    • Comment
    • Sun 3 Oct 2004
    • 0533
    Nico wrote in to say...

    If I click the dropdown-list a but then move the mouse somewhere else without selecting something from the list, a grey rectangle stays where the list was (Moz 1.7)

    • #25
    • Comment
    • Sun 3 Oct 2004
    • 0637
    Arjan wrote in to say...

    That is probably caused by bug 206000
    https://bugzilla.mozilla.org/show_bug.cgi?id=206000

    • #26
    • Trackback
    • Sun 3 Oct 2004
    • 1028
    Received from Web Standards Project BUZZ

    Standard Slideshow System
    Eric Meyer has released a second beta of his web standards-based slideshow system. I haven’t mucked about with it yet,…

    • #27
    • Trackback
    • Sun 3 Oct 2004
    • 1218
    Received from Not an artist

    Slide Show in XHTML/CSS
    A good one-file slideshow X-HTML/CSS/JS-based system is available at Eric’s Archived Thoughts

    • #28
    • Comment
    • Sun 3 Oct 2004
    • 1220
    Andreas wrote in to say...

    Opera has created technical documentation that describes a standard fileformat used for slideshows. It might be worth checking out. It would rock if one common format is used (when it comes to writing applications that manages these slideshows anyway).

    Technical Documentation of Opera Show Format 1.0
    Stylesheets
    Javascript addons

    That and more at the OperaShow Center

    • #29
    • Comment
    • Sun 3 Oct 2004
    • 1239
    paul haine wrote in to say...

    “I’ve also scripted things so that the system works in Opera 6 and up, basically allowing those browsers to fall back to using Opera Show.”

    I’m using Opera 7.54 on WinXP, but when I view the slideshow, I see a brief flash of styled content, and then the slideshow displays in an unstyled version…

    • #30
    • Comment
    • Sun 3 Oct 2004
    • 1348
    Eric wrote in to say...

    In response to various comments…

    Bruce: I agree. I don’t have Keynote, but as I understand it the files are just XML. If you’d like to send me an example slide show or two, I could take a peek at the file format.

    Nico: yes, the gray rectangle happens for me too, and it looks like bug 206000 is responsible. There’s really not much I can do about it, and even if there were, I probably wouldn’t bother. That’s a painting bug that needs to be fixed in Firefox.

    Andreas: It looks as though the formats are basically the same, when it comes to the slide markup, although the IDs I generate are shorter than those called for in OSF. That’s easily fixable, as is adding the div class="presentation" to surround the slides. What wouldn’t be the same is the OSF meta tags, which I’m not about to add to my files but which wouldn’t interfere with moving slides from OSF to this system, or vice versa. The other difference is that OSF apparently requires XHTML, whereas this system does not; either HTML or XHTML works as well. Also, the layout stuff is quite different; I’m not sure how easy it would be to harmonize the two. I’ll think it over.

    But as I say, with a couple of tweaks it would be dirt-simple to move the actual slides from one format to the other. I think being in harmony there is probably a good idea.

    Paul: That’s exactly what you should see. If you then invoke Opera Show (F11), you’ll see the slide show. The navigation menu will not work, and the navigation keys will be those built into Opera Show (page up and page down, maybe others).

    • #31
    • Comment
    • Sun 3 Oct 2004
    • 1659
    Mark Schenk wrote in to say...

    First off, I would like to congratulate you on your work, especially on making it nicely compatible with Opera Show.

    There have been several attempts at making HTML/CSS/JS-based presentation tools (such as MozPoint) but none have been designed with the same cross-browser compatibility in mind as you have done. So I sincerely hope that your effort will be generally adopted if people want to use another browser than Opera for presentations.

    Secondly, I would like to comment a bit on the abovementioned Opera Show Format, as I wrote the new Generator and the documentation last summer.

    The OSF meta-tags are primarily there to make it easier for editors such as QuickShow to distinguish between different fileformats and to convert one into the other. I would therefore like to suggest that you consider adding a metatag of your own, so that future editors can also import your format.

    As you pointed out, OSF requires XHTML (the same doctype as you seem to be using) but I would like to add that the presentations will also work fine when using an HTML doctype. So why did I decide to use XHTML? The well-formedness will make it easier for editors to parse the information. Furthermore, some JavaScripts require a clearly defined DOM to work properly, which is not always the case when using HTML tagsoup.

    The layout section in the code is also there, with scalability in mind. This way editors can easily distinguish content from layout and when certain naming conventions are used (e.g. topleft, topright, etc.) then editors can provide a UI for editing the headers/footers.

    Another major difference between your format and OSF is that the latter requires an id for each slide. That makes it easier to link to different slides from an external source, e.g. a teacher giving a link to slide 25 from the last lecture.

    If anyone has suggestions or improvements for the Opera Show Format, they are always welcome.

    Last thing I would like to add: the idea of using a select box for navigating between slides is great! For the Opera Show Generator I wrote a script which generates a kind of navigation menu, with an ordered list of the slides, but I hadn’t though of using a select box. Nice one!

    • #32
    • Comment
    • Sun 3 Oct 2004
    • 1850
    Andreas wrote in to say...

    I really like the XHTML requirement. It means that I can easily parse the slideshows for use in other contexts. Tonight I threw a quick script together that collects metadata from all OperaShow Presentations and displays them on a webpage. My OperaShow Manager (screenshot is just a small example of what can be done quickly.

    I’m a practical guy so I’d prefer formats to be as easy to convert as possible. It makes my life easier. :)

    • #33
    • Comment
    • Sun 3 Oct 2004
    • 1958
    Phil Burns wrote in to say...

    Very nice work Erik,

    I am currently working on a new version of QuickShow which among other things has the ability to open/save in OperaShow Format (I collaborated a little with Mark on the OSF spec).

    As a test I opened your test presentation with my latest build and it parses perfectly, nice. I think it wouldn’t be too much work for me to add the cross-browser support to the output.

    While QS doesn’t mind too much about Doctypes when it opens a file it edits and saves as XHTML so it would be very nice indeed if we were all using the same flavour of HTML (XHTML), and generally swimming in one direction.

    • #34
    • Comment
    • Sun 3 Oct 2004
    • 2137
    Bjoern Graf wrote in to say...

    Hendryk is kind of on the right track with the IE event think (and this is based on just scimming over the comment shere and not looking at the real code): window.event is true for all versions of IE, but when using el.attachEvent the event is passed as argument (not sure whether that is IE6 only or if it works for earlier versions, too). The event.target error is due to the fact that IE’s event object names it event.srcElement, so to get the target in a x-browser way this code snippet is the best to use: var target = event.srcElement || event.target;.

    Not sure if this is relevant at all (just saw some new Option(...) stuff in the comment), but here’s a link to a Select Manipulation test page :)

    I’m not sure if that’s all to say but it is all I found during the skimming :)

    — b.gr

    PS: Why’s there no preview?

    • #35
    • Comment
    • Mon 4 Oct 2004
    • 0458
    Henryk Pl wrote in to say...

    Moin,

    Bjoern: Yes, attachEvent is a different method of getting event handlers called in IE (one that I didn’t know about before). However, according to the examples in Microsoft’s documentation on attachEvent there will be no parameter to the function that is being used as event handler.

    Of course the preferred way of handling events would be using DOM Level 2 Events, but unfortunately these are not supported by any version of IE. Given that current Geckos as well as current IEs still support the old way of using object.onfoo = handlerfunction (albeit with slightly different semantics in the handler, as I explained in the comments above) I don’t think it is beneficial to switch over to using DOM Events (for Geckos and similarly advanced browsers) and attachEvent (for IEs since 5). Maybe, in three years or so, when the IE folks got DOM Events into their browser …


    Henryk Pl

    • #36
    • Comment
    • Mon 4 Oct 2004
    • 0628
    Michael Guitton wrote in to say...

    Eric,

    Obviously the reason why the list doesn’t show up in IE5/Mac is because there is an error in the following statement:

    list.options[list.length] = new Option(n+’ : ‘+otext,n,false,false);

    which should read:

    list.options[list.options.length] = new Option(n+’ : ‘+otext, n);

    #20 is right in pointing out there are remnants of useless code.

    Also I’d like to share a debugging tip for IE5/Mac. You must embed the whole script in the HTML and turn on ‘display script errors’ checkbox in the prefs. It’s the only way to track down potential problems in your source code with this browser.

    Likewise, I can’t get the menu to show up with keyboard shortcuts. Unfortunately I’m quite busy at work so I can’t tell when I can take time to fix this. Perhaps later this week if I’m lucky.

    Last point, I noticed that there isn’t much defensive coding. When the (X)HTML code does not contain the required elts or when there is a typo in an ID, you end up most of the with a script error. For example, you should wrote:

    var obj = document.getElementById(‘slideProj’);
    if (obj) {

    }

    • #37
    • Comment
    • Mon 4 Oct 2004
    • 0631
    Michael Guitton wrote in to say...

    Oops, in #35, you should read “you end up most of the time with…”

    • #38
    • Comment
    • Mon 4 Oct 2004
    • 0733
    Henryk Pl wrote in to say...

    Moin,

    Michael: Yeah, you’re right with regards to defensive coding. This certainly is not ready for prime time yet, but serves to be a pretty good proof of concept.

    I took the last hour to simplify (well, kind of …) slideJump() and fix its bugs: the rest of the script didn’t know about jumps done by this function, which made strange things happen when you advanced slides; also the slide number wasn’t displayed at the bottom. Instead I now simply call go() from there which will take care of everything necessary. Then I added new functionality: You can now use regular anchors (<a name="..."> or even <a id="...">) in the slides which will work with ordinary browsers and have slideJump() go to the right slide. This only works onLoad() though, I’m not sure we can capture jumps between slides in JavaScript. E.g. clicking <a href=”#somewhereelse”> won’t work in presentation mode.

    This way you can have more permanent (when moving slides around) links to certain parts of the text that even work in old style browsers or with javascript disabled. I think this is something Mark wanted. I tested the new code in Gecko and IE 6 (should work with IE 5 too, not sure about Mac). For obvious reasons you can’t have anchors named s123 (with arbitrary values of 123). If you don’t like the new functionality you can remove everything from the first “else {” to the corresponding “}”. Then you will also see why I said that I simplified the code ;-)

    function slideJump() {
        if(window.location.hash == null) return;
        var sregex = /^#s(\d+)$/;
        var matches = sregex.exec(window.location.hash);
        var dest = null;
        if(matches != null) {
            dest = parseInt(matches[1]);
        } else {
            var target = window.location.hash.slice(1);
            var targetElement = null;
            var aelements = document.getElementsByTagName("a");
            for(i = 0; i < aelements.length; i++) {
                var aelement = aelements[i];
                if( (aelement.name && aelement.name == target)
                 || (aelement.id && aelement.id == target) ) {
                    targetElement = aelement;
                    break;
                }
            }
            while(targetElement != null && targetElement.nodeName != "body") {
                if(targetElement.className == "slide") break;
                targetElement = targetElement.parentNode;
            }
            if(targetElement != null && targetElement.className == "slide") {
                dest = parseInt(targetElement.id.slice(1));
            }
        }
        if(dest != null)
            go(dest - snum);
    }


    Henryk Pl

    • #39
    • Comment
    • Mon 4 Oct 2004
    • 1014
    Michael Guitton wrote in to say...

    Henrik, good work on slideJump(). I had found in the meantime that there was some duplicated functionality between go() and this function. Thanks for doing all the dirty work. Too bad because I had something similar in my JS code library. ;)

    BTW, I noticed that GetElementsWithClassName would fail for elements having more than one class name specified.

    if (allElements[i].className == className) { … }

    … should read:

    if (allElements[i].className.search(‘(^|\s)’+className[i]+'(\s|$)’) { … }

    Also did somebone try to remove the onload handler of body element and insert instead the call to startup() in a script section before closing body tag and with attribute defer set to true.

    • #40
    • Comment
    • Mon 4 Oct 2004
    • 1056
    Henryk Pl wrote in to say...

    Moin,

    Thanks, Michael. With regards to the onload handler: I agree that setting it in the HTML body tag is not particularly elegant. The usual solution is to remove the onload="startup();" from the body tag and instead append window.onload = startup; at the bottom of slides.js. This way the user never comes into contact with even a single line of JavaScript (except from the <script src=...>, of course). For that reason I would deem adding a script section to the presentation HTML even more ugly.

    Your idea about the className is very good. There are however some errors in your code, so here is a replacement line that actually works:
    if (allElements[i].className.search('(^|\s)'+className+'(\s|$)') != -1) {


    Henryk Pl

    • #41
    • Comment
    • Mon 4 Oct 2004
    • 1219
    Michael Guitton wrote in to say...

    Henryk, thanks for correcting my code oversight in #38. I did a cut and paste but forgot to type in the inequality test (!!) Actually it’s kind of difficult typing code accurately in a textarea ;)

    BTW, don’t you think it should be possible to merge keysIE() and keys() ? Obviously something analog has been done in clicker()


    function keys(e) {

    if (!e) {
    e = window.event;
    if (!e.target) e.target = window.event.srcElement;
    e.keyCode = e.keyCode || e.which;
    }

    switch (e.keyCode) {
    ...
    }
    }

    • #42
    • Comment
    • Mon 4 Oct 2004
    • 1400
    Bjoern Graf wrote in to say...

    In response to Henryk in #34: There are lots of benefits, the most obvious one is that addEventListener/attachEvent do not override previously assigned event handlers (see AttachEvent.js for a nice wrapper around all possible attach event methods). And do people really care about v4 browsers nowadays? Within the scope of this site I highly doubt anyone does ;)

    The fact that the sample on MSDN’s documentation for attachEvent does not demonstrate the event passed as argument does not mean it is not, it is.

    I guess it’s the right time to take a look at the actual code myself :)

    — b.gr

    • #43
    • Comment
    • Mon 4 Oct 2004
    • 1401
    Eric wrote in to say...

    Update: the test file has been updated, along with all the CSS and JS; the archive is also up to date as of this post. These changes bring the format more in line with OSF (though not completely) and includes nearly all the JS changes suggested. I’m discussing improvements to OSF compatibility with Mark, and we’ll see how that turns out. As Phil pointed out, the two formats are very close together, and I’m hoping we can make them still closer. The idea of having them interoperable really appeals to me.

    Thanks especially to Michael G. for pointing the way to having GetElementsWithClassName() handle multiclass values properly, something I’ve meant to do for a while now but wasn’t sure how to go about doing; and to Henryk, for all the excellent contributions.

    • #44
    • Comment
    • Mon 4 Oct 2004
    • 1445
    heads wrote in to say...

    I like the slideshow and would like to adapt it for presenting fiction on the web. Is there any way to re-work it so that the link box does not show up? Just wondering…the linkbox is not really needed for what I have in mind.

    • #45
    • Comment
    • Mon 4 Oct 2004
    • 1640
    Eric wrote in to say...

    Heads– it depends. If you set the whole control area to display: none then it should suppress the display of any descendant elements. Alternatively, you could use CSS positioning to throw the link box off-screen, thus rendering it inaccessible to the user. Well, to the vast majority of users, anyway.

    • #46
    • Comment
    • Mon 4 Oct 2004
    • 1652
    Henryk Pl wrote in to say...

    Moin,

    Uhm, your renaming the slide ids to ‘slide0′ etc. broke part of my slideJump() modifications. Also initially I didn’t think of multiple classes, so that will have to be fixed, too. I suggest adding a convenience function isClass() to wrap around that rather lengthy regex.

    function isClass(object, className) {
        return (object.className.search('(^|\s)' + className + '(\s|$)') != -1);
    }

    Then replace (in GetElementsWithClassName())
    if (allElements[i].className.search('(^|\s)' + className + '(\s|$)') != -1) {
    with
    if (isClass(allElements[i], className)) {

    While I’m at it I might as well go fancy and make internal links work in the process. First I’m extracting the slide finding code from slideJump():
    function findSlide(hash) {
        var target = null;
        var aelements = document.getElementsByTagName("a");
        for (var i = 0; i < aelements.length; i++) {
            var aelement = aelements[i];
            if ( (aelement.name && aelement.name == hash)
             || (aelement.id && aelement.id == hash) ) {
                target = aelement;
                break;
            }
        }
        while(target != null && target.nodeName != "body") {
            if (isClass(target, "slide")) {
                return parseInt(target.id.slice(5));
            }
            target = target.parentNode;
        }
        return null;
    }

    the interesting part from slideJump() now reads:
    if (matches != null) {
        dest = parseInt(matches[1]);
    } else {
        dest = findSlide(window.location.hash.slice(1));
    }
    if (dest != null)
        go(dest - snum);

    what’s missing is a mind boggling, sense warping, ultimately eloquent piece of code to attach proper handlers/listener to all internal links:

    function fixLinks() {
        var thisUri = window.location.href;
        thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length);
        var aelements = document.getElementsByTagName("a");
        for (var i = 0; i < aelements.length; i++) {
            var a = aelements[i].href;
            if(a && ((a.slice(0, thisUri.length) == thisUri))
                 && (a.slice(thisUri.length, thisUri.length + 1) == "#")) {
                var dest = findSlide(a.slice(thisUri.length + 1));
                if(dest != null) {
                    if(aelements[i].addEventListener) {
                        aelements[i].addEventListener("click", new Function("e",
                            "if(document.getElementById('slideProj').disabled) return;" +
                            "go("+dest+" - snum); " +
                            "if(e.preventDefault) e.preventDefault();"), true);
                    } else if(aelements[i].attachEvent) {
                        aelements[i].attachEvent("onclick", new Function("",
                            "if(document.getElementById('slideProj').disabled) return;" +
                            "go("+dest+" - snum); " +
                            "event.returnValue = false;"));
                    }
                }
            }
        }
    }

    and a call to that function in startup() somewhere behind the call to slideLabel().

    Just in case I got you lost on the way I’ve uploaded a modified slides.js. (As always: Tested with Gecko and IE 6.)


    Henryk Pl

    • #47
    • Comment
    • Mon 4 Oct 2004
    • 1748
    Jamie wrote in to say...

    You can add Firefox 1.0PR to your list of compatible browsers. I know nothing of javascript, but everything looked right to me and worked very well. Good job all!

    • #48
    • Comment
    • Tue 5 Oct 2004
    • 0446
    Michael Guitton wrote in to say...

    In response to Bjoern in #41. “Do people really care about v4 browsers nowadays?” As pointed out in the source code of AttachEvent.js, IE5/Mac — which is not a v4 browser — doesn’t support attachEvent nor addEventListener. Using old-style event handlers can work equally well assuming you take additional steps to preserve any event handler that has been assigned previously.

    Ex:
    // onmouseover
    obj.onmouseover_eh = obj.onmouseover;
    obj.onmouseover = function(e) {
    // your code here
    ...
    // call previous event handler
    if (this.onmouseover_eh)
    return this.onmouseover_eh(e)
    };

    You get the idea. You can find a similar code sample at squidfingers.com. It only applies to window property but could be adapted to work with other elements.

    Also nobody noticed my earlier post about new Option(...) assignment which simpy doesn’t work “as is” in IE5/Mac (either running Mac OS 9 or Mac OS X). You should write it as follows:

    list.options[list.options.length] = new Option(n+� : �+otext, n);

    In addition, you must reset the list items before the initial for loop because of an obscure bug in IE when you hit the back button:

    for (var i = list.options.length - 1; 0 < i; i--)
    list.options[i] = null; // null out options in reverse order (bug work-around)

    As for the pop-up not showing up in IE5/Mac, I can tell this stuff works when CSS is disabled (!) Therefore this must be an issue with the positioning rules.

    A nice add-on would be to have the pop-up state stay in sync with the current slide by assigning the current slide number to the selectedIndex property of select elt.

    • #49
    • Comment
    • Tue 5 Oct 2004
    • 0724
    Henryk Pl wrote in to say...

    Moin,

    Yikes! I just noticed that you write <div onmouseover="javascript:showHide('s');" ... in the HTML document. This is evil. Never ever shall you use “javascript:” in any onfoo event handler! The only reason this seems to work is that by pure coincidence foo: bar is a labeled statement in ECMAScript.

    Another point I don’t like is that the empty <select> prevents proper HTML validation. Actually I wanted to remove the form from the HTML anyways and dynamically insert it in JavaScript later so that non-Javascript-capable clients won’t see it at all. The only thing that needs to be left is a stub <div id="controls"></div>.

    Add this function:
    function createControls() {
        controlsDiv = document.getElementById("controls");
        if(!controlsDiv) return;
        controlsDiv.innerHTML = '<form action="#" id="controlForm">'+

        '<div>'+

        '<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;</a>'+

        '<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;</a>'+

        '<a accesskey="x" id="next" href="javascript:go(1);">&raquo;</a>'+

        '</div>'+

        '<div onmouseover="showHide('s');" onmouseout="showHide('h');"><select id="jumplist" onchange="go('j');"></select></div>'+

        '</form>';
    }

    and a call to it as the first line of startup():
    if(!isOp) createControls();

    This way Opera doesn’t see the controls as they won’t work, but that also needs a modification of slideLabel(). Insert if(isOp) continue; after the line obj.setAttribute('id',did); to make it skip the rest of the loop. (Alternatively don’t call slideLabel() for Opera at all.)

    There is only one thing left that I’d love to have: Have the text resize automatically according to the window size. Otherwise text in presentations created at 1024×768 will look kind of lost at 1600×1200 or similar. In fact even the example presentation looks strange at my 1400×1050.

    This is something I need help with, as I’m not too proficient with the CSS. I’d suggest adjusting the font-size of <body> element according to the ratio of the window size the presentation was designed with and the current window size. After that all lenghts and positioning of elements inside the body would need to use relative units. I have the script code ready and working, but it doesn’t play too well with the current style sheet.

    function resizer() {
        if(!baseWidth || !baseHeight) return;
        var width = document.getElementsByTagName("html")[0].clientWidth;
        var height = document.getElementsByTagName("html")[0].clientHeight;
        var ratioW = width / baseWidth;
        var ratioH = height / baseHeight;
        var ratio = Math.min(ratioH, ratioW);

        document.getElementsByTagName("body")[0].style.fontSize = ((Math.floor(ratio * 100) / 100) * 2) + "em";
    }

    (The * 2 in the last line stems from the fact that the stylesheet has font-size: 2em defined for body. Adjust as necessary.)

    Call it with window.onresize = resizer; resizer(); directly below the line document.onclick = clicker; in startup(), and of course insert a definition of the baseWidth/Height in the surrounding HTML file:
    <script type="text/javascript">var baseWidth=1024, baseHeight=768</script>
    before the <script src=....

    Tested with Gecko and IE6, but doesn’t work too well in Gecko and has some slight problems in IE.


    Henryk Pl

    • #50
    • Comment
    • Tue 5 Oct 2004
    • 0752
    Mark Schenk wrote in to say...

    Henryk: having the design scale to different resolutions is quite tricky. There are currently two approaches already being used:

    1) use JavaScript to query the width of the screen and set a base value for the <html> or <body> tags and then use relative fontsizes for the rest of your styles. This is what QuickShow does.

    2) use CSS3 Media Queries which is currently only supported in Opera 7.x (and that is only experimental).

    I decided to use Media Queries for the Opera Show Generator, as documented here. I could use it because the queries are only used in combination with the @media projection and Opera is the only one to support that.

    For cross-browser compatibility, JavaScript seems to be the way to go but that means that all values in the stylesheet should be relative ones (including padding/margins). That is quite well possible, but needs some work to scale nicely.

    • #51
    • Comment
    • Tue 5 Oct 2004
    • 0801
    Michael Guitton wrote in to say...

    In response to Bjoern in #41. “Do people really care about v4 browsers nowadays?” As shown in the code sample you pointed out, IE5/Mac does not support attachEvent nor addEventListener. Using old-style handlers is not such a bad practice presuming you take the necessary steps to preserve the previously assigned event handler.

    Ex:

    // onmouseover
    obj.onmouseover_eh = obj.onmouseover;
    obj.onmouseover = function(e) {
    // your event handler code here...
    if (this.onmouseover_eh)
    return this.onmouseover_eh(e);
    };

    You get the idea. You’ll find similar code at squidfingers.com.
    It only applies to window property but it can be easily adapted for DOM elts.

    • #52
    • Comment
    • Tue 5 Oct 2004
    • 0822
    Michael Guitton wrote in to say...

    Nobody seemed to notice my warning in #35 regarding new Option(..) not working in IE5/Mac.

    Code in slideLabel() should read:

    list.options[list.options.length] = new Option(n+' : '+otext, n);

    Also — in the event we end up assigning location.hash with current slide number — it might be mandatory to add the following statement in slideLabel() that prevents some mess in the pop-up items when someone hits the back button in IE:

    for (var i = list.options.length - 1; 0 < i; i--)
    list.options[i] = null; // null out options in reverse order (bug work-around)

    BTW, a nice add-on would be to assign the slide number to the selectedIndex of select element to keep the pop-up in sync with the current slide.

    One last thing. When CSS is disabled in IE5/Mac, the pop-up onmouseover and onmouseout handlers work as expected. Therefore I guess this an issue with the CSS positioning rules. Could anyone confirm this?

    • #53
    • Comment
    • Tue 5 Oct 2004
    • 1032
    Eric wrote in to say...

    Okay, I sense this is beginning to run away from itself. I’ve dropped a few of the suggested fixes into place– sorry I didn’t act on comment #35, Michael, it was an oversight– but some of the more esoteric stuff I’m going to have to postpone until later. The one thing I’d like to do is add the suggested selectedIndex massaging, but I tried two different ways I thought would work and neither did. If I could get some example code, that would be great.

    The font resizing is something I already tried, and discovered that in Gecko browsers things fell apart pretty badly. This appears to be because the element boxes do not change once calculated, so the when the font size changes everything goes to hell. So for v1.0, the font size will be set in the CSS. If a presenter needs to change it, he can do so by editing the body‘s font size value. This will not account for slides posted to the Web and viewed under varying conditions, but that is not a project goal. The idea here is to provide a lightweight presentation solution along the lines of Opera Show, but in a cross-browser fashion.

    Things like font scaling may be added later. But not now.

    Similarly, I got lost enough trying to follow the internal-links code that I’m probably going to push it off to a later version. It’s nothing against you, Henryk; your contributions have been great and have deeply influenced the JS as it now stands! I hope to revisit what you did for v1.1. Since (as I understand it) the internal-links code won’t affect the markup structures, I’m willing to delay that feature introduction.

    At this stage, I’m focused on, pretty much in this order:

    1. Beating down any bugs in the current functionality (as opposed to browser bugs that draw gray rectangles, introduce slight scrollbars, and so on).
    2. Ensuring as much OSF 1.0 compatibility as possible.
    3. Creating documentation for a v1.0 release.
    4. Adding the selectedIndex bit Michael mentioned in comment #51.

    I’ll be updating the JS and HTML files in a few minutes.

    • #54
    • Comment
    • Tue 5 Oct 2004
    • 1225
    Henryk Pl wrote in to say...

    Moin,

    As you probably already noticed that your selectedIndex approach doesn’t work this way. Instead the line has to read:
    document.getElementById('jumplist').selectedIndex = snum;

    Additionally there’s a minor bug in isParentOrSelf: the contents of nodeName are always uppercase. So it can never match 'body', but only 'BODY'.

    With regards to link following: TMTOWTDI. I’ve got a less cryptic solution here (hey, it even got comments! ;). There was also a very minor bug in clicker(): Clicking something inside a link (e.g. the image in <a><img></a>) would not be detected by target.href != null. This is fixed in my modified code.

    function linkFollower(target) {
        // See whether target or one of its parents is an <a>
        while(target != null && target.nodeName != "BODY") {
            if(target.nodeName == "A") break;
            target = target.parentNode;
        }
        if(target && target.nodeName != "A") return false; // no <a>
        var link = target.href;
        if(link == null) return false; // not a link
        var thisUri = window.location.href;
        thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length) + "#";
        // thisUri now contains the current URI without the hash part, but with a hash
        if(thisUri != link.slice(0, thisUri.length)) return; // not an internal link
        link = link.slice(thisUri.length); // the name of the anchor to jump to
        var dest = findSlide(link);
        if(dest != null)
            go(dest - snum);
        return true;
    }

    Replace (in clicker()):
    if (target.href != null || isParentOrSelf(target, 'controls')) return true;
    with
    if (isParentOrSelf(target, 'controls') || linkFollower(target)) return true;

    (Obviously the function needs my findSlide() function. Attention: findSlide() contains an occurence of nodeName, too, and I initially made the same mistake of writing 'body'.)

    Yet another thing: pretty.css is not valid CSS. There’s a typo (padding; 0;) and a missing unit (line-height: 1;). (On a related note: Sorry about messing the markup of this page up in my comments above.)


    Henryk Pl

    • #55
    • Comment
    • Tue 5 Oct 2004
    • 1552
    Eric wrote in to say...

    I’d tried the .selectedIndex but it didn’t seem to work. Turns out that’s due to Safari, not the code. That’ll teach me not to test in multiple browsers.

    I fixed the padding error, thanks. The line-height: 1 is valid: http://www.w3.org/TR/CSS21/visudet.html#propdef-line-height .

    • #56
    • Comment
    • Tue 5 Oct 2004
    • 1718
    Val wrote in to say...

    Just curious — how much do you think this work overlaps SlideML? I ask because I was hunting for somethign like this a few weeks back and found SlideML. It seems very similar: you author in a single file in a small SlideML syntax + XHTML, run thru an XSLT stylesheet to emit multiple XHTML files. It has some problems that still need cleaning up — the JavaScript to navigate slides is hinky (and this thread illustrates the difficulty!), but seems like there’s a lot of overlap here. Not having used SlideShow, can anyone do a quick comparison and discuss the pros & cons?

    • #57
    • Comment
    • Wed 6 Oct 2004
    • 0944
    Mikael Jervelind wrote in to say...

    A suggestion!
    It would be nice if it was possible to navigate to a slide by means of pressing a number (one or more number keys) and then Enter. This is a feature in for example PowerPoint which is sometimes useful.
    I think it is just as simple as to store the numbers in a variable and check if there are something stored when the Enter key is pressed.
    The store should be cleared for any key but numbers.

    • #58
    • Comment
    • Wed 6 Oct 2004
    • 1201
    christian wrote in to say...

    Not what you are asking for, some kind of off-topic: i was curious, if that could be done without div’s with class=’slide’, just a ‘ instruction ‘ for certain elements ( var slides=[‘h1′,’h2′]; ) to make a ‘ cut ‘ in the normal document flow.

    You can check out a sketch for such a solution here, if you like. ( the key handlers are a bit different )

    ( any Element before the first ‘ cut ‘ is displayed always )

    • #59
    • Comment
    • Wed 6 Oct 2004
    • 1357
    headsfromspace wrote in to say...

    Eric ::

    Re: #44

    Thanks for the info. I’m not sure which elements of the CSS to set to display: none–could you be more specific? I appreciate your help very much.

    -heads

    • #60
    • Comment
    • Wed 6 Oct 2004
    • 1809
    Eric wrote in to say...

    Val: I would say that this system, like OSF, is something that SlideML could use as a target format. In other words, someone could create a SlideML document and then run a transform to turn it into OSF or this format. There is certainly overlap in terms of intended use, but that doesn’t strike me as being a problem.

    Mikael: That would be nice, but won’t be part of the initial release. I’ll have to look at doing that in a later version.

    Christian: My original Opera Show files did exactly that, only without the JavaScript. I’ve instituted the class="slide" constructs because it’s more compatible with OSF 1.0. Okay, to be totally honest, originally I instituted them because it was easier to process the DOM structure that way, but at this point they’re staying in due to OSF 1.0 compatibility.

    Heads: div#controls {display: none !important;} or a rule to that effect. Alternatively, div#controls {position: absolute; top: -1000em;}.

    • #61
    • Comment
    • Wed 6 Oct 2004
    • 1931
    christian wrote in to say...

    It does not break the OSF 1.0, actually the idea was to make it more similar to it (in the projection css: body>h1, body>h2 {page-break-before: always;} and in the js: var slides=[’h1′,’h2′]; ). You can test it ( still here ), with js disabled it does work as normal OSF in projection mode ( little problem with the test image, which is a little bit to high, and the whole thing is still just a sketch ) and with js enabled it does work on the same way as in the Fox and in ie.

    ( i think i could be possible to ‘ parse ‘ the projection css for the Fox and for ie, so that it would work with such a js module with no more additional adaptions, but perhaps a little bit to much ‘ music ‘ )

    But it’s more for personal interests, your current solution is sure ok.

    ( and i am a Opera user, so i would never work contra my browser :) )

    • #62
    • Comment
    • Wed 6 Oct 2004
    • 2004
    Eric wrote in to say...

    The content of a slide must be enclosed by a div with a class=”slide” attribute and a unique id=”slide[counter]” where the [counter] is replaced by the slide number. The id is required to be able to link to specific slides in a presentation.

    From Opera Show Format 1.0 documentation. In the format I’ve created, the slide IDs are dynamically assigned instead of placed in the XHTML, but they use exactly the same format (slidenn).

    So taking out those divs would, in fact, make the format more incompatible with OSF 1.0.

    • #63
    • Comment
    • Thu 7 Oct 2004
    • 0506
    christian wrote in to say...

    I see, sorry, you’re right.

    ( i have hade in mind just the technical point of view )

    • #64
    • Comment
    • Thu 7 Oct 2004
    • 0643
    Michael Guitton wrote in to say...

    Apologies for duplicate comment entries in #47, #50 and #51. When I posted #47 using Camino, this browser freezed (!) and when I visited this page subsequently using Safari and IE, my comment was nowhere to be seen… making me think the previous POST request did not succeed.

    • #65
    • Comment
    • Sat 9 Oct 2004
    • 1357
    headsfromspace wrote in to say...

    Eric ::

    re: #59

    Thanks for the tip. I did play around with assigning display: none to the div control tag but found the arrows and toggle switch disappeared too–I’d like those to display. I’ll fool around with it some more but if you have an idea of how to get just the linkbox to not display I’d appreciate it.

    -heads

    • #66
    • Comment
    • Fri 22 Oct 2004
    • 0848
    Bruce D'Arcus wrote in to say...

    I’m trying to work out how best to deal with image inclusion via CSS. I’ve wrapped each image in a div with an “image” class. Any suggestions on how to best modify my definition to properly handle sizing? I’m tranforming via XSLT, so don’t want to hard code sizing information in the img elements. I just want to constrain the div to a certain proportion of the “slide.”

    div.image {float: right;}

    • #67
    • Comment
    • Fri 22 Oct 2004
    • 0901
    Bruce D'Arcus wrote in to say...

    Also, I think I’d like to remove the images from the outline view, but am not sure how to do that.

    • #68
    • Comment
    • Sun 21 Nov 2004
    • 2205
    Jon Malachowski wrote in to say...

    Thank you so much for this. I am an Engineer at George Mason and I think this is a great solution to basic presentations. I made one for class and the professor was impressed. I left s^5 on the footer for you! If anyone would like to see: http://mason.gmu.edu/~jmalacho/prsp.html

    • #69
    • Comment
    • Sun 9 Jan 2005
    • 2223
    Johan Steenkamp wrote in to say...

    1. I added a cookie to retain the current slide. I found this useful in cases where you leave the presentation to visit another site or link in a slide that does not open a new window. Hitting your browser back button would take you back to the start of the preso – the cookie solves that problem. The cookie is set to expire within 1 dayso you can take a lunch break and pick up where you left off :-)

    http://www.assetnow.com/anx/index.cfm/1,8,106,html

    2. Also made a variation on the S5 script to allow paged content. Divide a long document into div’s with class=”page” and it display one page at a time like the slide show.

    http://www.assetnow.com/anx/index.cfm/1,8,167,html

    • #70
    • Comment
    • Tue 8 Mar 2005
    • 1224
    Eric Everman wrote in to say...

    I’ve noticed that in the current version (as of March 2005), clicking a slide in Firefox will cause the ‘blinking cursor’ to remain on the screen. With large font sizes, this is a REALLY BIG blinking cursor which means the clicking is not a usable way to go to the next slide.

    Has anyone come up with a fix for this?

    Thanks

    –Also, is there a more appropriate user’s discussion list? –

    • #71
    • Comment
    • Sun 29 May 2005
    • 1409
    Jeroen van der Vegt wrote in to say...

    Hi, this seems to have evolved to something quite usable, but development seems halted. Before I make any contributions, I’d rather know if Eric still feels like updating the program (I would like adding functional (b)lack/(w)hite keys, and #56).

    I also found that variable ‘n’ or ‘i’ is often not declared properly, and the function names could use an update (function names starting with a capital, a function called ‘showHide’….)

    • #72
    • Comment
    • Sun 29 May 2005
    • 1513
    Eric Meyer wrote in to say...

    Hi Jeroen– type-number-to-jump is already in the latest version of S5; this post is very old and doesn’t come close to representing the latest code. Most if not all of the variable declarations were fixed as well. See http://meyerweb.com/eric/thoughts/2005/02/03/s5-11b5/ for the latest beta version of S5 1.1, and http://meyerweb.com/eric/thoughts/category/tech/s5/ for all posts referncing S5.

    • #73
    • Comment
    • Sat 29 Oct 2005
    • 1329
    Matthias Ebert wrote in to say...

    I’ve got Two Change Requests for S5-Slideshows

    E-Mail: Matthias.Ebert@gmx.de
    Tested on Version: S5.1

    Recommendations:
    1) ALLOW DIRECT LINKS FROM OUTSIDE
    2) SLIDE-LOOP toggled on/off by variable

    1) ALLOW DIRECT LINKS FROM OUTSIDE
    ———————————-
    To allow a direct link from outside to a specific slide,
    I recommend to use the usual parameters behind the URL-name,
    i.e. s5-demo.html?3
    This example presents slide3 in the browser.

    HOWTO:
    You can simply add the following javascript function to slide.js:


    function getParameter()
    {
    var url = window.location.href;
    parameter = url.split("?");
    return parameter[1];
    }

    This function has to be called in the last row of startup()

    function startup()
    {
    ...
    goTo(getParameter());
    }

    2) SLIDE-LOOPS controlled by the variable loop
    ———————————————-
    Endless slide-loops are importent i.e. on fares,
    where a endless presentation is going on while the crowd walks by

    HOWTO:
    Two new global variables are needed:

    var loop = true;
    var loop_timeout =10000; // im miliseconds

    Then add the following javascript function to slide.js:

    function nextSlide()
    {
    var target = snum+1;
    if (target >= smax) target = 0;
    var url = window.location.href;
    parameter = url.split("?");
    document.location.href = parameter[0] + "?" + target;
    }

    This function has to be called in:
    – the startup(),to be used by slide0
    – the last row of go(), to be used by all other slides

    function startup()
    {
    ...
    if (loop) setTimeout('nextSlide()', loop_timeout);
    goTo(getParameter());
    }

    function go()
    {
    ...
    if (loop) setTimeout('nextSlide()', loop_timeout);
    }

    TODO
    —-
    – The variables should be controlled by the user!
    – The user-interaction-menu didn’t work when loop=true.
    – The loop didn’t show the sub-steps

    • #74
    • Comment
    • Mon 4 Jul 2011
    • 2321
    robonoob wrote in to say...

    Thanks Eric for the great S5.

    I read the comment about Slippy the HTML Presentation and find your comment (http://seld.be/notes/introducing-slippy-html-presentations). In fact, I used S5 quite a lot well before finding Slippy.

    As S5 was released quite a long time ago, I am thinking if there is an updated version available with adoption of HTML5 and jQuery. If not, I may try to follow the S5v2Beta or Slippy and develop on top of that.

Leave a Comment

Line and paragraph breaks automatic, e-mail address required but never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Remember to encode character entities if you're posting markup examples! Management reserves the right to edit or remove any comment—especially those that are abusive, irrelevant to the topic at hand, or made by anonymous posters—although honestly, most edits are a matter of fixing mangled markup. Thus the note about encoding your entities. If you're satisfied with what you've written, then go ahead...


October 2004
SMTWTFS
September November
 12
3456789
10111213141516
17181920212223
24252627282930
31  

Sidestep

Feeds

Extras