You are reading an archived post from the first version of my blog. I've started fresh, and the new design and content is now at boxofchocolates.ca

Dockable Comments: Intelligent DOM Scripting

May 23, 2005

About a month ago I wrote Browser Elitism and Browser Elitism Part 2. These posts saw fairly high traffic and got quite a few comments. So much so in fact that I didn’t find it very easy to comment properly and address the points that people were making in their comments. A few days after I set out to “solve” that problem, only to find out weeks later that Jonathan Snook had done something similar in his post Experiment with position: fixed.

Cool that we came up with similar ideas at almost the same time. Spooky that we only live about 10 minutes from each other. I love that the fixed comment form was integrated into Jonathan’s 78th redesign. I, on the other hand, am not quite ready for a full redesign, but wanted to implement the functionality right away. So, here it is – dockable comments.

(If you just want to try it out, go straight to the comment form)

Principles and Goals

I had a few guiding principles and goals in mind when I was implementing this functionality:

  1. make it easier to comment on other comments using copy and paste
  2. maintain my live preview
  3. use JavaScript unobtrusively so that those without appropriate JavaScript support maintain their base commenting functionality
  4. selective population of controls. That’s what I call using JavaScript to dynamically add elements to the DOM that will only work when JavaScript is on. Its a term of convenience, really, but I think it captures the essence of what we are aiming for.

The CSS

I implemented a few new style rules to make this happen. Unlike the days of old where we dynamically changed CSS style rules one by one, I used pre-defined styles to define a few different “states” for my dockable comment div that I wrapped around the comment box, its label, the dock control and live preview.

I defined a normal state with some default values, an “outlined” state that gives a visual clue as to how much will get docked when you click on the “Dock Comment” link, as well as a “docked” state that defines the CSS that locks the comment form to the left side of the window. My values were specifically chosen to work well with my liquid layout – when docked, my comment div takes a width of 32%, to fit nicely within the left side of my blog where it won’t obscure the content.

  1. /* define styles for dockable comment in normal state */
  2. div#dockableComment {
  3. width: 32em;
  4. padding: 0.5em;
  5. border: 3px double #f5f5eb;
  6. background-color: #f5f5eb;
  7. }
  8. /* define style for outlined state */
  9. div#dockableComment.outlined {
  10. border: 3px double #ddd;
  11. }
  12. /* define styles for docked state */
  13. div#dockableComment.docked {
  14. padding: 0.5em;
  15. border: 3px double #ddd;
  16. background-color: #f5f5eb;
  17. position: fixed;
  18. top: 1em;
  19. left: 1em;
  20. z-index: 100;
  21. }
  22. /* feed this style to Opera */
  23. div#dockableComment.docked {
  24. width: 64%;
  25. }
  26. /* feed this style to Gecko based browsers */
  27. /* uses attribute selectors to look for the class of docked */
  28. div#dockableComment[class$=”docked”] {
  29. width: 32%;
  30. }
  31. * html div#dockableComment.docked {
  32. width: 68%;
  33. }
  34. div#dockableComment.docked textarea {
  35. width: 96%;
  36. border: 1px solid #aaa;
  37. }
  38. span#dockcontrol {
  39. float: right;
  40. }
  41. /* modify styles for Live Preview */
  42. div#dockableComment.docked #TextDisplay {
  43. width: 96%;
  44. height: 20em;
  45. overflow: auto;
  46. }
  47. /* override some styles for IE */
  48. * html div#dockableComment {
  49. position: static;
  50. }
  51. * html div#dockableComment.docked {
  52. position: absolute;
  53. }

The JavaScript

The final component to add is the JavaScript that controls the changes of state. Again, I wanted to make sure that everything still works when JavaScript is off, or unsupported. I won’t go through line by line, but here are the basics:

First, I want to add an event so that the script runs when the page loads – I used Scott Andrew’s addEvent script. I also need a reference to the dockable comment div that I created.

  1. addEvent(window, “load”, dockable_init);
  2. var dockable = document.getElementById(‘dockableComment’);

This calls the function dockable_init on page load, so now I need to define that function:

  1. function dockable_init() {
  2. if (!document.getElementById) return;
  3. var dockcontrol = document.getElementById(‘dockcontrol’);
  4. if (!dockable || !dockcontrol) return;
  5. var docklink = dockcontrol.appendChild(document.createElement(‘a’));
  6. docklink.href=”#commentform”;
  7. var docktext = docklink.appendChild(document.createTextNode(‘Dock Comment’));
  8. docklink.onclick = function() {
  9. if (!/docked/i.exec(dockable.className)) {
  10. dockable.className += ” docked”;
  11. docktext.nodeValue = “Undock Comment”;
  12. } else {
  13. dockable.className = dockable.className.replace(/docked/g, “”);
  14. docktext.nodeValue = “Dock Comment”;
  15. }
  16. }
  17. }

