page level onclick - can I detect nearest word

P

p7eregex

Hi,

I want to install a page level onclick handler that gives me the
nearest displayed word that the mouse was clicked. Is this possible?

Andy
 
T

Thomas 'PointedEars' Lahn

I want to install a page level onclick handler that gives me the
nearest displayed word that the mouse was clicked. Is this possible?

Unlikely. I presume it is at least not possible in every runtime environment.


PointedEars
 
P

p7eregex

Unlikely.  I presume it is at least not possible in every runtime environment.

PointedEars

Can I get the x,y position of the click and walk the DOM to see the
paragraph that contains it, and then approximately infer the word?
 
J

Jeremy J Starcher

Can I get the x,y position of the click and walk the DOM to see the
paragraph that contains it, and then approximately infer the word?

Perhaps if you explained what you are trying to accomplish?

Knowing your goal might help come up with a better route.
 
P

p7eregex

Perhaps if you explained what you are trying to accomplish?

Knowing your goal might help come up with a better route.

I'm trying to insert annotations in a page onclick that are tied to
the word clicked. Will store the annotation in a DB with AJAX.

Andy
 
T

Thomas 'PointedEars' Lahn

Thomas 'PointedEars' Lahn wrote:
I want to install a page level onclick handler that gives me the
nearest displayed word that the mouse was clicked. Is this
possible?

Unlikely. I presume it is at least not possible in every runtime
environment.

[...]

Please trim your quotes to the relevant minimum, don't quote signatures.
And get a real name.
Can I get the x,y position of the click and walk the DOM to see the
paragraph that contains it,

Yes, theoretically. Practically, there are too many variables to
consider, including computed font size and zoom level.

But you don't have to _traverse_ the _document tree_ (the DOM is an API
specification) here because the ‘click’ event bubbles (in all known
DOMs), that is, it is propagated upwards in the document tree by
default. Therefore, a non-capturing event listener added to an ancestor
node of the event target can handle this event for all descendant
(element) nodes:

document.body.addEventListener(
"click",
function(e) {
var t = e.target;
console.log(t.nodeName + ": '" + t.textContent);
},
false);

This is the standards-compliant approach which should work in Gecko-,
WebKit-, and Opera-based browsers (start in console mode or enable
Firebug [Lite]). I recommend you search for "_addEventListener" and
"dhtml.addEventListener" from my dhtml.js in order to get an idea of how
a cross-browser solution could look like.
and then approximately infer the word?

Unlikely. For that, Jeremy's suggestion is your best bet.


HTH

PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
document.body.addEventListener(
"click",
function(e) {
var t = e.target;
console.log(t.nodeName + ": '" + t.textContent);
},
false);

This is the standards-compliant approach [...]

Supplemental:

However, this dynamic aproach (some call that "Unobtrusive JavaScript",
misguidedly), is only ever needed if

A) you don't have access to the markup of the ‘body’ element

or

B) the event does not bubble in all (target) environments.

In all other cases, the following is recommended (and equally
standards-compliant except ‘event') and should suffice (assuming HTML
4.01):

<head>
...
<!-- may be located within the ‘body' element instead -->
<script type="text/javascript">
function bodyClick(e)
{
/* see above */
}
</script>
</head>

<body ... onclick="if (typeof event != 'undefined') bodyClick(event)">
...
</body>


PointedEars
 
M

Martin Honnen

I want to install a page level onclick handler that gives me the
nearest displayed word that the mouse was clicked. Is this possible?

Mozilla exposes properties named rangeParent and rangeOffest, here is an
example for that:
http://home.arcor.de/martin.honnen/javascript/2008/12/test2008122201.html

In that example the click event listener is only set up for a div but
you could of course do that for the body element or the document object
itself if needed.

And it is only an example showing how to use event.rangeParent and
event.rangeOffset, the algorithm for finding a word is far from perfect,
in particular if a word could be marked up by several elements e.g.
<b>f</b<i>oo</i>
then you would need to improve that algorithm to find the word a lot.


