Multiple Modal Popups with the ASP.NET Ajax Toolkit

At the moment I’m building a CMS with ASP.NET, ASP.NET Ajax and the ASP.NET Ajax Toolkit. One of the great features that the AJAX Toolkit provides us is the possibility of adding modal popups.

I’m using them for gridviews that contains a lot of columns, and cannot be displayed in the page without the horizontal scroll. My solution for that is displaying the more important data, and then, when a row is selected, a detailform is displayed with all the data in a popup panel. My solution is based on Matt Berseth excellent post: Master-Detail with the GridView, DetailsView and ModalPopup Controls. This solves the problem of editing rows, but what happens when we want to add a new one?

The gridview control doesn’t have a built-in way of adding new items. One standard way of solving this is adding the add form in the footer of the gridview, but we don’t have the horizontal space needed for it if we have more data than the displayed on the gridview!

I planned to add a “Add element” link at my page, and adding a new popup for adding data. But it didn’t worked. My search of “multiple modal popups” didn’t give me any solutions. So I looked at what was happening there, and I created a simple test page like this:

    <asp:LinkButton ID="lnk" runat="server" Text="hi"></asp:LinkButton>
    <br />
    <asp:LinkButton ID="lnk2" runat="server" Text="hi2"></asp:LinkButton>
    <ajax:ModalPopupExtender ID="mpe" runat="server" TargetControlID="lnk" PopupControlID="pnl"
        CancelControlID="close" />
    <ajax:ModalPopupExtender ID="mpe2" runat="server" TargetControlID="lnk2" PopupControlID="pnl2"
        CancelControlID="close2" />
    <asp:Panel ID="pnl" runat="server" CssClass="popupPanel">
        <div>
            Hi!!!
        </div>
        <asp:Button ID="close" runat="server" Text="Close" />
    </asp:Panel>
    <asp:Panel ID="pnl2" runat="server" CssClass="popupPanel">
        <div>
            Hi2222!!!
        </div>
        <asp:Button ID="close2" runat="server" Text="Close" />
    </asp:Panel>

If I show the first panel, and hide it, the second panel is never shown.
The problem is that, in the generated HTML code, the second panel is a child of the first one, instead of being at the same level on the DOM tree.

IMHO this is an Ajax Control Toolkit bug, and I hope that I’ll find time, and I will take a look and send a patch. But for now, I used a workaround. I placed the modal popup panels inside of another one wrapping each one, and it did the trick.

Hope this helps somebody.

UPDATE 2008/03/03:
Merenzo has resolved the mistery. See the comments.

Scripting con MSN Plus! Actualizando el mensaje personal con Twitter

Hoy Vargas me comentaba que algunos de sus contactos de Messenger utilizaban el mensaje personal de estado como si fuera Twitter, cambiándolo cada poco tiempo. Así que he decidido echar un rato, para ver si hacía un script que utilizara Twitter para modificar el mensaje de estado del Live Messenger, utilizando para ello MSN Plus!.

Aquí está el resultado:

var originalMessage = null;
var lastTwitt = null;
// we assume that the user has 
// the same id in twitter & messenger
var twitterServiceUrl = 
     "http://twitter.com/statuses/user_timeline/"+ 
     Messenger.MyEmail.split("@")[0] +".json";

function OnEvent_Initialize(MessengerStart) {
     originalMessage = Messenger.MyPersonalMessage;	
     // first twitt
     get_twitt();	
}

function OnEvent_Uninitialize(MessengerExit) {
     // recover the original message
     // before running the script
     if (originalMessage != null) {
          Messenger.MyPersonalMessage = originalMessage;
     }
}

function get_twitt() {
     var request = new ActiveXObject("Microsoft.XMLHTTP");
     if (request) {
          request.onreadystatechange = function() {
               if  (request.readyState == 4) {
	       var x = eval(request.responseText);
                    if (x.length > 0 && lastTwitt != x[0].id) {
                         lastTweet = x[0].id;
                         Messenger.MyPersonalMessage = x[0].text;					
                         }
                    }			
               };
          request.open("GET", twitterServiceUrl, true);
          request.send(null);
     }
     MsgPlus.AddTimer("twittTimer", 1000 * 60);
}

function OnEvent_Timer(id) {
     if (id == "twittTimer") {
          get_twitt();
          MsgPlus.AddTimer("twittTimer", 1000 * 60);	
      }
}

