Friday, 1 June 2007

Everything you always wanted to know about Javascript but were too afraid to ask

I’ve been hacking with Javascript since ’97 or so and it always seemed so accessible I never thought about sitting down to actually discover what it’s all about. Between AJAX and widgets and funky calendar controls I've recently came across constructs I'd never seen before—admittedly Javascript is, even after nearly x years, a mystery to me. Or rather it was, until I read this article:

http://odetocode.com/Articles/473.aspx

The article is reasonably short, very concise and explains a lot about the language itself. Better still, the article is targeted at .NET C# developers who know more about classes and method than prototypes. The examples are great as well.

Looks like Javascript isn’t going away any time soon so I’d suggest this article as a great intro to the rest of your life as a Javascript developer ;-)

Thursday, 31 May 2007

Localizing Web Parts, Custom Controls, and Class Libraries

If you've dealt with the ResourceManager in .NET 1.x--or never touched resources altogether, moving to .NET 2.0 simplifies the process to the point where it all seems too simple. Simplicity is generally a good thing, of course, and once you understand localization in .NET 2.0 you'll probably agree there's no reason why pretty much every application shouldn't be localized from the beginning (I'm in the process of localizing and existing MOSS 2007 site, hence the sentiment just expressed).

Localization is a good thing because it:

  • Allows you to refactor hard-coded strings for labels, menus, and so on out of your code and into .resx files;
  • Enables your application to display a user interface relevant to users of different languages.

Localization won't translate your interface for you--that still has to be done manually.

Visual Studio 2005 now takes care of all the hard work needed to develop a fully localized app in no time at all. Firstly, it provides a convenient designer for creating resource files through which you can add strings, images, icons, and text/script files. Secondly, any .resx file added to your project are automatically compiled to a .resources file and linked to your main assembly. Finally, a resource file wrapper class is generated automatically, granting you strongly-typed access to the contents of your resource files. What more could you ask for?!?

Working with resources is really straight forward if you're writing user controls or web pages (apparently WinForms are just as straightforward but I don't know much about WinForms) because both the UserControl class and Page class both derive from System.Web.UI.TemplateControl. TemplateControl exposes the protected GetGlobalResourceObject ( ) and GetLocalResourceObject ( ) methods. When a user control or web page has a resource file available to it, you also get strongly-typed access to the file like this:

Resources.MyResourceFile.MyKey;

