Vous aurez beau commencer un geste de drag à partir d'une appli flash, aucune application, même pas le navigateur html, ne reconnaitra cela comme étant un mécanisme de drag and drop. Pour la simple raison qu'il n'y aucune API disponible dans Flash pour notifier de tels évènements au système. C'est particulièrement balot, quand on sait que même en HTML (et en XUL), il y a tout ce qu'il faut. L'inverse est également vrai : dragguez quelque chose du navigateur (l'url de la barre de navigation), où encore d'une autre application, vers l'application flash, vous n'avez aucun moyen en Flash/ActionScript, de prendre en charge ces évènements, et donc de permettre un drop.

Cela est particulièrement ennuyeux dans notre logiciel ZoomCreator2, que nous développons, David et moi. C'est un éditeur permettant de créer des documents zoomorama. Nous réutilisons notre application flash, légèrement modifiée, pour la zone principale d'édition "wysiwyg". Notre logiciel est basé sur XulRunner, donc son interface est du XUL, CSS, HTML etc. Nous voudrions pouvoir faire du drag and drop de cette zone flash vers le reste de l'application et vice versa, ou même à partir de l'extérieur de l'application vers notre zone flash (pour drag and dropper des images d'un explorateur vers notre éditeur par exemple). Cependant, à cause des lacunes de flash, c'est impossible de l'implémenter.

Ou alors en rusant.

J'ai en effet trouvé un hack, mais un hack qui n'est pas trop moche à mon sens.

L'idée générale est la suivante : puisque Flash ne génère pas, ni ne reçoit des évènements de drag and drop, virons-le, cachons-le, temporairement, en le remplaçant par un élément XUL ou HTML. Ce remplacement s'effectuerait immédiatement lorsqu'on détecterait le début d'un drag dans l'application (évènement dragstart, ou dragenter quand le drag vient de l'extérieur). Pour cela, pas de souci. Reste à faire ce remplacement proprement dit.

La première solution imaginée a été de positionner un élément XUL ou HTML transparent, au dessus de la balise object de flash. Hélas, ça marchouillait, voir pas du tout. Impossible de mettre cet élément "au dessus", il restait à coté, certainement à cause du modèle de boîte XUL. Et de toute façon, même en HTML pure, il y a des soucis, qui différent selon les plateformes si mes souvenirs sont bons.

Je n'ai pas trop persisté dans cette direction, sachant que j'allais certainement arriver à une impasse. Et puis en fait, j'ai eu une autre idée, celle d'utiliser <canvas>. Pour les développeurs d'extensions et d'applications XUL (mais pas pour les applis web), <canvas> possède un méthode drawWindow. Vous lui donnez un objet window (typiquement, la fenêtre d'une page HTML), les coordonnées d'un rectangle, et ça affiche dans <canvas> une capture d'un morceau de la fenêtre correspondante aux coordonnées données. C'est particulièrement utilisé dans des extensions qui vous affichent vos bookmarks avec une capture de la page web correspondante, ou pour faire un "alt+tab' sexy etc.

Ainsi donc, dés que je détecte le début d'un drag dans l'application :

  • je donne à la méthode drawWindow d'un élément <canvas> la fenêtre de notre application XUL, en lui donnant les coordonnées (x,y + taille) de l'emplacement de l'affichage de la balise object de notre zone flash.
  • dans ce canvas, j'ai alors une capture de ce qu'affiche le flash.
  • je rend invisible le flash, et fait apparaitre le canvas au même emplacement. Merci CSS et le modèle de boite XUL j'ai juste à faire en faite un display:block sur le canvas, canvas qui est un élement frère de ma balise object, et tout deux dans une boite XUL. Un overflow:hidden sur cette boite fait que le canvas "pousse" l'object vers le bas, mais du coup invisible, et sans faire apparaitre de scrollbar.
  • tout ce passe instantanément, et on ne remarque rien.

En définitive donc, je n'ai plus de "trou noir" dans l'interface de l'application, que des éléments XUL et HTML sur toute la surface. Je suis à même alors de recevoir tout les évènements drag and drop sur ce canvas et de les traiter. Une fois traités (évènements dragend ou drop), je fais disparaitre le canvas, la balise object reprend sa place, le flash est de nouveau là. Ni vu ni connu.

Vivement WebGL et/ou l'accélération matérielle graphique pour canvas dans tout les navigateurs, Ce sera alors certainement suffisamment performant pour se passer de Flash pour notre technologie de zooming, et nous évitant tout ces hacks acrobatiques :-)