DP and HTML5 – strange bedfellows

So a few days back I got my hands a bit dirty with HTML5’s CANVAS tag.  And some number of weeks ago I got into the history object and HTML5’s improvements to that.  Today I got my feet a little wet with the AUDIO tag.

It’s an interesting concept, really.  This most recent journey has been within the context of the home audio system, and I was just just just remarking to myself that development was at a virtual standstill for a number of months – and here it is that HTML5 is enabling a new coding push with real-world usability.

Well, that’s the theory.

The truth is that HTML5 and embedded media consumption are themselves strange bedfellows, and as a result, I find myself in the same position in my relationship with HTML5.

So forget about the abstracts.  My music collection is overwhelmingly encoded in the MP3 format.  And when I say overwhelmingly, I really mean completely – with the exception of perhaps 20 tracks, vs. the other 35,064 which are MP3’s.  The problem with MP3 – besides its lossy, yesteryear compression – is that it’s not in the public domain.  This doesn’t really mesh well with HTML5 – specifically, the AUDIO tag of HTML5 – which wants to work with open standards and hence is at odds with MP3.

So how does this affect me and my home audio system?  Glad you asked.

You may recall that the system consists of 2 physical zones, 4 general-purpose streaming zones and one special-purpose streaming zone.  It’s the general-purpose streaming zones that I use extensively when I’m not at home – ie, at work or in the car.  And despite advancements in the manner by which my intranet resources are made publicly “available”, the real truth is that using the streaming zones has always been a two-part affair; part one is to interact with the system using a browser, part two is to connect to the zone using a program on the client device.

Granted, quite often I can eschew part one, as the zone is loaded and good-to-go as soon as the client connects.  But one thing that really dogged me incessantly – besides security considerations that I won’t go into here – is the absence of any ability to play a single track without having to leave the web browser.

Yes, I’m talking about a desire to implement an audio client within the browser itself.

Now, Flash is capable of doing this.  And while Shelly’s phone doesn’t support Flash (argh), the truth is that Flash isn’t completely suited to the next logical step in this thought process – which is, replacing the streaming zones with a webpage and embedded player.  I mean, I could code a Flash app, but trust me when I say that that’s not going to happen.

But would could happen – and indeed, what I really, really, really want to happen – is to code an HTML5 “app” that can do this.  This would actually solve all sorts of niggling problems, like the issue of transport control that I talked about here.  The truth is that it could actually serve as a bonafied mobile music app, optimally designed for the small screen.

It could, if… MP3 and HTML5 played nicely together in all modern browsers.

And that’s the problem I’m having right now.  I’ve worked out the interaction, I’ve figured out that the current home audio system can easily support the types of XHR calls I’d need to make, I’ve got some working knowledge of JSON… heck, I’ve even got a working implementation now of an embedded player for playing single tracks.  But to make this all work I need HTML5 and it’s DOM-accessible AUDIO element, and I need cross-browser support of MP3 files via that same AUDIO element.

Desktop support is sketchy – as is mobile support.  I find it strange that Opera on Windows doesn’t support MP3 but Opera on Android does…?  And the native Android browser is supposed to support MP3 but it actually doesn’t.  <sigh>  The truth is that there’s no point burning the proverbial midnight oil on an HTML5 music player app for my audio system if support is hit-and-miss – across the devices that I actually use.

So as much as I’d love to cuddle up close to HTML5, the unfortunate truth is that it’s playing hard to get.

Using up/down arrows with the script.aculo.us Autocompleter

I came across a problem recently, using the Autocompleter API of the script.aculo.us library.  Some amount of Googling later and I still couldn’t find a solution, but I discovered that there was misery in company – other devs were having the same issue.

Basically, when the autocomplete list is generated, and said list has a scrollbar on it, clicking on a scrolling arrow (or the scrollbar itself) would cause the list to disappear. Why? Because the input field’s onblur() would fire and close the list.

So I looked through the code a bit, and came up with this simple solution.

First: make sure that you save a reference to the Ajax.Autocompleter object that you create:

var oAutocompleter = new Ajax.Autocompleter()

Second: define an undocumented option in the options parm list:

onHide:	fOnHide

…where fOnHide is a function we’ll define later.

Third: add a boolean var to the Autocompleter object:

oAutocompleter.lcl_bActive = false;

Fourth: apply some event handlers to the div that is populated with the results:

