Demos for LearnSWFObject have been moved

For the record, all demos for LearnSWFObject.com have been relocated from my personal server to GitHub. The root URL has changed from demos.learnswfobject.com to learnswfobject.com/demos.

This enables me to keep all of the demos in the same repo as the primary LearnSWFObject site. The site and demos are old, and have not been updated for years, but are still useful to some members of the Flash community. Moving the files to GitHub is a nice way to keep the tutorials and demos online while reducing my personal burden for hosting the sites.

Using the object element to dynamically embed Flash SWFs in Internet Explorer

This is a journey into the madness of Internet Explorer.

Yes, there is a happy ending. Jump to the end of the post if you just want the solution and don’t care about how we got there.

The Scenario

You want to embed a Flash SWF into your HTML document using the object element, and you need to be able to do it using JavaScript. (Let’s pretend SWFObject doesn’t exist, ok?)

If you were using HTML markup without JavaScript, embedding a Flash SWF using an object element would be pretty straightforward:


<object id="mySWF" width="550" height="400" 
        data="mymovie.swf" 
        type="application/x-shockwave-flash">
   <param name="flashvars" value="dog=woof&cat=meow" />
</object>

Microsoft designed Internet Explorer’s object to work a bit differently, so the markup for Internet Explorer becomes:


<object id="mySWF" width="550" height="400"
        classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
   <param name="movie" value="mymovie.swf" />
   <param name="flashvars" value="dog=woof&cat=meow" />
</object>

The key differences are:

  • Internet Explorer requires the classid attribute instead of type
  • Internet Explorer requires the param name="movie" child node instead of the data attribute in the object

Annoying, perhaps, but workable. If you’re working with hard-coded markup — what SWFObject refers to as static publishing — you can drop in some conditional comments and be done:


<!--[if IE]>
<object id="mySWF" width="550" height="400"
        classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
   <param name="movie" value="mymovie.swf">
<![endif]-->

<!--[if !IE]>-->
<object id="mySWF" width="550" height="400"
        data="mymovie.swf"
        type="application/x-shockwave-flash">
<!--<![endif]-->

   <param name="flashvars" value="dog=woof&cat=meow" />

<p>Fallback content for people without Flash Player</p>

</object>

That’s nice, but I need to use JavaScript

On the surface, using JavaScript to recreate the HTML markup appears to be a trivial task; we just need to add conditional logic to handle the two small differences between Internet Explorer’s object element and the object element used by the other browsers:


var target_element = document.getElementById("replaceMe"),
   obj = document.createElement("object"),
   isMSIE = /*@cc_on!@*/false;

//Add attributes to <object>
obj.setAttribute("id", "myObjID");
obj.setAttribute("width", "550");
obj.setAttribute("height", "400");

//Add <param> node(s) to <object>
var param_flashvars = document.createElement("param");
param_flashvars.setAttribute("name", "flashvars");
param_flashvars.setAttribute("value", "cat=meow&dog=woof");
obj.appendChild(param_flashvars);

if (isMSIE) {            

   //IE requires the 'classid' attribute
   obj.setAttribute("classid", "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000");
   
   //IE requires the 'movie' <param>
   var param_movie = document.createElement("param");
   param_movie.setAttribute("name", "movie");
   param_movie.setAttribute("value", "test.swf");
   obj.appendChild(param_movie);

} else {

   //Non-IE browsers require the 'type' attribute
   obj.setAttribute("type", "application/x-shockwave-flash");
   
   //Non-IE browsers require the 'data' attribute
   obj.setAttribute("data", "test.swf");

}

//Replace targeted DOM element with our new <object>
target_element.parentNode.replaceChild(obj, target_element);

Seems simple enough, right? Not so fast. If you try running this in Internet Explorer (6-9), you’ll notice the SWF fails to load, and IE will behave as though it’s stuck trying to load a file — the “loading” icon never goes away.

Issues with Microsoft’s proprietary classid attribute

It turns out Internet Explorer’s object does not like having the classid appended after the object has been created. This is very similar to the well-known IE bug for adding the name attribute to certain form elements. For the form element bug, Microsoft’s solution is to include the name attribute in the createElement string:

Attributes can be included with the sTag as long as the entire string is valid HTML. To include the NAME attribute at run time on objects created with the createElement method, use the sTag.

Microsoft provides the following example:


var newRadioButton = document.createElement("<INPUT TYPE='RADIO' NAME='RADIOTEST' VALUE='First Choice'>")

