Posts Tagged ‘Javascript’

Safari Popup Blocker And Flash AS3

On a recent project we came across an issue where user initiated popups get blocked in Safari when being called by an AS3 Flash app. The issue doesn’t happen in AS2 and I’d not come across it before, but when I did and I researched it I found it was a well documented issue with no solution. Most popup blockers are able to distinguish between a user initiated popup and an automatic one, and this is the case with all browsers with AS2 or all browsers except Safari with AS3. But what do you do if a popup is an integral part of your design and you’re using AS3? As far as I can tell there is no fix for this issue, we found some apparent solutions but when when tested them they failed.

What I came up with isn’t a fix so much as a working solution. When you initiate a popup in Flash it’s done by calling a JavaScript function called window.open(). This function returns a boolean of True upon success or False upon failure. So programmatically this gives us a way of knowing if the popup has been blocked. In which case we offer the user up an HTML link to the popup that we know won’t get blocked. I believe that when designed well and with thought this can be an elegant solution for a small base of users who are probably already used to seeing certain functionality across the web fail for them.

There’s obviously a number of way to implement this, but as a quick and dirty example lets create a hidden HTML block to appear if the popup fails:


Okay now lets look at the popup JavaScript function that Flash calls:

function shareFacebook(){
	success=window.open('http://www.facebook.com/sharer.php?u=http://richie-p.com/blog','FacebookShare','toolbar=0,status=0,width=626,location=no,menubar=no,height=436');
	if (!success){
		document.getElementById("popupMessage").style.display="block";
	}
}

So basically what’s going to happen is that the hidden window appears only if the popup failed, thus allowing for the user to click the HTML which doesn’t get blocked.

But what if we have multiple popup windows? We need a way to have one message div that can trigger an endless number of popups. And why does the message have to remain forever visible once it appears?

Bearing this in mind here’s an example of a more elegant generic version. Again it’s quick an dirty code and I wouldn’t necessarily expect it to be in a production environment in its current state:

This time we have the popupMessage call a generic function:


The actual popup JavaScript function that Flash calls is the same, but this time we need it to set global variables:

var popupFunc="";
var popupTimer="";
function shareFacebook(){
	p=window.open('http://www.facebook.com/sharer.php?u=http://richie-p.com/blog','FacebookShare','toolbar=0,status=0,width=626,location=no,menubar=no,height=436');

	if (!p){
		popupFunc="facebookShare";
		clearTimeout(popupTimer);
		$("#popupMessage").slideDown("slow");
		popupTimer=window.setTimeout('$("#popupMessage").slideUp("slow")',10000);
	}
}

So what basically happens is if the popup fails we set the name of the popup function that failed into a global variable called popupFunc. We use the jQuery slideDown() method to gracefully make the message appear. We also use a global variable called popupTimer to hide the message after 10 seconds. And in case the message is already showing from a different request we clear the popupTimer so it doesn’t disappear too quickly.

And finally lets look at the generic popup function:

function launchPopup(){
	$("#popupMessage").slideUp("slow");
	eval(popupFunc+"()");
}

We hide the message and call the popup function.

Like I say this is all quick and dirty for display purposes. But I really believe this to be a solid and elegant solution to a frustrating and problematic situation.

Thursday, December 17th, 2009

Embedding Facebook Share Into Your Site

Facebook_logoWe’ve got this project going on where users can create their own artwork which is saved to the server as an image, and we want them to be able to post it into Facebook.  At first I thought it was going to take some effort and have to use the Facebook Connect API.  But I was hoping for something easier, kind of how easy it is on Twitter to just tag a status GET string onto the URL.  Then I remembered Facebook recently released something that does exactly this.  It’s all very simple and pretty cool really, check it out here.

I’m doing something simple so I didn’t really need the share count.  So I threw together a super simple JavaScript implementation:

function fbshare(url,title){
  window.open('http://www.facebook.com/sharer.php?u='+encodeURIComponent(url)+'&t='+encodeURIComponent(title),'FacebookShare','toolbar=0,status=0,width=626,height=436');
}


 Test it out by clicking here

As you can see there’s nothing to it. It’s nice because it sends the user directly to Facebook, and if they are already logged-in then they are instantly presented with the familiar form.

Something to note is that if you are posting a web page then the title will likely be overridden and pulled directly from the page title (just as the page description and thumbnail images). But if you are posting an image or another URL then the title will definitely come in handy.

Wednesday, November 18th, 2009

The Definitive Modal Layer