There are a number of basic points to note in this function:

  • Line 2 of the function uses DOM capability detection rather than old school DHTML browser sniffing. The code if (!document.getElementById) return; basically says, if the browser doesn’t support document.getElementById, leave the function.
  • Line 3 of the function gets a reference to our dock control – where we will dynamically add a link with an href so that we have a link that toggles the state of our dockable comment (seen in lines 7, 8 and 9).
  • Line 4 is a safety net: if (!dockable || !dockcontrol) return; If we don’t have a reference to either our control or our dockable comment div, we return and go no further.
  • on line 11 we define our function to respond to the click on the dock control link we created with docklink.onclick = function() {

Lines 12 through 18 perform most of the work that needs to be done to switch state, simply by changing the class of the dockable comment div:

  • Line 12: if (!/docked/i.exec(dockable.className)) { uses the regular expression engine to see if the class “docked” is found anywhere in the className DOM attribute of the dockable comment div. Note that the DOM attribute className gives you a string that lists the current CSS classes that are defined for that node. This line basically says that if it isn’t already docked, execute the next few lines of code.
  • Line 13: dockable.className += " docked"; This appends the string ” docked” to any current classes that already exist for the dockable div. You could also use dockable.className = "docked";, but I prefer to append the class so that you don’t completely override other classes that may be defined on that div now, or in the future.
  • Line 14 and 17: toggles the text in the dockcontrol link between “Undock Comment” and “Dock Comment”
  • Line 16: in the other case (i.e., when the div is already docked and we want to undock it), instead of simply changing the className to be nothing to return to the normal state, we use the regular expression engine again to replace any instances of “docked” with the empty string “”. Again, I prefer this so that we can maintain any existing classes that we’ve added to that div with other scripts.

That’s it for the basic script. The final script includes the ability to toggle to an “outlined” state by adding the following to the dockable_init function, using the same principles as above. This state occurs when you mouseover or focus on the “Dock Comment” control link. Note the filter that only turns on the outline state when the comment isn’t already docked:

  1. docklink.onmouseover = function() {
  2. if (/docked/i.exec(dockable.className)) return;
  3. dockable.className += ” outlined”;
  4. }
  5. docklink.onmouseout = function() {
  6. if (/docked/i.exec(dockable.className)) return;
  7. dockable.className = dockable.className.replace(/outlined/g,””);
  8. }
  9. docklink.onfocus = docklink.onmouseover;
  10. docklink.onblur = docklink.onmouseout;

Finally, I added support for IE since it doesn’t support position: fixed. (C’mon – after I wrote those Browser Elitism articles, you couldn’t possibly have thought I’d leave IE out, could you?) I did this with a function that gets called using the addEvent script again.

  1. addEvent(window, “scroll”, calcIEPosition);

And then the calcIEPosition function itself. Note that I’m not 100% sure I like it yet – it isn’t smooth for in IE, and it uses a DOM based filter that I haven’t fully investigated yet, but that I found a while ago. Note that line 2 in the listing below starts a try {...} catch () {...} structure that returns if the DOM function getComputedStyle is not supported. IE doesn’t support it and better browsers do. So, if I get into the catch portion of the structure, I can calculate the offset amount that the IE user has scrolled and position the dockable comment div accordingly.

  1. function calcIEPosition() {
  2. try {
  3. if (getComputedStyle) return;
  4. } catch (e) {
  5. if( document.documentElement) {
  6. topY = document.documentElement.scrollTop;
  7. } else {
  8. return;
  9. }
  10. dockable.style.top = topY;
  11. }
  12. }

Not quite finished

Here is the final version of the script – feel free to use it and/or modify it as you wish. I would appreciate a link back or attribution in the comment of your script, but I won’t require it.

I’m not quite done with it yet, as I’m sure I’ll find some other things that I want to tweak, but there it is – a dockable comment that hopefully makes commenting on blog posts easier.

64 Responses »

Comment by goodwitch — May 23 2005 @ 9:31 pm

Perfect post to add dockable comments to, D. Thanks for sharing your new toy with us all.

Comment by Andrew K — May 23 2005 @ 10:41 pm

Nice!

Few small complaints:
1) Opera — doesn’t look real flash :\ (v.8)
2) Usability concern — If the ‘name’ and ’email’ fields are empty, it would be nice if the docked comment box contained a friendly reminder that there are required fields that are still empty.

