Retrieving html control by specifying coordinates - javascript

How can I get the id of a html control just by specifying the coordinates of a triggered event (like onmousedown, onmouseup, onclick, etc..). the coordinates can be got by:
e.clientX , e.clientY where e is the event object.
The idea is to get the id of control on which a click event is done without having any onClick event in that control's definition.
This will dispense the need of specifying the onClick event for multiple controls.

I do not believe that this is possible, but fortunately (if I understand your requirements correctly) you do not need to:
If you want to get the HTML element where a user clicked, without specifying a click event handler on each element, simply specify a click handler on a top level element (one that contains all the other interesting elements - maybe even "document"), and then look at the MouseEvent's target property - it will specify the HTML element that received the click initially and not the element where you specified the onclick event handler (this can be gotten to simply by using the "this" keyword).
If you have firebug, try this out in your firebug console right here on StackOverflow:
document.getElementById('question').onclick = function(e) {
var target = window.event?window.event.srcElement:e.target;
alert("Got click: " + target);
}
Then click anywhere on your question text to get an alert with the correct HTML element :-) .

This is a very good question, lets suppose the function we are looking for is something like this:
document.elementFromPoint = function(x,y) { return element; };
This obscure function is actually implemented in Firefox 3.0 using the gecko layout engine.
https://developer.mozilla.org/en/DOM/document.elementFromPoint
It doesn't work anywhere else though. You could build this function yourself though:
document.elementFromPoint = function(x,y) {
// Scan through every single HTML element
var allElements = document.getElementsByTagName("*");
for( var i = 0, l = allElements.length; i < l; i++ ) {
// If the element contains the coordinate then we found an element:
if( getShape(allElements[i]).containsCoord(x,y) ) {
return allElements[i];
}
}
return document.body;
};
That would be very slow, however, it could potentially work! If you were looking for something like this to make your HTML code faster then find something else instead...
Basically what that does is it goes through every single HTML element there is in the document and tries to find one which contains the coordinate. We can get the shape of an HTML element by using element.offsetTop and element.offsetWidth.
I might find myself using something like this someday. This could be useful if you want to make something universal across the entire document. Like a tooltip system that works anywhere, or a system that launches context menus at any left click. It would be preferable to find some way to cache the results of getShape on the HTML element...

this will dispense the need of specifying the onClick event for multiple controls.
If this is your only goal, I suggest using jQuery to elegantly specify event handlers on multiple elements.
This one of examples from jQuery tutorial that does exactly this:
$(document).ready(function() {
$("a[href*=/content/gallery]").click(function() {
// do something with all links that point somewhere to /content/gallery
});
})

When your HTML page renders positions of various elements will be derived dynamically by the rendering engine of your browser. The only elements which can reliably be tested for their resulting layout properties are images.
To do what you want, therefore, you would need to use absolute positioning for all your elements and have a page map stored elsewhere to tie up controls to locations. This would be way too complicated I think!
Although it contradicts your question somewhat, you should, via javascript or server side, attach onclick events to your controls. Sorry!

You don't actually need the position. What you need is the target property of the event object. I don't know how this is handled in jQuery but here's a quick example inspired from the above resource:
JavaScript
<script type="text/javascript">
window.onload = function() {
document.body.onclick = function(event) {
alert(event.target.id);
}
}
</script>
CSS
div {
width: 200px;
height: 200px;
margin: 30px;
background: red;
}
HTML
<div id="first-div"></div>
<div id="second-div"></div>

Related

Need to get first child a and create a click event with the result

