ClientSideExtender, version 0.0.0.1

Damn, it was so much fun to play a little with TDD and abstract the lousy API given by Microsoft to register client-side script. I’ll write about the process and design changes I’ve made due to testability reasons. TDD is a great design tool, it’s amazing to witness the “before” and “after” of your code, all because of the requirements to test things separately.


Here are a few API samples, taken from the Demo project (you can play with it and see the results):


public partial class _Default : Page
{
   protected void Page_Load(object sender, EventArgs e)
   {
      ClientSideExtender script = ClientSideExtender.Create(this);

      script.RegisterMethodCall(“alert”).WithParameters(“hello world!”).ToExecuteAt(Target.EndOfPage);

      script.RegisterVariable<string>(“myStringVar”).SetValue(“test”).ToExecuteAt(Target.EndOfPage);
      script.RegisterVariable<int>(“myIntegerVar”).SetValue(5); // Target.BeginningOfPage as default

      script.RegisterScriptBlock(“alert(‘proof of concept – state:’ + document.readyState);”).ToExecuteAt(Target.PageLoaded);
   }
}


Keep in mind that I’m only supplying a different API (abstraction) of Microsoft’s implementation. In order to accomplish that, I’m using Windsor to wire the ClientSideExtender with the new ajaxian ScriptManager(supports UpdatePanel), which will actually be responsible to register the script under the hood. You can look at the web.config (under the <castle> element) for more details.


Source:
Lnbogen.Web.UI.zip (253.56 KB)

 

Creating a decent API for client side script registration

I’ll start my post with a question:
What’s the difference between ScriptManager.RegisterClientScriptBlock and ScriptManager.RegisterStartupScript methods?


Well, the only way to find out is not by looking at the method names but rather to look in MSDN. According to MSDN the former registers your script after the <form> element while the latter is registering your script just before the </form>. Now, let me ask you this – how the word “Startup” can be interpreted as “end of page”?


So OK, the naming is really bad but what’s even worse are the arguments of these methods:


public static void RegisterClientScriptBlock(Control\Page control\page, Type type, string key, string script, bool addScriptTags);
public static void RegisterStartupScript(Control\Page control\page, Type type, string key, string script, bool addScriptTags);


Now, most of us write this code 95%(+) of the times:


ScriptManager.RegisterClientScriptBlock(this, this.GetType(), “some stupid key”, “the script here, finally…”, true); //like someone is stupid enough to give false – if you have a full script, why not putting it inside myFile.js and add it to the header?


I don’t understand the real need behind creating a “unique” key from the type+key given to this method. Why not creating a unique key each and every time? You need to create a simple API for the common (90%) tasks. I almost never actually asked about IsClientScriptBlockRegistered. But enough complaining, time to write a few bits & bytes.


I tried to play with the API a little and here is what I came up with (it’s merly the beginning, I’ll update on my progress during the week):


PageClientSideExtender clientSide = new PageClientSideExtender(Page);


// A better approach, IMHO, to ScriptManager API
clientSide
  .RegisterScript(“alert(‘run at the beginning of the page’);”)
  .AddScriptTags()
  .RunAtTheBeginningOfThePage();

clientSide
  .RegisterScript(“<script>alert(‘run at the end of the page’);</script>”)
  .RunAtTheEndOfThePage();

//let’s register something like:
// var width = 300;
clientSide.RegisterLocalVariable<int>(“width”).SetValue(“someValue”);

//let’s register something like:
// var data = ‘width:300;height:500’;
clientSide.RegisterLocalVariable<string>(“data”).SetValueFormatted(“width:{0};height:{1}”, 300, 500);

// Let’s register to the onload of the <body> and trigger a nice alert
clientSide.Body.Load += ClientSideScriptHelper.CreateHandler(“alert(‘run on body onload! cool ah??’);”);


//Or:

clientSide.Body.Load += delegate { return “alert(‘another message shown after the page onload event was raised. sweet!’);”; };




The Fluent interface gives it a nice “read-the-code-like-a-story” look&feel which makes things really easy to understand. There is no thinking here, the code says it all.