oAutocompleter.update.onmouseover = function() {oAutocompleter.lcl_bActive = true;};
oAutocompleter.update.onmouseout = function() {oAutocompleter.lcl_bActive = false; oAutocompleter.element.focus();};

Fifth, and finally: define the fOnHide() function:

function fOnHide() {
  if (!oAutocompleter.lcl_bActive) {
    new Effect.Fade(oAutocompleter.update,{duration:0.15});
  }
}

Now – how does this work? (good to know, since I’m sure it’s inevitable that it won’t work for somebody or at some point in time)

It seems that somebody ends up calling the onHide() function of your instantiated Ajax.Autocompleter object whenever the input field’s onblur() fires. Normally this results in an Effect.Fade being instantiated, and your result list fades out of existence.

We interrupt that process – instead of calling the Effect.Fade() directly, we first check to see if a flag has been set.  The flag is set to true whenever the pointer is hovering over the list – manipulating the scroll buttons or scrollbar or just hanging out.  In those instances, the onHide will essentially do nothing, and your autocomplete list will not disappear.

Once you move away from the list, the flag is reset and, crucially, focus is returned to the input field.  This is done so that the field’s onblur() can fire when appropriate, as it would have done before we made any code changes.  Now, when the field loses focus, the fOnHide() function will perform the default task of running the Effect.Fade() function.

Easy breezy 🙂

Wifey say, wifey do: zone drag/drop active

I don’t really know what to say about the titles that I come up with.  I mean, they’re my ideas, so I can’t sit here and shake my head in disbelief or some mild form of pity.  But really, what the heck does this one mean?

Well, at least the second part is fairly self-explanatory – to a degree.  It’s now possible to drag-and-drop an album or song directly onto a zone while in the browse view.  The idea is that you can queue up – or begin playing – an album/song without going through the steps that previously existed (and still exist) to perform this apparently arduous task.

Yes – “apparently” – and this is where the first part of our interesting title is explained.  One day, a long long time ago, Shelly said that it really should be possible to drag-and-drop an album onto a zone.  I believe that I was in the midst of showing her the ability to drag-and-drop an album/song onto the working list and have the item added to the list.

I’m not sure what prompted her to make this suggestion.  The thing is, the drag/drop facility is only available on platforms that support dragging – like a laptop or desktop – and not at all on platforms like smartphones which have no concept of how to perform a drag/drop action.  And – you guessed it – Shelly users her smartphone to interact with the system.

Nevertheless, I said “yes ma’am” and eventually got to work.  And the fruits were fully realized today (well, a couple of days ago but polished a bit today) with code that makes Shelly’s suggestion a reality.  As I said, from the browse view, you can drag an album/song over the existing play icon, which will cause a popup to be dynamically created containing all of the zones.  Finish the drag/drop operation by dropping the album/song on one of these zones, et voila, Something Happens(tm).

That “something” is dependent on a few things.  For an unloaded/unlinked zone, the operation will always end with the zone being shown and playback started.  Depending on your prefs, you may be asked if you want the zone to be linked.

For a zone that is already linked, the operation will cause the dragged item to be added to the linked list.  You remain on the browse view, but there is a helpful popup that says “Added” just to confirm that, indeed, Something Was Done(tm).

Now, the 5-billion-dollar question is: is this really necessary?

Well let’s look at the title for the most obvious answer: Wifey say, wifey do.  Wifey said “Do it”, and now wifey can do it.  Easy breezy.

Okay, how about a more general discussion?

I’ll oblige.  If you have the ability to perform this drag/drop operation, then you have the ability to use the other nifty features presented by the interface – most notably, the ability to take advantage of dynamically-loaded popups and inline information.  Previously – and currently – the steps to play an album or song (we’ll just say an “entry”) could most easily be performed by clicking the popup icon for that entry, clicking the play icon in the resulting popup, and then clicking the zone in the resulting zone list that got dynamically loaded into the popup.  This operation would always result in you getting transferred to the zone, where playback would have been started.  In the case of a zone that was previously linked, the linked list would be overwritten (unless the list was not an auto-generated linked list – in which case you’d get an error).

So if anything, that’s three clicks and waiting around for two dynamic operations to complete (the popup and the inline zone list) before anything could happen.

With the new drag/drop ability, you really only click once and you have to wait for one dynamic operation to complete – ie, the popup containing the zone list.