What happens if we use this solution for the classid issue?


var node_name = (isMSIE) ? "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' />" : "object";
var obj = document.createElement(node_name);

This works like a charm… in IE 8 and lower. Unfortunately, IE 9 chucks a wobbly. Microsoft, in their wisdom, decided that angled brackets should no longer be valid inside the createElement method. This is actually excellent news: Internet Explorer 9 is behaving like other browsers, so let’s just use a try/catch to target IE versions prior to IE9, and use standard W3C code for IE9:


var target_element = document.getElementById("replaceMe"),
   isMSIE = /*@cc_on!@*/false,
   obj;

if (isMSIE) {

   try {
      
      //For IE 8 and lower
      obj = document.createElement("<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' />");

      //IE requires the 'movie' <param>
      var param_movie = document.createElement("param");
      param_movie.setAttribute("name", "movie");
      param_movie.setAttribute("value", "test.swf");
      obj.appendChild(param_movie);
      
   } catch (e) {
      
      //Let IE9 and higher fall through and use the standard browser markup
            
   }
   
}

if (!obj) {

   obj = document.createElement("object");
   obj.setAttribute("type", "application/x-shockwave-flash");
   obj.setAttribute("data", "test.swf");
   
}

//Add attributes to <object>
obj.setAttribute("id", "myObjID");
obj.setAttribute("width", "550");
obj.setAttribute("height", "400");

//Add <param> node(s) to <object>
var param_flashvars = document.createElement("param");
param_flashvars.setAttribute("name", "flashvars");
param_flashvars.setAttribute("value", "cat=meow&dog=woof");
obj.appendChild(param_flashvars);

//Replace targeted DOM element with our new <object>
target_element.parentNode.replaceChild(obj, target_element);

Still works in Internet Explorer 8 and lower, but fails in IE 9. Okay, perhaps IE9 still requires the classid attribute and ‘movie’ param. Let’s fork the code some more and try it out.


var target_element = document.getElementById("replaceMe"),
   isMSIE = /*@cc_on!@*/false,
   obj;

if (isMSIE) {

   try {
      
      //For IE 8 and lower
      obj = document.createElement("<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' />");
      
   } catch (e) {
      
      //IE9 doesn't support classid in createElement, so let's add it afterward
      obj = document.createElement("object");
      obj.setAttribute("classid", "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000");
      
   }

   //IE requires the 'movie' <param>
   var param_movie = document.createElement("param");
   param_movie.setAttribute("name", "movie");
   param_movie.setAttribute("value", "test.swf");
   obj.appendChild(param_movie);
   
} else {

   //Standard browsers
   obj = document.createElement("object");
   obj.setAttribute("type", "application/x-shockwave-flash");
   obj.setAttribute("data", "test.swf");
   
}

//Add attributes to <object>
obj.setAttribute("id", "myObjID");
obj.setAttribute("width", "550");
obj.setAttribute("height", "400");

//Add <param> node(s) to <object>
var param_flashvars = document.createElement("param");
param_flashvars.setAttribute("name", "flashvars");
param_flashvars.setAttribute("value", "cat=meow&dog=woof");
obj.appendChild(param_flashvars);

//Replace targeted DOM element with our new <object>
target_element.parentNode.replaceChild(obj, target_element);

Are you ready for the surprise? This doesn’t work in IE9, either. Adding classid to the object after it has been created simply will not work in any version of Internet Explorer. Microsoft removed their own recommended workaround — adding the attribute in the createElement string — to standardize their browser, yet they failed to provide full support for the related W3C standards being used by their competitors.

In their announcement of the createElement change for IE9, Microsoft recommended using the W3C standard setAttribute method, yet it fails for classid. *grumble*

To their credit, Microsoft also provided a second workaround consisting of strings and innerHTML:


var parent=document.createElement("div");
parent.innerHTML="<div id='myDiv'></div>";
var elm=parent.firstChild;

For our purposes, it would look like this:


function createIeObject(){
   var div = document.createElement("div");
   div.innerHTML = "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'></object>";
   return div.firstChild;
}

var target_element = document.getElementById("replaceMe"),
   isMSIE = /*@cc_on!@*/false,
   obj = (isMSIE) ? createIeObject() : document.createElement("object");

if (isMSIE) {
   //IE requires the 'movie' <param>
   var param_movie = document.createElement("param");
   param_movie.setAttribute("name", "movie");
   param_movie.setAttribute("value", "test.swf");
   obj.appendChild(param_movie);
} else {
   obj.setAttribute("type", "application/x-shockwave-flash");
   obj.setAttribute("data", "test.swf");
}

