Monday, May 23, 2011

SimpleModal and ShareThis - Positioning and Ajax

I recently had to fix an issue with the implementation of a ShareThis button in a SimpleModal. Easy right? Sort of. Below I will walk through my issues and the fixes. The screen captures are intentionally blurred. This is a bug fix effort, the base implementation already existed, so I will not cover how to setup a basic ShareThis button or SimpleModal. Refer to their respective web sites.

ShareThis container position 

The first issue is that the SimpleModal remains positioned to the window and as you scroll, the modal re-centers in the middle of the browser window, the share this container doesn't. See the image below. The page has scrolled down, and the ShareThis is remaining placed and will eventually remove from the screen. The initial flyout of the ShareThis is mostly directly under the button placement. This is not the case here.


To solve the problem, the ShareThis container needs to be moved around when the page scrolls. The container however is an iframe, and the actual containers you inspect will be contained within that frame, and therefore you cannot act on those elements in Javascript. The ShareThis content is sand boxed from yours due to the cross domains.

The implementation fix will move the ShareThis on a page resize and to set ShareThis frame position as fixed. The ShareThis is offset from the SimpleModal:

var offsetFrom = $("#simplemodal-container:visible");
$("#stLframe:visible").css("left",offsetFrom.css("left"));
$("#stLframe:visible").css("top",offsetFrom.css("top"));
$("#stLframe:visible").css("position","fixed");
$("#stLframe:visible").css("z-index","1002");


This will position the share this modal against the corner of the SimpleModal. I'll explain the visible and the z-index in a bit.

Multiple ShareThis buttons on Ajax page loads

The ShareThis buttons don't really work on Ajax calls that return HTML and Javascript, meaning the ShareThis button is defined in the synchronous data. The implementation I worked on was a search results page with a modal view per product. The search results has paging and filtering options that fire Ajax calls and returns the needed JSON to adjust the page.

By default, the ShareThis code will only execute once the initial DOM is ready, any additionally added items, will not be setup as share buttons. The ShareThis code provides a method call to relocate the buttons on the page for setup:

stButtons.locateElements();

Execute this inside your Ajax success callback in order to setup the buttons on the page.

But before you can locate the buttons, they need to be added to the page. As I mentioned, the page load was Ajax returning JSON for the search. The page results are built client side and each result as a modal that is also fetched with Ajax, but returns HTML (where the ShareThis button needs to go). The HTML results can't include the ShareThis button due to the way the button elements are located. Therefore, the HTML result just has a place holder that is later replaced with the actual ShareThis button. See the following:

var shareParentPrependTo = $("#modal-share-this").parent();
$("#modal-share-this").hide();
// find the share this element and prepend it to the parent so it appears first
$("#share-this-" + id).prependTo(shareParentPrependTo);
$("#share-this-" + id).show();


The "#modal-share-this" is the placeholder. Then the actual ShareThis button is prepended to the placeholder's parent. There is a ShareThis button per search result, where each has a unique ID to use for selection. The actual buttons are hidden in the page until that result is selected. It's then added into the modal and shown. These unique elements are built via the JSON results, then added to the modal container.

Closing the ShareThis button - Positioning

When moving the ShareThis container, the clicking on the "X" to close the flyout on click did nothing. If the hover option was on, then the flyout would go away after moving the mouse away. But when this wasn't the case, there was no way to close the ShareThis container once opened.

At first, I was trying to inspect the close button but then realized that the inspected element was inside the cross browser frame, so I couldn't act on it even though I could inspect it via Firebug. I couldn't adjust the click event for example.

Then I noticed an element outside of the frame "div.stclose". For whatever reason, the element "div.stclose" was positioned elsewhere on the page and not over the closing corning of the ShareThis container. The result was having to reposition the "div.stclose" element with the overall ShareThis button as well. The trick is, rather than having the close button on the top left, the button needed to be the top right of the container (not too complex).

// frame width
var closeWidth = parseInt($("#stLframe:visible").css("width").replace("px",""));

// frame left corner
closeWidth = closeWidth + parseInt($("#stLframe:visible").css("left").replace("px",""));

// left corner minus the width of the close icon
closeWidth = closeWidth - 12;

$("div.stclose").css("left",closeWidth + "px");
$("div.stclose").css("top",offsetFrom.css("top"));

$("div.stclose").css("width",12);
$("div.stclose").css("height",12);

$("div.stclose").css("position","fixed");


As shown, the width of the ShareThis is added to the left corner to get the right corner. I am not sure if the "px" replace and additions are needed above, but they work. The position is then moved in 12 pixels which is the width of the button. The close is aligned with the top of the SimpleModal (offsetFrom). The position must also be fixed to ensure the page scrolling doesn't move the element out of view.

The z-index of the ShareThis container is important here. The "stclose" element must be index above the iframe contents so it can be clicked by the user correctly. If under, then nothing would happen.

Closing the ShareThis button - Remembering ShareThis elements

Now remember, the buttons are hidden in the outter page, and then moved to the modal when shown. When the modal is closed, we need to move the added ShareThis element back out into the window, incase its added again. Otherwise, we will have lost the ShareThis element for the given ID.

It doesn't matter where it goes back to because it's hidden and we can select it by ID later. Therefore, the onClose event on the modal needs to be adjusted:

$('#modal').modal({ onClose: function (dialog){
   var shareThisBackToWindow = $("#modal-share-this").siblings(":first")
   shareThisBackToWindow.hide();

   shareThisBackToWindow.appendTo($("#whatever"));
   $.modal.close();
}} );


The first sibling to the "#modal-share-this" element is the added element that was moved from outside the modal, then into it. This needs to be moved back somewhere else now, "#whatever", then hidden, and then the modal can be cleanly closed. If the modal was just closed, the ShareThis button would be destroyed for that ID.

This is why the visibility selectors are in use in the examples. Since many button elements exists, we only want the one shown to act on, verses the hidden. This applies for the ShareThis, verses the modal which is removed and then re-created.

Easy, right?

Took me about 3 days to break this down, understand the problems and fix it. I also had to fix the scroll bar shown in the screenshot inside the modal, but that was easy. I saw a lot of Ajax questions on the ShareThis forums too with no good solutions, except for the "locateElements" thread.

Hopefully this helps someone. If not, it's at least good note taking for myself.

No comments:

Share on Twitter