For the last couple of years we’ve been using modal layers where it made sense, basically most places where we would’ve used pop-ups in the old days, i.e. modal layer is to Web 2.0 what the pop-up was previously. But all the while I never felt like I was able able to lock down any solid way of doing this. Every time the issue came up I’d re-visit the functionality, never overjoyed with my latest implementation, so I never came up with a final solution. Depending on the website I was working with and the libraries they were already using I’d sometimes use Prototype or YUI, or if it was a good fit I’d implement a pre-built lightbox gallery, or even just code up something quick and simple from scratch.

And it’s not just me, I’ve noticed throughout the web bad implementations of this technology. I won’t get specific with names but I’ve seen some funky stuff even on well-known popular sites when it comes to the modal layer. Typical issues I’ll see is where the grayed out background doesn’t fill the whole screen, or it fills too much of the screen and triggers scrollbars, or if the page is really long you can still scroll and the modal layer isn’t sticky and you can lose where it’s at.

So the solution sort of hit me when I was having trouble graying out the background – when calculating the width some browsers include the vertical scrollbar in the result where as other browsers don’t, so in some cases it was overflowing and actualy creating a horizontal scrollbar.  This is not surprising as we have made a career out of fighting the various browser discrepancies and it would be normal to have multiple javascript conditions to query the user agent and modify the width accordingly.  But as I started to write those conditionals I watched my nice simple code quickly get complex and it suddenly hit me – why have the horizontal scrollbar at all?  Really it was that simple.  Good UI design dictates that if the modal content is bigger than the screen space available then a modal box is not the right approach, at which point the content does in fact require its own page (or dare I say a popup), or in cases where it is acceptable for the modal content to be bigger than the screen space available then the modal box itself should have the scrollbars.  So why even have it?  There’s no reason, and I would even go as far as saying that if there is no reason for having it then it is better UI design to actually remove it.

Okay so here’s the code, I used jQuery but it would be simple to convert it to any library or even make it stand alone:

//Create Modal Layer
modalLayer = document.createElement("div");
modalLayer.setAttribute("id","modalLayer");
var cssObj = {
	'background' : 'url(img/gray_opacity_80_percent.png)',
	'height' : '100%',
	'width' : '100%',
	'margin' : '0 auto',
	'padding-top' : '25px',
	'text-align' : 'center',
	'position' : 'absolute',
	'top' : '0px',
	'left' : '0px',
	'z-index' : '1000',
	'display' : 'none'
}
$(modalLayer).css(cssObj);
modalLayer.innerHTML="<div id='modalBox'>Modal Content</div>";
$("#page").after(modalLayer); //insert after a valid page object

function showModalLayer(){
	$('body').css('overflow','hidden'); //disable browser scrollbars
	$("#modalLayer").css("top",$('body').scrollTop()); //move modal layer to scroll position
	$("#modalLayer").css("display","block"); //display modal layer
}

function hideModalLayer(){
	$('body').css("overflow","visible"); //enable browser scrollbars
	$("#modalLayer").css("display","none"); //hide modal layer
}

An example of where I’ve used this code is on the CCS donation page, but it’s not that great of an example because the page content isn’t long enough to trigger scrollbars.

Friday, October 16th, 2009

Running jQuery alongside MooTools

For my latest project I was given the fun task of having to build a microsite modal layer for a third party website that I had no access to, not even to a dev environment.  I figured the best way to do it would be to do everything in a JS file that would inject all the html and such, so there’d no need for the mess of sending over instructions to add multiple chunks of html/css/js into various spots on the page, just the one JS call.  And jQuery was perfect for this, so I set on my merry way and coded the whole thing into a nice neat JS file, had it all working great locally, and sent it over to the clients hosting company with the simple instructions of just calling in the two JS files (the jQuery JS file and the one I’d written) into their page.  Of course rookie mistake number one – they were already using MooTools in their site, and the syntax of the jQuery and MooTools libraries totally clash.

I have no problem using MooTools and it wasn’t a lot of code so I downloaded the latest version and adjusted the syntax to match that of the MooTools library.  Of course that was rookie mistake number two – when I was done and it was all working again I remembered to check their version and it was then that I realized that they are using a fairly old version of MooTools, and the syntax was all different and I couldn’t find decent documentation to switch it out.  Of course I probably could’ve worked it out but my code was going backwards – I was all proud of my nice clean jQuery, and then it became MooTools which was okay, but now it was some funky old version of MooTools.  So I decided to switch gears and figure out how to run the two alongside eachother.

It didn’t take me long, jQuery is badass and they’ve thought of everything, there is a built-in way to run it alongside other libraries that use the same $() syntax (Prototype is another library that I can think of as well as MooTools that has this same syntax).  So consider the following:

<html>
  <head>
    <script src="mootools.js"></script>
    <script src="jquery.js"></script>
    <script>
      //mootools document ready function
      window.addEvent('domready',function() {
        //disable classic jQuery
        jQuery.noConflict();

        //do something with jQuery
        alert(jQuery(document).height());

        //do something with MooTools
        alert($(document).getSize().y);
      }
     </script>
  </head>
  <body></body>
</html>

As you can see once you run jQuery.noConflict() you can still use $() for MooTools but for jQuery you use jQuery() instead. Pretty cool huh?

That’s basically it but there are a couple more tricks. For example if you load in the jQuery library before the MooTools library apparently there’s no need to call the jQuery.noConflict() method. And also you could assign jQuery.noConflict() to a short variable name for less code. Read more here.

Tuesday, September 1st, 2009

Youtube videos within websites on the Safari iPhone

Launching a site recently that uses Youtube embedded videos, I found the videos didn’t show in the Safari browser on my newly purchased iPhone. This was a shame because the rest of the site worked perfectly (well almost but I’ll get to that in another post), it was like a lil’ cute mini version of the site!

Being an iPhone n00b I didn’t think much of it, I knew it was possible as I’d seen it working on other sites, but when I began to research my problem I became painfully aware that there is very little info on this issue out there. (That statement is not entirely true as I was being rushed, as always in advertising, to the finish line and not being allowed the time to think about my problem, in other words I was asking Google the wrong question).

But really it wasn’t easy to find out how to embed Youtube videos into your sites on the iPhone. Multiple searches using different terms wouldn’t provide me with the information I needed to understand what the HTML needs to look like to get the Youtube video to show up in a website. Eventually, after a couple of useful links from a buddy, I found out that the Safari browser on the iPhone automatically generates the necessary Youtube embed code, it’s as simple as that. When Safari sees the Flash embed code pointing to the Youtube player it converts it, so instead of the Flash player you will get the video placeholder image with the play button, which when clicked will take you to the iPhone Youtube player (which when you hit ‘Done’ takes you straight back to the site). It will look something like this:

So it automatically gets converted…So why the hell wasn’t it working on my beautiful new site??? Doh, I was using SWFObject :p Now as far as I am aware SWFObject has become somewhat of an industry standard (though lately I had seen some flaws with it and questioned its usefulness), at least within my agency we’ve adopted it as a standard. What does SWFObject do exactly? It checks to see if your browser has the Flash plugin installed and if it does it replaces the target object with the Flash embed code, and if not then it does nothing. This allows the target object to contain alternative content when Flash isn’t available, usually something simple such as ‘This site requires Flash’, along with a link to the Adobe plugin. (SWFObject is also good for controlling the Flash version, so the user may have the Flash plugin but not the right version – the script definitely has its uses, but also its flaws.)

So I now understood what the problem actually was. So this time I was able to ask Google the right question, and it was able to give me the right answer – http://code.google.com/p/swfobject/wiki/iphone_mp4. The browser couldn’t convert the Youtube embed code because the SWFObject wasn’t ever allowing it to exist. If you ask me that’s another flaw with SWFObject, it should have been updated by now to manage itself correctly on the iPhone – 1. Check to see if it’s the iPhone Safari browser, and if so then 2. Check to see if it’s pointing to the Youtube player. Maybe writing that code will be my next task.

From there on it was easy sailing. I didn’t add to the SWFObject code itself as I wanted to maintain the integrity of that file, instead I wrote a wrapper within the target object. (Still rushed I made the mistake of doing the browser-detect back-end in PHP, which is great if you aren’t sat behind a 4 hour Akamai cache!!)

So the simple javascript code to check for the iPhone is:

<script>
  var agent=navigator.userAgent.toLowerCase();
  var is_iPhone = (agent.indexOf('iphone')!=-1);
</script>

This gives you the Boolean is_iPhone which you can then use set your SWFObject target object default HTML like:

<div id="youtubeContent">
  <script>
    if (is_iPhone){
      document.write('<embed src="http://www.youtube.com/v/0uSnyL-RfHw&hl=en&fs=1&rel=0&showinfo=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="562" height="341"></embed>');
    }else{
      document.write('You must have the Flash plugin to see this content');
    }
  </script>
</div>

And finally call the SWFObject embed method:

<script>
  swfobject.embedSWF("http://www.youtube.com/v/JHQ9xNyBC0w&hl=en&fs=1", "youtubeContent", "562", "341", "8");
</script>

Not the most graceful method of doing this I’m sure, but within the time we had it serves us well.

And finally you can check the Youtube videos working within your iPhone Safari here www.thefordstory.com.

Tuesday, February 17th, 2009