Blog

Hacking (Cool Techniques) for Visual Studio 2008 Javascript Intellisense.

So I’ve been in the lab working on a javascript work flow for Visual Studio 2008. I know you might being thinking of a work flow engine cause you’re a crazed developer, but I’m actually talking about the whole project/flow of development for doing controls, widgets, libraries and such for javascript in a visual studio type environment. 

This is all experimental at this point, thus subject to change. I’ve put in some bugs/suggestions in regards to intellisense to the visual studio team, of course quite a few were closed “by design”.  But thats ok, I can be the bigger developer and find ways around it .  First off, the xml comments and structure of getting intellisense is pretty constrained.  So the best way I can think of at this point, to get around this without having verbose Javascript, is to have a skeleton file for visual studio to use for intellisense versus, using the actual code file.  

Yeah this requires extra files, but at least you’re getting the benefit of inline documentation and the classy “control + space-bar” action of autocomplete.  Basically if you use something like the Prototype Library, a class might look like the following…..

Amplify.UI.ContextMenu = Class.create(Amplify.UI.Panel, {    initialize: function(element, options) {        this.setOptions(options);        this.load(element);    },    // other methods here...    _onClick: function(e) {        this.dispatcher = e.element();        e.stop();        this.setPosition(e);        this.show(e);        Event.observe(document, 'click', this.hideHandler);    }});

Well to work some magic in getting this work work nicely in visual studio it would need to do the following….

Amplify.UI.ContextMenu = function(element, options) {       ///  ....       /// element        /// options }Amplify.UI.ContextMenu.prototype = {        initialize: function(element, options) {        ///  ....            /// element             /// options     },    // other methods here...    _onClick: function(e) {        ///  ....            /// Event     }});Amplify.UI.ContextMenu.__class = true;Amplify.UI.ContextMenu.___type = "Amplify.UI.ContextMenu";Amplify.UI.ContextMenu.__baseType = Amplify.UI.Panel;Amplify.setParent(Amplify.UI.ContextMenu, Amplify.UI.Panel);// Amplify.setParent does the following... which adds methods from the parent if not overridden...//for(var property in inheritedType.prototype) {//  if(!type.prototype[property])//          type.prototype[property] = inheritedType.prototype[property];//  }

As you can see… the syntax is a bit bloated, so separating this into its own file isn’t a bad thing, not to mention, you can use these files for Ajax Doc, in order to create msdn style documentation, without having to keep the comments inside your actual code files. However you’ll also see what I’m doing to create the inheritance of javascript objects for Visual Studio to use that stems from the Asp.Net Ajax Javascript format already in place. 

Now that we have this in place, we need to be able to run these two code places on the same page without a lot of copy and paste for something the homemade Specification library that Im using for BDD style development.  So we need to make some adjustments and use a base .aspx page for specifications, with the following code in it. 

public class SpecPage : System.Web.UI.Page{    protected override void OnPreRender(EventArgs e)    {        base.OnPreRender(e);        Control[] controls = new Control[this.Header.Controls.Count];        this.Header.Controls.CopyTo(controls, 0);        this.Header.Controls.Clear();        foreach (Control control in controls)        {            if (control is LiteralControl)            {                LiteralControl lit = (LiteralControl)control;                if (lit.Text.Contains("script"))                {                    lit.Text = lit.Text.Replace("intellisense.", "");                }            }            this.Header.Controls.Add(control);        }    }}

Now that we have something like this place we can use the intellisense files to create BDD stub and write our real code, which might look like the following….

Spec.CreateDoc();Spec.Define(    new Functionality(        "Amplify", //name        "Amplify.js is the core script that contains only centeralized functions needed constantly",        function () {            Spec.Expects(typeof($log), ToBe.Defined, "$log",                "$log serves as helper method for logging messages to a div \                 without the need to constantly open up alert boxes."            );            // more stubs there....            Spec.ExpectsAfter(                function() { //the path is changed...                    Amplify.changePath("/Amplify.Js/javascripts/amplify-prototype/");                },                [                    new Conditional((Amplify.Scripts._scriptPath == "/Amplify.Js/javascripts/amplify-prototype/"), "the script path should be '/javascript/amplify-prototype/'")                ],                "When you use 'Amplify.changePath()' the new path should be set."            );            // There should be a better way of doing this.....            Amplify.using("spec-test");            Amplify.invokeOnLoad(function() {                Amplify.Tests.newValue = "newValue";                Spec.Expects(typeof(Amplify.Tests), ToBe.Defined, "Amplify.Tests",                    "Amplify.Tests should now be defined after Ampllify.using('spec-test') is called"                );            });        }    ));Spec.Run();

When I have the api done and finish the initial documentation, I’ll put together a code tool for helping to keep documentation and stubs in sync between the javascript files in order to help this process along.   Not to mention creating a file for the Prototype Library that Visual Studio can use, will be a beast in itself to complete. 

currently listening to.. Foo Fighters Echoes, Silence, Patience & Grace The Pretender