So from that point of view, I suppose I can agree that the new method is indeed more efficient.  I have to wonder how many times in one session a user is likely to load an entry to a zone – or in other words, how much impact this increased efficiency would have in the real world – but I suppose one can’t argue when it comes to the inherent goodness that is “increasing efficiency”.

But wait… perhaps there’s more to this.

What really makes this worthwhile is that the code is linked-status-aware.  Meaning, it does different things depending on the linked status of the destination zone.  This was alluded to earlier, but allow me to focus on it in more detail.

While it’s all well and good to drop an album on a zone and call it a day for the next 60 minutes, what happens if you’re putting together a 4-hour playlist of albums – or a 60-minute playlist of songs?  Now we’re no longer talking about loading a single entry to a list.

The previous (and still existent) optimal method for doing this would have been to create a new playlist and select it as the working list – or perhaps to load the first entry to the zone, then select the resulting list as the working list.  This doesn’t always work well if you’re working with albums, as the system isn’t guaranteed to create a linked list for a single album depending on how your prefs are set.  But supposing that it’s set appropriately, either of these methods would get you pointed in the correct direction.

Then, you could drag/drop additional entries to the list – or use a pulldown, or a checkmark,  or whatever other method you liked.  But the point is that you’d want to select the list that ended up getting linked to the zone of interest.  Or, if you manually created the list, then you’d select this list as the one that you will eventually load to the zone of interest.

With this new method, the only thing you need to know is what zone you want to work with.  You could have an entirely different list selected, or no list at all.  The list is not important – only the zone.  So the new sequence of events becomes: drag/drop an entry to the zone, return to your browse results, and drag/drop more entries to the zone.  The backend will take those additional entries and add them to the list associated with the zone.

You can see that this method offers clear benefits.  Again, there’s no need to work with or even know which list is linked to the zone.  This is especially useful if your current working list was used as part of the criteria in your current search.  Changing your working list to become the linked list would alter your search results, which may make it difficult to select more entries to add to the working list.

But most crucially, you get to take advantage of the increased efficiency that we discovered previously.  Yes, you could already drag/drop entries onto your working list – ie, the same efficiency that drag/drop onto a zone offers (better efficiency in fact, since there’s even less dynamic loading going on) but again, this only factors in if you select the linked list as your working list.  Now, even without selecting the relevant linked list, you can drag/drop and end up at the same place.

So ya, that’s cool.  I did some initial work in the backend to allow the user to drop a search result onto a zone as well.  I don’t have  draggable defined for this, but once I define one then it should Just Work(tm).  Truthfully it would also be nice to be able to drag/drop multiple items at once.   This may be straightforward for the backend to handle, but I imagine the frontend would need some serious work.  I’ll hold off on getting that going, but I suppose it is a project to look forward to.

From a technical point of view, I will say that getting this to work took a few days, but the hooks were mostly present to make it all go.  The stuff that I added amounted to handling a new breed of popups, which are non-modal and presented more as a menu anchored by an element on the page.  This comes with the need to define a relationship to that anchor, manage timers (which close the menu appropriately), clean up everything when a drop occurs or a drag is cancelled, and defined special “action” elements to overcome z-index issues.  The action elements – “actionables”, as I call them – were already necessary for regular drag/drop operations (again, due to z-index issues) but needed to be extended to work with menu-ish popups.

C’est tout.

What’s this? No updates?

Something (somebody…?) has been keeping me busy. Sorry!

A couple of interesting developments, all of a techie nature.

One… is that I got hit by a drive-by virus infection at work the other day. Imagine that – me, getting a computer virus! I became aware of its presense almost immediately, as I tend to do a lot of work online and I was suddenly unable to do anything. Existing connections – like the VPN to my home network – continued to work fine, but I couldn’t visit new sites.

The culprit was some trojan or whatever that was opening untold numbers of TCP connections in an attempt to send email. And while I suppose that this is a good, self-serving way to propagate, it’s not terribly inconspicuous. However, it took an entire day to get the thing removed; the eventual victor was a tool named ComboFix.

But that’s neither here nor there.  The point of interest is that Firefox has been Behaving Badly(tm) since then, using copious amounts of CPU every time it changes pages.  I suspect it’s been damaged in some way – or maybe it’s trying to phone home somewhere – but suffice it to say that it’s now maddeningly frustrating to use.  I can’t see any phone-home connections, but that hasn’t stopped 2.x, 3.0 and 3.5 from all being naughty in this regard.

