Tuesday, April 15, 2008

Using #region Directive With JavaScript Files in Visual Studio

Suppose how nice it would be to use #region directive when writing javascript code.

Javascript is becoming more and more complicated, and it is hard to scroll up and down every time we want to find needed function name and see what parameters it accepts.

I was so tired with this scrolling that started to search some alternative small IDE-s or highlighting text editors which would allow me to use collapsible regions in js files, but in this case I would lose javascript intellisense in VS 2008. I even thought about creating my own text editor plug-in for VS, but again - what about intellisense.

Earlier or later, I found one nice solution to the problem on Microsoft forums. Yes - it's so simple. The solution uses simple macros which parses current document and creates collapsible regions for

//#region

//#endregion

pairs.

So simple :)

Thanks to the author!

And because I don't not find it to be easily detectable in the internet, I decided to blog this.

 

Just do the following steps to support //#region directive:

1) Open Macro explorer:

image

2) Create new macro:

image

3) Name it "OutlineRegions":

image

4) Click "Edit" macro and paste the following VB code into it:

Option Strict Off
Option Explicit Off

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Collections

Public Module JsMacros

    Sub OutlineRegions()
        Dim selection As EnvDTE.TextSelection = DTE.ActiveDocument.Selection

        Const REGION_START As String = "//#region"
        Const REGION_END As String = "//#endregion"

        selection.SelectAll()
        Dim text As String = selection.Text
        selection.StartOfDocument(True)

        Dim startIndex As Integer
        Dim endIndex As Integer
        Dim lastIndex As Integer = 0
        Dim startRegions As Stack = New Stack()

        Do
            startIndex = text.IndexOf(REGION_START, lastIndex)
            endIndex = text.IndexOf(REGION_END, lastIndex)

            If startIndex = -1 AndAlso endIndex = -1 Then
                Exit Do
            End If

            If startIndex <> -1 AndAlso startIndex < endIndex Then
                startRegions.Push(startIndex)
                lastIndex = startIndex + 1
            Else
                ' Outline region ...
                selection.MoveToLineAndOffset(CalcLineNumber(text, CInt(startRegions.Pop())), 1)
                selection.MoveToLineAndOffset(CalcLineNumber(text, endIndex) + 1, 1, True)
                selection.OutlineSection()

                lastIndex = endIndex + 1
            End If
        Loop

        selection.StartOfDocument()
    End Sub

    Private Function CalcLineNumber(ByVal text As String, ByVal index As Integer)
        Dim lineNumber As Integer = 1
        Dim i As Integer = 0

        While i < index
            If text.Chars(i) = vbCr Then
                lineNumber += 1
                i += 1
            End If

            i += 1
        End While

        Return lineNumber
    End Function

End Module

5) Save the macro and close the editor.

6) Now let's assign shortcut to the macro. Go to Tools->Options->Environment->Keyboard and search for your macro in "show commands containing" textbox:

image

7) now in textbox under the "Press shortcut keys" you can enter the desired shortcut. I use Ctrl+M+E. I don't know why - I just entered it first time and use it now :)

 

That's it, now if you write the following javascript code:

/// <reference name="MicrosoftAjax.debug.js" />
/// <reference name="MicrosoftAjaxTimer.debug.js" />
/// <reference name="MicrosoftAjaxWebForms.debug.js" />

// KWB.BaseWizard class constructor
//#region
Type.registerNamespace("KWB");
KWB.BaseWizard = function(field) {
    // call base constructor
    KWB.BaseWizard.initializeBase(this);
    this._state = null;
}
//#endregion

