Last week I sat down to create a proof of concept for a Visual Studio-style intellisense implementation written purely in Javascript. I’m quite pleased with the results, although it’s not very robust. Let’s cut to the chase - have a look at the pure javascript intellisense demo, or download an archive.
Now, let me explain what’s happening there before you get too underwhelmed. Basically, when you type, the script runs a tokenizer to split your previous text into chunks. When that tokenizer hits upon a delimiter, in the demo that’s the “.” character, it’ll send your previous token to the server and popup the result in the intellisense box. You can tab to the box and hit enter to select an option. Pressing tab also cycles through the options in the box.
What I’ve written is very simple. The tokenizer can be totally swapped out, so you could define your own rules for parsing your input and obtaining a token. And when the token gets to the server, you can interpret it in any way, returning anything back to be put in the intellisense box.
Like I say, this is proof of concept stuff only but I can definitely see applications for it. It’s been tested in FF3 and IE8 Beta - nothing else. I’ve got an SVN repo online and would happily accept patches or comments. Download Javascript Intellisense here.
I’m working with the awesome ExtJS framework again, creating an administrative interface to a huge amount of data. Each screen on this interface is basically a pageable grid with an editor window which pops up if you click a row. The grids can be sorted, and a separate filter area allows you to narrow down the items displayed on the grid in a manner unique to each screen.
The first time I wrote something like this using Monorail and ExtJS, I’d estimate that the javascript code was about 300 lines and the C# was maybe 150. Bear in mind that these screens, while differing due to the data being displayed, were essentially just CRUD interfaces. That means that to create a new screen, I’d be copying and pasting a lot of very similar code.
I’m sure you’ve been in this sitation before. If you’re really only going to be using this code in one or two places, there may be little value in making it a bit more generic. However, as soon as you break past that and find yourself copying and pasting the same code over and over, it’s a sure sign that you need to step back and pull out common functionality. That’ll provide three benefits:
- Less code means less to maintain
- It’s easier to create a new screen (copy/paste is never nice)
- Code reuse means silly errors are more quickly caught
In my situation I first created an abstract CrudController
In the ExtJS side of things, I was able to subclass the GridPanel component and have a component that would automatically have a PagingToolbar, a particular click handler, and other default settings. I was also able to tailor the arguments to reduce the amount of code I needed to write to create it. Here’s a simple example.
this.grid = new App.standardGrid({
cm: new Ext.grid.ColumnModel([{
header: 'Id',
dataIndex: 'Id'
}, {
header: 'Created',
dataIndex: 'CreatedOn',
renderer: function(val) {
return val.format('l d F Y');
}
}]),
fields: [
{name:'Id', type:'int'},
{name:'CreatedOn', type:'date'}
],
url: '/admin/quote/getjsonlist.castle',
edit: this.edit,
scope: this
});
Secondly, I could create a subclassed Ext.Window which would give me a better reusable editor dialog. Here’s how I defined that:
App.window = Ext.extend(Ext.Window, {
height: 500,
width: 500,
modal: true,
resizable: false,
draggable: false,
closable: false,
bodyStyle: 'background: #eee'
});
As you can see, this is just a matter of giving sane defaults for a modal window, but later I subclassed App.window itself to create App.formWindow which was much more powerful.
These three steps dramatically reduced the code required to create a new admin screen in my application. More importantly, I cut the amount of boilerplate code I was copying every time to zero, which meant the code I did have to write was all important stuff. Less wading through identikit javascript means I’m a much happier developer!
After my earlier post on JS generation from C#, I wanted to investigate my options. Although zproxy highlighted the jsc project, I wanted to focus on a real world scenario first and so I’m looking at ExtSharp, which relies on Script#, a project which will “compile your C# source code into JavaScript”.
ExtSharp leverages Script# to allow you to write ExtJS applications in C#, which was my target when I began thinking about JS generation. I’d like full intellisense, documentation and compile-time checking when working with this rich framework. Will ExtSharp give me that?
Downloading ExtJS2Samples-v2.0.1.zip from the Google Code site gives me a solution of samples. Here an interesting implementation issue arises - all of the actual C#-Javascript class files are in a separate project to the .aspx pages which display them. This is down to necessity; Script# uses an assembly called sscorlib which, bizarrely, seems to provide its own implementations of many of the .NET types found in the mscorlib assembly.
This separate project also runs an MSBuild targets file from Script# which runs after main compilation to compile the C# into Javascript. Straight away I’m seeing two bits of magic - sscorlib and post-build events - which I’m not too keen on. But the solution builds, and after changing the web.config references to nStuff.ScriptSharp.Web to 0.4.5.0, I am able to view the samples.
Based on my earlier post, I was interested in the Window sample, but unfortunately that didn’t work. The array Grid one did though, and it operated just as the ExtJS website sample does. Many of the other samples are missing, which is disappointing; of the ones which are present, most work very well. Overall, I was encouraged, and I moved on to looking at the C# code which was generating these samples.
Let’s look at how a ColumnModel is built when working in Javascript:
var colModel = new Ext.grid.ColumnModel([
{id:'company',header: "Company", width: 160, sortable: true, dataIndex: 'company'},
{header: "Price", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'},
{header: "Change", width: 75, sortable: true, renderer: change, dataIndex: 'change'},
{header: "% Change", width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'},
{header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
]);
I think that’s pretty concise - there’s not a lot of cruft. Now the ExtSharp version:
ColumnModel colModel = new ColumnModel(new Dictionary[] {
new Dictionary("id", "company", "header", "Company", "width", 160, "sortable", true, "locked", false, "dataIndex", "company"),
new Dictionary("header", "Price", "width", 75, "sortable", true, "renderer", new MoneyRenderer(Format.usMoney), "dataIndex", "price"),
new Dictionary("header", "Change", "width", 75, "sortable", true, "renderer", new ColumnRenderer(change), "dataIndex", "change"),
new Dictionary("header", "% Change", "width", 75, "sortable", true, "renderer", new ColumnRenderer(pctChange), "dataIndex", "pctChange"),
new Dictionary("header", "Last Updated", "width", 85, "sortable", true, "renderer", Format.dateRenderer("m/d/Y"), "dataIndex", "lastChange")
});
Hmm. Lots of strings - I’m not keen. This is one of two methods of providing a configuration to an Ext class, the second of which involves a specific config class:
Ext.grid.GridPanel grid = new Ext.grid.GridPanel(new Ext.grid.GridPanelConfig()
.el("grid-example")
.ds(ds)
.cm(colModel)
.autoExpandColumn("company")
.height(350)
.width(600)
.title("Array Grid")
.ToDictionary()
);
Unconventional style, to say the least, but at least it’s properly typed. This is pretty far away from my ideal API for this kind of thing. Let’s look at how this is turned into Javascript.
As I previously mentioned, the Script# project contains MSBuild targets which generate the JS code after the build is complete. This code can then either be referenced directly, or via some ASP.NET controls from your ASPX pages. As well as your own generated code, you must also reference a couple of Script# files and a wrapper file for Ext itself. That wrapper file is actually what makes everything work here - rather than your C# code being converted into something which works with the Ext library, it instead only works with the Ext wrapper provided by ExtSharp.
Looking at the ExtSharp project overall, I’m not a convert. There are too many layers between your C# and where it finally touches the “real” Javascript:
1. Your generated JS
2. ExtSharp JS wrapper
3. Script# utility JS
The C# API is also pretty horrible - certainly not in my style but also far from being an API I recognise from any other project I’ve worked on. Whether this is a style choice or due to technical limitations, I’m not sure.
The ExtSharp project definitely drew my curiosity, and could hold promise. In its current state, I wouldn’t consider using it in a project of my own, as the API is not strong enough to make me swap from native Javascript. Still, I will continue to follow future work with interest.
Javascript Generation - A Change Of Heart
April 2nd 2008, 3:03 pm in .NET, C#, Development, Ext, Javascript.
I’ve previously talked about my dislike for code generation in Javascript. I still standby that, but I am beginning to have a change of heart for certain scenarios. I’ve been working on a couple of ExtJS applications recently and I’ve got lots of code which is purely ExtJS stuff on its own - no HTML or other code in there really. It’s been a project where I’ve been using C# 3 and it’s partly the similarities between the two languages which have triggered this rethink.
Take a look at this code:
var win = new Ext.Window({
title: 'Order Viewer', layout: 'border',
width: 500, height: 500,
modal: true, resizable: false, closable: false, draggable: false,
items: [ frm, lst ]
});
win.on('render', function() {
load(5);
});
win.show();
That’s pretty standard stuff for what I’m doing with Ext right now - I create a new window with a load of configuration options, then add in an event handler for the window’s render event, and finally show the window on screen. Now imagine that you could write the following in C# 3:
var win = new Ext.Window{
Title = "OrderViewer", Layout = Layout.Border,
Width = 100, Height = 200,
Modal = true, Resizable = false, Closable = false, Draggable = false,
Items = new [] { frm, lst }
};
win.Render += delegate {
load(5);
};
win.show();
As far as I’m aware, all of the above is valid C# 3 code. I’ve basically written it as I’d like to use it, with an enum for the Layout type, and C# style event handler syntax, but the interesting thing to me is how very similar it is to the Javascript version.
The ExtSharp project allows you to write your Ext code in C# and have it rendered as Javascript. I’m going to explore it in my next post, and examine how closely it can be made to fit the code sample above.
I had a change request today to label a couple of text input fields with a watermark. The client didn’t think it was immediately obvious what the user was supposed to enter, but we didn’t have space for the traditional text labels next to the inputs. The suggested solution was to have a watermark which "underlayed" the input box with the label text which disappears on focus and reappears on blur.
I love it when a plan comes together (a tale of Monorail, ActiveRecord and ExtJS)
October 8th 2007, 11:10 pm in .NET, Ajax, C#, Castle, JSON, Javascript, Monorail, Screencasts.
I’ve blogged before about the enabling features of Monorail and Active Record, part of the Castle stack. Another piece of software which is making my development life a pleasure is ExtJS - a collection of javascript goodies created by Jack Slocum and his team - and when these three things come together, watch that coding fly…. I’ve created a screencast in which I demonstrate how easy it is to build a paging, sorting, filtering, AJAX-powered grid using ExtJS and Castle, and you can watch it here. It’s 20 minutes long but filled with goodness - and a couple of hacks (forgive me :). Don’t forget to check out all my past screencasts too.
UPDATE: As requested in the comments, you can MonorailExt1 VS Project directory of this.
FormHints - Javascript Form Help Bubbles
May 15th 2007, 10:21 am in FormHints, Javascript, Projects.
When creating Wiretap, I wanted some kind of inline help system which would not only help users but would not detract from the layout of the form. I’ve seen lots of systems where there’s a little question mark next to the form elements, or where there is a big lump of text underneath every box. So I wanted mine to be unobtrusive and flexible. (more…)
Working with JSON and C# 3.0
May 8th 2007, 8:59 pm in .NET, Ajax, C#, JSON, Javascript, Visual Studio.
I’ve been using libraries such as NewtonSoft’s JSON.NET or AjaxPro to serialize a class to JSON. There’s something about my approach which didn’t really sit too well, and C# 3 has an elegant solution.
(more…)
I’ve updated my javascript TickerTape to version 1.1, and introduced a couple of new features. Firstly, one which was requested by a few people, rolling over the ticker now causes it to stop scrolling until you move out again. This prevents the item you’re interested in zipping off the screen before you can click it.
Secondly, the ticker can now be configured to scroll horizontally, which opens up a whole new slew of applications. You can see both of these features in action in the new horizontal demo. The current version of the TickerTape component can always be found here:
Latest JavaScript TickerTape Component
Incidentally, because IE7 doesn’t allow XMLHttpRequests to the local filesystem, you’ll have to upload the demos to your own webserver rather than view them on your own PC. They work locally in Firefox just fine.
stchur tackles an issue which has cropped up for me in the past - that mouseout and mouseover on a container element will also trigger for its children. This can be incredibly annoying, and it surprised me to find out that Internet Explorer has a built-in solution in the mouseenter and mouseleave events. These are only triggered for the container element, not for the children. However, non-IE browsers don’t support this and so stchur made mouseenter and mouseleave for Firefox. Extremely useful, and I’ll be using his work as inspiration for a new feature in the next TickerTape version.