# Tuesday, February 03, 2009

Over the last 4 years, JavaScript has been critical to the majority of the web applications that I have worked on; dealing with the logical organization of said files has always been a less-than-satisfactory experience until about 2 years ago when I began using the following techniques for a easier design-time experience.

Page-Specific JavaScript Files

Let's say I have a page named foo.aspx and I have JavaScript specific to it contained in a file - I name the .js file foo.aspx.js. Then, in a base class for the pages of the application, I have the following code:

   1: protected override void OnLoad(EventArgs e)
   2: {
   3:     base.OnLoad(e);
   4:     AttachPageSpecificJavaScriptFile();
   5: }
   6:  
   7: private void AttachPageSpecificJavaScriptFile()
   8: {
   9:     var appRelativeVirtualPath = string.Format("{0}.js", TemplateControl.AppRelativeVirtualPath);
  10:     RegisterJavaScriptFile(appRelativeVirtualPath);
  11: }
  12:  
  13: protected void RegisterJavaScriptFile(string appRelativeVirtualPath)
  14: {
  15:     if (JavaScriptFileExists(appRelativeVirtualPath))
  16:     {
  17:         string url = ResolveClientUrl(appRelativeVirtualPath);
  18:         ClientScript.RegisterClientScriptInclude(url, url);
  19:     }
  20: }

Essentially, for each page in my application, the app will look for a *.aspx.js file that matches the name of the page (in our example, foo.aspx.js) and place, within the rendered page, a script tag referencing it.

Since every request to a given page would need to check to see whether or not an associated .js file existed, and considering the fact that checking with the file system each time would be somewhat costly, I have the following code take care of checking and then caching the results at the application level:

   1: private Dictionary<string, bool> JavaScriptFileRegistry
   2: {
   3:   get
   4:   {
   5:     var javaScriptFileRegistry = Application["JavaScriptFileRegistry"] as Dictionary<string, bool>;
   6:     if (javaScriptFileRegistry == null)
   7:     {
   8:       javaScriptFileRegistry = new Dictionary<string, bool>();
   9:       Application["JavaScriptFileRegistry"] = javaScriptFileRegistry;
  10:     }
  11:     return javaScriptFileRegistry;
  12:   }
  13: }
  14:  
  15: protected bool JavaScriptFileExists(string appRelativeVirtualPath)
  16: {
  17:   var registry = JavaScriptFileRegistry;
  18:   if (registry.ContainsKey(appRelativeVirtualPath) == false)
  19:   {
  20:     registry.Add(appRelativeVirtualPath, File.Exists(Server.MapPath(appRelativeVirtualPath)));
  21:   }
  22:   return registry[appRelativeVirtualPath];
  23: }

To complete this, I have a registry hack that will cause any *.aspx.js files to collapse underneath the *.aspx page in the solution explorer of Visual Studio (i.e. it will hide underneath the page, just like the *.aspx.cs file does). Depending on the version of Visual Studio you are using, the registry hack is different. Here are a couple that I use with Windows XP (I don't know if they differ for Vista because I don't use Vista) - copy each one into a text file and rename it with a .reg extension, then execute the file.

Visual Studio 2005
   1: Windows Registry Editor Version 5.00 
   2: [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Projects\{E24C65DC-7377-472b-9ABA-BC803B73C61A}\RelatedFiles\.aspx\.js] 
   3: @=""
Visual Studio 2008
   1: Windows Registry Editor Version 5.00 
   2: [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Projects\{E24C65DC-7377-472b-9ABA-BC803B73C61A}\RelatedFiles\.aspx\.js] 
   3: @=""

You will probably need to reboot your machine before these take effect. Also, the nesting will only take place for newly-added .js files, any that you have which are already named *.aspx.js can be nested by either re-adding them to the project or manually modifying the .csproj file's XML.

Anyway, that is how I do things and it really helps to keep things organized. I also do all of this for user controls (ascx files) - with the above, it should be simple enough to figure out how to do this for the user controls and ascx file extension.

Hope this helps someone!

Kick It on DotNetKicks.com

posted on Tuesday, February 03, 2009 2:21:51 PM (Mountain Standard Time, UTC-07:00)  #    Comments [6]
# Thursday, November 01, 2007

I sure hope so! I noticed this quite some time ago when I first saw the syntax for anonymous types in C#. Being a lover of JavaScript, I quite like the ability to do things in C# in a manner consistent with the syntax I am used to using in JavaScript (my current favorite programming language, especially thanks to MochiKit). The syntax I refer to is partly alluded to in this post by Eilon Lipton (first time I have ever heard of Eilon), where he talks about substituting an anonymous type for a Dictionary<string, string>, using said Dictionary for setting attributes on HTML tags he is creating in C#. Sound familiar? I mentioned something similar in my post yesterday.

To illustrate the syntax I keep referring to, here is what I am used to doing in JavaScript, particularly with MochiKit - let's say I want to create a div element programmatically (and let's spit it out as HTML so we can better get the gist of things):

 toHTML(DIV({id:"myDiv", class:"myCssClass"}, P({ style:"font-weight:bold" }, "Hello World!")));

The HTML rendered looks like:

 <div class="myCssClass" id="myDiv"> <p style="font-weight: bold;">Hello World!</p> </div>

So, rather than declaring a the JavaScript function "DIV" or "P" (which create div and paragraph DOM elements, respectively) with every possible option as a parameter to said function (e.g. id, style, class, etc.), you simply pass in an anonymous object which contains values for the properties you care about setting. This is a fairly typical way of doing things in JavaScript, and despite the protests from the academic portion of my brain as well as other developers, I would love to be able to do the same in C#.

 

Technorati Tags: , , ,
Kick It on DotNetKicks.com

posted on Thursday, November 01, 2007 11:38:15 AM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Sunday, October 29, 2006


For the last client I worked for, we extensively modified a MochiKit port of a well-known 'Lightbox' implementation so that it would utilize IFrames - the users of the application loved it because they were used to primitive JavaScript alert and confirm boxes, and since a modal dialog was still the appropriate thing to do, it worked well.

A short time later, I found ThickBox - seems to be a much better implementation of this now-common technique, and I thought it might prove useful to have a MochiKit version of it in case I decide I want to use it (it is built on jQuery, which I don't personally use or care for, notwithstanding the library having a few useful constructs that I would like to see ported over to MochiKit).

In porting this script, I tried not to 'improve' it at all; i.e. I left nearly everything as-is with regards to naming conventions, use of certain constructs that I would like to improve, etc. and leave it up to you, if you choose to download it, to make any changes you see fit. Of course, any bugs you find would be great to know about, as well as ideas for enhancements, etc. and I will probably update this when I get time, because I would like to do things much differently (maybe I am smoking crack, but this whole idea of connecting to things based on the value of the 'class' attribute of a tag just seems stupid to me...).

My port of ThickBox isn't perfect and I did it as quickly as I could because I wanted to get it into the hands of those smarter than I - that means you. There are places in the code that are inconsistent and I will be working on that, but for now it does the job and should be a good starting point for those that find this useful.

Download ThickBox for MochiKit.

Kick It on DotNetKicks.com

posted on Sunday, October 29, 2006 11:02:53 AM (Mountain Standard Time, UTC-07:00)  #    Comments [2]