Building JavaScript Controls


In this section, you learn how to build three custom JavaScript controls. You start with a simple sample of a custom control that renders JavaScript. We build a NewWindowLink control that enables you to open a new browser window when you click a button.

Next, we build a WebWindow control that enables you to render a virtual browser window. This control enables you to simulate multiple windows in a single web form page.

Finally, we create a ClientTabs control. This control enables you to switch between different tabs of content on the client without a postback to the server.

Building a NewWindowLink Control

Being a good web developer is hard. To be a good web developer, you need to know HTML, Cascading Style Sheets, SQL, XML, and JavaScript. You also need to know about the different implementations of these technologies in the case of different browsers and different operating systems.

One of the main jobs of a framework, such as the ASP.NET Framework, is to shield you from all the underlying technologies on which the framework is built. If you integrate JavaScript into a custom control, then you can learn the JavaScript for five minutes and then never need to worry about it again.

For example, in this section, we build a NewWindowLink control that opens a new browser window (see Figure 32.1). The JavaScript required to open a new window is quite simple. However, the advantage of creating a control that opens a new window is that you don't need to remember the JavaScript in the future.

Figure 32.1. Opening a new browser window with the NewWindowLink control.


The code for the NewWindowLink control is contained in Listing 32.1.

Listing 32.1. NewWindowLink.vb

[View full width]

Imports System Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Namespace myControls     Public Class NewWindowLink         Inherits WebControl         Private _text As String = "Click Here!"         Private _navigateUrl As String         Private _target As String = "_blank"         Private _windowWidth As Integer = 400         Private _windowHeight As Integer = 300         Private _windowLeft As Integer = 100         Private _windowTop As Integer = 100         Private _fullScreen As Boolean = False         Private _resizable As Boolean = True         Public Property Text() As String             Get                 Return _text             End Get             Set(ByVal Value As String)                 _text = value             End Set         End Property         Public Property NavigateUrl() As String             Get                 Return _navigateUrl             End Get             Set(ByVal Value As String)                 _navigateUrl = value             End Set         End Property         Public Property Target() As String             Get                 Return _target             End Get             Set(ByVal Value As String)                 _target = value             End Set         End Property         Public Property WindowWidth() As Integer             Get                 Return _windowWidth             End Get             Set(ByVal Value As Integer)                 _windowWidth = value             End Set         End Property         Public Property WindowHeight() As Integer             Get                 Return _windowHeight             End Get             Set(ByVal Value As Integer)                 _windowHeight = value             End Set         End Property         Public Property WindowLeft() As Integer             Get                 Return _windowLeft             End Get             Set(ByVal Value As Integer)                 _windowLeft = value             End Set         End Property         Public Property WindowTop() As Integer             Get                 Return _windowTop             End Get             Set(ByVal Value As Integer)                 _windowTop = value             End Set         End Property         Public Property FullScreen() As Boolean             Get                 Return _fullScreen             End Get             Set(ByVal Value As Boolean)                 _fullScreen = value             End Set         End Property         Public Property Resizable() As Boolean             Get                 Return _resizable             End Get             Set(ByVal Value As Boolean)                 _resizable = value             End Set         End Property         Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)             Dim fullscreenValue As String = "no"             If (_fullScreen) Then                 fullscreenValue = "yes"             End If             Dim resizableValue As String = "no"             If (_resizable) Then                 resizableValue = "yes"             End If             Dim features As String = "width={0},height={1},left={2},top={3},fullscreen={4} , resizable={5},status=no,toolbar=no,menubar=no,location=no"             Dim featuresValue As String = String.Format(features, _windowWidth,  _windowHeight, _windowLeft, _ windowTop, fullscreenValue, resizableValue)             Dim script As String = String.Format("window.open('{0}','{1}','{2}');return  false;", Page.ResolveUrl(_navigateUrl), _target, featuresValue)             writer.AddAttribute(HtmlTextWriterAttribute.Onclick, script)             writer.AddAttribute(HtmlTextWriterAttribute.Href, Page.ResolveUrl(_navigateUrl))             MyBase.AddAttributesToRender(writer)         End Sub         Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)             writer.Write(_text)         End Sub         Protected Overrides ReadOnly Property TagKey() As HtmlTextWriterTag             Get                 Return HtmlTextWriterTag.A             End Get         End Property     End Class End Namespace 

