21 February 2011

Escape the iOS SDK: Building iPhone (and Android) apps via Flash

http://www.infoworld.com/d/developer-world/escape-the-ios-sdk-building-iphone-and-android-apps-flash-158

09 February 2011

Audio files with the JW Flash Player

We're converting some old RM (RealMedia) files to use Flash instead; most are video but a small number are audio-only. To get these to work with the JW Flash Player, I used MediaCoder to convert the files. The container to use is M4A, as discussed in this thread. Here are the settings in MediaCoder:

Start by setting the video to off. Then change the audio settings; note that we set the audio container to MP4. MediaCoder automatically resolves this to M4A for audio-only files:

And finally set the main container type to Default.

07 February 2011

Moving to 64-bit Firefox on Windows 7 x64

Recently, I've noticed that I have a lot of tabs open in Firefox and taking up 700MB or more of memory. Things slow down. What to do? The PC has Win 7 x64 with 8GB of RAM. It might be time to move to the 64-bit version of Firefox and take advantage of the extra legroom on this system.

The problem is how to move the profile from my 32-bit version to the 64-bit "Minefield" beta edition of Firefox 4. The solution? Use the new Sync feature in FF 4, which allows you to store your bookmarks, etc., to a Firefox server, then load the information into another copy of Firefox.

If you open your old 3.6.13 version of Firefox, it, too, will pop up a box to ask if you want to sync things up. Then you can have this be your base version, which holds all your profile. Then when you open the beta 4.0 32-bit, it can pull in the data. And the 64-bit one can also pull the information, too. I'm new to it and haven't yet figured out how the form usernames/passwords are pulled in; the experts say we need to use the 32-bit edition awhile for the sync to pick up all the data.

Either way, this is a fantastic new addition to Firefox. It makes moving profiles so easy. Just ensure that you save your Firefox Sync Key somewhere that you can find it; all other browser versions will require that key to connect.

Some final thoughts: The 32-bit version of the Flash player won't work in the 64-bit version of Firefox; you'll need to download the preview version of Adobe's 64-bit player. In addition, some add-ons won't load via Firefox; you'll have to download the XPI then run them. Firebug loads fine using this technique.

04 February 2011

Cufon not working on Opera

This is an interesting issue: Opera 10.63 for Windows couldn't show the Cufon web font effect, but it worked across all the other browsers. Some research revealed a known issue: If any of your CSS files aren't found, Opera will not be able to apply the Cufon effect.

How do you determine if any of your CSS files are missing? Firefox' Web Developer Toolbar comes to the rescue. Go to the CSS button > View CSS. Now ensure that all the files are expanded so you can see the details. Look for a block similar to the following:
http://localhost:8090/joomla/templates/system/css/system9.css

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

<head>

<title>Object not found!</title>

<link rev="made" href="mailto:postmaster@localhost" />

<style type="text/css"><!--/*--><![CDATA[/*><!--*/