I am trying to create a JavaScript program that looks through a DOM to find the first <a href> which is NOT a mailto: - it needs to be a 'real link' and return the href value. I then need the to create a click event with the result.
What I need it for is an HTML encapsulating the author stuff of a post.
This needs to be clickable - but without using the onclick in the markup.
It needs to be an event - invisible in the HTML markup.
The wrapping section should also be clickable, but not be affected by whatever happens in what I described above.
Markup is this:
<section>
<figure>
<img>
</figure>
<div>
<h2>
<p>
</p>
</div>
</section>
/* EDIT */
OK found this.
function (a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,a‌​rguments):b}
This is the string i get in the Event window in FireBug from the site I'm trying to get this function from. Does anybody understand this? That string is what makes it work. I've just copied the entire js over and it works on my site. But I would like to isolate this particular function since the original file is huge. Anyone?
http://jsfiddle.net/LrgQH/
var links = document.getElementsByTagName('a');
var link, i;
for(i=0; i<links.length; i++) {
link = links[i];
if (link.href.indexOf('mailto:') !== 0) {
break;
}
}
link.onclick = function(e) {
alert('allo');
}
Vanilla JS should work anywhere.
Edit:
http://jsfiddle.net/LrgQH/2/
This should do it, and you'll have to prevent other links to work but it's getting complicated. Keep in mind that in Javascript the event system works by bubbling. The most deep object will get the click event, and then if it can handle it, it will handle it. When handling the event, it can prevent it to go further and the event will not propagate further. If it decide not to block the event, it will go to the parent element and so on until it reaches the HTML element.
If the element cannot handle an event, it will go to the parent automatically until if finds one element that can handle the event. If no element can handle the event, then it will not get handled. I suggest you to read more about it on the w3c website.
http://www.w3schools.com/

Properly tidying up a jQuery Dialog

I hit a problem when using jQuery's Dialog widget...
I have a solution, but wondered if there was a more standard way (or I had mis-understood something):
Background
I have a web site that makes heavy use of AJAX, in that most of the time only portions of the page are updated. One portion of the page contains some JS that opens a dialog. When flipping between that portion and another, on opening the dialog for a second time things get messed up.
Reason
$el.dialog() removes the DOM element that is to become the popup ($el[0]) from its original place in the document hierarchy and appends it to the document body instead. When I then remove the popup element's original parent element, the popup element doesn't get removed.
This then means that doing this (changing / removing that portion of the page and then changing it back) all again results in duplicate element IDs which unsurprisingly confuses the hell out of the dialog widget.
Solution
I have come up with a solution that overrides the $.fn.dialog function and makes use of jQuery special events. It attaches a listener to the custom event 'destroyed' on the original parent element, the 'destroyed' event is triggered when jQuery removes any element, the listener reacts to this event by removing the popup element wherever it now might be in the document heirarchy.
Here it is:
(function($) {
$.event.special.destroyed = {
remove: function(o) {
if (o.handler) {
o.handler.apply(this, arguments);
}
}
};
var originalDialogFn = $.fn.dialog;
$.fn.dialog = function(firstArg) {
if (!this.data('dialog') && firstArg != 'destroy' && !this.data('dialogCleaner')) {
this.data('dialogCleaner', true);
var $parent = this.parent();
var $dialogEl = this;
$parent.bind('destroyed', function(e) {
if (this == $parent.get(0)) {
$dialogEl.remove();
}
});
}
return originalDialogFn.apply(this, arguments);
};
})(jQuery);
Are there any better ways of doing this? It seems like a slight flaw in the way the jQuery dialog works, in that it's not that easy to tidy it up nice and generically.
Of course I am aware of the dialog('destroy') method but doesn't seem particularly easy to hook that into my page fragment/portion handling.
You could do what I do in these situations. Capture the parent element prior to making the dialog and then, after the dialog is created, detach it from the DOM and re-append it back to the parent element.
var dlg = $('selector.dialog'),
dlgParent = dlg.parent();
dlgParent.append(dlg.dialog().detach());
This works especially well when dealing with ASPX forms (because any server-side tags that I need to get a postback value from must remain within the form).

How to stop event propagation from within an anchor's href attribute without using onclick or onmousedown