The majority of the code in Listing 32.1 is devoted to declaring a set of properties. The NewWindowLink control includes properties for the new window's position and size. It also includes properties you can set to open a window that is resizable or full screen.

The JavaScript for opening the window is contained in the AddAttributesToRender() method. This method adds a client-side OnClick handler to the link rendered by the control. When you click the link, the window.open() method is called on the client.

The page in Listing 32.2 illustrates how you can use the NewWindowLink control in an ASP.NET page. The page contains two instances of the NewWindowLink control. The first instance opens a normal window. The control opens the page specified by its NavigateUrl property in a new window.

The second instance of the NewWindowLink control opens a full-screen window. A full-screen window is supported only with Internet Explorer. (You get a normal new window when the control is used with other browsers such as Firefox.) After you open a full-screen window, you can close it by selecting Alt+F4.

Listing 32.2. ShowNewWindowLink.aspx

<%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <title>Show NewWindowLink</title> </head> <body>     <form  runat="server">     <div>     <custom:NewWindowLink                  Text="Open Window"         NavigateUrl="~/Default.aspx"         Runat="server" />     <br /><br />     <custom:NewWindowLink                  Text="Open Full Screen Window"         NavigateUrl="~/Default.aspx"         FullScreen="true"         Runat="server" />     </div>     </form> </body> </html> 

Building a WebWindow Control

There are several disadvantages that result from using separate browser windows in a web application. First, communicating information between multiple browser windows is difficult. When you update one window, you must reload the other windows to reflect the new information. Furthermore, new browser windows can be blocked by pop-up blockers.

A better alternative is to create virtual windows by creating floating <div> tags. Unlike true browser windows, you don't run into problems communicating information between virtual windows. Furthermore, a virtual window will never be blocked by a pop-up blocker.

By taking advantage of a little JavaScript, you can even drag and drop a virtual window. In other words, you can position a virtual window at different locations on the screen.

The code for the virtual window control, the WebWindow control, is contained in Listing 32.3.

Listing 32.3. WebWindow.vb

[View full width]

Imports System Imports System.Web.UI Imports System.Web.UI.WebControls Imports System.ComponentModel Namespace myControls     <ParseChildren(False)> _     Public Class WebWindow         Inherits WebControl         Implements IPostBackEventHandler         Private _windowTitleText As String = "Untitled"         Public Event Closed As EventHandler         Public Property WindowTitleText() As String             Get                 Return _windowTitleText             End Get             Set(ByVal Value As String)                 _windowTitleText = value             End Set         End Property         Protected Overrides Sub OnPreRender(ByVal e As EventArgs)             If Not Page.ClientScript.IsClientScriptIncludeRegistered("WebWindow") Then                 Page.ClientScript.RegisterClientScriptInclude("WebWindow", Page .ResolveClientUrl("~/ClientScripts/WebWindow.js"))             End If             Dim startupScript As String = String.Format("WebWindow.init('{0}');", Me.ClientID)             Page.ClientScript.RegisterStartupScript(Me.GetType(), Me.ClientID,  startupScript, True)         End Sub         Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)             RenderTitleBar(writer)             writer.AddAttribute(HtmlTextWriterAttribute.Class, "webWindowBody")             writer.RenderBeginTag(HtmlTextWriterTag.Div)             Me.RenderChildren(writer)             writer.RenderEndTag()         End Sub         Private Sub RenderTitleBar(ByVal writer As HtmlTextWriter)             writer.AddAttribute(HtmlTextWriterAttribute.Class, "webWindowTitleBar")             writer.AddAttribute("onmousedown", "WebWindow.mouseDown(event)")             writer.AddStyleAttribute(HtmlTextWriterStyle.TextAlign, "right")             writer.RenderBeginTag(HtmlTextWriterTag.Div)             writer.AddAttribute(HtmlTextWriterAttribute.Class, "webWindowTitleText")             writer.RenderBeginTag(HtmlTextWriterTag.Span)             writer.Write(_windowTitleText)             writer.RenderEndTag()             RenderCloseButton(writer)             writer.RenderEndTag()         End Sub         Private Sub RenderCloseButton(ByVal writer As HtmlTextWriter)             Dim eventRef As String = Page.ClientScript.GetPostBackEventReference(Me,  String.Empty)             writer.AddAttribute(HtmlTextWriterAttribute.Class, "webWindowClose")             writer.AddAttribute(HtmlTextWriterAttribute.Onclick, eventRef)             writer.RenderBeginTag(HtmlTextWriterTag.Span)             writer.Write("X")             writer.RenderEndTag()         End Sub         Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)             writer.AddStyleAttribute(HtmlTextWriterStyle.Position, "absolute")             writer.AddAttribute(HtmlTextWriterAttribute.Class, "webWindow")             MyBase.AddAttributesToRender(writer)         End Sub         Protected Overrides ReadOnly Property TagKey() As HtmlTextWriterTag             Get                 Return HtmlTextWriterTag.Div             End Get         End Property         Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements  IPostBackEventHandler.RaisePostBackEvent             RaiseEvent Closed(Me, EventArgs.Empty)         End Sub     End Class End Namespace 