With IE you should be able to create a TextRange
http://msdn.microsoft.com/en-us/library/ms535872(VS.85).aspx#
and use moveToPoint() to position it where the user clicked, then you
should be able to expand that range with expand("word") to find a word.
 
M

Martin Honnen

Martin said:
With IE you should be able to create a TextRange
http://msdn.microsoft.com/en-us/library/ms535872(VS.85).aspx#
and use moveToPoint() to position it where the user clicked, then you
should be able to expand that range with expand("word") to find a word.

Here is the previous example updated to work with Mozilla as well as IE:
http://home.arcor.de/martin.honnen/javascript/2009/04/test2009040501.html

Only the behaviour in Mozilla and IE is quite different as the
expand('word') in IE works quite different from what I tried to
implement for Mozilla. With Mozilla if you click white space between
words then no word is found while it seems that expand('word') expands
to the nearest word to the right or left from the white space. On the
other hand the expand('word') in IE works well with clicking inside of
'Kibo' in e.g.
<strong>Kibo</strong>logy
to find the word 'Kibology' while my attempt for Mozilla does not work
for such cases, as already pointed out you would need to improve the
algorithm a lot to cover such cases.
 
G

Garrett Smith

Thomas said:
Thomas said:
document.body.addEventListener(
"click",
function(e) {
var t = e.target;
console.log(t.nodeName + ": '" + t.textContent);
},
false);

This is the standards-compliant approach [...]

Supplemental:

However, this dynamic aproach (some call that "Unobtrusive JavaScript",
misguidedly), is only ever needed if

[...]

Event handler content attributes are best avoided. The use results in
the creation of a function with an augmented scope chain.

The design of a program where the callback exists in one place
(implementation js) and the registration exists in a separate file
(markup) is tight coupling; one type of change can require changing both
files together.
standards-compliant except ‘event') and should suffice (assuming HTML
4.01):

<head>
...
<!-- may be located within the ‘body' element instead -->
<script type="text/javascript">
function bodyClick(e)
{
/* see above */
}
</script>
</head>

<body ... onclick="if (typeof event != 'undefined') bodyClick(event)">
...

Don't do that.

Using onclick in the body element will have different results in
different browsers. This fact was discussed here in recent months.

Give the example a doctype (to trigger standards mode), and a border on
body, and a simple statement inside the bodyClick function:
function bodyClick(e) {
alert(this + ", " + (e.target||e.srcElement));
}

The event handler gets mapped either to the window or to the body
element, depending on the browser and version (and doctype). The
attribute behavior is ambiguous. When the browser sees the event handler
attribute, it must create a function for either window or body. If the
browswer has an event for window, the window gets the event. For
example, all browsers have an onload for window and few have one for the
body element. SOme browsers have an onclick for window and an onclick
for body. Most browsers have an onfocus for window and many of those may
have an onfocus for body element (not to be confused with the body tag).

Garret
 
J

John G Harris

Event handler content attributes are best avoided. The use results in
the creation of a function with an augmented scope chain.

The design of a program where the callback exists in one place
(implementation js) and the registration exists in a separate file
(markup) is tight coupling; one type of change can require changing
both files together.
<snip>

Surely the alternative to a handler attribute requires the HTML element
to have an ID attribute that is known to some javascript code somewhere.
The ID must never, ever change or be removed by mistake. If you remove
an element you have to check that the js code hasn't used that element.
That's even tighter, or at least dodgier, coupling.

John
 
T

Thomas 'PointedEars' Lahn

Garrett Smith said:
Thomas said:
Thomas said:
document.body.addEventListener(
"click",
function(e) {
var t = e.target;
console.log(t.nodeName + ": '" + t.textContent);
},
false);

This is the standards-compliant approach [...]

Supplemental:

However, this dynamic aproach (some call that "Unobtrusive
JavaScript",
misguidedly), is only ever needed if

[...]

Event handler content attributes are best avoided.

Nonsense. We've been over this.
The use results in
the creation of a function with an augmented scope chain.

