Tagged jquery

On Safari Mobile for iOS 5, event.pageY is the new event.clientY

safari-logo-lg

We have some tooltips running at my work that are used to render sharing buttons when a user clicks or taps on them. When the recent upgrade to iOS came around, the tooltips stopped being rendered properly in iOS 5.

After running into a few problems with jQuery Tools and the iPad, I came up with a solution for getting the tooltips to appear next to the anchor element like they were supposed to. By using the event.clientY value from the touch event, I was able to detect where in the DOM the touch had happened, and simply position the tooltip right next to it, with something like this:

$('#tooltip').css('position', 'absolute !important').css('top', event.clientY);

In iOS 4.3, event.clientY was reporting the absolute position of the touch event relative to the entire document. In iOS 5, I discovered that it was reporting the position of the touch event relative to the window. So, if you tapped a tooltip way down on the page, but near the top of the current viewport window, the tooltip would appear right near the top of the document, completely off screen.

A little digging on Google yielded this page on the Apple site. The reference to an event.pageY property made me think that maybe that would do the trick, and it seems to work.

$('#tooltip').css('position', 'absolute !important').css('top', event.pageY);

Now, with iOS 5, the touch event was properly setting the tooltip’s top value to the position of the touch event within the entire DOM, not just the viewport. I’m not exactly sure what’s changed between iOS 4.3 and 5, but at least now I have something that works for both.

Lazy-load a LinkedIn Sharing button after the JavaScript window.load event

Adding social networking sharing buttons to your site has become almost a ubiquitous step in Web development, to the point when some designers have stopped thinking about the performance impact of rendering multiple buttons via JavaScript while a page is still loading. The delay might not be noticeable for, say, 1 or 2 buttons, but when you’re rendering multiple buttons per page (when you have a button to share individual Tweets on a page, for example), it can get out of hand (turns out JavaScript crashing the browser creates a user-unfriendly experience for most people).

The solution is to lazy-load the buttons when you need them, either when a user clicks to expose a previously hidden div, or at the very least after the window.load JavaScript event, to prevent slowing your pageload times down. Here’s an example of a simple way to lazy-load a LinkedIn Share button on window.load:

First, include the necessary scripts (LinkedIn’s in.js and jQuery). You can do this in the footer if you want…after all, you’re not doing anything with them until much later in JavaScript-time:



Next, add some jQuery in a script tag that looks for any script tag with a type of ‘unparsed-IN/Share’ (the name doesn’t matter, as long as it’s NOT IN/Share, since the whole point here is you don’t want the in.js script to parse the tag). Depending on the size of your DOM, you may want to be more specific with your jQuery selector…a div or a section of content is fine, and you can bind to a click event, a scroll event, or whatever else you’d like to initiate the parsing of your LinkedIn buttons:

 jQuery(window).load(function(){
    jQuery('body').find('script[type="unparsed-IN/Share"]').each(function(){
      jQuery(this).attr('type', 'IN/Share');
      IN.parse(document); //you can also use getElementById('id') in place of document here
    });
  });

Finally, you just need to add LinkedIn sharing tags in the following manner. The key here is to change the JS script type from IN/Share to unparsed-IN/Share (or whatever you chose in the jQuery above), which will cause the tag not to be rendered when in.js is loaded, allowing you to control with the JS when the tag is actually parsed, using IN.parse (which can be applied to the document as a whole, or an element as retrieved by the built-in JS document.getElementById method.


Update: As Howard points out in the comment section, if you don’t need to load the in.js script to render any LinkedIn buttons or content earlier, you can always accomplish lazy-loading by simply deferring the script load until you want to render the buttons. This allows you to avoid parsing and replacing the ‘type’ on each JavaScript snippet. If you need LinkedIn content to render both before the onload event as well as after, though, you’ll still need to do the replacement.

jQuery – Excluding elements with attributes ending in a particular string

Ok, let’s say you have some data that looks like this:

A title
Some content
A title
Some content

Now, if you need to style just the elements that are NOT post-modal, you have a problem. You can’t just select elements that start with an id value of ‘post,’ because then you will be selecting all the divs within the container. You could style the html with an additional class, but in this case the html wasn’t changeable, and adding a class with jQuery presents the same problem as selecting the elements–they’ll all match at the start of the id, even the ones we don’t want. The solution is this:

$(".container").children().not('[id$=modal]').each(function(){
//you can do something to each non-modal element in here
});

Now we’ve selected only the elements within our container that don’t contain the word ‘modal’ at the end, and we’re free to do whatever we need to them (in my case, it was pagination). For additional info on the .not() method, check out the jQuery doc.