//Add attributes to <object>
obj.setAttribute("id", "myObjID");
obj.setAttribute("width", "550");
obj.setAttribute("height", "400");

//Add <param> node(s) to <object>
var param_flashvars = document.createElement("param");
param_flashvars.setAttribute("name", "flashvars");
param_flashvars.setAttribute("value", "cat=meow&dog=woof");
obj.appendChild(param_flashvars);

//Replace targeted DOM element with our new <object>
target_element.parentNode.replaceChild(obj, target_element);

This feels like it’s getting us somewhere. Unfortunately, the SWF still doesn’t load. What else can we try? What if the ‘movie’ param were added at the same time the object is created and classid attribute is specified in Internet Explorer?


function createIeObject(url){
   var div = document.createElement("div");
   div.innerHTML = "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'><param name='movie' value='" +url + "'></object>";
   return div.firstChild;
}

var target_element = document.getElementById("replaceMe"),
   isMSIE = /*@cc_on!@*/false,
   obj = (isMSIE) ? createIeObject("test.swf") : document.createElement("object");

if (!isMSIE) {
   obj.setAttribute("type", "application/x-shockwave-flash");
   obj.setAttribute("data", "test.swf");
}

//Add attributes to <object>
obj.setAttribute("id", "myObjID");
obj.setAttribute("width", "550");
obj.setAttribute("height", "400");

//Add <param> node(s) to <object>
var param_flashvars = document.createElement("param");
param_flashvars.setAttribute("name", "flashvars");
param_flashvars.setAttribute("value", "cat=meow&dog=woof");
obj.appendChild(param_flashvars);

//Replace targeted DOM element with our new <object>
target_element.parentNode.replaceChild(obj, target_element);

EUREKA! The SWF now displays as it should in all versions of Internet Explorer, and IE no longer behaves as if it’s stuck trying to load something. The takeaway is that Internet Explorer’s proprietary classid attribute and ‘movie’ param need to be created together or all is lost.

Why not use innerHTML all the way?

Many developers will say: Why not use innerHTML for the whole thing? After all, SWFObject 2.0 through 2.2 uses string building and innerHTML for the entire object creation in Internet Explorer:


el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';

In SWFObject, the attributes (att) and parameters (par) are added to the string via string concatenation. This is functional, but means that a completely different workflow — one devoid of standard W3C techniques — is required for Internet Explorer versus all other browsers.

For example, if there are many param nodes to add to the object, they will have to be generated as a long string of params in IE, while the fork for the non-IE browsers will all use a createElement/appendChild combination. In my opinion, it would be best to keep the code simple and use the same code for handling attributes and parameters in all browsers. This is ideal for maintenance, security, and file size.

Using the proposed IE solution allows us to modify the object via W3C techniques — we can add parameters and attributes and they all function as expected. The only difference between IE and other browsers is the creation of the initial object, but once it’s set up, IE’s object behaves the same in all browsers.

The obligatory poke at Microsoft

This is a perfect example of why there is not much love for Internet Explorer (and by extension, Microsoft) in many web developer circles. A task that should be trivial is utterly complicated, and requires hours of troubleshooting and experimentation just to achieve some basic functionality.

It’s my sincere hope that Internet Explorer 10+ will use the standard object code, but it probably won’t, since IE will probably still rely on ActiveX for the Flash Plugin. Falling short of using the standard object element, I hope that IE 10+ will at least allow us to add the classid attribute using setAttribute, and also allow us to add the movie param using createElement and appendChild.

Sniffing Internet Explorer via JavaScript

I’ve been reviewing bug submissions for the SWFObject project and was reminded of a big problem with SWFObject 2.2: the JavaScript technique it uses for detecting Internet Explorer does not work in Internet Explorer 9.

SWFObject 2.2 currently uses an IE detection technique proposed by Andrea Giammarchi in 2009:


var isIE = !+"v1";

It’s a hack that relied on Internet Explorer’s unique handling of vertical spaces (v). Now that it has stopped working, I decided to take a quick look at what others are doing.

One of my favorite approaches is Dean Edwards’ “sniff” technique, which takes advantage of Microsoft’s conditional compilation.


var isIE = /*@cc_on!@*/!1;

It’s 4 years old, but still works like a charm. The only problem is that some JavaScript compressors and optimizers (including YUI Compressor and Google Closure) have a hard time with the inline comment and strip it out. It makes the code difficult to maintain, because it requires editing post-compression.