Correct, but irrelevant since the necessity to consider that fact can be
avoided when using as few properties in the attribute value as possible,
like here. You have been told before.
The design of a program where the callback exists in one place
(implementation js) and the registration exists in a separate file
(markup) is tight coupling; one type of change can require changing
both
files together.

Don't start that stupid "Unobtrusive JavaScript" routine again, it's not
going to work.
Don't do that.
Nonsense.

Using onclick in the body element will have different results in
different browsers.

It will have the same result in all browsers as long as ’this’ is not
used (like here).
This fact was discussed here in recent months.
Give the example a doctype (to trigger standards mode), and a border
on
body, and a simple statement inside the bodyClick function:
function bodyClick(e) {
alert(this + ", " + (e.target||e.srcElement));
}

‘this' is not used in my example, and it is not necessary to solve the
OP's problem.
The event handler gets mapped either to the window or to the body
element, depending on the browser and version (and doctype). The
attribute behavior is ambiguous. When the browser sees the event
handler
attribute, it must create a function for either window or body. If the

browswer has an event for window, the window gets the event. For
example, all browsers have an onload for window and few have one for
the
body element. SOme browsers have an onclick for window and an onclick
for body. Most browsers have an onfocus for window and many of those
may
have an onfocus for body element (not to be confused with the body
tag).

Entirely irrelevant here. And you are confused about the meaning of
‘this’ in functions called from event-handler attributes.


PointedEars
 
P

p7eregex

Entirely irrelevant here. And you are confused about the meaning of
‘this’ in functions called from event-handler attributes.

PointedEars

Thomas, these postings have left me confused. I generate the HTML
from a database and have complete control over the content. Based on
what everyone seems to be saying, I have to wrap every single word
with a handler and or ID. Am I on the wrong track? By the way, I am
a relative Javascript newbie even though I've read the book twice.

Andy
 
P

p7eregex

Entirely irrelevant here. And you are confused about the meaning of
‘this’ in functions called from event-handler attributes.

PointedEars

Thomas, these postings have left me confused. I generate the HTML
from a database and have complete control over the content. Based on
what everyone seems to be saying, I have to wrap every single word
with a handler and or ID. Am I on the wrong track? By the way, I am
a relative Javascript newbie even though I've read the book twice.

Andy
 
G

Garrett Smith

John said:
<snip>

Surely the alternative to a handler attribute requires the HTML element
to have an ID attribute that is known to some javascript code somewhere.
The ID must never, ever change or be removed by mistake. If you remove
an element you have to check that the js code hasn't used that element.
That's even tighter, or at least dodgier, coupling.

Repost. apparently the previously sent message did not get sent, though
my "sent" folder indicates it was (and should have been posted after
2:06 PDT).

document.body works fine and does not require an ID attribute (and you
would not have to worry about removing that element, for obvious reasons).

Obviously, there is no tag for |window|. Something like onload, for
example, would be registerd on BODY and the browser would map the
callback to the window.

Some browsers support mouse events on window. Declaring a body onclick
attribute can result in the creation of an event handler callback on
either the window or the body element (the browser has to make a
decision). Some browsers might fire the callback from anywhere in the
window, others might only fire it from the body element. These some of
the inconsistencies.

You've argued that registering an event without using an handler
attribute requires the HTML element to have an ID attribute, creating
coupling. While the coupling of element id to script might be less
obvious, the argument is based on a false premise that an ID is
necessary to register an event. An element having an ID attribute is not
necessary and may not even be desirable in order to register events
(giving body an ID, for example, would not be necessary). It is
*impossible* to give the document itself an id attribute (no tag). By
registering mouse events on the document, the bubbled event can be
caputured there and the target/srcElement interrogated.

You've argued that if an element is removed, the developer must check to
see if the js has used that element. That is true, any change to a DOM
structure of a web application should be checked. Scripts can reference
many things that are directly related to that element: title, tagName,
className, parentNode, for example.

To me, changing that ID would seem to be a more intentional act than
changing some other parts of the HTML, such as adding a div somewhere.
If an author wants to signify meaning of an element, a meaningful ID can
convey that importance well to other humans (who might be reading that
source).

<span id="eventPickerActuator"
class="panelActuator">choose an event</span>