Due to restrictions, even though it is something i avoid altogether, in a certain situation i have to use the javascript: syntax in a href attribute of an achor tag.
(EXPLANATION: In my CMS i use a rich text editor to allow the user to make changes to text elements, including links. In some cases specific javascript: calls are required and i banned onclick completely from the link editing features (to simplify the process for the user). However, as one of the links appears within a block that reacts to an onclick event, the thing double-fires)
Like this:
My problem is that this link is inside a container that already reacts to an onclick event. Therefore i wanted to pass the event object along to the doSomething() method, so that i could then use jQuery's
event.stopPropagation()
method.
Unfortunately however, it seems that passing the event object along
does not seem to work at all. Safari won't say anything while Firefox will report ReferenceError: event is not defined
I assume that this is the case because href="" is not a script-initiating attribute (such as onclick). The problem is that in this situation i won't be able to access the tag beyond what i already do.
Therefore i either need
1.) A way to pass the event object to the doSomething() function from within the href attribute
or
2.) A way to stop the event propagation right in that anchor (after its clicked) by other means.
Thank You for any constructive input!
You cannot stop event propagation from the href attribute because:
When the href code executes, it is not an event. It just executes that code, similar to the "location hack". Like entering javascript:doSomething() in the browser's address bar.
The href code executes after the events fire on the link -- including bubbling.
You can see that behavior in this jsFiddle. Note that mouseup, mousedown, and click all fire both for the link, and on the container when the link is clicked, before the href code executes.
If there are event listeners that you want to block, you'll have to find another way.
But, if you can append javascript to the document you can block the href using preventDefault().
For example:
jQuery, before version 1.7:
$("#container a").bind ("mousedown mouseup click", function (e) {
e.preventDefault();
} );
jQuery 1.7 and later:
$("#container a").on ("mousedown mouseup click", function (e) {
e.preventDefault();
} );
or (better):
$("#container").on ("mousedown mouseup click", "a", function (e) {
e.preventDefault();
} );
You can see this last version live at jsFiddle.
If you cannot alter the link itself (to use onclick) then your only option is to alter the onclick handler of the container.
Can you do something like
function containerClickHandler(e) {
e = e || event;
var el = e.target || e.srcElement;
if (el.nodeName === 'A' && someOtherMatchChecks) {
// eat event
}
else {
// process event
}
}
Well, this is an old question, but in my particular case I did find a hack around it, but it might only apply to a subset of situations. I have a div that has an onclick. But if an inside that div is clicked, I don't want that div's onclick to fire. Here is what I do:
function myOnClick () {
// loop over all <a>'s, and test if they are hovered over right now.
var allLinks = document.links;
var dont = 0;
for (var i = 0, n = allLinks.length; i < n; i++) {
// pure javascript test to see if element is hovered.
if(allLinks[i].parentElement.querySelector(":hover") === allLinks[i]) {dont = 1; }
};
if(dont)return;
// your stuff here, only fires when dont is false.
}
I learned about the queryselector trick here: https://stackoverflow.com/a/14800287/2295722
I don't know if there is a way to get the arguments if you write your javascript in href attribute. But you can get it as following in onclick, but as you say this isn't the best practice:
<a onclick="console.log(arguments)">your link</a>
in arguments array you'll get your event object.
here is a demo for you:
http://jsfiddle.net/tEw5J/1/

Setting default onclick behavior for <img> tag in generated html

So i have a web app I have been building, and I receive generated html from a server for a post, and place it within the body. My question is: is there a way to set a default onclick behavior for the tag within that message? I'd rather avoid parsing through the html and setting behavior for each tag. I may just be having a brain fart but felt its best just to ask. The goal behind this is to enable a card switch to full screen the image. I just cant figure out how to set the click behavior. Thanks in advance.
Most js libraries have a binding service function...
in extJS it's apparently
Ext.select('img').on('click', function);
Use a css selector in place of 'img', and you can do images with a certain class, or of a certain ID, or really whatever you like.
Documentation
You can use an Ext JS component to do this. Any number of the Ext components will work this way but the base Component is all that is needed.
Once the server returns the html data, use the Component's update method. Bind to the click event of the Component's html element and then any html element that is clicked inside of the component will fire the click event. Within the function bound to the event, the event object will be available and will tell you what was clicked.
Ext.onReady(function() {
var htmlContainer,
htmlFromServer;
/*
* you can create a component that will be
* be used to set the html into the page
* while allowing it to be managed from Ext JS
*/
htmlContainer = Ext.create('Ext.Component', {
renderTo: Ext.getBody(),
width: 400,
height: 400
});
/*
* this would be html from your service call
* this is just a simplified example
*/
htmlFromServer = '<div>Click this Div and this will be the event target. Click the image and that will be the value of the event target.</div><img src="http://www.sencha.com/img/apple-touch-icon.png" /><span>And this is some span-wrapped content.</span>';
/* update the component with the html you want it to contain */
htmlContainer.update(htmlFromServer);
/* bind to the click event of the components html element */
htmlContainer.getEl().on('click', function (event) { console.log('event object and html element that was clicked:', event, event.target)});
});​
You could do this a number of ways, but if the images you want to add click events to are stored in a center element, retrieve that element(via document.getElementByTagName, byId, byClassName, etc), then you could do the following:
// Create a few variables to help us out
var index = 0,
imgs = centerEle.getElementsByTagName("img"),
eventType = "addEventListener", // Default event listener function
eventPrefix = ""; // default prefix for event names
// IE event model support:
if (!document.hasOwnProperty("addEventListener")) {
eventType = "attachEvent";
eventPrefix = "on";
}
// Loop through images in the central element
for (var a = 0; a < imgs.length; a += 1) {
/* if you wanted to exclude certain iamges:
if (img[a].src !== "http://somesite.com/img.jpg" &&
img[a].src !== "http://somesite.com/img2.jpg") { */
img[a][eventType](eventPrefix + "click",function(evnt) {
// 'this' is the img
// evnt is the event that was raised
// everything within this function will be called when the image is clicked
});
// }
}
A few notes:
Instead of taking the easy way out, I used an event listener instead of onclick this is because if the element already has a onclick event specified any later specified onclick properties will overwrite the previous one.
Along with using event listeners instead of event properties, I included IE support. This is why I included the eventType and eventPrefix variables
You can get the all the IMGs in your page using document.getElementsByTagName("IMG") or using jquery selector and associate your default click handler with onclick event on each IMG element. (for exact syntax of how to do it with jquery, you can refer to a manual).
I believe this is what jQuery's .live() (< jq 1.7) and .on() (>= jq 1.7) methods are for. You can use this to bind events to elements that do not exist at the time of binding.