One way to get around the compressor issue (as pointed out by a commenter on Dean Edwards’ post) is to wrap the conditional compilation statement in an eval() function:


var isIE = eval("/*@cc_on!@*/!1");

Since eval() is evil, I won’t use this approach.

One of the most long-standing methods of detecting Internet Explorer is to examine the userAgent string:


var isIE = /msie/gi.test(navigator.userAgent);

However, this isn’t foolproof, as most browsers allow you to change the userAgent string at will. For example, I changed Safari’s userAgent string to report itself as Internet Explorer 8, and /msie/gi.test(navigator.userAgent); returned true!

So far, the only test I’ve found that seems to fit the bill is the old navigator.appName test:


var isIE = navigator.appName === 'Microsoft Internet Explorer';

Is it perfect? Not a chance, but it has a lot of upside: it works in IE9, doesn’t get damaged when compressed, doesn’t rely on any hacky tricks (as fun as they might be), and isn’t affected by spoofed userAgent strings.

What are the Frameworks using?

jQuery uses userAgent sniffing, and includes a warning that it’s unreliable. MooTools uses a combination of properties from the navigator object, including navigator.userAgent and navigator.platform. It’s interesting to note that MooTools previously used feature detection to infer the browser brand, but changes introduced by Firefox 3.6 prompted the MooTools team to switch to a userAgent-based detection method instead. (Nicholas Zakas wrote an interesting blog post about MooTools’ prior detection technique.)
Dustin Diaz’s Bowser detection script uses userAgent exclusively.

Why sniff in the first place?

Before you get down on me for even talking about sniffing, relax, I agree with you. I much prefer feature detection to browser sniffing; this is especially important with our quickly changing browser landscape: HTML5, web storage, geolocation, etc. (Modernizr is a great tool for modern feature detection.)

But Internet Explorer always makes us do things we’re not quite comfortable doing. Sometimes it’s not very easy to detect IE’s support for a given issue. For example, IE is notorious for not allowing JavaScript developers to set the name attribute of form elements via setAttribute; it requires including the name in the createElement invocation. Craziness!

So we carry on. I use feature detection for just about everything, but once in a while I need a global “are you Internet Explorer?”, and browser sniffing fits the bill.

Introducing LearnSWFObject.com

I’m happy to introduce you to my latest project, LearnSWFObject.com

It’s been many, many months in the making, and has rudely been put aside a number of times when my life left me no free time to work on it. Happily, I’ve been able to push through the last remaining barriers and get the site out the door. Hopefully someone will find it useful.

I’ve ported my most popular SWFObject tutorials and examples to the new site — updated, of course — and have added a few new tutorials, too. As part of the housecleaning effort, I’ve removed all SWFObject examples and tutorials from pipwerks.com. 301 redirects will re-route the most popular posts to their LearnSWFObject.com equivalent, but the odds and ends have been sent to the compost heap.

I’m most excited about the brand-new code generator (written from scratch) that will write your SWFObject embed code for you. Some notes about the generator:

  • It can write HTML 5, HTML 4 (transitional/strict), and XHTML 1 (transitional/strict) doctypes
  • It provides code for both types of SWFObject embeds: dynamic (JavaScript) and static (markup)
  • It includes a download link that lets you save your generated markup in an HTML file
  • The static publishing option includes an option for a nice, shorter syntax
  • The generator uses progressive enhancement techniques, meaning it’s nicer with JavaScript enabled but fully functional without it

Give it a try!

LearnSWFObject.com will remain a work in progress, as SWFObject itself continues to evolve and people find news ways to break use it in their sites. I will continue to play with the formatting and layout from time to time.

In other SWFObject news, I think I’m allowed to report that SWFObject 2.3 is in the works, and will contain mostly bug fixes and an enhancement or two. Bug reports and feature requests are always welcome at SWFObject’s Google Code site. If you have questions about how to use SWFObject that aren’t answered by the LearnSWFObject.com tutorials, please post them on the SWFObject Google Group.

Eolas is at it again

Eolas Technologies is a company that manages licensing for patents.

Eolas seeks to return value to its shareholders by commercializing these technologies through strategic alliances, licensing and spin offs. (source)

The problem is that Eolas is generally regarded as a bully trying to enforce a patent (Patent 5,838,906) that many experts feel should not have been issued.

The 906 patent, received in 1998 by the University and licensed exclusively to Eolas, describes ways that a Web browser can use external applications. (source)

