Feed Sign in with OpenID OpenID

Simon Willison’s Weblog

easytoggle and debugging in Safari

I’ve been working on a new inobtrusive DHTML effect: easytoggle, which is an inobtrusive implementation of the common effect where links or tabs can be clicked to reveal part of a page while hiding the other parts. It’s similar in some ways to the Multi part forms with Javascript technique.

The idea is pretty simple—all you need are a bunch of links and a bunch of elements that should be toggled by those links. When adding special behaviour to links it is always a good idea to ensure that they still link to something sensible, so that in user agents without Javascript support they still do something useful. In this case, it makes sense for them to act as anchor links that point to the elements with which they are associated. With easytoggle, all you need to do is define the links, point them at an element with an ID and assign them the class ’toggle’. The script does the rest of the work. For example, for a simple set with only two panels the markup would look something like this:

<ul>
 <li><a href="#p1" class="toggle">Panel 1</a></li>
 <li><a href="#p2" class="toggle">Panel 2</a></li>
</ul>

<p id="p1">This is panel 1</p>
<p id="p2">This is panel 2</p>

That’s all it takes—the demo has a very slightly more complicated example.

I thought it was finished, until I tested it in Apple’s Safari browser. In Safari, the worst possible thing happens. The initialisation code which hides all of the panels after the first one works fine. Unfortunately, the code that causes the links to change which panel is visible fails silently, leaving only the first panel accessible to users with that browser. That’s a big problem.

It was at this point that I discovered that Safari’s support for debugging Javascript sucks rocks. Firstly, the browser gives no indication that a bug has been encountered. I’m sure this is a deliberate usability decision, but it also means users who encounter a bug won’t even know that there is a problem with the site. A quick Google led me to this page, which told me how to enable Javascript error reporting:

  1. In a command line shell, execute defaults write com.apple.Safari IncludeDebugMenu 1 (apparently Safari Enhancer lets you do this from a GUI).
  2. Reload Safari and check the “Log Javascript Exceptions” option in the newly enabled Debug menu.
  3. Start Console.app, which lives in /Application/Utilities. Note that this is not the same thing as the command line console. This took me a few moments to figure out. Macs remain a strange new realm of discovery.
  4. Javascript exceptions will now appear in the Console.app window.

Excellent—just what I needed to know. The entire error message I got when I clicked a link? (event handler):Undefined value. Gee, thanks a lot Safari. If anyone has any ideas how I can fix the script in Safari (or at the very least prevent it from being unusable) please leave me a note.

Update: Thanks to a tip from David Lindquist, the updated version of the script now works in Safari. It’s a little bit uglier though.

This is easytoggle and debugging in Safari by Simon Willison, posted on 6th November 2003.

View blog reactions

Next: Usability guidelines available online after all

Previous: Javascript Mojo

