Bye-bye <applet>. Hello <object>!
The object tag, xHTML-strict, loading-bars, applet preloading and appletobject.js
A quick summary since the text kinda grew long:
(1) Download these template(s) if you want to export your sketches from Processing to be embeded into valid xHTML 1. Versions for OpenGL applets are in there too.
(2) I found a method with fallbacks to improve the user experience with startup and loading times for applets on websites.
Enter here.
Processing allows for generating web-ready applets via it's "export for web" feature. Currently this generates an applet-folder containing the source-files as .java and .pde, one or multiple jar-files (depending on your preferences settings), a loading-image (Processing icon, "loading.gif") and a (almost xHTML-1.0-Transitional) xHTML-file. This file is based upon two templates that come with Processing, applet.html and applet-opengl.html, which live inside Processings </path/to/app>/lib/export folder. One can alter the HTML being used for export by placing a template-file named "applet.html" inside your sketches root directory.
Following up on multiple requests on Processings discourse-forum for a standarts compliant, valid (xHTML) version of the template, i decided to spend some time making one.
The current situation is, that the <applet> tag as used by Processing is deprecated in xHTML-1.0-Strict. It will still work with most new browsers but should shift them into what's called the quirks-mode since the source-XML will not validate. This behavior might go away in the future and the exported applets might not be displayed anymore. As much as i doubt this will happen any time soon, it's not a bad idea to move on to be both as forward and backward compatible as possible.
I've based my approach on several sources, many of which do a lot of explaining on the change from <applet> to <object>, so i'm not going into much detail with that.
- (Multiple Browser Supported) Java applet using XHTML 'object' tag
- Using OBJECT, EMBED and APPLET Tags in Java Plug-in
- Java Plug-in 5.0 Developer Guide Contents
- Objects, Images, and Applets in HTML documents
The main target of this little research is to have the xHTML object tag to embed an applet be:
- valid with w3c
- as compatible as possible
- working with OpenGL applets
- keep the loading icon and -bar of the current applet tag
- have fallbacks in case Java is not installed or disabled
Test setup
As testcases i made two simple sketches:
- xhtml1
- xhtml1_opengl (.. right, with OpenGL)
- read a param from the tag they were started with to see which was used
- callback to javascript (message pops up) to see if mayscript works
- display the text from the param and a counter in applet as some feedback
Each sketch was exported using one of two templates (see above), and these are the resulting files from Processing:
- A1 with applet tag as currently exported by Processing (*)
- A2 with applet tag for OpenGL as currently exported by Processing (*)
- O1 with object tag, based on Shayne Steeles version
- O2 with object tag for OpenGL, mixing A2 and O1
(*) with minor modifications to be almost xHTML-Transitional. The only thing that breaks it is the mayscript-attribute, which is not valid XHTML. Sadly FireFox will not recognize it if passed as param, therefore i left it in as was.
Results without OpenGL
All testing was done on a Mac PowerBook G4 1.67 Ghz, 1GB RAM.
Additional Systems were run with VirtualPC.
Systems:
- osx = OsX 10.4.8, Java JRE 1.4.2_09
- xp = WinXP SP2, 686, 333MHz, 256 RAM, Java JRE 1.4.2_12
- lin = Linux Debian Sarge i686, 333MHz, 256 RAM, Java JRE 1.4.2_03
Jump down below "Notes" for a summary of the results. ----------------+---------------+---------------+-------+-------+--------------+ Browser |fallback(*) | |js- |param |icon, | | | |called |read |loadingbar | | | | | | | | | | | | O1 | A1 | O1 | A1 | O1 | O1 | A1 | ================+=======+=======+=======+=======+=======+=======+=======+======+ IE 3.0 (xp) | X | X | - | - | | | | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ IE 4.01 (xp) | X(1,2)| X | Xi | - | X | X | 1 | | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ IE 5.01 (xp) | X | X | Xi | X | X | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ IE 5.23 (osx) | X(20) | X | Xo(9) | X | -(19) | -(19) | 0 | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ IE 5.5 (xp) | X | X(3) | Xi | -(3) | X | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ IE 6.0 (xp) | X | X | Xi | X | X | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ FF 1.5 (xp) | X | -(4) | Xo | X | X | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ FF 1.5 (osx) | X | -(8) | Xo | X | X | X | (22) | (22) | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ FF 2.x (osx) | X | -(8) | Xo | X | X | X | (22) | (22) | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ FF 2.0 (xp) | X | -(4) | Xo | X | X | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ NS 6.2.3 (xp) | X | X(5) | - | -(21) | | | | | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ NS 6.2 (osx) | X(10) | X | -(10) | -(10) | | | | | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ NS 7.2 (osx) | X | -(12) | Xo | X | (13) | X | 0 | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ NS 7.2 (xp) | X | X(6) | Xo | X | - | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ NS 8.x (xp) | skipped, uses IE / FF renderer | | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ OP 8.54 (xp) | X | X(7) | Xo | X | X | X | 0 | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ OP 6 (osx) | X | -(25) | -(24) | X | - | - | | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ OP 8.5 (osx) | X | X(15) | Xo | X | X(14) | X | 0 | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ OP 9.1 (xp) | X | X(7) | Xo | X | X | X | 0 | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ OP 9.1 (osx) | -(25) | X(7) | Xo | X | X(14) | X | 0 | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ Lynx (osx) | X | X | text browser | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ Sa 1.3.2 (osx) | X | X | Xo | X | X | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ Sa 2.x (osx) | X(25) | X(26) | Xo | X | X | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ appletviewer osx| no html | Xi | X | | X | | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ appletviewer lin| no html | Xi | X | | X | | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ KO 3.3 (lin) | -(16) | X | Xo | X | X | X | 0 | 0 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ EP 1.4.8 (lin) | X | -(17) | Xo | X | X | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ MO 5.0 (lin) | X | -(17) | Xo | X | X(23) | X | 1 | 1 | ----------------+-------+-------+-------+-------+-------+-------+-------+------+ (*) Fallback means the fallback-text (inside applet or object) was used if Java was disabled via browser preferences / options. X = OK Xi = OK, inner object tag used Xo = OK, outer object tag used - = did not pass 0 = browsers own text, no icon, no loading-bar, sometimes status-bar has more info 1 = only icon was shown 2 = icon and loading-bar + text (as expected since Java 1.4.2) IE = Internet Explorer FF = Firefox NS = Netscape OP = Opera Sa = Safari (AppleWebKit 418.9.1) KO = Konqueror (khtml 3.3.2) EP = Epiphany Web Browser (same as MO?) MO = Mozilla -------------------------------------------------------------------------------- (1) IE 4.01 (xp): Java not installed: shows two fields: missing image-field for outer tag, applet runs inside inner tag Java disabled: ( gone away after installing Java 1.4.2 ) (2) IE 4.01 (xp): misses to ask about loading the plugin (as do all other IEs on win) (3) IE 5.5 (xp): crashed every time after loading (might be due to multiple IEs / my setup) (4) FF all (xp): No Java installed: misses fallback text but shows a: "Click here to download Plugin" (puzzle piece icon) Java disabled: nothing, no text, ... (5) NS 6.2.3 (xp): Java not installed: misses fallback-text, shows "Click here to get the .." (puzzle piece icon) no link given to download Java Java disabled: works. (6) NS 7.2 (xp): Java not installed: like (5), but link to sun works Java disabled: emtpy, no applet, no error, nothing. (7) OP all (xp), 9.1 (osx): Java not installed: message pops up "You need to install Java to view all content on this page. Do you want to download Java now? ( OK / No )" applet field is mini, misses size settings in tag Java disabled: just the mini-block saying something like "Java a" (8) FF all (osx): Java disabled: misses fallback text. no indication that something's not displayed. (9) IE 5.23 (osx): although it loads the applet the fallback-text is shown (10) NS 6.2 (osx): java.lang.NullpointerException, not sure why ... (12) NS 7.2 (osx): no fallback-text, no indication that something is missing (13) NS 7.2 (osx): using lib "netscape.javascript" causes applet to fail: status says "Applet started" but field is just a white box (14) OP all (osx): using processing lib "netscape.javascript" causes applet to fail: field is just a white box (15) OP 8.5 (osx): like (7) but no popup, just mini box (16) KO 3.3 (lin): Java not installed: just a brown-grey box where the applet should be Java disabled: applet ran nonetheless ... (17) EP 1.4.8 (lin), MO 5.0 (lin): Java not installed: (puzzle piece icon) with link, pops up alert saying that a plugin is missing Java disabled: blank block where applet should be (19) IE 5.23 (osx): complains about script error, since it's not showing the alert-message i think this might happen when js is called from applet ... might be a wrong encoding in the js-string. (20) IE 5.23 (osx): uses the standby-attribute text from object tag as fallback. (21) NS 6.2.3 (xp): (puzzle piece icon) + missing plugin, clicking it goes to a missing page at netscape.com ... (22) FF all (osx): seems to wait until the page is fully loaded (including applet) before displaying anything, bad with big applets (jars). no icon, no loading-bar, no text ... (23) MO 5.0 (lin): javascript alert-window hung and was not closeable. (24) OP 6 (osx): fallback text was displayed instead of applet (25) OP 6, 9.1, Safari 2.0 (osx): Java disabled: applet ran anyway (26) Sa (osx): Removing the Java-Plugins will sometimes not show fallback-text with applet-tag: Java enabled gives error-message, Java disabled gives empty block -------------------------------------------------------------------------------- Notes: - Many (most?) browsers seem to use internal caches for jars (and classes?). Caching was disabled in the plugin, nonetheless they reloaded the applet almost instantly on a different page and tag. - IE 5.2.3 osx : does not like the ";jpi-version=1.3.1" with object-tag as in: type="application/x-java-applet;jpi-version=1.3.1" - Safari pre 2.x: there were reports saying that pre2.x versions did not read the params. could not confirm that ... might be due to a more recent applewebkit/418.9.1 on my machine (os-x 10.4.x) - Safari 2.0.4, others?: using codebase=".." as attribute in the outer object tag is not working, make it a param just as with the inner-IE tag: <param name="codebase" value="--your-codebase--" /> - Safari 2.0.4, others?: calling javascript from applet when javascript is disabled is an instant force-quit. not sure if this is happening in JSObject or via showDocument( 'javascript:..' ); --------------------------------------------------------------------------------
Again, bye-bye <applet>, hello <object>!
As much as i dislike the object tag code-wise, it generates better results. It is by one case more compatible (compare 4th and 5th columns) and in regard to displaying the fallback-text it is far more reliable ( 2nd and 3rd column: 23-17 !).
Adding OpenGL
Changing the object tag to be OpenGL compatible was a snap and it turns out that it works as good as the old one. I've not done as extensive testing as applet-vs-object, but all major browsers supported it:
- InternetExplorer 6 xp
- Safari 2 osx
- FireFox 2 xp
- Opera 9.1 xp
Still not the best user experience.
After all this testing i figured (following another string of discussions) this might be a good chance to try to tackle some of the most annoying user-experience problems with applets: the long starting time the Java plugin (JVM) needs and the only-sometimes-working loading status display.
- Processing/ Java Preloader
- pre loader?
- javascript loading animation
- streaming applet code/libs – any suggestions?
- Loading time too long ?!
- Different loading times with different JVMs
- improve user-experience with Java-plugin / jvm startup time
- improve status feedback of loading applets
Applets are not really user-friendly. Starting the Java-Plugin and with it the JVM takes time and once it's up you have to wait until all files (classes, jars) are downloaded for the applet to start. There are some things that we as developers can do to speed things up, but still a user with an old machine and a slow connection will look at a mostly ugly box until at least the very first class is loaded and running. This got a little better around Java 1.4.2, when the loading-image, message and bars were included, but they seems to have went away again with 1.5 (Java 5) leaving us with a funny sun.
There's only so much you can do on the Java side. A lightweight Java preloader would allow for an image or a message to be displayed, think splash screen. You could even try (java security?) to write your own ClassLoader which would theoretically give you access to the amount of bytes downloaded per file. But still the JVM must have started and the first file must be up and running.
Then i ran into Aaron Steeds (st33d) post about his appletobject.js. His idea was to use the same concept as the SWFObject for Flash, similar to what Karsten Schmidt (toxi) did here, and apply it to applets. Bravo!
Javascript to the rescue.
I've been playing with javascript based improvements to the applet loading status before. Back then i attempted to hide the applet-DOM-element until the applet was fully loaded and running. It worked sometimes, but not too many browsers liked it.
Aarons appletobject.js sparked the idea to go back and merge the two together (expanding both on the way). Here's what i have so far.
How it works ...
It's based on the Java to javascript connection called LiveConnect. After the AppletObject has been created and it's preload() function has been called it goes into a forked loop. For each jar that's needed for the applet to run there's a tiny applet injected to the page that loads a small class plus one jar to preload. That applet calls back (from Java to javascript) to the AppletObject once it's init() and again once it's start() functions were called by the Java-Plugin. When these get called the jar was successfully loaded into the Java cache. These callbacks are rerouted (after being handled internally) to user-defineable functions of the AppletObject (oninit(), onfail(error), onstep(percent), onload()). By overriding these you can for example add your own javascript magic to update a loading-bar on your page.
See sources for additional info: appletobject.js index.html
This method resolves both problems: the JVM is started before the applet is rendered to screen and all jar-files are preloaded. But it's not perfect; if your sketch consists of only one jar, then you should consider adding a spinning-icon instead of the loading-bar. Another problem is javascript and Java fighting for processor cycles, some browsers don't like that an might even crash. Let me know how it works for you and i'm happy to improve things if i can.