chrome-205_noshadowSo I’ve been using Google Chrome for my browsing needs.  Again, that’s neither here nor there.  The real message… which is quite selfish really… is that I’ve been using Chrome with the Whole Home Audio web interface and it’s quite a slick experience.  Which is to say – in a very, very, very long-winded way – that I’ve come a long way from Firefox-dependence with respect to said interface.

I still don’t have workable drag-drop support, and its absence is notable during some playlist maintenance operations.  But with this one exception it’s all slick as snot.

And while I’m on the topic of the Whole Home Audio interface… I made a small discovery the other day with IIS’ setup that was potentially causing some consternation.  The interface will show you what’s playing on a particular zone, and the page which shows this information is very dynamic; a draggable, self-updating time bar; a self-updating, dynamic tracklist; a dynamic track position time counter, and some other goodies.

Anyhoo, this all is made possible with XHR objects, all of which make their requests back to IIS.  IIS normally logs every HTTP request, but when you’re making one call every second it gets a little silly.  (On a side note, I may look into using a keepalive connection to do these updates; I don’t know if anybody else does this, but it’s an idea that could reduce the overhead of handling all of these sequential async requests)  Sooooo… the XHR objects would make their requests to a virtual directory which was told to not log any requests.  Great.

Except that, for whatever reason, I had configured this virtual directory with its own “application”.  I have no idea why I would have done this if the only thing I was trying to accomplish was to keep logging in check.  So that config has been removed, and since then the XHR requests have worked as expected.

What else?  Oh yes.

lastfm

The collection is constantly growing, especially since I made a ton of room on my disk by moving some movies to my netbook.  So as any music listener knows, it’s nice to discover new music.  Having a kick-@ss way of navigating my existing collection is great, but what about discovering similar music or artists?

Last.fm is great for this kind of thing.  And even greater is the API, which allows my music application to query their database.  Today I’ve got a button that can retrieve similar artists and even populate a playlist with their albums.  Using that I’ve added a considerable number of new artists to the stable.  The next step, I think, is to make use of their “scrobbling” feature – allowing my application to update a last.fm user profile with tracks played, so that last.fm can make better recommendations.

This comes dangerously close to the “user” feature that the wifey nixed, but I think I can work around it; I’ll make a playlist “property” which is associated with a last.fm profile, and if you play from a linked playlist then my app will scrobble to the associated last.fm user profile.

So I guess those are the biggies, for now.  Some other small stuff, nothing blogworthy though.  So that’s it fer now.

Useful, or crammed?

New article on Piper’s Pages:

Something was bothering me with my fancy-shmancy AJAX/DHTML popups in the Home Audio interface.

It manifested itself mostly when adjusting track BPMs for a new album.  Basically, one has the ability to browse on an album’s tracks, then get the track popup for any particular track and – using forward/back navigation in the popup – move around the browse entries via the track popup.

This is cool in practice.  You can see more detailed deets for browse entries (as well as options like track suggestions) and quickly compare between tracks by clicking prev/next.  No need to display the popup, close it, then display the popup for another track in the results.  Same goes for albums, of course.

So when BPM’ing an album, I had two options: 1) use the quick-edit links so that I could get the edit popup straight from the browse results, or (2) display track details and use the edit link from the popup which then loaded the edit popup.

It was kinda nice using the second option, because sometimes you don’t need to edit the BPM and you can just next-next-next through the entire list – no need to scroll the list, figure out which track you’re working on, then click to get the details popup or the edit popup.

BUT… sometimes you’re not sure if the BPM that’s in the DBMS is correct, you want to use the edit popup so that you can tap out the beats and see if it’s a match.  If it’s a match, you close the edit popup – but the entry doesn’t highlight since you didn’t change anything, so you lose visual reference as to where you are in the list.

You could use the details popup, then go to the edit popup, but same problem – once you closed the edit popup you were back to a list of tracks with no visual reference as to what you last looked at.

And this underlined a more general problem – with all these dynamic popups, what happens if you want to go back one popup?  What happens if you want to display the details popup, then the edit popup, but then go back to the details popup so you can “next” to the next entry?

