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:
2) Create new macro:
3) Name it "OutlineRegions":
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:
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:
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.
Thanks this is great
ReplyDeleteThanks 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
Hmm... I'm using VS 2008 and this doesn't seem to work for me. The macro runs but nothing ever gets collapsed...
ReplyDeleteAny ideas..??
Hi Jason,
ReplyDeleteI use this macro in VS 2008 and it works ok,
try to repeat steps described in the article again,
hope this helps.
Kirill
Thank you very much!!! This is a precious help for the ExtJS developers using VS2008.
ReplyDeleteJason:
You must check the name of the module in the above code with the name of your new Macro. both names must match!
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.
ReplyDeleteAlso, 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'.
seeker,
ReplyDeleteYes 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
Thanks Kirill.
ReplyDeleteI 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.
Thanks again Kirill! I've been using you're comment method now for almost two weeks. It's a huge help.
ReplyDeleteMuch obliged,
ReplyDeletereally useful and quick to set up.
Was about to give up on VS2008 and JS. Thank-you!
ReplyDeletevery helpful..
ReplyDeletethanks..
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
ReplyDelete--lkspencer
Thank you very much for this!
ReplyDeleteThis is fantastic, thanks for pointing it out.
ReplyDeleteMade my day!
ReplyDeleteFantastic work dear!!
ReplyDeleteThanks a lot.... It works in vs05 and vs08 both..
May I suggest you edit the Macro to enable the text on the #region line to be visible?
ReplyDeleteChange: -
' 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.
This is awesome! Thank you very much
ReplyDeleteassert(Your.KungFu == STRONG );
ReplyDeleteThx a lot for helping me to clean up my js-files ;).
ReplyDeleteGreat work, greetings from Austria.
awesome! thanks!
ReplyDeleteNie script.
ReplyDeleteI 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!
Anyone having a problem with this in VS2010?
ReplyDeleteGood work. I added this to collapse regions of HTML/ASPX pages too.
ReplyDeleteSub 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)
...
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.
ReplyDeletethis is really cool stuff, really i liked very much. I implemented for VS2008
ReplyDeleteNice!
ReplyDeleteThanks, really great.
ReplyDeleteKizmar, it works in VS2010 too.
Just don't forget to import the System.Collections namespace like:
Imports System.Collections
Best regards
Muchas gracias!
ReplyDeleteNice 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!
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
ReplyDeleteHello Kiril,
ReplyDeleteThank 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.
Hi Eman,
ReplyDeleteWhat 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
Flippin' sweet! Thanks!
ReplyDeleteHi guys!
ReplyDeleteYou may be interested to have js code outlining as addin for VS2008?
Here it goes...
JsOutline
Any comments appreciated!
Thanks a lot for this... It worked really well in VS2010.
ReplyDeleteI 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.
ReplyDeleteGreat article...
ReplyDeleteReally helped...
Thank you very much...
God bless you...
Keep sharing such things...
Great post
ReplyDeleteCan i ask if you have a script that can expand all regions
thanks :)
Works Great.. Really Cool Thanks
ReplyDeleteIt is a pity that MS have removed macros from 2012 but not given us this functionality.
ReplyDeleteApparently 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
Just found this for Visual Studio 2012:
ReplyDelete/*#region RegionName*/
css goes here
/*#endregion*/
:)
If I do want use this on vs2012 to apply regions to any type file? It's possible?
ReplyDeleteI just made it work!!! Great job!!!
ReplyDeleteThanks!