Another rant I have is that all of the API examples I’ve demonstrated so far are implemented although not fully tested as using Microsoft classes requires a lot of work in order to abstract. The funny thing is that they(Microsoft) have decoupled things in the new Microsoft ASP.NET Ajax library(System.Web.Extension.dll) but they made everything internal!  You have IPage, which is really useful abstraction to the Page class, sitting there as an internal member. I had to come up with some heavy abstraction to make things play nice together.


To sum up, I would really appreciate YOUR feedback about the API and any kind of suggestion or things that you would like to see in future API. I’ll release the code later this week with a short demo to get you going.

 

Roee Daliyot makes the web a little easier and a lot more yummy!

It’s about time.


Our CTO, Roee Daliyot, is finally taking the time to write about the things he loves – GUI programming.


After writing about delegates & anonymous methods via JavaScript, he just released 2 must-see client-side controls for Drag&Drop and Clone&Drag&Drop.


So go on and pay him a visit.


Tell him I sent you.

 

DropDownList in a popup window behavior

I have a popup window(calendar control) which contains a drop-down-list with many items in it. The problem occurs when I try to select the year 1930, which is outside of the popup frame:


 


calendarbug.gif


 


This close the the entire popup window instead of selecting the year 1930 as expected (well, I did anyway). I tried to cancel the event from bubbling, to set the height of the select object (doesn’t work), you name it !


*btw*: I don’t want to change the entire flow or to work with a different window model – to much work.


Any ideas ??

 

How to refresh a Modal Dialog window

In one of our screens we were required to refresh a Modal Dialog window in order to redraw the entire screen. Trying to refresh a Modal Dialog window will resolve in a new window with the same url.

A possible solution is to create a new “container” file (MyContainer.aspx) which will only have an IFrame with the “real” page(MyPage.aspx) in it as src; Your main page (MyMainPage.aspx) will open the “container” as Modal Dialog instead of the “real” page. The trick is that the IFrame can refresh itself so we’ve created a Modal Dialog which behaves as a normal window. if you need to set the Modal Dialog returnValue parameter you can call “top.returnValue=….” from the “real” page.


The downside of this solution is QueryString delegation – if you need to send a QueryString parameter(s) to your “real” page you will now have to pass it via the “container” file.

 

Changing Microsoft’s TabStrip disabled property via javascript.

This task can be a little tricky, so after messing with it’s HTC (TabStrip.htc) here is how you do it:


To enable tab:


document.all.tags(“TabStrip”)[0].getTab(0).setAttribute(“disabled”, false);


To disable tab:


document.all.tags(“TabStrip”)[0].getTab(0).setAttribute(“disabled”, true);


* You can select other tabs of course or loop over them to disable\enable all of them at once (as needed).


Maybe it can save someone else the time I’ve wasted on it.


Back to code…

 

Tip: Closing the window without a confirmation screen.

Sometimes we have to close the window after our screen logic has executed, so usually we’re writing window.close(); in our page BUT this causes this message to arise –


close_areyousure.gif


If you want to avoid this message, simply write:


window.opener = window;
window.close();

 

The Markowitz HACKED the(my) system !

Did I mention that I’m working with a well known hacker ?
Well, It’s about time, so I present to you – Amir Markowitz aka “The Hacker”.


Amir taught me today how to send javascript commands directly through the address bar !
Look at the “damage” he did to my site !


redbackground1.gif


As you can see, he managed to change the background color in one simple command.


Think about changing Page_IsValid property or performing __doPostBack(“”,””) through the address bar –


javascript:void(Page_IsValid=true); __doPostBack(“”,“”);


This could be deadly if you don’t perform Server-side validation as well !


 


 

 

Javascript debugging via “debugger;”

Sometimes my VS.NET just can’t “catch” my breakpoints in my .js files for some reason.
Yes, I made sure that the “Script” box is checked on the attached process, still, no luck.


Fortunately debugger; command is in the house !


It’s simple to use and it can be great for production debugging as well.


example (in myexample.js file):
function MyMethod()
{
   debugger; // ==> this will make the debugger to take over (you can use VS.NET or any other suitable program).   


   // your code to debug here.
}