FoxyTunes is an extension which allows you to control any media player from within the browser.
This article describes a technique that allows the user to interactively reposition the FoxyTunes widget anywhere in the browser using Drag and Drop.
It doesn't go deep into the exact technical details, but is more like a guided tour of the FoxyTunes repositioning code which is open.
In the first public version of FoxyTunes, the widget was positioned on the status bar. Its position was to the left of the "Updates" panel and couldn't be changed.
I received a few requests from people that wanted to be able to reposition the FoxyTunes widget on the status bar. They pointed me to the excellent WeatherFox extension that allowed this.
In the WeatherFox options dialog, there are two combo-boxes - one for the main position of the widget (status bar, toolbar etc.) and one for the exact position (to the left of the "Updates" panel, to the right of the main menu etc.).
I loved the idea, but wanted to make this process more interactive and user friendly. Naturally, drag and drop came to mind.
Mozilla has a very good support for drag and drop. Basically elements can register to events that signal that the user has started the drag, that the element is being dragged over other element and then dropped.
These events are: draggesture
, dragover
, dragenter
, dragexit
and dragdrop.
The idea is: FoxyTunes widget registers for the draggesture
event that signals drag start. It also registeres all its potential targets (status bar, toolbars etc.) for the other events.
FoxyTunes has an element which has a ondraggesture
event handler defined.
When the user starts dragging this element, the event handler does the following:
dragover
, dragexit
and dragdrop
events for all the elements that can host the FoxyTunes widget. This includes the status bar and all the toolbars/toolboxes (all the toolboxes can be found using the document.getElementsByTagName('toolbox')
command).
When the user drags the FoxyTunes widget over one of its valid targets, its ondragover
event handler gets called. The event handler checks which specific child element is being dragged over and marks this element with a red line, so the user can see where exactly the widget will be positioned if he releases the mouse button. This element is remembered in a global variable for exactly that case.
When the mouse leaves an element the dragexit
event handler gets called. All it does in this case is to clear the active target mark set by the ondragover
event handler.
When the user finally releases the mouse button over a valid target, the ondragdrop
event handler gets called. The handler checks which element got the event so it knows before or after which element to insert the FoxyTunes widget. The parent of this element should be a status bar or a toolbar and it should become the new parent of FoxyTunes.
Now we have all the information needed to reposition the FoxyTunes widget. First, foxytunesWidget.parentNode.removeChild(foxytunesWidget)
is used to remove FoxyTunes from its previous parent.
Then, something like newParentElement.insertBefore(foxytunesWidget, insertBeforeElement)
can be used to insert it to its new position.
At this stage we can remove the event handlers we registered for the potential drop targets.
From now on, we want FoxyTunes to appear at its new location. To achieve this, we remember the two elements we got in the drop event handler - the new parent and the new sibling element that FoxyTunes will appear before. Every time FoxyTunes is started, it is removed from its default location and inserted into its new saved location.
Another problem I've encountered is that the FoxyTunes widget is in fact a statusbarpanel
element, and when dragged to the toolbox it can be rendered incorrectly with some themes. To solve this, I use a little DOM programming to re-wrap FoxyTunes in a toolbaritem
element.