// KWB.BaseWizard Class Body
//#region
KWB.BaseWizard.prototype = {
    // Sys.Component Overrides
    //#region
    dispose : function () {
        this._state = null;
        this._stateField = null;
        this.lastClicked = null;
        Sys.Application.remove_load(this.appLoad);
        KWB.BaseWizard.callBaseMethod(this, 'dispose');
    },
    
    initialize : function() {
        KWB.BaseWizard.callBaseMethod(this, 'initialize');
    },
    //#endregion
    
    // Properties
    //#region
    get_state : function() {
        return this._state;
    },
    
    set_state : function(value) {
        this._state = value;
    },
    //#endregion
    
    // Methods
    //#region
    getNext : function(current) {
        /// <summary>
        /// Override. Called when 'next' is called. Determines next frame to display
        /// </summary>
        /// <param name="current">current SelectedIndex</param>
        return current + 1;
    },
    
    getPrevious : function(current) {
        /// <summary>
        /// Override. Called when 'previous' is called. Determines previous frame to display
        /// </summary>
        /// <param name="current">current SelectedIndex</param>
        return current - 1;
    },
    
    finish : function() {
        /// <summary>
        /// Override. Called when 'finish' is pressed
        /// </summary>
        return true;
    },
    //#endregion
    
    // Event handlers
    //#region
    nextClick : function() {
        //TODO: add contents later
    }
    //#endregion
};
KWB.BaseWizard.registerClass('KWB.BaseWizard', Sys.Component);
//#endregion

// WizardStepType enumeration
//#region
KWB.WSType = function(){};
KWB.WSType.prototype = 
{
        Server  : 1, 
        Client  : 2,
        Service : 4 
}
KWB.WSType.registerEnum("KWB.WSType", false);
//#endregion

if(typeof(Sys) !== "undefined")Sys.Application.notifyScriptLoaded();

Now click Ctrl+M+E and you will see:

image

 

Veeery handy !

 

This is possible in VS because actually you can outline and collapse any selection you like manually, this work in most editors for VS.

If you are interested about that shortcuts see Text Manipulation Shortcut Keys, Visual C# Scheme . The shortcuts starting with Ctrl+M are the ones that manipulate test outlining and toggling.

 

Check out my previous post related to js files in AJAX scenario, and see how we can remove unnecessary white spaces and comment blocks from them for use in production:

Auto generate release scripts for web application using T4 template

 

Hope this helps.

Technorati Tags:

kick it on DotNetKicks.com