The RenderContents() method in Listing 32.3 is responsible for rendering the virtual window. This method renders a title bar that contains a close button. It also renders a <div> tag that contains the window's contents.

All the magic happens in an external JavaScript file. A JavaScript include is rendered by the WebWindow control in its OnPreRender() method. The control assumes that a JavaScript file named WebWindow.js is located in a subfolder named ClientScripts.

The contents of the WebWindow.js file are contained in Listing 32.4.

Listing 32.4. ClientScripts\WebWindow.js

var WebWindow = new Object(); WebWindow.init = function(winId)     {       eval("place=" + this.getCookie(winId + "_place"));       place = place || {left:20, top:20};       var win = document.getElementById(winId);       win.style.left = place.left;       win.style.top = place.top;     } WebWindow.mouseDown = function(e)     {         var e = e || window.event;         var src = e.target || e.srcElement;         var win = src.offsetParent;         var startWinX = win.offsetLeft;         var startWinY = win.offsetTop;         var startMouseX = e.clientX;         var startMouseY = e.clientY;         var move = function(e)             {                 var e = e || window.event;                 win.style.left = (startWinX - (startMouseX - e.clientX)) + 'px';                 win.style.top = (startWinY - (startMouseY - e.clientY)) + 'px';                 if (document.all)                 {                     e.cancelBubble = true;                     e.returnValue = false;                 }                 if (e.preventDefault)                 {                     e.preventDefault();                 }             }         var up = function(e)             {                 document.onmousemove = null;                 document.onmouseup = null;                 WebWindow.setCookie(win.id + "_place", "{left:'" + win.style.left + "', top:'" + win.style.top + "'}");             }         document.onmousemove = move;         document.onmouseup = up;     } WebWindow.setCookie = function(name, value) {     var expires = new Date();     expires.setTime( expires.getTime() + 365 * 24 * 60 * 60 * 1000 );     document.cookie = name + "=" + escape(value) + ";expires=" + expires.toGMTString();         } WebWindow.getCookie = function(name) {       var aCookie = document.cookie.split("; ");       for (var i=0; i < aCookie.length; i++)       {         var aCrumb = aCookie[i].split("=");         if (name == aCrumb[0])         return unescape(aCrumb[1]);       }       return null; } 

The JavaScript file in Listing 32.4 contains the methods that enable you to drag the WebWindow around the page. When you click your mouse on the WebWindow's title bar, the WebWindow.mouseDown() method executes and records your current mouse position. As you move your mouse, the move() method executes and updates the WebWindow's position on the screen by modifying the left and top style properties of the WebWindow's containing div element.

Whenever you move a WebWindow, its new position is recorded in a browser cookie. The next time that you open the page, the WebWindow appears in the same location.

Warning

Be careful about where you declare the WebWindow control in a page. Do not declare the control inside of another <div> tag or you might encounter difficulties when you attempt to drag the control outside of its containing <div> tag. I've tested the WebWindow control with Internet Explorer 6.0, Firefox 1.0, and Opera 8.0.


The page in Listing 32.5 illustrates how you can use the WebWindow control in an ASP.NET page. When the page first opens, the WebWindow is not visible by default. When you click the Open Window link, the WebWindow is displayed (see Figure 32.2). Finally, when you click the WebWindow's Close button, the WebWindow1_Closed() event handler executes and the WebWindow is hidden.