body { color: #000000; background-color: #FFFFFF; }

a:link { color: #0000CC; }

p, address {margin-left: 3em;}

span {font-size: smaller;}

/*]]>*/--></style>

</head>

<body>

<h1>Object not found!</h1>

<p>

The requested URL was not found on this server.

The link on the

<a href="http://localhost:8090/joomla/">referring

page</a> seems to be wrong or outdated. Please inform the author of

<a href="http://localhost:8090/joomla/">that page</a>

about the error.

</p>

<p>

If you think this is a server error, please contact

the <a href="mailto:postmaster@localhost">webmaster</a>.

</p>

<h2>Error 404</h2>

<address>

<a href="/">localhost</a><br />

<span>02/04/11 15:48:16<br />

Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l mod_autoindex_color PHP/5.3.1 mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1</span>

</address>

</body>

</html>
Note the text "Object not found" (Error 404); Cufon can't handle missing CSS files on Opera and will not render your web font.

02 February 2011

Dynamically replace HTML5 video with Flash in Fancybox

For my current project, I needed to dynamically (based on whether the device supported HTML5 or not) replace HTML5 video tags with a Flash player. What made this more challenging was that the video player needed to be in a Fancybox.

A day's worth of coding resulted in the following JavaScript function. It's heavily commented so it should be self-explanatory. Drop me a comment if something doesn't make sense. You need to include the latest jQuery library for this to work.

function flashPopup(){
// Declare some variables.
var el = "";
var vidFileName = "";
var posterPath = "";
var placeHolderPosterPath = "";
var replacement = "";
var imgTitle = "";
var videoTag = "";
var boxId = "";
var flashId = "";
var dotPosition = "";
var swf = ""

// Loop over each video tag.
$("video").each(function(){
// Reset the variables to empty.
el = "";
vidFileName = "";
posterPath = "";
imgTitle = "";
placeHolderPosterPath = "";
replacement = "";
videoTag = "";
flashId = "";
swf = "";

// Get a reference to the current object.
el = $(this);

// Set some values we'll use shortly.
boxId = this.id + "_flashBox";
flashId = this.id + "_flashPlayer";

/*
Set the ID attribute of the first DIV in this element's parent's
parent. This "box" will have the Fancybox attached to it.
*/
el.parent().parent().find("div:first").attr("id",boxId);


/*
Fetch the MP4/M4V video from the <source> tags. Need to go to the
parent of the current tag to find them.
*/
el.parent().find("source").each(function(){
if ($(this).attr("src").indexOf("m4v") != -1 ||
$(this).attr("src").indexOf("mp4") != -1){
vidFileName = $(this).attr("src").substring($(this).attr("src").lastIndexOf("/")+1);
}
});

/*
IE (< 9) and older browsers use the Flash player, which overlays a 'Play' button
on the poster image by default; so we use a poster image that doesn't have
a play button. Otherwise we'd end up with a play button on top of a play
button.

We have an img tag inside the <video> tag which we'll use (by adding "-ie" to the
filename) for the Flash player's image attribute. The next two lines find the file
and its path.
*/
dotPosition = el.parent().find("img").attr("src").lastIndexOf(".");
posterPath = el.parent().find("img").attr("src").substring(0,dotPosition) + "-ie" + el.parent().find("img").attr("src").substring(dotPosition);

/*
Use the same image but this time don't add "-ie" to its name. This will be for the
main placeholder linked image; when the user clicks it, the Fancybox pops up with
the Flash player.
*/
placeHolderPosterPath = el.parent().find("img").attr("src");

/*
Fetch the image's title attribute, which we'll use for the linked image's title.
This will appear as the title on the Fancybox.
*/
imgTitle = el.parent().find("img").attr("title");

/*
Concatenate the linked image that will take the place of the <video> tag.
*/
replacement = "<a title='" + imgTitle + "' id='" + boxId + "' href='javascript:;'><img src='" +
placeHolderPosterPath + "' style='float:left; padding-left:5px; '/></a>"

// Replace the parent of the current element with the linked image HTML.
el.parent().replaceWith(replacement);

/*
The swfobject library can't be used with Fancybox (as far as I know). but
we can pass a Flash player of our own design into the Fancybox as its content.
Here, we concatenate the Flash player and point to the swfobject player.swf
file. We'll still use that player, but build our own OBJECT and EMBED tags.
*/
swf = "<object id='" + flashId + "' classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' width='372' height='209'>" +
"<param name='movie' value='global/vid/player.swf' />" +
"<param name='quality' value='high' />" +
"<param name='wmode' value='opaque' />" +
"<param name='swfversion' value='6.0.65.0' />" +
"<param name='expressinstall' value='global/vid/expressInstall.swf' />" +
"<!--[if !IE]>--> " +
"<object type='application/x-shockwave-flash' data='global/vid/player.swf' width='372' height='209'> " +
"<!--<![endif]--> " +
"<param name='quality' value='high' /> " +
"<param name='wmode' value='opaque' /> " +
"<param name='swfversion' value='6.0.65.0' /> " +
"<param name=flashvars value='file=" + vidFileName + "&autostart=false&image=" + posterPath + "'>" +
"<param name='expressinstall' value='global/vid/expressInstall.swf' />" +
"<div>" +
"<h4>Content on this page requires a newer version of Adobe Flash Player.</h4>" +
"<p><a href='http://www.adobe.com/go/getflashplayer'><img src='http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' width='112' height='33' /></a></p>" +
"</div>" +
" <!--[if !IE]>--> " +
" </object> " +
" <!--<![endif]--> " +
" </object> ";

/*
Now attach a Fancybox to this item and set its attributes. Note that
we need to disable the autoDimensions for SWF files or you'll get a
long, narrow box showing. We then set the width and height (which
usually requires some trial-and-error).

The two functions for onComplete and onClosed are custom code that
stop/start the AnythingSlider when the user opens the Fancybox and
closes it, respectively.

This entire function acts as an onClick handler for the object to
which it's attached (hence the "end click function" comment).
*/
$("[id="+boxId+"]").fancybox(
{
'content' : swf,
'autoDimensions' :false,
'height' :236,
'width' :375,
'padding' : 5,
'showCloseButton' : true,
'enableEscapeButton': true ,
'titlePosition' : 'outside',
'onComplete' : function() {stopSlider()},
'onClosed' : function() {startSlider()}
}
); // end click function
});
}

Update: A few requests have come in for a version of the code to allow HTML5 videos on a page to be placed into a Fancybox. Here's the demo, with a very special thanks to Pipsqueak.

Here's the HTML code, with the JavaScript followed a little further down:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Fancybox HTML5 Video</title>
<meta name="description" content="">
<meta name="author" content="alex cougarman">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.css" type="text/css" />
<!--
In addition to the stylesheet for the Fancybox
component, the following styles control the
look of the page and the linked image.
-->
<style type="text/css">
body {
margin:50px 0px; padding:0px;
text-align:center;
font:11px verdana, arial, helvetica, sans-serif;
}

#main {
width:500px;
margin:0px auto;
text-align:left;
padding:15px;
border:1px dashed #333;
background-color:#eee;
}
.img-link
{
border:1px solid #999;
padding:5px
}
</style>
<!--
Include the jQuery library, followed by the
Fancybox and the Easing libraries.
-->
<script type="text/javascript" src="js/jquery.fancybox-1.3.4/jquery-1.4.3.min.js"></script>
<script type="text/javascript" src="js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.pack.js"></script>
<script type="text/javascript" src="js/jquery.fancybox-1.3.4/fancybox/jquery.easing-1.3.pack.js"></script>

<!-- Add inline script code here. -->

</head>
<body>
<div id="main">
<h3>HTML5 Video in a Fancybox</h3>
<div>
<video id="vid-1" width="480" height="360" poster="btf.jpg" controls preload>
<source src="btf.mp4" type="video/mp4">
<source src="btf.ogv" type='video/ogg; codecs="theora, vorbis"'>
</video>
</div>
</div>
</body>
</html>
Replace the line above in the HTML that says "Add inline script code here." with this JavaScript:
<script type="text/javascript">
$(document).ready(function(){
fancyPopup(); // Replace the video tags.
});

/*
Function finds the video tags on the page. For each,
it fetches the video tag's HTML and replaces it with
a linked image that, when clicked, pops up a Fancybox
containing the HTML5 video.
*/
function fancyPopup() {
// Declare some variables.
var el = "";
var posterPath = "";
var replacement = "";
var videoTag = "";
var fancyBoxId = "";
var posterPath = "";
var videoTitle = "";

// Loop over each video tag.
$("video").each(function () {
// Reset the variables to empty.
el = "";
posterPath = "";
replacement = "";
videoTag = "";
fancyBoxId = "";
posterPath = "";
videoTitle = "";

// Get a reference to the current object.
el = $(this);

// Set some values we'll use shortly.
fancyBoxId = this.id + "_fancyBox";
videoTag = el.parent().html(); // This gets the current video tag and stores it.
posterPath = el.attr("poster");
videoTitle = "Play Video " + this.id;

// Concatenate the linked image that will take the place of the <video> tag.
replacement = "<a title='" + videoTitle + "' id='" + fancyBoxId + "' href='javascript:;'><img src='" +
posterPath + "' class='img-link'/></a>"

// Replace the parent of the current element with the linked image HTML.
el.parent().replaceWith(replacement);

/*
Now attach a Fancybox to this item and set its attributes.

This entire function acts as an onClick handler for the object to
which it's attached (hence the "end click function" comment).
*/
$("[id=" + fancyBoxId + "]").fancybox(
{
'content': videoTag,
'title': videoTitle,
'autoDimensions': true,
'padding': 5,
'showCloseButton': true,
'enableEscapeButton': true,
'titlePosition': 'outside',
}); // end click function
});
}
</script>
Replace the two videos (btf.mp4 and btf.ogv) with your own HTML5-compatible videos and try it. Demo, with a very special thanks to Pipsqueak.

Update: The good folks at Long Tail Video provide a great HTML5 video tag reference.