Fire jQuery event on div change

I have a div whose content may change in various ways: for instance its whole content may be reloaded via innerHTML, or nodes may be added via DOM methods. This in turn may happen via native Javascript or indirectly via calls the jQuery API or via other libraries.
I want to execute some code when the content of the div changes, but I have absolutely no control on how it will change. Indeed I am designing a widget that may be used by other people, who are free to change the content of their divs the way they prefer. When the inner content of this div changes, the shape of the widget may have to be updated as well.
I'm using jQuery. Is there a way to capture the event that the content of this div has changed, however it happened?
You can use DOMNodeInserted and DOMNodeRemoved to check if elements are added or removed. Unfortunately, IE doesn't support this.
$('#myDiv').bind('DOMNodeInserted DOMNodeRemoved', function(event) {
if (event.type == 'DOMNodeInserted') {
alert('Content added! Current content:' + '\n\n' + this.innerHTML);
} else {
alert('Content removed! Current content:' + '\n\n' + this.innerHTML);
}
});
Update
You could save the initial contents and future changes with .data(). Here's an example.
var div_eTypes = [],
div_changes = [];
$(function() {
$('#myDiv').each(function() {
this['data-initialContents'] = this.innerHTML;
}).bind('DOMNodeInserted DOMNodeRemoved', function(event) {
div_eTypes.concat(e.type.match(/insert|remove/));
div_changes.concat(this.innerHTML);
});
});
Example output:
> $('#myDiv').data('initialContents');
"<h1>Hello, world!</h1><p>This is an example.</p>"
> div_eTypes;
["insert", "insert", "remove"]
> div_changes;
["<iframe src='http://example.com'></iframe>", "<h4>IANA — Example domains</h4><iframe src='http://example.com'></iframe>", "<h4>IANA – Example domains</h4>"]
Update 2
You may want to include DOMSubtreeModified as well, because I've found out that DOMNodeInserted and DOMNodeRemoved don't trigger if an element's innerHTML is replaced directly. It still doesn't work in IE, but at least it works fine in other browsers.
try something like this...
$('#divId').bind('DOMNodeInserted', function(event) {
alert('inserted ' + event.target.nodeName + // new node
' in ' + event.relatedNode.nodeName); // parent
});
IE doesn't support this propert but i think the nearest to this is the propertychange event, which fires in response to a change in an attribute or CSS property of an element, but it doesn't fire in response to innerHTML changing, which would have been close to what you wanted.
one more feasible solution is to override manipulation function of jquery...
Have a look on this discussion..Preferred way of modifying elements that have yet to be created (besides events)
There is no such an event (onChange) in javascript nor jQuery, you would have to create a custom event.
One solution could be using lowpro to attach a behavior in this element you want to be controlled, this behavior would serialize the element and then build a poll that checks every x miliseconds to see if the element has changed, if changed then trigger your custom event on that element.
You have some examples on how to use lowpro with jQuery here:
http://www.learningjquery.com/2008/05/using-low-pro-for-jquery
Good luck!

Categories