Listing 32.5. ShowWebWindow.aspx

<%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server">     protected sub lnkOpenWindow_Click(sender As object, e As EventArgs)         WebWindow1.Visible = true     End Sub     protected sub WebWindow1_Closed(sender As object, e As EventArgs)         WebWindow1.Visible = false     End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <style type="text/css">         .webWindow         {             width:400px;             height:400px;             border:Outset;             background-color:white;         }         .webWindowBody         {             padding:10px;         }         .webWindowTitleBar         {             font:14px Verdana,Sans-Serif;             padding-left:10px;             background-color:Blue;             color:white;             cursor:move;         }         .webWindowTitleText         {             float:left;         }         .webWindowClose         {             background-color:Red;             cursor:pointer;         }     </style>     <title>Show WebWindow</title> </head> <body>     <form  runat="server">     <div>     <asp:LinkButton                  Text="Open Window"         OnClick="lnkOpenWindow_Click"         Runat="server" />     </div>     <custom:WebWindow                  WindowTitleText="The WebWindow Title"         Visible="false"         OnClosed="WebWindow1_Closed"         Runat="server">         Here is some content     </custom:WebWindow>     </form> </body> </html> 

Figure 32.2. Displaying a virtual window with the WebWindow control.


Building a ClientTabs Control

In Chapter 4, "Using the Rich Controls," you learned how to use the Menu control with the MultiView control to display tabbed content in a page. The drawback of using these controls is that they require you to post the page containing the controls back to the server each and every time you click a tab.

In this section, you learn how to create a client-side tab control named the ClientTabs control (see Figure 32.3). This control renders the contents of all the tabs to the browser. However, it hides the contents of all the tabs except for the selected tab. When you select a new tab, JavaScript is executed on the browser to hide the contents of all the tabs except the newly selected tab.

Figure 32.3. Displaying tabs with the ClientTabs control.


