Putting functionality back into

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
In "the other place" Jukka has pointed out that semantically <blockquote/>
is useless in many browsers, so I'm experimenting with Javascript to put
some functionality back into <blockquote/>.

The basic idea is to use Javascript to pop up a small link to the
blockquote's cite attribute on hover.

You can see what I have so far here:


There are two things that still need fixing though, and that is where all
you lovely people come in, as I sadly don't have the JS knowledge to fix
it on my own.

1. When the "cite" text is hovered over, the link goes invisible. The link
still works, but this is certainly not desirable behaviour. I believe it
has to do with event bubbling. Any ideas?

2. I need a way to attach the bqHover and bqHoverOut functions to the
blockquote without using the onmouseover and onmouseout HTML attributes so
that all the JS can go in one external script file. I think
addEventListener comes into play here, but I don't know very much about
that and have never gotten such things to work in anything besides Gecko.
Ideally I'd want a solution that works in IE6/Win, Gecko and Opera 7.
Konqueror, Safari and IE5 for Windows and/or Mac would be a bonus. But
I'll take what I can get.

Thanks in advance for any light you can shed onto the matter.

Toby A Inkster BSc (Hons) ARCS
Contact Me - http://www.goddamn.co.uk/tobyink/?page=132

Re: Putting functionality back into

Toby A Inkster wrote:

Quoted text here. Click to load it

I'm not well-versed in HTML subtleties, but according to the HTML
reference, BLOCKQUOTE elements only offer a "cite" attribute, aside of
the ones defined by the %attrs; entity. Since you're likely to want to
precise source, date, author etc, ISTM that blockquote cannot be
particularly enhanced, you'd indeed use a larger structure most of the
time (for instance a DIV as a container and other tags for other

The enhancement you want to set up is probably the only logical one
(apart from working with extended DTD), although I think that having the
link already existing as part of an additional tag would probably be
safer (for instance you position your link relatively to the top-left
blockquote point, but what if the quotation needs scrolling?).

Quoted text here. Click to load it

That's correct, moving into an inner element fires the mouseout event of
the outer element, then the event mouseover event is fired from the
inner element and bubbles to the outer element; each time the
appropriate handlers being triggered.

You can manage this issue by studying the origin/direction of the event
and taking adapted decision (or using mouseenter-mouseleave non-standard

Quoted text here. Click to load it

You can always define mouseover/mouseout handlers outside of the tag
declaration, using a reference to the element, so that's not a problem.
Alternatively, you could also set up some kind of mousemove conception,
though this would be more complex to manage.

"addEventListener" is a way to define a handler, it is useful when you
want to set up many listeners to the object (and for the sort of script
you want to design it would indeed make sense to use addEventListener
and IE's attachEvent methods - I prefer using a specific function for
that, though).

Here's a simple example of what you're asking; tested IE6, Mozilla 1.5,
Opera 7 - you might surprisingly experience flickering with IE if you
include several block-level elements in the blockquote - I think that
nothing can be done about that. All the script part can be safely
inserted as a js include if needed.

<script type="text/javascript">

   var CITE_VALUE="Jump!";
   var CITE_CLASS="jsCite";

   function _e(obj, evt, func) {
     if(obj[evt]) {
       obj[evt]=(function(originalHandler) {
         return function () {
           func.apply(obj, arguments);
           return originalHandler.apply(obj, arguments);
     } else

   function contains(container, containee) {
     if(container.contains) {
       return container.contains(containee);
     } else {
       while(containee && containee!=container)
       return !!containee;

   function mover (evt) {
     var related=evt.fromElement||evt.relatedTarget;
     if(related) {
       if(!contains(this, related)) {
         Cite.define(this.citeObject, this);

   function mout(evt){
     var related=evt.toElement||evt.relatedTarget;
     if(related) {
       if(!contains(this, related)) {
         Cite.define(this.citeObject, this);

   var Cite = (function() {
     var $child, $parent;
     return {
       define:function(child, parent){
         if(!child) {
           var a, c, d=document;
           if((c=parent.getAttribute("cite"))!="") {
         if($child && $parent)

   if(typeof Function!="undefined" &&
      Function.prototype &&
      Function.prototype.apply) {
     _e(window, "onload",
         var d=document;
         if(d && d.body && d.createElement && d.body.appendChild &&
            typeof d.body.parentNode!="undefined" &&
            d.getElementsByTagName) {

           var bq=d.getElementsByTagName("blockquote");
           for(var ii=0; ii<bq.length; ii++) {
             _e(bq[ii], "onmouseover", mover);
             _e(bq[ii], "onmouseout", mout);


<style type="text/css">
   blockquote {
     position: relative;
     margin-left:0; padding-left:4em;
   blockquote .jsCite {
     font-size: 85%;
     position: absolute;    top: 0;    left: 0;
     padding: 1px;
     border: 1px dotted black;

<blockquote cite="hello.html">


Re: Putting functionality back into

Quoted text here. Click to load it

Knowing your interest in such things, you might like to know that I
recently did a speed test of:-

var boolValue = !!x;

- against -

var boolValue = Boolean(x);

- (both executed in the context of a global function) and
type-converting to boolean by calling the Boolean constructor as a
function outperformed the double NOT operation by about a factor of 4
(with the usual browser variations). Unfortunately they are not directly
comparable operations, as the scope resolution of - Boolean - as an
identifier would influence the results. With a long scope chain the
extra work in the resolution of the identifier might swing the
performance of the forced type-conversion back in favour of double NOT.

Quoted text here. Click to load it

I was a little surprised not to see an explicit test for
d.body.removeChild among those.  ;-)


Re: Putting functionality back into

Richard Cornford wrote:

Quoted text here. Click to load it


Quoted text here. Click to load it

I believe that according to Ecma, this would make sense, although the
implementation of Boolean isn't described (it is just said it should
call toBoolean).

Ah! but now I'm quite confused with the following simple test case here,
which gives opposite results on my WinXP/PIII450:

        IE6        Mozilla1.5    Opera7.23
Using Boolean    3265        650        1372    
using !!    2584        271        1062

<textarea id="results" rows="10" cols="60"></textarea>
<script type="text/javascript">
function test(){
   var d1, d2, d3, b;

   d1=new Date();
   for(var ii=0; ii<100000; ii++)
   d2=new Date();
   for(var k=0; k<100000; k++)
   d3=new Date();

     "Boolean:"+(d2-d1)+"    !!:"+(d3-d2)+"\n";


What do I miss?

Quoted text here. Click to load it

Argh! You're right of course, this test is absolutely required here - it
seems I tend to be dreaming too much when finishing writing scripts:-)


Re: Putting functionality back into

Quoted text here. Click to load it
Quoted text here. Click to load it

Probably a mistake in my test script. I cannot find it now, which is odd
because I keep all my seed test scripts together (I also cannot find a
similar test comparing concatenation with the String constructor when
forcing type-conversion to a string). But I recreated the script and got
opposite results, specifically double NOT outperformed the Boolean
constructor (by a factor of 10 this time). Sorry for being misleading.


Site Timeline