One way to do this is to keep a history in the backend of popups you’ve looked at.  Problem is – and this has cropped up before – the application is purposely free-flowing, and you can have multiple windows/tabs open all using the same session (sharing the same search history, context, etc.)  If you’ve got popups going in two windows, the history will be intermingled and thus useless.

So I took a different approach.  Instead of a popup yielding more popups, I decided that additional popups could be dynamically loaded into the first popup.  So for example, you get track details in a popup, then click to edit BPMs and the edit dialog is loaded into the current popup rather than appearing as a new popup.  Submit your changes and the main popup remains.

Works a treat.

The only problem is that the popup is meant to be somewhat small relative to the main interface, and when we start dynamically inserting some of these other popups – ie, the zone selector – the popup gets to be a little large and looks a little “crammed” – hence the title of this article.  But I think that’s a small price to pay for the increased usefulness (again, linking back to the title of this article), and I can probably make it more palatable with careful application of visual styling elements (via CSS).

Yup, so that’s that yo.

I also added the ability to start a new search using a popup – not just a saved search as before, but actually specifying search conditions.  Not all of the fields are displayed in the popup as they are when you actually navigate over to the search page, but in concert with dynamic search fields it offers a handy way of firing off a quick search.

Werd up.

Eat my shorts! AJAX drag-and-drop baby!

New article on Piper’s Pages:

In my neverending quest to learn (everything?) AJAX, I decided to dip my fingertips into the pond that is drag-and-drop.

Probably the most famous of AJAX techniques, it allows you to grab something on a page and move it somewhere else – either because you like to assert your creativity, or because you want to Do Something(tm) (like add an item to shopping cart).

Well ladies and gents, we’ve taken our implementation of drag-and-drop to a Whole New Level(tm).

You may recall that we’ve had AJAX popups for ages now (ages <= 1 year) and you could grab those popups and move ’em around, just cause they might be covering stuff you want to see. Cool, but… that didn’t DO anything really.

So here’s what I envisioned.

I envisioned an interface with multiple panes – one for browsing, one may contain a zone, and another may contain a list. It would be wicked and wild if you could drag an album on your list or onto the zone to queue that album.

This obviously requires more kung-fu than just moving popups around the screen.

So…. if I’m not mistaken I’ve been using Scriptaculous for the popup dragging, and after trying to bake my own more-advanced solution I realized that Scriptaculous could do what I wanted (and it was even using the same terminology I was using – “draggables” and “droppables”).

So the first crack at this yielded the ability to drag stuff from the browse view onto the link that indicates your working list. That causes the album/song to be added (or removed) from said list, which also happens to flick the checkmark for that item (this happens as a result of existing code).

Okay, so that’s cool I guess, but said checkmark could simply be clicked to achieve the same results. Nothing really new here folks, so move along!

My pleasure. My next effort was to enable drag-and-drop table reordering. Currently, in list view, you’ve got teeny weeny icons that you can use to move a row up or down, one at a time. Sure, you can select a bunch of rows and move them all up or down at once, but again they’ll move one at a time.

With these handy dandy scrolling tables, it sure would be nice to grab a row by the scruff of its neck and manhandle it into a new position, right?

Yes, it would. And while Scriptaculous provides an easy breezy way to get this done, fact is that my implementation of dynamic tables is slightly incompatible with Scriptaculous. If I had to actually take time to explain why, I would say that it has to do with my padding process – which means that in any given table, some of the rows have actual data and some do not. I use different DOM ID prefixes to track this, but even if I used a seperate array to do the same thing I’m pretty sure we’d run into context issues: does it make sense to reorder a row that hasn’t been filled in yet?

Sure, the way I’m registering draggable items means those rows wouldn’t be considered draggable by Scriptaculous until they were force-fed useable data by backend, but… why are you trying to convince me to use Scriptaculous for this??? Look, the fact is I wanted to keep my DOM ID convention, and I don’t like the way Scriptaculous reports the new ordering to the backend. When you’ve got a table that can contain, oh, 30000 rows the last thing you want to do is iterate through a serialized list of row IDs and tell a DBMS to reorder based on that list. Ugh.

So I baked my own solution, which was based on the work I did (and partially abandoned) for effort 1.

And… it works!

At least in Firefox. It looks like it wants to work in Chrome and Opera, but I’ve got stoopid text selection issues to overcome still. But at least the concept works, and admittedly it’s quite handy.

So ya – drag-and-drop/table-reordering with backend updates. Funky fresh.