43 comments:

  1. Thanks this is great
    Thanks for passing this on
    I searched for regions and js in google and found your post
    I am using ExtJs in VS2008 and had about 400 lines of js that was becoming difficult to manage

    Andy

    ReplyDelete
  2. Hmm... I'm using VS 2008 and this doesn't seem to work for me. The macro runs but nothing ever gets collapsed...

    Any ideas..??

    ReplyDelete
  3. Hi Jason,
    I use this macro in VS 2008 and it works ok,
    try to repeat steps described in the article again,
    hope this helps.
    Kirill

    ReplyDelete
  4. Thank you very much!!! This is a precious help for the ExtJS developers using VS2008.

    Jason:
    You must check the name of the module in the above code with the name of your new Macro. both names must match!

    ReplyDelete
  5. Nice, but you still have to manually type the comments //#region, //#endregion. I would really like to be able to outline large javascript files without typing the region comments.

    Also, beware that you must have a empty line after the last //#endregion comment or the macro will produce an error stating 'Value does not fall within the expected range'.

    ReplyDelete
  6. seeker,
    Yes it does make sence if you need to outline the region only once,
    while using //#region comment directive you are stating the regions which are checked into source control with code itself,
    it means any developer working with the code can download it from source server, press shortcut buttons in editor and that's it - the js file is outlined into logical groups.

    Regards,
    Kirill

    ReplyDelete
  7. Thanks Kirill.

    I will use your method going forward. I had just inherited a 4300 line Javascript file and it sure would've been nice to click a button and wham, everything is outlined. At least the next guy to get this file can do that after I comment it.

    ReplyDelete
  8. Thanks again Kirill! I've been using you're comment method now for almost two weeks. It's a huge help.

    ReplyDelete
  9. Much obliged,

    really useful and quick to set up.

    ReplyDelete
  10. Was about to give up on VS2008 and JS. Thank-you!

    ReplyDelete
  11. very helpful..

    thanks..

    ReplyDelete
  12. If you look at the previous page you'll see my post about how to collapse the code without having to put in region lines. I've made some major changes to it since the original post (updates to have it use regular exp to find the funtion lines). If I get some time I might post the new code as it is much nicer than my original post

    --lkspencer

    ReplyDelete
  13. This is fantastic, thanks for pointing it out.

    ReplyDelete
  14. Fantastic work dear!!

    Thanks a lot.... It works in vs05 and vs08 both..

    ReplyDelete
  15. May I suggest you edit the Macro to enable the text on the #region line to be visible?

    Change: -
    ' Outline region ...
    selection.MoveToLineAndOffset(CalcLineNumber(text, CInt(startRegions.Pop())), 1)

    To: -
    ' Outline region ...
    selection.MoveToLineAndOffset(CalcLineNumber(text, CInt(startRegions.Pop())), text.Length)

    This will enable collapsed sections to read: -
    [+]//#region Region Description [...]

    Which has greater readability than: -
    [+][...]

    A useful macro. Thanks for presenting it.

    ReplyDelete
  16. This is awesome! Thank you very much

    ReplyDelete
  17. assert(Your.KungFu == STRONG );

    ReplyDelete
  18. Thx a lot for helping me to clean up my js-files ;).

    Great work, greetings from Austria.

    ReplyDelete
  19. Nie script.

    I got the "Stack Empty" Error.

    I noticed that I used to have
    //#region automation part
    //#endregion automation part

    this macro didnot like anything after word region on the same line. I removed and standardised to
    //#region
    //#endregion

    and works like a charm!

    Thanks hips!

    ReplyDelete
  20. Anyone having a problem with this in VS2010?

    ReplyDelete
  21. Good work. I added this to collapse regions of HTML/ASPX pages too.
    Sub OutlineRegions()
    Const REGION_START As String = "//#region"
    Const REGION_END As String = "//#endregion"
    OutlineRegionsSub(REGION_START, REGION_END)
    End Sub

    Sub OutlineRegionsHTML()
    Const REGION_START As String = "<!--#region-->"
    Const REGION_END As String = "<!--#endregion-->"
    OutlineRegionsSub(REGION_START, REGION_END)
    End Sub

    Sub OutlineRegionsSub(ByVal REGION_START As String, ByVal REGION_END As String)
    ...

    ReplyDelete
  22. I can't get this to work in VS2010 RC. The macro isn't erroring when I run it, but I'm getting no collapsing.

    ReplyDelete
  23. this is really cool stuff, really i liked very much. I implemented for VS2008

    ReplyDelete
  24. Thanks, really great.
    Kizmar, it works in VS2010 too.
    Just don't forget to import the System.Collections namespace like:

    Imports System.Collections

    Best regards

    ReplyDelete
  25. Muchas gracias!
    Nice Post!

    Esto es de mucha utilidad.

    Esto es de mucha ayuda para las personas que trabajan con .Net y quieran agregar regiones a traves de #region y #endregion en JavaScript

    Saludos!

    ReplyDelete
  26. Hi, Im using ur tooltip.when i click my menu tab im getting javascript error.delete this.get_element().htIFrame; this is error.Plz answer me.its urgent

    ReplyDelete
  27. Hello Kiril,
    Thank you for this job.
    It is very useful.
    I wonder if it possible to remove this collapse.
    when i want to change place of //#region .
    Because, it is still there. Thank you.

    ReplyDelete
  28. Hi Eman,

    What if you try to close the file and open / run macro again?

    I think this should work.

    (cannot test as dont have environment setup for this)

    Regards,
    Kirill

    ReplyDelete
  29. Hi guys!
    You may be interested to have js code outlining as addin for VS2008?

    Here it goes...
    JsOutline

    Any comments appreciated!

    ReplyDelete
  30. Thanks a lot for this... It worked really well in VS2010.

    ReplyDelete
  31. I could kiss you! - But instead I will just leave you a positive comment. This worked great for me and is a welcome feature with long winded js files.

    ReplyDelete
  32. Great article...

    Really helped...

    Thank you very much...

    God bless you...

    Keep sharing such things...

    ReplyDelete
  33. Great post

    Can i ask if you have a script that can expand all regions

    thanks :)

    ReplyDelete
  34. Works Great.. Really Cool Thanks

    ReplyDelete
  35. It is a pity that MS have removed macros from 2012 but not given us this functionality.
    Apparently they removed it as it was not being widely used. So instead of leaving it and not updating it, they removed it entirely. Thank you Microsoft :p

    ReplyDelete
  36. Just found this for Visual Studio 2012:

    /*#region RegionName*/
    css goes here
    /*#endregion*/

    :)

    ReplyDelete
  37. If I do want use this on vs2012 to apply regions to any type file? It's possible?

    ReplyDelete
  38. I just made it work!!! Great job!!!

    Thanks!

    ReplyDelete