(The US Patent and Trademark Office has made notoriously bad decisions relating to Internet technologies, causing many to wonder if they truly even understand the patents they’ve granted. Blackboard vs Desire2Learn is a great example; Blackboard acted much like Eolas, and their patents were eventually nullified by the PTO.)

Eolas sued Microsoft in 1999 for violating Patent 5,838,906, and in a rare show of solidarity, the Web and Open Source communities — normally very anti-Microsoft groups — rallied to Microsoft’s side. This included Sir Tim Berners-Lee, the founder of the Internet. They pleaded with Eolas to release the patent into public domain for the greater good of the global community.

Anybody in the browser field that studies the technology will see that its a very fundamental and basic patent to the World Wide Web. (source)

Despite the overwhelming negative response from the Web and Open Source communities, Eolas would not relent and forced Microsoft to modify Internet Explorer in a way that broke functionality on over hundreds of millions of web pages. Microsoft eventually forked over tens of millions of dollars in a settlement that allowed them to restore the functionality they had been forced to remove.

Other companies and products have used the same technology for years without paying royalties — Mozilla Firefox and Opera being the most well-known — but were not sued by Eolas, who chose to focus on the deep-pocketed Microsoft. (An initial jury verdict in 2003 awarded Eolas $521 million, but an undisclosed settlement was reached in 2007 after the case went through several appeals.)

This week — a year and a half after settling with Microsoft — Eolas has gone on the attack again, filing suit against “Adobe, Amazon, Apple, Argosy Publishing (publisher of The Visible Body), Blockbuster, Citigroup, eBay, Frito-Lay, GoDaddy, J. C. Penney, JPMorgan Chase, ‘transactional’ adult entertainment provider New Frontier Media, Office Depot, Perot Systems, Playboy Enterprises, Rent-a-Center, Staples, Sun Microsystems, Texas Instruments, Yahoo, and YouTube.” (article)

For the record, Eolas was founded by former University of California, San Francisco (UCSF) staff, and the patent they’re suing others for violating was developed at UCSF in the 90s. http://en.wikipedia.org/wiki/Eolas

I work at UCSF and am ashamed of these lawsuits.

The University of California owns Patent 5,838,906 and has licensed it to Eolas. The Regents of University of California are therefore the driving force behind Eolas’ behavior. By extension, UC is a driving force behind one of the biggest and most unpopular disruptions the Internet has known. If UC is really interested in public interests and good will — not to mention good publicity — I hope Patent 5,838,906 will be released into the public domain.

On a side note, knowing the University of California is being hit hard with budget cuts, I wonder if this latest blitz of lawsuits is an attempt at making up for budget shortfalls?

The pipwerks forum is dead, long live the new eLearning Technology and Development Google Group!

A year ago this week, I launched the not-for-profit and ad-free pipwerks E-Learning Development Forum. It was mostly intended to be a way for me to answer questions about some of my projects, such as the SCORM API wrapper, SCORM ActionScript classes, and my many Captivate hacks. The forum wasn’t a vanity project so much as an attempt to avoid email… I’d rather post answers online where everyone can see them than reply to individual emails. I had also hoped other people in the e-learning community would get involved and ask/answer questions beyond the scope of my pipwerks projects.

Now that a year has passed, I decided to step back and evaluate the success of the forum. The numbers aren’t bad: over 200 members, over 550 posts. Of course, it isn’t about the numbers, but about helping people; I’d like to think that most of those 200 people found the answers they were looking for. This is great, and makes me happy. If I helped even one person, the forum can be considered a success.

However, I also noticed a considerable lack of participation from others. Aside from a few helpful folks, I wound up answering most of the questions myself. This means it wasn’t so much a forum as an “Ask Philip” column. Not exactly what I had in mind.

When combined with the effort it takes to maintain a website (security patches, compatibility issues, styling, etc.), the forum started to feel more like a weight on my shoulders than anything else. So, as of today, I have closed down the forum and moved over to a Google Group: the eLearning Technology and Development group.

I’ve been using Google Groups for over a year with the SWFObject Google Group and Aaron Silvers’ Flash For Learning Google Group (no longer online). It isn’t a perfect system, but I’ve learned to enjoy its simplicity. It’s also free and relieves me of administrative hassles such as applying updates and backing up data. Sweet. Plus you can use Google Groups via email, which means you never even need to visit the site. Bonus.

I’d like to say thank you to all the people who posted in the pipwerks forum, and invite you to join me in the new eLearning Technology and Development group.