Espero que os guste.

Modificando un textarea desde javascript

Para modificar en Javascript el contenido de un textarea, podemos usar las propiedades selectionStart y selectionEnd que tenemos disponibles en Firefox y Opera.
Sin embargo, éstas no están disponibles en IE, por lo que debemos utilizar un feo truco para añadirlas.
Ahí va el código:

function UglyFixForSelectionStartAndSelectionEndForIE(id) {
    var element = $get(id);
    if(document.selection) {
        // The current selection 
        var range = document.selection.createRange();
        // We'll use this as a 'dummy'
        var stored_range = range.duplicate();
        // Select all text 
        stored_range.moveToElementText( element );
        // Now move 'dummy' end point to end point of original range 
        stored_range.setEndPoint('EndToEnd', range );
        // Now we can calculate start and end points 
        element.selectionStart = stored_range.text.length - range.text.length;
        element.selectionEnd = element.selectionStart + range.text.length;
    }
}

Y si estamos usando el ASP.NET Ajax Control Toolkit, bastará con utilizar:

        var element = this.get_element();
        if (Sys.Browser.agent === Sys.Browser.InternetExplorer)
            UglyFixForSelectionStartAndSelectionEndForIE(element.id);
        var start = element.selectionStart;
        var end = element.selectionEnd;
        var length = element.textLength;

La función es original de Stickblog

Depurando Javascript

Uno de los mayores problemas que, históricamente, han sufrido los desarrolladores de Javascript es la depuración de código. Actualmente, es bastante más sencillo gracias a las múltiples extensiones de Firefox disponibles para dicha tarea, de las cuales mi preferida es Firebug.

Sin embargo, en IE7 seguían apareciéndome problemas que no era capaz de identificar. No conozco ningún debugger con la potencia y sencillez de Firebug, pero también podemos encontrar la manera de localizar nuestros errores. Para ello, primero debemos activar el debugging en IE7, pues viene desactivado por defecto.
Para ello, vamos a Tools / Internet Options / Advanced, y en la sección Browsing desmarcamos las opciones Disable Script Debugging (Internet Explorer) y Disable Script Debugging (Other). Con esto ya IE nos permitirán depurar el código.
Para ello, podemos utilizar la herramienta gratuíta de Microsoft Script Debugger, aunque mi preferencia es usar Visual Studio 2005 para ello.

Para el desarrollo web, y concretamente de Javascript, recomiendo el IDE libre Aptana. Basado en Eclipse, permite la inserción de snippets, nos va mostrando mediante Intellisense la ayuda de las funciones javascript (y más importante, su disponibilidad en distintos navegadores), facilitando nuestra tarea. Además, integra los frameworks javascript libres más conocidos, como Yahoo UI, Prototype, JQuery, Rico, Script.aculo.us o Dojo.

Opensource rocks!

OpenLayers
Hoy estoy contento. He hecho mi primera aportación de código (ojo, de documentación llevo unas pocas) a un proyecto OpenSource existente.

OpenLayers, una librería en Javascript que simplifica y unifica las APIs de varios sistemas de información geográficas existentes, y basado en estándares.

Recientemente, por el uso que hago de OpenLayers en el trabajo, he descubierto varios bugs en la versión 2.2, rellenando su correspondiente ticket. Pues bien, hoy encontré uno nuevo, y me atreví. La última vez que intenté resolver un bug que encontré, pasé horas y no lo resolví (es lo que tiene no ser un h4x0r de Javascript y que el código sea de otro). Pero esta vez hubo más suerte, y mandé mi parche, que fue aplicado en el trunk casi sin mirarlo (¡se fían de mí y tó!) 😀


Ticket #422: Problems with the inner HTML in a popup
The inner HTML in a popup doesn't fill the popup width. Maybe it is related to ticket #415.

A screenshot

My patch

Index: Popup.js
===================================================================
--- Popup.js (revisión: 134)
+++ Popup.js (copia de trabajo)
@@ -207,6 +207,10 @@
this.div.style.width = this.size.w + "px";
this.div.style.height = this.size.h + "px";
}
+ if (this.contentDiv != null){
+ this.contentDiv.style.width = this.size.w + "px";
+ this.contentDiv.style.height = this.size.h + "px";
+ }
},

/**

Y ahora se muestra el texto llenando el Popup 😀