Putting functionality back into <blockquote />

T

Toby A Inkster

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:

http://www.goddamn.co.uk/tobyink/scratch/bq

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.
 
Y

Yann-Erwan Perio

Toby said:
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/>.

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
information).

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?).
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.

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
events).
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,

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">
(function(){

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);
}
})(obj[evt]);
} else
obj[evt]=func;
}

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

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

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

var Cite = (function() {
var $child, $parent;
return {
define:function(child, parent){
if(!child) {
var a, c, d=document;
if((c=parent.getAttribute("cite"))!="") {
a=d.createElement("a");
a.href=c;
a.appendChild(d.createTextNode(CITE_VALUE));
parent.citeObject=d.createElement("span");
parent.citeObject.className=CITE_CLASS;
parent.citeObject.appendChild(a);
child=parent.citeObject;
}
}
$child=child;
$parent=parent;
},
setVisible:function(bVisible){
if($child && $parent)
$parent[(bVisible?"append":"remove")+"Child"]($child);
}
}
})();

if(typeof Function!="undefined" &&
Function.prototype &&
Function.prototype.apply) {
_e(window, "onload",
function(evt){
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);
}

}
}
);
}
})();
</script>

<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;
}
</style>

<blockquote cite="hello.html">
<p>Hello</p>
</blockquote>



HTH
Yep.
 
R

Richard Cornford

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

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.

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

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

Richard.
 
Y

Yann-Erwan Perio

Richard Cornford wrote:

Knowing your interest in such things,
Indeed:)

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).

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++)
b=Boolean(document);
d2=new Date();
for(var k=0; k<100000; k++)
b=!!document;
d3=new Date();

document.getElementById("results").value+=
"Boolean:"+(d2-d1)+" !!:"+(d3-d2)+"\n";
}

test();
</script>


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

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:)


Cheers,
Yep.
 
R

Richard Cornford

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
What do I miss?

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.
<snip>

Richard.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top