Modal windows does not resize automatically

I’m not sure if this is a bug or a feature, but when using modal windows in Internet Explorer, your HTML is not updated when the window.onresize event is fired. This is pretty annoying, since it is possible and even valid to open modal windows that is resizable:

var result = window.showModalDialog("/mypage.aspx", window, "dialogHeight:500px; dialogWidth:700px; resizable:Yes; scroll:No");

Notice the resizable:Yes parameter, which allows the modal window to be resized.

If your window contains HTML that resizes to the client width and height, and you resize the window, the window.onresize event is in fact fired, but your HTML does not change.

How do you overcome this issue? You will have to resize the HTML yourself, by hooking into the window.onresize event. Add the following to your HTML:

<script language="javascript" type="text/javascript">
  window.onresize = function() {
  }
</script>

There is several ways to write HTML that can be resized. First of all, and most important, the elements that needs to be resized must be accessible from Javascript, so you will have to add the id attribute to the HTML elements to resize.
In my own project I added a table to my HTML. The table has the advantage of being dynamic in nature, and it is possible to select which columns that have a variable size and which have a dynamic size. Observe the following example:

<table id="tbl" width="700px" border="0" cellpadding="0" cellspacing="0">
  <tr>
    <td width="200px">
      <div id="colLeft">
        <!-- Some html -->
      </div>
    </td>
    <td width="100%" valign="top">
      <div id="colCenter">
        <!-- Some html -->
      </div>
    </td>
    <td width="200px">
      <div id="colRight">
        <!-- Some html -->
      </div>
    </td>
  </tr>
</table>

My table has an id called “tbl” and starts with a width of 700px which is the default size of the modal dialog. The first and last columns are fixed in size, leaving the middle column resizable. To resize the table by width, all I have to add to my window.onresize is:

window.onresize = function() {
  document.getElementById("tbl").width = document.documentElement.clientWidth;
}

The height is pushed to the default modal box height of 700px using the 3 div tags in each column, by adding a fixed height of 700px to each column:

#colLeft, #colCenter, #colRight {
  height:700px;
}

To resize in height i will need to resize each div tag individually:

window.onresize = function() {
  document.getElementById("tbl").width = document.documentElement.clientWidth;
  document.getElementById("colLeft").style.height = document.documentElement.clientHeight;
  document.getElementById("colCenter").style.height = document.documentElement.clientHeight;
  document.getElementById("colRight").style.height = document.documentElement.clientHeight;
}

Please notice that 2 onresize events are fired: One when resized in height and one when resized in width. You can therefore make your Javascript more effeicient by saving the old clientWidth and clientHeight in variables, and only resize the HTML if the values are changed:

var oldClientHeight = 0;
var oldClientWidth = 0;

window.onresize = function() {
  if (document.documentElement.clientWidth != oldClientWidth) {
    document.getElementById("tbl").width = document.documentElement.clientWidth;
    oldClientWidth = document.documentElement.clientWidth;
  }
  if (document.documentElement.clientHeight != oldClientHeight) {
    document.getElementById("colLeft").style.height = document.documentElement.clientHeight;
    document.getElementById("colCenter").style.height = document.documentElement.clientHeight;
    document.getElementById("colRight").style.height = document.documentElement.clientHeight;
    oldClientHeight = document.documentElement.clientHeight;
  }
}

This reduces flickering a little bit.

Using modal windows from C# code

In user interface design, a modal window is a child window that requires the user to interact with it before they can return to operating the parent application, thus preventing the workflow on the application main window. Modal windows are often called heavy windows or modal dialogs because the window is often used to display a dialog box.” (source: Wikipedia)

Modal windows in websites are client-controlled windows. A modal window is opened using a piece of Javascript:

var result = window.showModalDialog("/MyModalWindow.aspx"", """", ""status:no"");
alert(result);

The modal window return value is also generated using client side Javascript:

window.returnValue = "OK";
window.close();

When you want to use a modal window from server-side C# code you can choose between several strategies. This is a strategy I have used with success.

Step 1: Set up the Modal window

This sample modal window contains only 2 buttons, an OK button and a Cancel button. Both buttons are server-side buttons. This is the HTML for my modal window:

<head runat="server">
  <title>My Modal Window</title>
  <base target="_self" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <asp:Button ID="btnOK" runat="server" text="OK" onclick="btnOK_Click" />
      <asp:Button ID="btnCancel" runat="server" Text="Cancel" onclick="btnCancel_Click" />
    </div>
    </form>
</body>
</html>

Please notice the <base target=”-self”/> tag in the header. Without this tag, all postbacks will open a new window.

The codebehind for the OK and Cancel button are the same, except for 2 things:

  • When pressing the “OK” button i set the data to return from the modal window in a Session variable.
  • The modal window return value is “OK” if I pressed btnOK or “Cancel” if I pressed btnCancel.

When pressing a button I simply generate a client script block that will close my window:

protected void btnOK_Click(object sender, EventArgs e)
{
  Session["MySession"] = "this is the data to return from my modal window";
  StringBuilder sb = new StringBuilder();
  sb.AppendLine(@"<script language=""javascript"" type=""text/javascript"">");
  sb.AppendLine(@"  window.returnValue = ""OK""");
  sb.AppendLine(@"  window.close();");
  sb.AppendLine(@"</script>");
  ClientScript.RegisterClientScriptBlock(GetType(), "close", sb.ToString());
}

protected void btnCancel_Click(object sender, EventArgs e)
{
  StringBuilder sb = new StringBuilder();
  sb.AppendLine(@"<script language=""javascript"" type=""text/javascript"">");
  sb.AppendLine(@"  window.returnValue = ""Cancel""");
  sb.AppendLine(@"  window.close();");
  sb.AppendLine(@"</script>");
  ClientScript.RegisterClientScriptBlock(GetType(), "close", sb.ToString());
}

Step 2: The calling code

The modal window is called by pressing a button from a Web Form.

<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
    <div>
      <asp:Button ID="btnOpen" runat="server" Text="Open Modal Window" onclick="btnOpen_Click" />
    </div>
    </form>
</body>
</html>

The button also generates a startup script when clicked:

protected void btnOpen_Click(object sender, EventArgs e)
{
  StringBuilder sb = new StringBuilder();
  sb.AppendLine(@"<script language=""javascript"" type=""text/javascript"">");
  sb.AppendLine(@"  var result = window.showModalDialog(""/MyModalWindow.aspx"", """", ""status:no"");");
  sb.AppendLine(@"  if (result == ""OK"")");
  sb.AppendLine(@"    " + Page.ClientScript.GetPostBackEventReference(form1, "MyArgument"));
  sb.AppendLine(@"</script>");
  ClientScript.RegisterStartupScript(GetType(), "btnOpen", sb.ToString());
}

The Javascript does the following:

  • Opens the modal window and waits for a return value.
  • If the return value is “OK” (= the user clicked the “OK” button in the modal window) I do a client-side postback, posting an argument called “MyArgument” (it is the GetPostBackEventReference that handles the postback for me).

The postback can be intercepted on the Page_Load event by looking for the value “MyArgument” in the __EVENTARGUMENT querystring. If such value exist, I can retrieve the value from the modal dialog:

protected void Page_Load(object sender, EventArgs e)
{
  if (!string.IsNullOrEmpty(Request["__EVENTARGUMENT"]) && Request["__EVENTARGUMENT"] == "MyArgument")
  {
    string value = Session["MySession"];
    // now I can work with the value from the modal window
  }
}

Sitecore 5.3 HandleMessage and ShowModalDialog

Creating your own Sitecore Fields can be tricky. The best way to start is to download one of Sitecores examples (the composite control is a good example).
In this example I’ll use the HandleMessage function in my control to open a modal window, do some stuff and return the values to my control.

The HandleMessage function reacts on events from the Sitecore Client. Each message contains the ID of the current control, which I will use to react to messages that belongs to me:

public override void HandleMessage(Sitecore.Web.UI.Sheer.Message message)
{
  if (message["id"] == this.ID)
  {
    if ( message.Name == "MyControl:message" )
    {
      System.Web.HttpContext.Current.Session["MyControl.ID"] = this.ID;
      ClientCommand command = Sitecore.Context.ClientPage.ClientResponse.ShowModalDialog("MyPage.aspx", "300px", "630px", "my:Message", false);
    }
  }
}

The trick is now that when the modal dialog closes, a message called “my:Message” will be thrown. Unfortunately there is no control ID attached to the message. In order to identify which control opened the modal window, I store the control’s ID in a session variable, and use this ID when handling the my:Message message:

if ( message.Name == "my:Message" )
{
  string id = System.Web.HttpContext.Current.Session["MyControl.ID"] as string;
  if (id == this.ID)
  {
    // do my work, and remember to clear the session
  }
}

Follow

Get every new post delivered to your Inbox.

Join 92 other followers