Unfortunately, the entire code for the ClientTabs control is too long to include in the body of this book. However, the complete source code (in both Visual Basic .NET and C#) is included on the CD that accompanies this book. Listing 32.6 contains a partial listing of the ClientTabs control.

Listing 32.6. ClientTabs.vb (Partial Listing)

[View full width]

Namespace myControls     <ParseChildren(False)> _     Public Class ClientTabs         Inherits WebControl         Implements IPostBackDataHandler         ''' <summary>         ''' Render tabs and tab content         ''' </summary>         Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)             RenderTabs(writer)             RenderTabContent(writer)         End Sub         ''' <summary>         ''' Render the tab strip         ''' </summary>         Private Sub RenderTabs(ByVal writer As HtmlTextWriter)             writer.AddAttribute(HtmlTextWriterAttribute.Class, "tabs")             writer.RenderBeginTag(HtmlTextWriterTag.Table)             writer.RenderBeginTag(HtmlTextWriterTag.Tbody)             writer.AddAttribute(HtmlTextWriterAttribute.Id, TabContainerID)             writer.RenderBeginTag(HtmlTextWriterTag.Tr)             Dim index As Integer             For index = 0 To Controls.Count - 1 Step index + 1                 Dim currentTab As Tab = CType(Controls(index), Tab)                 Dim script As String = String.Format("ClientTabs.selectTab('{0}','{1}')",  Me.ClientID, currentTab.ClientID)                 writer.AddAttribute(HtmlTextWriterAttribute.Onclick, script)                 If index = SelectedIndex Then                     writer.AddAttribute(HtmlTextWriterAttribute.Class, "tab selectedTab")                 Else                     writer.AddAttribute(HtmlTextWriterAttribute.Class, "tab unselectedTab")                 End If                 writer.AddAttribute(HtmlTextWriterAttribute.Id, currentTab.ClientID + "_tab")                 writer.RenderBeginTag(HtmlTextWriterTag.Td)                 writer.Write(currentTab.Text)                 writer.RenderEndTag()             Next             writer.RenderEndTag()             writer.RenderEndTag()             writer.RenderEndTag()         End Sub         ''' <summary>         ''' Render the tab contents         ''' </summary>         Private Sub RenderTabContent(ByVal writer As HtmlTextWriter)             writer.AddAttribute(HtmlTextWriterAttribute.Id, TabContentContainerID)             writer.AddAttribute(HtmlTextWriterAttribute.Class, "tabContent")             writer.RenderBeginTag(HtmlTextWriterTag.Div)             Dim index As Integer             For index = 0 To Controls.Count - 1 Step index + 1                 Dim currentTab As Tab = CType(Controls(index), Tab)                 If index <> SelectedIndex Then                     currentTab.Style.Add("display", "none")                 End If                 currentTab.RenderControl(writer)             Next             writer.RenderEndTag()         End Sub     End Class End Namespace 

Listing 32.6 contains the code for rendering the tabs. When the ClientTab control renders its contents, it iterates through its child controls in two passes. First, it renders the tab links. Next, it renders the body of each tab. Any tab that is not selected is hidden by the CSS display:none property.

One special feature of the ClientTabs control needs to be explained. Imagine that each of the tabs contains a separate form with a separate button. When you click the button and submit the form to the server, you want the same tab to be displayed again when the page is reloaded. In other words, to function properly, the ClientTabs control needs to retain state across postbacks.

The ClientTabs control registers a hidden form field in its OnPreRender() method. When you select a new tab, the ID of the selected tab is assigned to the hidden form field. When the page is posted back to the server, the value of the hidden form field is used to determine the currently selected tab. That way, when the ClientTab control renders its tabs again, the tab selected on the client remains selected when the control is rendered on the server.

The ClientTabs control uses a Cascading Style Sheet file to format the appearance of the tabs. This Cascading Style Sheet file is added to the page containing the ClientTabs control by the ClientTabs control's OnPreRender() method. The contents of the Cascading Style Sheet file are contained in Listing 32.7.

Listing 32.7. ClientScripts\ClientTabs.css

.tab {     padding:2px 25px;     border:solid 1px black;     cursor:pointer; } .unselectedTab {     background-color:#eeeeee; } .selectedTab {     background-color:White;     border-bottom:solid 1px white; } .tabs {     position:relative;     top:3px;     left:15px; } .tabContent {     border:Solid 1px black;     background-color:White;     padding:10px; } 

Finally, the ClientTabs control executes a client-side JavaScript function named ClientTabs.selectTab() when a user selects a new tab. The JavaScript library is added to the page in the ClientTabs control's OnPreRender() method. The ClientTabs control assumes that there is a JavaScript file named ClientTabs.js that is located in the ClientScripts folder. The contents of this JavaScript file are contained in Listing 32.8.

Listing 32.8. ClientScripts\ClientTabs.js

var ClientTabs = new Object(); ClientTabs.selectTab = function(controlId, tabId)     {         // Get previous value         var hiddenField = document.getElementById(controlId + '_hidden');         var prevTabId = hiddenField.value;         // Hide previous tab         document.getElementById(prevTabId + '_tab').className = 'tab unselectedTab';         document.getElementById(prevTabId).style.display = 'none';         // Show new tab         document.getElementById(tabId).style.display = 'block';         document.getElementById(tabId + '_tab').className = 'tab selectedTab';         // Update hidden value         hiddenField.value = tabId;     } 

The page in Listing 32.9 illustrates how you can use the ClientTabs control within an ASP.NET page. The page in Listing 32.9 contains a ClientTabs control that contains three Tab controls. The final Tab control includes a simple form with a Button control. Notice that after you submit the page to the server, the correct tab is selected when the tabs are rendered back to the client.

Listing 32.9. ShowClientTabs.aspx

<%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <title>Show ClientTabs</title> </head> <body>     <form  runat="server">     <div>     <custom:ClientTabs                  Runat="server">         <custom:Tab  Text="First Tab" runat="server">             Contents of the first tab         </custom:Tab>         <custom:Tab  Text="Second Tab" runat="server">             Contents of the second tab         </custom:Tab>         <custom:Tab  Text="Third Tab" runat="server">             Contents of the third tab             <br /><br />             <asp:Label                                  Text="User Name:"                 AssociatedControl                 Runat="server" />             <asp:TextBox                                  Runat="server" />             <asp:Button                                  Text="Submit"                 Runat="server" />         </custom:Tab>     </custom:ClientTabs>     </div>     </form> </body> </html> 




ASP. NET 2.0 Unleashed
ASP.NET 2.0 Unleashed
ISBN: 0672328232
EAN: 2147483647
Year: 2006
Pages: 276

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net