I think like Flambino mentions, we would be well served by some comments. But here are a few of my observations:
You are using a self-executing anonymous function. This is awesome for encapsulation and fighting memory leaks, so well done IF this is your intended purpose. If the entire contents of the script are meant to be "do this once, bind some events, and then forget about it" then great. But that brings me to #2:
I don't see many opportunities for re-using code here. As soon as you find yourself wanting to fit a headliner, hide excerpts, or show excerpts again, you will want to break out of this all-encompassing self-executing function and create an "application" that has methods which will live on in a namespace.
It's not clear why there's a setTimeout on the textFill. I cannot tell without comments when in the "flow of events" the first textFill is supposed to happen, but using a timeout to beat a race condition is not good practice. You should identify which completion action should fire the textFill and call it appropriately.
I have found $elem.parent()
to be future-resistant in my code. As soon as you change your markup structure (for whatever reason), the parent could change and depending on when that revision happens, it might be a bit of a hunting expedition to find out why the code broke! However, it is somewhat more likely that you'll have a container of a particular class or element type. Your mileage may vary, but for my own code, I prefer using $elem.closest()
. Note, you may also want to revise semantics to avoid calling it the 'parent' but that's also up to you (note, you were also missing a var declaration for $excerptParent which was putting it into the global scope):
Syntax:
var $container = $excerpt.closest('.containerName');
Along the same lines, you may want to use $elem.find()
instead of $elem.children()
, so that it can traverse the DOM deeper if your structure changes:
var $boxInfo = $container.find('.modalExcerpt');
Because there's more potential DOM to traverse, I'm guessing it's not quite as performant, but we're talking hundreds of thousands of operations per second either way.
Instead of using $elem.css
, consider using classes and $elem.addClass()
. If you truly don't think it's worth potentially polluting your stylesheet, you get to make that decision. However, a nice semantic class that does what you want it to do makes for readable code AND better maintenance. Your JavaScript gets to say "Make this a disabledExcerpt" which the stylesheet may simply set the element to have display:none;
for now, but in the future maybe it's greyed-out and italicized or something.
I do not personally favour the $elem.click()
method for binding the event handler. Too often I have written methods that modify the DOM one way or another, and the handler is lost. Instead, bind the listener to the nearest ancestor that you can predict with pretty good certainty won't get destroyed. If you are absolutely positive that you are never going to lose your elements that are listening for their own clicks, then you're fine already. Otherwise, here's the pattern:
HTML:
<div class="container">
<div class="someContent">
<p>Foo to the bar to the baz.</p>
<button class="clickerator">Click me!</button>
</div>
</div>
JS:
$('.container').on('click', '.clickerator', function(e) {
e.preventDefault(); // well, IF you want to prevent default behaviour...
alert('Hi, I am doing stuff on click of clickerators!');
})
The JS event binding can be read in plain English thus: "On click of clickerators found in containers, do this function". The container is the one listening for the clicks.
Once again, it's not quite AS performant, and the higher up in the tree your ancestor is, it becomes even less so. That said, people do just fine with highly dynamic websites when they throw their hands in the air and say, "heck with this, my listener will be the document itself... for ALL THE EVENTS!" There comes a time when performance is an academic exercise and the soft costs of development are worth more. I personally do not bind listeners to document, but there's usually at LEAST one container ancestor on a given page that you can be assured will not be destroyed.
setTimeout
was added because it appeared that there is a race betweendocument.ready
and DOM load. You can see the in depth discussion here: stackoverflow.com/questions/30563880/… \$\endgroup\$