Normally I wouldn’t have bothered with number two, but I’d expect you to make the same comment if the roles were reversed ;)

Comment by Sam — May 23 2005 @ 11:03 pm

When I UnDock my comment in Safari 2.0 the Dock Comment box lands on top of the Name Email & URI form fields. I had to refresh the page to fix this and fill it out.

Worked fine in Firefox OSX when I checked a minute ago!

Comment by Derek Featherstone — May 23 2005 @ 11:29 pm

@Glenda: no problem! I’m happy to share…

@Andrew: Opera should be ok now – I added a CSS filter to accomodate the way that it calculates the width of the dockable div. It seemed to be calculating it based on the width of the content div (IE does the same) on the right side whereas Gecko calculates it correctly based on the width of the document.

And, point taken about the required fields. I’ll add that in soon enough.

@Sam: Unfortunately, I’m without Safari as I’m not on a Mac (though soon hope to be). If you have any insight as to why it might be doing that, I’d appreciate it as I’d love to squash any bugs that are in there.

Comment by Jonathan Snook — May 23 2005 @ 11:37 pm

fixed comments are hot! ;) I like how large your comment area is.

Comment by John Oxton — May 24 2005 @ 2:19 am

This is a great addition, might have to pinch this little baby for my own site.

Thanks for sharing Derek :)

Comment by Matthew Pennell — May 24 2005 @ 3:11 am

Very, very nice – and a great evolution of Jonathan’s (scrolls back up to check he’s spelled Jonathan correctly) fixed comment form.

I’ll take this opportunity to predict what the next step in comments development will be – truly ‘live preview’ using Ajax to fill in comments on the site as they are made…

Comment by Conánn — May 24 2005 @ 3:17 am

It’s a beautiful thing! thanks for sharing.

Comment by Jonathan Snook — May 24 2005 @ 6:05 am

Matthew: oh, I already thought of that! :) but the implementation seemed like it might be off because I’d also have to take into account other users posting comments at the same time and having those reflected more in “real time”… what would be freaky would be seeing new comments pop in while you’re typing.

Comment by Jesse — May 24 2005 @ 7:59 am

Safari problems aside… very cool. Although if you scroll to the top the left side stuff looks a little funny. Maybe hide the left stuff when you dock the comment?

When you ordering that PB? ;)

Comment by Stuart — May 24 2005 @ 1:42 pm

Nice work – might use this myself at some point.

Comment by shane — May 24 2005 @ 1:46 pm

VERY Cool!!

Comment by brian — May 24 2005 @ 2:25 pm

Hi, just learning

Comment by nevermore — May 24 2005 @ 2:38 pm

does not work with safari…so i dont like ;)

Comment by Roger Johansson — May 24 2005 @ 3:56 pm

Very neat, Derek! I had a look at the Safari problem but didn’t find a workaround. If you resize the browser window after undocking the comment it snaps into position, so it isn’t completely broken.

Comment by porneL — May 24 2005 @ 4:06 pm

Fantastic idea. First good use of position:fixed I’ve seen :D

Comment by Bosstimer — May 24 2005 @ 4:55 pm

I just want to see WTF this does.

Comment by Bo Randahl — May 24 2005 @ 5:10 pm

Hejsan och hoppsan trallala

Comment by steve — May 24 2005 @ 6:12 pm

hello world

Comment by catogeorge — May 24 2005 @ 8:18 pm

test

Comment by Dave — May 24 2005 @ 9:52 pm

well, let’s see: how does this work??

mmhh, KEWL! ;-)

Comment by Adam Bramwell — May 24 2005 @ 11:05 pm

What a great bit of functionality, this’d be hella useful on some of the web forums I frequent..

Comment by DAvid — May 25 2005 @ 3:04 am

ŽluÃ…Â¥oučký kůň úpÄ›l ďábelské ódy.

Comment by swwet — May 25 2005 @ 6:50 am

OK so there we were

Comment by Pat Crenshaw — May 25 2005 @ 9:35 am

Just what do you think you’re doing?

Comment by brian — May 25 2005 @ 10:12 am

hmmm lets see what this does. wow even has the preview part. muy bueno

Comment by Stephen — May 25 2005 @ 10:53 am

This tool is great..thanks a lot for sharing with us.

Comment by jakob — May 25 2005 @ 11:32 am

sounds nice…well see..

woha…nice work! And its useful!!

Comment by Shawn Grimes — May 25 2005 @ 11:43 am

Wow, this is pretty neat. Nice work Derek.

Comment by Nate Cavanaugh — May 25 2005 @ 12:23 pm

