Rapid Fluid support
- Tags
- Posted
- Fri 26 Dec, 2008
- Comments
- 2
Fluid is a Site Specific Browser (SSB) for Mac OS. It allows web applications to run in their own window with a dock icon, dock badge and supports Growl notifications. You can support Fluid in your web app without any server-side code changes.
I recently added Fluid support to Deadline. Deadline basically a calendar/reminder system, so it works particularly well with Growl notifications. It was a rewarding development experience: Fluid’s API is clean and delivers excellent results with minimal effort.
Browser support detection
It’s important to check if Fluid is available before trying to call its API.
The easiest way to do this is:
if (!Object.isUndefined(window.fluid)) {
return new FluidAppMode
}
This stops browsers from trying to load Fluid functionality when its not available.
Auto-refresh
Deadline displays a list of events with no automatic browser refresh. When adding Fluid support I decided to automatically update the displayed items using PeriodicalExecuter (from Prototype). This makes it feel a little bit more application-like. Deadline shows inline editors, so it’s trivial to check if any inline editors are visible to hold off PeriodicalExecuter to prevent it from updating while the user is editing.
As time goes by each deadline’s event date is reached and a notification is displayed. To track which ones have been displayed I use a cookie that stores a list of deadline IDs.
Dock badge
Deadline reminders that are ready are counted and displayed in the dock icon:

Changing the dock icon is easy: window.fluid.dockBadge = count. To avoid changing server-side code, I derive the dock badge count by counting the number of deadlines marked with “Now”.
Growl Notifications

Growl notifications can be displayed with this Fluid API call:
window.fluid.showGrowlNotification({
title: "Deadline Reminder",
description: message,
priority: 1,
sticky: false,
identifier: message_id
})
You can’t just display notifications blindly, however. For Deadline I decided to record the displayed deadline IDs using a cookie. We have an internal JavaScript library called Azuki which abstracts cookie management, but you should be able to follow this code without it:
showNotifierMessage: function(message, message_id) {
if (this.displayedMessage(message_id)) {
return
}
window.fluid.showGrowlNotification({
title: "Deadline Reminder",
description: message,
priority: 1,
sticky: false,
identifier: message_id
})
this.logMessageDisplay(message_id)
},
logMessageDisplay: function(message_id) {
// Log message to cookie
var deadline_notifier_messages = Azuki.Storage.Cookie.find('deadline_notifier_messages')
if (Object.isUndefined(deadline_notifier_messages)) {
deadline_notifier_messages = message_id
} else {
deadline_notifier_messages = deadline_notifier_messages + ',' + message_id
}
Azuki.Storage.Cookie.create('deadline_notifier_messages', deadline_notifier_messages, 365)
this.log(deadline_notifier_messages)
},
displayedMessage: function(message_id) {
var deadline_notifier_messages = Azuki.Storage.Cookie.find('deadline_notifier_messages')
message_id = parseInt(message_id)
if (Object.isUndefined(deadline_notifier_messages)) {
return false
}
var message_ids = $A(deadline_notifier_messages.split(','))
return message_ids.find(function(logged_id) {
if (parseInt(logged_id) == message_id) {
return true
}
})
}
As you can see I store each displayed deadline ID separated by commas in a cookie. This then allows Deadline to only notify new deadlines.
Supporting multiple SSBs
There’s a few SSBs available. I’ve chosen to support Bubbles for Windows.
To support multiple SSBs you could either use inheritance or delegation to manage shared code. In Deadline’s case I’ve shared the notification cookie management code and the use of PeriodicalExecuter between Fluid and Bubbles using inheritance. Remember that Prototype’s inheritance mechanism is now specified through Class.create
var FluidAppMode = Class.create(WebAppMode, {
initialize: function() {
I’ve detected the availability of Bubbles as follows:
if (typeof(SSB) != 'undefined') {
return new BubblesAppMode
}
Bubbles’ API is accessed through the SSB singleton object.
Share your SSB support
Have you supported an SSB with your web app? Why not share your links and experiences in the comments?
Henrik N
Jan 5
Since you didn't explicitly say: Object.isUndefined is Prototype-specific. Wouldn't "if (window.fluid) { ... }" work as well and read better, in this case?
alex
Jan 5
I was just being literal in the sense of checking if window.fluid is defined or not.