Next up in this series on replacing the Ajax Control Toolkit functionality with client side logic is the ACT PopUp control extender.

I have to admit that I stumbled a little on this one.

Here are the examples provided by the Ajax Control Toollkit demo site.

One sample is a multi-select, but this usage seems unecessary. I’d just use a drop down.

Another was this calendar pop-up,but for this I would use one of the plethora of Date Selector controls that are available out three.

Still, there is a scenario where the user could benefit from some field specific associated data (but a lot more than a tool-tip.)

So I decided to implement a Pop-Up that shows a <div> element. Inside that div we can put anything. Markup, Client Side Controls, Server Side Controls, and JavaScript code (so if we wanted to we could put code in the pop-up that interacted with the corresponding DOM element that it was “Poped Up for”).

For such JavaScript to be reusable though, it needs to be responsible for its own positioning.

I’ve written this as plain old JavaScript. I plan in the near future to convert this to a jQuery Plugin.

Here’s what the finished code looks like in execution.

In the above screenshot I’ve bound a Pop-Up to the SECOND TextBox and when I click or tab into that TextBox the Pop-Up is displayed.

The JavaScript code automatically figures out where the TextBox is displayed and places the Pop-Up under the TextBox slightly indented.

Of course we want to make the feature as simple to call as possible.

Here is the markup that results in the above page.


<%@ Page Title='Home Page' Language='C#' MasterPageFile='~/Site.master'
         AutoEventWireup='true' CodeFile='Default.aspx.cs'
 Inherits='_Default' %>
<asp:Content ID='HeaderContent' runat='server' 
             ContentPlaceHolderID='HeadContent'>
<link href='Styles/FieldPopUp.css' rel='stylesheet' type='text/css' />
<script src='Scripts/FieldPopUp.js' type='text/javascript'></script>
</asp:Content>
<asp:Content ID='BodyContent' runat='server' 
             ContentPlaceHolderID='MainContent'>
    <h2>Welcome to ASP.NET!</h2>
    <p>
        To learn more about ASP.NET visit
        <a href='http://www.asp.net' title='ASP.NET Website'>www.asp.net</a>.
    </p>
<br />
Text 1 - <input type=text id='t1'><br />
Text 2 - <input type=text id='targettextbox'
                onfocus='SetPopup('divtopop','targettextbox', 'S');'
                onblur='SetPopup('divtopop','targettextbox', 'H');'>
<br />
Text 3 - <input type=text id='t3'><br />
<div id=divtopop class='boxover'>
This Field <br />
<hr>
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled it to make a type
specimen book. It has survived not only five centuries, but also the leap into
electronic typesetting, remaining essentially unchanged.<br /><br />
<div style='text-align: center;'>[ Hide ]</div>
</div>
</asp:Content>

Notice the OnFocus and OnBlur event handlers that call the SetPopUp JavaScript Function.

Doesn’t this syntax suddenly seem cumbersome after working with jQuery for even a short while?  Even though this is pretty simple to use it will still be more elegant when implemented as a jQuery Plugin so that we can apply the functionality via a jQuery selector.

The JavaScript is somewhat more complex.


// Get the position of the html element specified.
function getAbsolutePosition(element) {
    var ret = new Point();
    for (;
        element && element != document.body;
        ret.translate(element.offsetLeft, element.offsetTop),
        element = element.offsetParent
        );
return ret;
}

// A screen coordinate.
function Point(x, y) {
    this.x = x || 0;
    this.y = y || 0;
    this.toString = function () {
        return '(' + this.x + ', ' + this.y + ')';
    };
   this.translate = function (dx, dy) {
   this.x += dx || 0;
   this.y += dy || 0;
   };
   this.getX = function () { return this.x; }
   this.getY = function () { return this.y; }
   this.equals = function (anotherpoint) {
   return anotherpoint.x == this.x && anotherpoint.y == this.y;
   };
}
// Cause the popup to by displayed of hidden depending on the action parameter
function SetPopup(popupname, showforname, action) {
   // If popup or target is not passed.
   // No action won't cause errors but no action will be taken.
   if (popupname.length < 1 || showforname.length < 1) {
      return;
   }

// Get reference to the html element to be &quot;poped up&quot;
var dialog = document.getElementById(popupname);
// Get reference to the element that is activating the popup.
var control = document.getElementById(showforname);
// Get the position of the id that is activating the popup.
var pos = getAbsolutePosition(control);
// Horizontal Position of Popup.
dialog.style.left = (pos.x + 15) + 'px';
// Vertical Position of Popup.
dialog.style.top = (pos.y + 25) + 'px';

switch (action) {
   // Show Popup
   case 'S':
      dialog.style.display = 'block';
      break;
   // Hide Popup
  case 'H':
      dialog.style.display = 'none';
      break;
   // Do nothing.
   default:
      break;
   }
}

The getAbsolutePosition() does just what you would assume. It gets the position of whatever HTML element it is passed.

The Point function starting on line 13 represents a screen coordinate pair (X,Y)

The rest of the code calls getAbsolutePosition() passing in the HTML Element that the PopUp is to be associated with, adds a 15×25 px offset to that position and then, depending on what the “Action” input argument is sets the display attribute on the HTML Element to be displayed (also passed in as an argument.)

The look of the box is determined by the following bit of CSS


.boxover
{
display: none;
position: absolute;
background-color: white;
border-style: solid;
padding: 5px;
border-width:thin;
width: 300px;
}

You can download a complete working sample [ HERE ]

I’ll revisit this code after i convert it to a jQuery PlugIn but feel free to use it as is.