Just testing this :) Sorry for the spam :D

Comment by izmier — May 25 2005 @ 12:54 pm

You cool tool, thnaks for that, will trie it in my upcoming blog.

Comment by Thibaut — May 25 2005 @ 1:43 pm

nice idea !

preview doesn’t wrap text, but does it wraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaap
when submitted ?

Comment by Thibaut — May 25 2005 @ 1:44 pm

oups, sorry for the layout explosion ;)

Comment by kdys — May 25 2005 @ 2:24 pm

Just testing…

Comment by Geoffrey Long — May 25 2005 @ 8:17 pm

Testing, testing. One two, one two. Sibilance. Sibilance.

Comment by chris — May 25 2005 @ 11:51 pm

testasdfasdfasdfasdfasf

Comment by Adrian Agafitei — May 26 2005 @ 4:37 am

You have a nice tool here. I would like to use it in the future. Now I have to find a place where to put it :)

Comment by laboratik — May 26 2005 @ 6:55 am

just wanna test this out :-)

Kinda nice and clean site by the way
love it

Comment by ai — May 27 2005 @ 3:12 am

testies in bold

Comment by Nick Toye — May 27 2005 @ 3:43 am

Its the future…i’ve been there and seen it

Comment by okke — May 27 2005 @ 3:56 am

just testing it, hey, this is nice. :-)

Comment by Roan Lavery — May 27 2005 @ 4:24 am

Impressive results.

Seems like there’s so much intersting stuff around at the minute!

Comment by dsdsdsd — May 27 2005 @ 5:30 am

just testing

Comment by Nick — May 27 2005 @ 10:10 am

Blah blah blah! I’m a — live preview thingy. *this* isn’t bold. Is this? Yup. What about _italics_ hm. Nothing. This worked though. Cool.

The only thing I’m not a fan of is that the name, email, url fields don’t “dock” too. A trivial problem certainly, but I know I started typing here before I filled out my comment’s metadata.

Great concept Derek.

Comment by Andrew K — May 27 2005 @ 6:21 pm

Consider your concept appropriated
Basecamp Comment Controls. :)

Comment by Petrosky Sablevetch — May 27 2005 @ 11:46 pm

what is that at the bottom of my screen…argh!

Comment by Petrosky Sablevetch — May 27 2005 @ 11:47 pm

oh, I get it…very nice indeed!

Comment by Michael — May 28 2005 @ 3:27 pm

Here is my comment.

Comment by Jeff Wheeler — May 30 2005 @ 1:39 pm

I think what would be the coolest, is to allow an arrow pointing to where the comment will be placed, and then allow comments in specific parts of the post.

For example, let’s say I’m commenting on the section titled ‘The Javascript.’ A pointer on the side of the comment dock would tell me I was at that point, and I would type my comment. Then, when other people viewed my comment, it would be placed in a third column next to the ‘The Javascript.’

This would obviously be much more javascript, and much harder, but it’d be cool nonetheless.

Also, I think the name, email, and URI should be docked as well. People forget to fill those out otherwise.

Comment by manju — May 31 2005 @ 2:42 am

Cool function

Comment by Peter — May 31 2005 @ 3:32 am

This is just a test I write

well, let's see: how does this work??

Comment by Peter — May 31 2005 @ 3:33 am

Now try it docked ….

Comment by fred — May 31 2005 @ 11:03 am

testing, umm yeah not sure its all that usefull, but nice bit of scripting.

Comment by John — May 31 2005 @ 12:59 pm

Testing 1 2 3

Comment by William Gates — May 31 2005 @ 10:41 pm

Hmm, I really like the site

Comment by Faruk Ateş¸ — Jun 03 2005 @ 9:01 am

Nice additional flexibility for Snook’s concept, which I saw a while ago. Very nice! :)

Comment by Tony B — Jun 07 2005 @ 4:16 pm

Hello

Comment by Tom — Jun 07 2005 @ 8:02 pm

Dum Dum Dum, test, works good

Comment by asdf — Jul 30 2005 @ 11:55 am

Xczcv

Comment by Rob Cottingham — Jul 30 2005 @ 4:13 pm

Hey… that’s brilliant. Congratulations.

Comment by Trond — Aug 17 2005 @ 7:28 am

haha.. awesome.
Very handy tool

Comment by Rob Lewis — Aug 21 2005 @ 12:36 pm

Brilliant! Works beautifully!

Rob

Comment by Taniec — Aug 22 2005 @ 4:20 pm

This is great :)

Comment by yury — Aug 27 2005 @ 5:44 am

nice development, maybe i try it on my next project

Comments are closed.