(where 'Resources' is some weird namespace that only comes to life when you've got .resx files in your project)

On the other hand, if you're writing web parts, custom controls, or class libraries, you're probably not deriving from TemplateControl (especially in the web part case where you class inherits WebPart). You can still add resource files to you project and use a ResourceManager to pull out the stuff you need but there's an easier way.

  1. Create a new class library project; name it MyCustomWebParts or whatever you like. The name you give your project will also become the name of the assembly and be used as the default namespace for any classes you add and any classes added by Visual Studio (this last bit is really important).
  2. Create a new resource file (Add new item...) named strings.resx in the root of the project (you can also place your resource files in an arbitrarily-named folder but doing so will change how the file is accessed programmatically). Add a new string with a name of labelText and a value of Hello World.
  3. Create a new class that derives from
    System.Web.UI.WebControls.WebParts.WebPart; name it MyWebPart or whatever you like.
  4. Add a CreateChildControls ( ) method to your class and within the method body, instatiate a new Label object and add it too the Controls collection.
  5. Immediately after the Label is instantiated, set its Text property from the resource file. You do this by referencing [the default namespace for the assembly].[the name of the resource file with no extension].[the resource key name].
  6. Add or update a globalization element to your web.config file and set both the culture and uiCulture attributes to auto:
    <globalization uiculture="auto" culture="auto" />
    This works on a regular ASP.NET site but MOSS doesn't automatically assign the browser's current language to the System.Threading.Thread.CurrentThread.CurrentCulture and CurrentUICulture properties so you may wish to do this yourself and forego the above web.config setting.
  7. Build the project and register the web part in a .aspx page--and that's it!

namespace MyCustomWebParts
{
public class MyWebPart : WebPart
{
protected override void CreateChildControls ()
{
Controls.Clear ();
Label label = new Label ();
label.Text = MyCustomWebParts.strings.labelText;
Controls.Add (label);
}
}
}

As mentioned, adding a .resx file to your project prompts Visual Studio to generate a strongly-typed wrapper class for accessing the file; this class is created in the project's default namespace. If your web part or control is the same namespace you don't need to qualify your resource file within the MyCustomWebParts namespace--you can access it directly: strings.labelText. If you've got multiple namespaces in your project (or not) it's probably a good practice to always qualify the resource class name.

If you do drop your .resx files into a folder you'll need to modify the way you reference them:

MyCustomWebParts.MyFolder.strings.labelText;

Either way, IntelliSense will help you out as you go if everything's in the right place.

To tweak performance, you can tell ASP.NET which resources are contained in the default assembly by adding an attribute to your class library's AssemblyInfo file:

[assembly: System.Resources.NeutralResourcesLanguageAttribute ("en")]

And the end result: localized web parts, custom controls, and class libraries. Cool.

 

Wednesday, 16 May 2007

A comprehensive review of how to make an anchor tag do nothing

What's the best way to fire a javascript event from an anchor tag without mucking up your navigation? For that matter, what's the best way to do anchor tags all together? Have a look at the tests below and review the source before making your own decision (you might want to copy the source out to your html file).

Here's a few things to consider:

  • We do not usually want a link to return the caret to the top of the page.
    Javascript may be disabled on the client side (but all solutions presented here are javascript-dependent)
  • Microsoft apparently recommends against using javascript: calls from within the HREF element of an anchor tag and its use may also impact accessibility.
  • If using a click event handler, place a hash in the href attribute and a return false; as the final code for the onClick attribute; ensure any preceding function calls can be interpreted and executed or the return false may never be reached.
  • Alternatively, use another tag (not an anchor tag) and its onClick attribute.

a (without href) (no underline)
a href="wwww.mysite.com" (normal link)
a href="" (opens containing folder in IE (when run without a web server); scrolls to top of page in FF)
a href="#" (scrolls to top of page)
a href="javascript:" (works in IE but pops up javascript console in FF)
a href="javascript: return false;" (javascript error)
*
a href="javascript: void(0);" (works but may cause problems)
*
a href="javascript: myFunc();" (works if myFunc () is defined - myFunc does not need to return false)
a href="javascript: myUndefinedFunc ();" (javascript error)
a href="top" (scrolls to top of page)
a href="null" (no underline)
* a href="#bookmark" (works if a name is defined immediately above)
a onclick="return false;" (without href) (no underline)
*
a href="" onclick="return false;" (works)
*
a href="#" onclick="return false;" (works)
a href="#" onclick="myBrokenFunc; return false;" (javascript error and scroll to top because return false never executes)
*
a href="#" onclick="myOnClickFunc (); return false;" (works)
* styled span (works but doesn't "select" on click or change color on visit)

* = A preferred way to do nothing links

Friday, 11 May 2007

Truths

A man in a hot air balloon realised he was lost. He reduced altitude and spotted a woman below. He descended a bit more and shouted, "Excuse me, can you help me? I promised a friend I would meet him an hour ago, but I don't know where I am".

The woman below replied, "You're in a hot air balloon hovering approximately 30 feet above the ground. You're between 40 and 41 degrees north latitude and between 59 and 60 degrees west longitude."

"You must be in I.T," said the balloonist.

"I am," replied the woman, "How did you know?"

"Well," answered the balloonist, "everything you told me is technically correct, but I've no idea what to make of your information, and the fact is I'm still lost. Frankly, you've not been much help at all. If anything, you've delayed my trip."

The woman below responded, "You must be in Management."

"I am", replied the balloonist, "but how did you know?"

"Well," said the woman, "you don't know where you are or where you're going. You have risen to where you are due to a large quantity of hot air. You made a promise, which you've no idea how to

Wednesday, 9 May 2007

The New westernaustralia.com Launched

Cool! Check out the latest site launched by our team here at Tourism Western Australia:

www.westernaustralia.com

The site launched successfully on Sunday and is built on Microsoft Office SharePoint Server 2007 (MOSS 2007). The site is branded to within an inch of its life and plays nicely with the BDC to pull tourism information from the Australian Tourism Data Warehouse.

Well done to the developer team (who, incidentally, started working on with MOSS back at beta 2)!

Friday, 20 April 2007

Fiddler Reverse Proxy Setup

The Fiddler documentation includes instructions on how to configure the tool as a reverse proxy (http://www.fiddlertool.com/Fiddler/help/reverseproxy.asp). Option #1 is only useful if you're setting up Fiddler as a local reverse proxy; if you want to use Fiddler from external clients, you need to go for Option #2.

The code snippet to be added to your custom rules file includes two string listerals: "webserver:8888" and "webserver:80". It's in important to note that "webserver" is not a variable name--it must be replaced with the name of your web server (i.e. MyServer, as in http://myserver). The other important thing is to add the code snippet to the OnBeforeRequest function and not the OnBeforeResponse function. You'll also probably want to allow remote clients to connet via Fiddler so make sure the Tools -> Fiddler Options... Allow remote clients to connect options is selected.

You can change the listen port from 8888 via Tools -> Fiddler Options... Listen Port if you want to use a port other than 8888.

If you implement both Option #1 and Option #2 you might end up with problems like an infinite loop.

The change may take a little while to come into effect so meanwhile, try restarting Fiddler, running an iisreset, or rebooting.

Tuesday, 17 April 2007

How to determine if a page is in edit mode

SPContext.Current.FormContext.FormMode == SPControlMode.Edit

Alternatively, use an EditModePanel (the PageDisplayMode can be set for specific display modes).

Javascript Debugging in VS2005

See this link for a useful article on Javascript debugging with Visual Studio 2005. I managed to get it working using a basic page consisting of a single button with an OnClientClick attribute calling a simple inline function. I also played around with using the Javascript debugger; statement to break into the runtime document, which proved handy when attaching to the running server process instead of starting off via F5.

By the way, Firebug has a Javascript debugger and while it's pretty clunky, it might help get you out of a jam (Firebug is useful for so many other reasons as well).

http://blogs.msdn.com/webdevtools/archive/2007/03/08/jscript-debugging-in-visual-studio-2005.aspx

Thursday, 12 April 2007

Determining the current variation

If you need to find out which variation a client has requested, this code might do the trick.

Start by getting the current VariationLabel; then compare its title against a known variation title.


VariationLabel currentVariation = PublishingWeb.GetPublishingWeb
(SPContext.Current.Web).Label;

if (currentVariation != null &&
currentVariation.Title.ToLowerInvariant () ==
"au")
{
//do something
}

Tuesday, 3 April 2007

Saturday Shopping

I don't understand what went wrong with my parent's generation. They showed so much promise with their bombs, telecommunication, and political reform but they make out as though the race to the moon was only the first stage in the race of life: hussle, bussle--they can't get there fast enough no matter the price. In contrast, I believe our generation is now responsible for putting the humanity back into a world left devoid of everything but some elusive end goal.

Saturday grocery shopping, if you do it regularly, makes the Christmas rush seem like nothing out of ordinary. The shops are busy, the shelves are empty, and no one really wants to be there. I'm a happy Saturday shopper and I use each experience to test and develop my patience. Most times I make it through.

This Saturday seemed especially busy for whatever reason. It was the first cool weekend in a long while so my guess is families were out to stock up after a month of lying around sweating. Nevermind, I thought, I'm in no rush today so I'll just have to try extra hard to be patient and polite; "after you", "go ahead", smile and say "excuse me, thank you." With the narrow isles full of the overweight, carts, and mothers with strollers for triplets, there would be, I knew, a lot of standing around waiting.

At one point, momentarily frozen int time waiting for the isle to clear before I could move past the stacks of broken eggs and on towards the vegetarian sausages, my personal space suddenly vanished as a well-dressed, dark-haired woman well into middle-age squeezed up next to me and then bolted past into the gap only to stop in front of me. "Now that's pushing it, lady," I thought to myself. No "excuse me", no smile, only an in-grained push to get there sooner, get the job done, and trample anyone in the way.

"Have a taste of your own medicine, if you're going to be that way," I shouted at her in my mind as I plowed into the melay of shopping carts and unwashed Saturday shoppers. With her cart in the mix, the gap had narrowed significantly so I pushed forward, nosing my cart into what must have been the one piece of unoccupied real-estate in the entire store. I plowed her cart out of the way and then knocked it again for good measure before continuing on my way, a dazed mother glaring at me all the while. Yes, shame on me for my childish retaliation but let that be a lesson to the pushy woman.

I shuffled on in my sandy thongs not feeling any better for my actions--on reflection, feeling worse. Nevertheless, my calm depened as I resolve to kick back against the rush and hurry imposed on me by this boom-time generation. With all the man-made pressures built into our lives I'm finally beginning to understand why so many of me friends and classmates turned to cigarettes, booze, and pot over the years.

I always think back to my drives between Montreal and Ottawa as a university student returning home for a weekend or during the holidays. The old Grand Marquis I drove (a 5.0 litre V8) handled the drive at 140km/h quite happily but as the car moved ever closer to the scrap heap, exaust fumes seeping in through the salt-rusted holes in the floor meant the trip had to be completed at 90km/h in the slow lane. At either speed, the journey always took two hours.