25 comments

  1. Hi Simon, Cool script. For Safari, the event target appears to be the Text node and not the anchor element, so you have to say:
    e.target.parentElement.href
    

    David Lindquist - 6th November 2003 01:58 - #

  2. Unobtrusive?

    preacher - 6th November 2003 02:51 - #

  3. I checked Dictionary.com and unobtrusive and inobtrusive both appear to be valid ways of saying the same thing. Mind you, Stuart calls it "unobtrusive" so I should probably follow his lead.

    Simon Willison - 6th November 2003 03:22 - #

  4. That's very smooth indeed. I shall be stealing this. :)

    sil - 6th November 2003 06:44 - #

  5. this is not the same thing as the command line console.

    Simon, the CLI is in the Terminal, not in the Console ;-) And that distinction is not particular to Mac OS X.

    padawan - 6th November 2003 08:23 - #

  6. Interesting. Recently I developed almost exactly the same script for the same purposes. Two remarks: 1) The Safari bug is caused by it not being able to read [linkElement].hash, that's always '#'. 2) In my script I did <ul> <li><a href="#p1" class="toggle">Panel 1</a></li> <li><a href="#p2" class="toggle">Panel 2</a></li> </ul> <p id="p1"><a name="p1"></a>This is panel 1</p> <p id="p2"><a name="p2"></a>This is panel 2</p> This keeps the page accessible to noscript browsers, since they simply jump to the internal anchor.

    ppk - 6th November 2003 13:41 - #

  7. Sorry, I forgot to add the pre: Code example should read:
    <ul>
     <li><a href="#p1" class="toggle">Panel 1</a></li>
     <li><a href="#p2" class="toggle">Panel 2</a></li>
    </ul>
    
    <p id="p1"><a name="p1"></a>This is panel 1</p>
    <p id="p2"><a name="p2"></a>This is panel 2</p>
    

    ppk - 6th November 2003 13:42 - #

  8. PPK: Nice accessibility workaround.

    P01 - 6th November 2003 19:03 - #

  9. First: Not all browser support targets that are IDs, so you should probably do a named anchor in there, too.

    Second: They're planning on removing the javascript console from Firebird and turning it into an extension. I think there will be a statusbar icon to indicate a problem, but no real information with the default configuration.

    alanjstr - 6th November 2003 22:37 - #

  10. The only browser I know of that doesn't follow anchors to IDs and has any noticeable browser share at all is Netscape 4, and I've got to the point now where I'm not going to degrade the quality of my markup for the sake of that browser, especially when the content remains essentially visible while only losing a small amount of functionality.

    Simon Willison - 7th November 2003 00:25 - #

  11. If you think it's a Safari bug try a trackback ping to Dave Hyatt's website. He responded to a query from me in a day. Then again I know nothing about JavaScript so maybe this is a feature ;-)

    oli - 9th November 2003 06:43 - #

  12. theres a really neat program called geekTool (http://projects.tynsoe.org/en/geektool/) which can display your console.log (or any other file or unix command for that matter)as an overlay on the desktop (you don't have to open console, etc...) Apart from this being unimaginably geeky and cool, it also makes the process of debugging Javascript with Safari much easier.

    simon - 10th November 2003 16:46 - #

  13. Hi, Just wondering how I would make this script work with an image. Current it uses a text link, however, I tried replacing with an image and when it is clicked, that specific panel is not displayed. Has anyone tackled this yet? thanks.

    VQC Designs, LLC - 19th December 2003 02:03 - #

  14. The demo shows N pages of content with one URL, with printing leaving N-1 pages worth of content hidden. Doesn't seem attractive to me.

    TvA - 16th April 2004 15:56 - #

  15. I can certainly see a use for it with forms, given that the browser don't lose form data between pages. Have to take a look meself:D

    waf - 27th April 2004 10:22 - #

  16. A nice script but I have one comment. Wouldn't it be nice, if one made a script, where you wouldn't need to make internal links, but instead just took an e.g. <h3> as the name of the tab:

    <div class="tab">
      <h3>Name</h3>
      <p>Tab 1</p>
    </div>

    That would put the content and the name of the tab closer together!

    Lars Olesen - 28th April 2004 14:34 - #

  17. Great script, Simon.

    I was wondering if there's a way to have more than one instance on a page. I'd like to use it in 2 places, but am not proficient enough to re-write the code.

    John Fujiwara - 13th May 2004 17:14 - #

  18. Simon,

    this is a great script, but i have 2 issues and a nice-to-have i hope you can address in a subsequent release.

    1. you aren't able to link directly to the requested named anchor by referencing the hash in the URL.
    2. there's no persistence in the visible panel for returning to the page via the back button
    3. a "you are here" styling on the link would be nice too, but now i'm just getting greedy.

    anyway, this is not to take away from your excellent script. keep up the good work.

    Cris - 10th September 2004 03:37 - #

  19. Very neat indeed. Works perfect in Safari and degrades with style in IE5 mac (from what I've tested). Following on John's suggestion: would it be possible to have two instances of the script running independently on the same page? Thanks a lot anyway for this great script!

    Antioche - 3rd October 2004 19:07 - #

  20. For those whom want this script to work with images instead of text.

    Mary - 15th January 2005 05:14 - #

  21. dir

    sawa - 13th February 2005 09:27 - #

  22. I'd like to second Cris's comments from 10 September 2004, especially the part about persistence. It would be great to see this script updated, and if there were an unobtrusive way to include persistence (i.e., along the lines of a PHP session rather than through the use of a cookie), I'd love to know about it.

    Brett - 11th March 2005 14:18 - #

  23. Just thought I'd let Simon (and everybody who finds this page in the future) know that Safari now (as of 2.0.3) has a javascript console much like the one found in firefox. You still have to go through the Terminal to set the default value that makes the debug menu display, however.

    The javascript console can be found in the debug menu, it is the 14th option, directly under "Log JavaScript Exceptions".

    Also I have to take a minute here while on my soapbox to plug MochiKit (www.mochikit.com), a nice set of JavaScript libraries that make writing it far less painful and somewhat more pythonic. If you write JavaScript, it will make your life better (but your pageloads slower :-( )

    James Kafader - 9th March 2006 21:45 - #

  24. You have coded a great piece of script. It was very easy to modify it for CSS usage.

    I send you my modifications, which ables color coding to maintain some "you are here" kind information, that was requested by a commenter; Cris - 10th September 2004.( I hope it is not so late!)

    Briefly, I added id's to li's, as li+href.value(after hash); like "lione", "litwo".... assigned a CSS class to li's, named menulist. Added a few styling for menulist and menulistselected in HTML document. And some code to the .js file to assign these class names occasionally.

    I think you don't mind if I use it on some site.

    Many thanks.

    ilker - 29th March 2006 18:06 - #

  25. Great stuff, but I like this one better:

    http://www.bobbyvandersluis.com/articles/unobtrusi veshowhide.php

    Uses images and/or text and seems leaner and meaner to me.

    tatlar - 3rd May 2006 20:11 - #

Comments are closed.

Previously hosted at http://simon.incutio.com/archive/2003/11/06/easytoggle

A django site