Stopping defaults and/or propagation

Noob alert! I was playing around with writing a simple script that would cause a kind of lightbox popup; on clicking a link, a div with several links overlies the page. It’s probably full of bad coding, but at least I got something to work. :slight_smile:

The main problem I had was that, if an overlay link was clicked, it also triggered the closing of the overlay. I played around with preventDefault(), but that didn’t work. Then I stumbled on stopPropagation(), which seems to do the trick.

So here’s what I have so far:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">

<style media="all">
.hide {display: none;}
.view {position: absolute; background: rgba(0,0,0,0.4); text-align: center; top:0; bottom: 0; left: 0; right:0; display: table; width: 100%; height: 100%;}
.view div {display: table-cell; vertical-align: middle;}
#buttons a {display: inline-block; color: white; background: #30353b; text-decoration: none; padding: 10px; border-radius: 10px;}
#buttons a:hover, #buttons a:focus {background: black; color: #e7e7e7;}
#buttons span {display: block; margin-top: 20px; cursor: pointer;}
</style>
</head>
<body>

<p><a id="share" href="#buttons">Share</a></p>

<div id="buttons" class="hide">
	<div>
		<a href="http://facebook.com">Facebook</a>
		<a href="http://twitter.com">Twitter</a>
		<a href="http://google.com">Google</a>

		<span>Exit</span>
	</div>
</div>

<script>
(function () {
	"use strict";
	var d, share, buttons, links, i;
	d = document;
	var share = d.querySelector('#share');
	var buttons = d.querySelector('#buttons');

	share.addEventListener('click', function(event) {
		event.preventDefault();
		buttons.className = 'view';
	}, false);

	buttons.addEventListener('click', function() {
		buttons.className = 'hide';
	}, false);

	links = d.querySelectorAll('#buttons a');
	for(i=0; i<links.length; i++) {
		links[i].addEventListener('click', function(event) {
			event.stopPropagation();
		}, true);
	}
}());
</script>
</body>
</html>

Is there a better way to do this than with stopPropagation()? I don’t really understand what it’s doing, so if anyone can explain, that would be great. And of course, if there’s a better way to go about all this, I’d be happy to know. This is mainly an excuse to learn a bit of JS, although I’m eventually aiming to use this in a project. It’s not an essential feature, so in the end, my plan is to create everything in JS and insert it into the HTML. (If JS is off or doesn’t fire for some other reason, I’d prefer to have nothing in the HTML.)

PS—I’ve purposely left out support for older browsers that don’t understand modern JS. Eventually I’ll add a test for older browsers and just abort the script if they don’t understand it.

I’m too sleepy to study the code sample now, but it sounds like a “bubbling” vs. “capturing” thing.
http://www.quirksmode.org/js/events_order.html
http://api.jquery.com/event.stoppropagation/
https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation

If @paul_wilkins; @felgall; or some other javascript savvy member desn’t solve by the time I get some ZZZZZZZ’s I look into it more.

preventDefault() stops any default action from occurring - for example code triggered by clicking on a link - the default acrion is to go to where ever the href attribute points to. By using preventDefault() you allow the JavaScript to run but without loading the new page specified in the href.

When you trigger an event listener the third parameter specifies whether you want the event processing to occur in capture mode or bubbling mode. With capture mode the processing starts at the body tag and moves inward tag by tag to the one closest to the point in the page where the click occurred. Bubbling mode then moves outward again from that point back out to the body tag. Where calling stopPropagation() comes in is that the capture/bubbling of the event terminates early at the time of that call so that subsequent tags that might have the same event attached to them will not have the code attached to those tags run unless the spot that triggers the event is outside of the tag that has the stopPropogation() in it.

So with the preventDefault() in the first event listener clicking on the link when JavaScript is enabled will not jump to <div id=“buttons”>

The stopPropagation() means that when one of the <a> tags inside of the <div id=“buttons”> is clicked that the event listener handling clicks on that <div> tag will not be run during bubbling because the bubbling will end at the <a> tag where the stopPropogation() is run rather than continuing to run any click event listeners all the way out to the <body> tag (with this code the only such listener is the one on the div tag.

So stopPropogation() as you have it is exactly the right way to achieve that desired result.

Cool, thanks for the explanation, Stephen. There are plenty of lightbox scripts around, but they all seem to use jQuery, so it’s harder to dig in to see how they handle this sort of thing. :slight_smile:

Thanks for your links too, Allan. I’ll check them out.