Quite a good title :-). Some weeks ago I find the time to create proof of concept for that task: create a jQuery wrapper for Script#. The result is a partial wrapper that could be completed to support all in all jQuery functionality.
The main issues I encountered while developing were:
- Write a Script# adapter
- Adapt event handlers interfaces
- Support jQuery overloads
At the same time I was learning a bit of Microsoft Ajax Client-Side Templates (preview 2), part of ASP.NET AJAX 4.0, which are not in preview 3 stage. I also had to to a minimal script# adapter for this, but it was totally ad-hoc.
Due to the dependence with Microsoft Ajax, aacorlib Script# engine is used, which doesn't support some C# features like foreach.
Write a Script# adapter
First of all you need to read some Script#. Then need realize that anycode that depends on a Script# adapter is not testable unless you implement some basic behavior of the adapted component.
For example the wrappers usually returns null, or default(T), for a function that it's return type is T.
jQuery use a fluent interface, so returning this instead of null
will allow a minimal chance be testable (to avoid spurious runtime null pointer exceptions.
Adapt event handlers interfaces
With jQuery an event handler is declared as follows:
var anchors = $("a");
anchors.click(function(){
var target = $(this).attr('href');
alert('anchor to ' + target + 'clicked.');
});
In C# the this keyword is binding to the current class, not as in Javascript. This force the full creation of a wrapper, previously I tried to just have a trivial wrapper with the ImportedAttribute
in every method, but wasn't enough.
After some tweaks I finally got this to work:
jQuery anchors = jQueryApi.Select("a");
anchors.click(delegate(object sender){
string target = jQueryApi.Select(sender);
Script.Alert("anchor to " + target + "clicked.")
});
And the "implementation" magic code is:
public class jQuery {
// ...
public jQuery click(EventCallback fn){
Script.Literal("{0}.click(function(){{ return {1}(this); }})", _jquery, fn);
return this;
}
}
Support jQuery overloads
In Script#, Javascript overloads are declared as extern
methods with AlternateSignatureAttribute
. What I try to get was a easy way to implement jQuery overloads. The
Function.apply
method was very useful.
In the following code it is shown how jQuery.attr methods are adapted, and how jQuery wrapper is maintained. It's not very nice, but is what is needed to get this works.
public class jQuery
{
[AlternateSignature]
public extern string attr(string key);
public jQuery attr(string key, string value)
{
object r = Script.Literal("{0}.attr.apply({0}, arguments)", _jquery);
if (r == _jquery) // preserve jQuery wrapper
return this;
else
return (jQuery) r; // cast for compilation, it will return corresponding type
}
}
Sample Application
Doesn't do much:
- Gets a hardcoded list of TODOs in JSON
- Unfold template using Client-Side Teamplates
- Add behavior to unfolded DOM
All this is implemented in Script# using an MVP pattern. Algo in Views/Tasks/Layout.aspx there is a commented Javascript implementation.
You can download the solution here.