You have a point that the ID is an abstraction that is not tied to a
script, while an event handler attribute is tied to a script. In that
case, it would require investigation as to what other code (if any)
cared about that ID.

Garrett
 
T

Thomas 'PointedEars' Lahn

[Restored attribution lines]

[Thomas 'PointedEars' Lahn wrote:]
Entirely irrelevant here. And you are confused about the meaning of
‘this’ in functions called from event-handler attributes.

[...]

Thank you for trying to trim to what is relevant. But please include/leave
in an attribution line for each quotation level (because it's relevant).
Please don't quote signatures if you are not explicitly referring to their
content (because they are not relevant then). Please get a real name by
subscribing to the newsgroup (and updating your profile there), or
(recommended) by not using Google Groups for posting but a decent locally
installed newsreader application (e.g., Mozilla Thunderbird or KNode).

Thomas, these postings have left me confused. I generate the HTML from a
database and have complete control over the content. Based on what
everyone seems to be saying, I have to wrap every single word with a
handler and or ID. Am I on the wrong track?

I'm afraid so. Since you have "complete control over the content" and the
`click' event bubbles in all known DOMs, it is unwise of you to add the
listener dynamically (with the element type identifier or the element IDs as
point of reference), to pay (efficiency-wise) for necessary branching for
each `span' element, and to risk its not working properly despite all these
efforts (for several reasons discussed before).

Instead, you should use the event-handler attribute as in my example which
so far is known to work reliably and consistently among browsers/DOMs.
Simply try it out with a <span>word</span> to see how it works. (If you
can't get console.log() to work at first, use window.alert() instead.) Of
course, you need to test the `tagName' property case-insensitively, and you
may use the `class' attribute (and `className' property), so that you only
consider relevant `span' elements.

See also:
<http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow>
<http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-flow>

Please take notice that W3C DOM Level 3 Events is not a Recommendation yet,
but its event flow definition is much the same as in W3C DOM Level 2 Events
which is a REC, and the definition in L3 are easier to understand
(especially for beginners) because of the graphical representation.

These can quickly become complex issues, rather difficult to explain to a
beginner (because of all the technobabble that is needed). Nevertheless, I
shall try to set you on the right track so that the scripts you're going to
write are considerably better than what most of the wannabes on the Web and
in books produce nowadays. To that end, I do hope I could clarify, and not
add to, your confusion :)

(What I mean above is that Garrett is confused as to the meaning of `this'
within the called function in my supplemental, bodyClick(). Since that
function is not an event listener but only *called from* an event listener,
`this' within it refers refers to the Global Object [of which it is a
method] always. However, `this' within the event listener created by the
event-handler attribute value, `onclick', (which does not occur here there)
has different meaning depending on the browser/DOM because the `body'
element has a known peculiarity there.

If you don't understand what all that means, you may, but do not need to,
ignore it for the time being.)
By the way, I am a relative Javascript newbie even though I've read the
book twice.

Which book? Chances are you've read a bad book anyway.


PointedEars
 
J

Jorge

(...) Based on
what everyone seems to be saying, I have to wrap every single word
with a handler and or ID. (...)

You ought to wrap each single word in a single htmlElement because the
target of a click event is an element.

If once you knew the target element you found it contained a hundred
words how would you tell apart the exact word then ?

OTOH, if you prepare the text in such a way that each target(able)
word is an individual element, then as the target element of the click
event contains the target word, you're done.
 
J

Jorge

3 event listeners for each of 298 span elements? You can't be serious.

No, just *one* global click event handler attached to document.body.

The onmouseover/onmousemove/onmouseout handlers aren't needed to
handle the clicks, I've put them there to highlight the words and
update the title in real time.
 
J

Jorge

No, just *one* global click event handler attached to document.body.

The onmouseover/onmousemove/onmouseout handlers aren't needed to
handle the clicks, I've put them there to highlight the words and
update the title in real time.

OTOH, it would be perfectly ok to have 900 event handlers in a page...
why not ?
 

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

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,162
Latest member
GertrudeMa
Top