I’d also like to ask anyone and everyone who develops e-learning to drop by and sign up for the eLearning Technology and Development group. Ask questions — lots of questions — and let’s see if we can get a good community going!

PS: If you’re wondering why I bothered creating a new group considering there are many other discussions groups/forums out there, the answer is simple: no product favoritism and no advertising. Product forums by vendors such as Adobe and Articulate are focused solely on their products, while bulletin boards by organizations such as the eLearning Guild tend to have a ton of ads and a focus on their events and sponsors. I’d like less clutter in my life, and a simple Google Group (even with the AdSense ads) is a nice clean way to handle discussions. Hope you agree!

SWFObject.js finds a home on Google servers

Cool news for SWFObject users: the swfobject.js file is now being hosted on Google’s servers as part of the AJAX Libraries API. This means you can directly link to the file on a Google server instead of maintaining a copy on your own server.

The benefits of using this service are many, with my favorites being:

  • You will not need to maintain your own copy of the library (which for many developers means we don’t have to maintain multiple copies spread all over the place).
  • Load time should be very fast because A) Google has speedy servers, B) Google’s versions are minified, and C) Google’s versions are properly gzipped.
  • Downloading from Google’s server benefits your page’s load time because if other people also use Google’s API service, there’s a good chance the swfobject.js file is already cached in your browser and won’t need to be downloaded again.

The AJAX Libraries API also hosts other script files, most notably the JS frameworks MooTools, jQuery and Dojo. There’s a great intro to the AJAX Libraries API by Dion Almaer at ajaxian.com.

Bobby Van der Sluis has updated the SWFObject documentation to include instructions for using the hosted version of swfobject.js.

Note: I have updated all of my SWFObject 2.0 examples to use the AJAX Libraries API; if you encounter any examples that don’t work properly, please let me know.


Introducing PDFObject

Update March 2011: PDFObject source code has been updated and moved to GitHub.

I recently worked on an e-learning course that required embedding some PDFs into an HTML file. PDF embedding piqued my curiosity, and has become something of a pet project. It sounds simpler than it is. No, scratch that… it is pretty simple. Stoopid simple. The problem is that there’s a lot of bad info about embedding PDFs floating around the www, especially regarding using the embed element.

Note to readers: embed bad, object good.

Unlike embedding SWFs, embedding a PDF is a breeze if you use the object element, and the object element has the added bonus of being totally standards-compliant.

As I tinkered on my new pet project, I decided it would be nice to have a JavaScript script that could dynamically embed PDFs as easily as SWFObject allows SWF embedding. I managed to whip up a script, and decided to name it PDFObject. (I know, I know… what a creative name!) As you may have inferred from the name, the concept and functionality is pretty similar to SWFObject. Like SWFObject, it’s also standards-friendly, and uses DOM scripting techniques to write a standard object element to the page.

One of the perks of using this script is that it makes working with PDF Open parameters much easier, similar to how SWFObject makes working with flashvars easier.

I’ve built a simple website for my PDFObject project named — drumroll, please — http://pdfobject.com. The most time-consuming part of this project has actually been building the website; it includes instructions, a ton of examples, and a compatibility table detailing results from browser/OS testing, including Mac OS X 10.5, Win XP, Vista, and Ubuntu. The site also features a section devoted to PDF embedding using standard HTML code without JavaScript (gotta promote standards!), and a handy code generator that makes writing the code as easy as filling out a form.

The site purposely does not include support or contact information; while I enjoy making things that help people out, I already know I don’t have the time to handle support issues. Sorry!

Anyway, PDFObject is completely free (as-is, no warranties) and my gift to the community. I hope some of you find it useful. 🙂

SWFObject example links fixed

When I recently reorganized my SWFObject examples (adding a bunch of SWFObject 2.0 examples), a few links were accidentally hosed. Links fixed. Sorry ’bout that.

There are now over 30 examples using over 50 files, and I just tested each and every one of them to ensure they work. 🙂

(Thanks to Winston for letting me know about the dead links.)

More SWFObject 2.0 examples

I just posted a few more SWFObject 2.0 examples:

  • Plain-vanilla SWF embedding using SWFObject 2.0
  • Using SWFObject 2.0 with ExternalInterface
  • Determining whether a SWF was successfully embedded (returning a boolean in JavaScript)
  • Using SWFObject with an ‘onclick’ event

Update: The SWFObject examples list is now located at http://learnswfobject.com