June 2006 - Posts

CSS For Printing

With CSS, you can create a specific style sheet for printing and link it to your pages. Browsers will still display your pages using your normal style sheet but, when a user prints your page, the print style sheet kicks in.

 Linking a Print Style Sheet

Linking a print style sheet to your pages is the same as linking a normal style sheet, but with one difference: you'll need to add a media attribute to your <link> tag. Like this:

 <link rel="stylesheet" type="text/css" href="printstyles.css" media="print">

 If you're using an internal style sheet, you can add that same media attribute to your <style> tag:

 <style type="text/css" media="print">

 body { font: 12pt Times, serif; }

</style>

 In both cases, you can still link your normal style sheet that the web browser will use for rendering your page. You can give that style sheet <link> a media attribute of "screen":

 <link rel="stylesheet" type="text/css" href="normalstyles.css" media="screen">

 It doesn't matter if the declarations in your "screen" and "print" style sheets overlap -- only one of them will be used at a time anyway.

 Changing Fonts

 The first thing you'll probably want to do in a print style sheet is set the fonts. Most web sites use sans-serif fonts (such as Arial or Verdana) since many studies have shown that those fonts are most readable on computer screens. But since a number of those studies show that serif fonts (like Times New Roman or Garamond) are most readable in print, you'll probably want to use serif fonts in your print style sheet.

 For instance, if your document consists of <h1> and <p> tags (styled with sans-serif fonts for the screen), you might add this declaration to your print style sheet:

 h1, p { font-family: Garamond, "Times New Roman", Times, serif; }

 In addition to changing the font, you may also want to change the font size and units of your document. Pixels and ems are common measurements when sizing text on the web, but points are the perfect measure for printed pages (that's what they were designed for!). So, you could amend the declaration above to include appropriate font sizing for your printed document:

 h1 { font: 24pt Garamond, "Times New Roman", Times, serif; }

 p { font: 12pt Garamond, "Times New Roman", Times, serif; }

 You could also add values for line-height, font weight, word spacing, justification (with the text-align property)... all of the same CSS properties available for displaying text on the screen    can be adapted to style your text for printing.

 Eliminating Elements

 Most browsers give you the option of printing backgrounds and images when you print a document. But what if you want certain images to be printed, but not others? For example, you might want users to see your logo when they print a page, but not the site navigation. How can this be done? Enter your new best friend: display: none.

When you set an element's display property to "none", the result is pretty straightforward -- the element doesn't appear. This can be a powerful tool in your print style sheet. For instance, if you gave each of your advertising images a class of "ad", you insert the following declaration in your print style sheet to hide them:

img.ad { display: none; }

You can use display: none to hide a <div> containing navigation, all <img> tags, or any number of elements. This is a great way to give the user a page that, when printed, contains only the elements they truly need and want (usually, just the text).

Margins, Colors, and More

Why stop there? You could also set margins on document elements -- for example, if you wanted to give the main text more room, you could use the following declaration (this example assumes the text is contained in a <div> with the id of "content"):

 div#content { margin-left: 1in; margin-right: 1.5in; }

 (Note that we used inches as the unit of measurement -- this makes much more sense for a print document than an on-screen document, where pixels are a more natural rule-of-thumb.)

 What if your web page uses a bright yellow font on a dark background? If the user is printing to a color printer and doesn't print the background, your text may be illegible. In that case (and  in many others -- you may want to change border colors, too), it might be best to set your text to black (or something grayscale) for your print style sheet. A simple declaration does the trick:

p { font: 12pt Times, serif; color: black; }

The printstyles.css Style Sheet

 The printstyles.css style sheet would look like this:

body {

  color : #000000;

  background : #ffffff;

  font-family : "Times New Roman", Times, serif;

  font-size : 12pt;

  }

a {

  text-decoration : underline;

  color : #0000ff;

 }

#navigation, #advertising, #other {

  display : none;

}

 Save printstyles.css in the same directory as the file, include the <link rel="stylesheet" type="text/css" href=" printstyles.css" media="print" /> in the head of your document, and page will print perfectly while displaying however you would like.

page-break-before and page-break-after

The CSS attributes page-break-before and page-break-after, both instruct the printer to begin printing a new page, with the difference being before or following the element the attribute is applied to. The possible values the two attributes accept are:

Value                                     Description
always                                   Always insert a page break
auto                                      Default value. Insert page break only if at end of page.
"" (empty string)                      Do not insert  a page break.

Let's say your page consists of multiple headers (with content following each). Want to divide each header into a separate page for printing?

<style type="text/css">
h1{
page-break-before: always;
}
</style>
How about getting even more personal, and divvying things up at specific location(s)?

content here
"
<DIV style="page-break-after:always"></DIV>
"
"
content here


Note that page-break-after may not work with <BR> or <HR> tag in some browsers.

Working with technology start-ups - the good,...

I'll admit it: I'm a start-up junkie.  I've done eight myself and helped friends with probably triple that.  So no surprise that at Ramp we have a New Venture Practice and are currently working with a number of techology start-ups.  Most are VC backed but some are founder or angel backed.  The first is building GPS based navigation for commercial aircraft.  One is in the wireless advertising space.  Another is an online image production company.  A fourth is an affinity marketing program.  One involves a completely new paradigm in software applications and development.  Another is poised to revolutionize advertising for both old media and new media.  All have technology at the core of their operations hence our value add.  

 

Last evening I saw a clip from an Clint Eastwood movie which is a very good way to look at our experience with start-ups:  the good, the bad and the ugly. 

 

First The Good - I love the unbridled enthusiasm, the entrepreneurs belief that anything is possible and just watching people create something out of nothing.  The latter thrill is all I can do these days as I promised my family that I wouldn't do another start-up myself! Words like passion, creativity, no rules, changing the world and energy are apt start-up terminology.  For a start-up the f-word is not what you would think instead is the one they won't ever say: failure.  It's just not an option!  At Ramp we joke that we only believe in successes and learning so you won't hear the f-word from us. One of the most difficult but rewarding things we often do is to help the entrepreneur to define their business.  In our experience the original vision almost always changes once customers and the real world intrude.  Hence flexibility and adaptability are critically important and something we view as key to architecture, data models and UX designs.  Experienced entrepreneurs try to get close with their first release but leave a chunk of budget - like half - for changes that follow customer feedback.  Smart customers really appreciate that.  There are many stories of stubborn entrepreneurs who stuck to their original vision even when all the data shows they should change.  Note that I didn't say advice as that is very often off base whereas data isn't.  That is totally contrary to our experience as we've seen much more success when entrepreneurs look particularly to customer data and morph to where the opportunity was.  

   

My next post will be The Bad...

Musings of a Serial Entrepreneur - Puget Sound Venture Club 20th Anniversary

Puget Sound Venture Club – 20th Anniversary Dinner June 6, 2006 – Speech by Terry Drayton  

 

Thanks Gary and congratulations on your 20th anniversary.  It’s a pleasure to be here this evening to support PSVC.  I’m a first hand beneficiary of your efforts to connect entrepreneurs and the angel community.  Plus as far as I’m concerned angel financing is THE most important source and one I’ve used in EVERY one of my eight start-ups.

 

Anyways Gary asked me to share a few lessons I’ve learned as a so called serial entrepreneur…a distinction to aspire to along with serial murderer!

 

First a bit of background on my path to entrepreneurship.  The reason I became an entrepreneur is simple: my dad.  Starting and running your own business was something we discussed every night around the kitchen table starting from when I was very young.  My dad was visiting a few weeks ago and we’re still doing it today. 

 

My first business was at age 11 when I started cutting a neighbor’s lawn.  Then another and another until I could use up all of my dad’s gas and not have the time to cut the lawn at home.  And the profit margins were great as my dad just kept on refilling the gas can!  A few years as a gardener lead to some construction projects and then working a waiter and salesperson during high school summers.

 

I was always a math and science geek so in college in Canada (eh) I started out in sciences on the way to becoming a doctor but switched into business after the first semester.  It would be nice to claim it was entrepreneurship calling but the real reason was the almost complete absence of girls in sciences.  Sad but true!

 

It was fun learning all the disciplines like marketing and finance and after graduation moved I chose Corporate Planning for a big natural resources conglomerate.  Not surprisingly there was not much entrepreneurial happening there but - like so many experiences - it absolutely told me what I DIDN’T want to do!

 

A year of corporate life and I was off to Toronto for an MBA.  I actually got accepted to Stanford and didn’t go.  To show you what a small world it is I’m friends now with several people who would have been my classmates and have all taken twisty paths to get here.  I took several courses in entrepreneurship in school which really awakened what I wanted to do.  After business school I moved into investment banking on Canada’s Wall Street.  My thought was that before you started a business you had to actually know something.  I spent three years watching entrepreneurs continually disprove that!

 

So in 1986 – at the age of 26 – I started my first new venture with two partners.  It was in the bottled water business that we knew absolutely nothing about.  We raised $1.3 million in angel funding and set put to go big time.  In our first six months we learned a lot: we had to get rid of one partner, we found out how hard sales is, we had to get rid of one difficult shareholder and then we ran out of money.  As a good MBA I’d modeled various negative scenarios including revenues being off by 1/3, operating costs be higher by 1/3 and capital costs higher by 1/3.  Of course I hadn’t done all three together  – which was exactly what happened!  Anyways we hunkered down raising another $1.3 million in VC funding and never looked back.  Three years in we’d acquired a 100 year old competitor who was twice our size, grown it into a profitable $10 million company with 100 staff and were the #2 company in Canada.  Although we’d had huge issues I thought “Hey, starting a business isn’t that hard”.  To this day those are some of the best memories I have and my original partner remains one of my best friends.

 

I actually learnt a lot more from my second start-up - which went very badly!  Hoping to cash in on the Hollywood move north to Vancouver (BC) I entered another business I knew nothing about – film and video post production.  It’s an awful business where you just keep buying new equipment that you need two years of rental to pay for but only ever get one year.  After a few sleepless years I sold out.  I dabbled in entertainment in Whistler before going back to the bottled water business.

 

Through a winding path I ended up buying my first company’s largest competitor – five times the size – and consolidating the Canadian industry.  We were a 1000 person, 500 truck company pushing close to $100 million in sales. – including my first company - selling it out to Dannon – the parent of Evian.   It worked out well for everyone.

 

I tried a few other businesses in Canada with reasonable success.  Then you’ve probably all heard of my next business – HomeGrocer.com.  The idea really came together in 1997 and I moved to Seattle and have been here ever since then.  We could talk about that for a month or two…but Gary only gave me 10 minutes. 

 

After the stunning idiots from Webvan destroyed our fine business we took the core technology team and founded two new businesses in late 2000 which I’m still involved in today.  One is Ramp Technology Group which we’ve grown to a 80 person IT consulting company whose largest clients are Microsoft, Marchex and several VC backed new ventures.  The second is Count Me In which we’ve grown to 600 customers across almost every state plus Canada, Germany, Italy and Japan.  We’ll process about $50 million worth of online registrations this year from Little League to cooking classes to Microsoft technology events.   Neither of my latest ventures raised any VC dollars but Count Me In raised almost $4 million in angel funding.  Interestingly we presented to PSVC in early 2001…but without success so sometimes even PSVC folks do make mistakes!

 

I love new ventures and so we set-up Ramp to get actively involved in one to two new ones each year.  That typically includes some conversion of consulting fees into stock plus taking a formal or informal advisor role.  Sometimes I’ll even sit as a director if it makes sense…and they can afford D&O insurance!  We’re currently working with mobile search company Medio and a very exciting new one called GoGo Images.

 

One of the things I’m often asked is what I look for in any new business.  The answer is pretty simple. 

 

First, great management.  And that absolutely must include a CEO who can take it from start-up to profitability.  Our VC friends may disagree but I’ve not seen any CEO recruited to fill those shoes after start-up who actually worked out.  In my experience you can recruit a great supporting cast but must have the leader.  Once it’s profitable you can transition to a new team but not until you are.

 

Second, a compelling customer value proposition.  If the customer doesn’t care and won’t pay you for your efforts then not much else really matters.

 

Last, a solid business model.  If the math doesn’t work then we are all just wasting time.

 

What I look for in key recruits for start-ups is relatively simple as well.  Clearly there must be a skill set match but then its candor, flexibility and persistence that matter most to me.  There is ZERO chance that reality will look like the Excel forecasts for any new venture so how the team deals with that is what makes the difference between success and failure.

 

There is some really good advice that someone once gave me - I wish my memory wasn't so bad - that I can share with budding entrepreneurs: work with people you like as life is just to short otherwise!  Also there are two great resources that you can work with as you build your new venture.  The first is the Entrepreneurs Organization and it's affilitate the Young President's Organization which bring together fellow entrepreneurs in a confidential, high trust environment.  I've participated in one or the other for close on 20 years and it has been the single best forum for learning and personal development.  The second is the local business school which is a great two way relationship where you share your real life experience with students and mix with really smart academics and other business community volunteers.  I've been involed with the UW's Center for Innovation and Entrepreneurship for many years.  It's a wonderful relationship and the more time I spend the more I get out of it. 

Thank you very much for your time.  

My Take on the .NET Framework 3.0 (WinFX)

There some information floating around in the developers' world about WinFX and what it means, but I still find that most developers aren't fully aware of what it is and how it will ultimately affect their development down the road. I wanted to express my take on the new movement in an effort to help bring clarity to the features and future of it as I understand it today.

First off, WinFX is no longer named WinFX, but actually it is now being called the .NET Framework 3.0. This name change was prompted due to some level of confusion as to whether or not WinFX replaced the .NET Framework or any components therein... in actually, WinFX (now referred to as the .NET Framework 3.0) is built entirely upon the .NET Framework 2.0. As initially planned, the .NET Framework 3.0 will ship with Windows Vista and will also be available on the Windows XP and Windows Server 2003 platforms. At the time of the writing of this blog, the .NET Framework 3.0 runtime components are in Beta 2 state.

Components of the .NET Framework 3.0

The .NET Framework 3.0 has a series of 4 new foundational components that are, in and of-themselves, functional frameworks for development. They are as follows:

Windows Presentation Foundation

The Windows Presentation Foundation (WPF), code name "Avalon", is a foundation for the development of slick 3-dimensional user interfaces that contain captivating graphical effects. These effects can be implemented declaratively (through markup language known as XAML) in a code file as well as programmatically via a programming language directly through an API. WPF provides an API for quickly developing data-driven applications that have amazing user interfaces with incredible new models of interactivity.

Windows Communication Foundation

Windows Comuunication Foundation (WCF), code name "Indigo", is an API for the development of web service based communication that allows for finer control and integration of security, reliable messaging and data transport. The core of WCF lies in the understanding of your "ABCs"... A is for Address, B is Binding and C is for Contract. Address is the location of the service and Binding defines the specifics of the communication (i.e. protocol, security, encoding). The Contract defines what can be communicated and the constraints upon the communication that need to be in place. The reason for the existence of WCF is to simplify the implementation details of developing distributed systems by allowing configuration to drive the details of communication between services instead of the code.

Windows Workflow Foundation

The Windows Workflow Foundation (WF) is effectively a general framework for defining workflow and rules based flow control in any kind of .NET application (i.e. Win Forms, Web Forms and Console Apps). WF even integrates directly into Visual Studio 2005 and provides a design view that allows you to create process flows in a similar fashion to developing orchestration components in BizTalk. In fact, it is currently planned that WF will replace the orchestration component in BizTalk Server in 2007!

Windows CardSpace

Windows CardSpace (WCS), formerly known as InfoCard, is an API to provide a consistent interface to a generic digital identity meta-system. The core concept behind WCS is centered on digital identity. Everyone who uses the internet has several peices of digital identification such as an account with Amazon, an email address with Yahoo or a Passport account with Microsoft. All digital entities (no matter what they are) have one thing in common... a security token. The security token simply expresses information about the digital identity of an individual and possibly additional sensitive information related to that individual. By applying a Provider model to the concept of digital identities, WCS endeavors to simplify the way applications work with and manipulate digital identities.

Get More Information

To get more information on the cool new components provided with the .NET Framework 3.0, check out the MSDN website at: http://msdn.microsoft.com/winfx/

At this website, you can get your hands on some beta bits and even some labs that walk through the process of creating applications that use the .NET Framework 3.0 components.

Adding ATLAS to an Existing ASP.NET 2.0 Website Project

AJAX development enabled through the ATLAS framework (download available for free at www.asp.net) enables your websites to be more dynamic and interactive for the user. When you install the ATLAS framework, you are given what you need in order to create a new ATLAS website from the ground up and work with the cool new features and controls the framework provides. However, if you’re like me, you may be thinking of adding ATLAS functionality to a few of your existing web projects. This blog entry is an instruction kit for taking an existing ASP.NET 2.0 web project and adding ATLAS to it.

First things first, let’s start with the installation of ATLAS. You need to navigate to www.asp.net and download the latest version of the ATLAS framework and follow their instructions for installation. Once you’ve completed this step, you’re ready to retrofit an existing ASP.NET 2.0 web project with ATLAS… now let’s get started.

Step 1

First, open your existing web project to take a quick inventory, looking for a bin folder and your web.config (if present).

Step 2

You need add the Microsoft.Web.Atlas.dll assembly to your web project bin folder. If you don’t see a “bin” folder in your web project, you should take this moment to right-click on the web project and choose “New Folder”. Create a new folder named “bin” at the root of your web project. Once you’ve created and/or located the bin folder in your web project, right click on the folder and choose “Add Existing Item…”. Navigate to the installation location for ATLAS on your machine (default is “<root drive>:\Program Files\Microsoft ASP.NET\Atlas\v2.0.50727\Atlas”) and select the “Microsoft.Web.Atlas.dll” assembly.

Step 3

You will next need to make the appropriate modifications to your web application’s web.config file. If you don’t have a web.config file your ASP.NET 2.0 application yet, right click on the project and choose “Add New Item…” and then select “Web Configuration File” from the list of items. After creating and/or locating your web.config file, open it up in the IDE.

Part 1

You will need to add the following configuration XML as a direct child of the "<configuration>" element in your web.config file:

<configSections>
   <sectionGroup name="microsoft.web" type="Microsoft.Web.Configuration.MicrosoftWebSectionGroup">
      <section name="converters" type="Microsoft.Web.Configuration.ConvertersSection" requirePermission="false" />
      <section name="webServices" type="Microsoft.Web.Configuration.WebServicesSection" requirePermission="false" />
      <section name="authenticationService" type="Microsoft.Web.Configuration.AuthenticationServiceSection" requirePermission="false" />
      <section name="profileService" type="Microsoft.Web.Configuration.ProfileServiceSection" requirePermission="false" />
   </sectionGroup>
</configSections>

<microsoft.web>
   <converters>
      <add type="Microsoft.Web.Script.Serialization.Converters.DataSetConverter"/>
      <add type="Microsoft.Web.Script.Serialization.Converters.DataRowConverter"/>
      <add type="Microsoft.Web.Script.Serialization.Converters.DataTableConverter"/>
   </converters>
   <webServices enableBrowserAccess="true" />
</microsoft.web>

Note: If there is already a "<configSections>" node within your web.config file, be sure just add the sectionGroup named "microsoft.web" to your existing configSections node.

Part 2

You will also need to make a modification to the "<compilation>" node located within the "<system.web>" element in your web.config file:

<compilation>
   <buildProviders>
      <add extension=".asbx" type="Microsoft.Web.Services.BridgeBuildProvider" />
   </buildProviders>
</compilation>

Part 3

Next, modify the "<pages>" node located within the "<system.web>" element in your web.config file:

<pages>
   <controls>
      <add namespace="Microsoft.Web.UI" assembly="Microsoft.Web.Atlas" tagPrefix="atlas"/>
      <add namespace="Microsoft.Web.UI.Controls" assembly="Microsoft.Web.Atlas" tagPrefix="atlas"/>
   </controls>
</pages>

Part 4

Now, you need to add the following nodes to your web.config file as direct children of the "<system.web>" node:

<httpHandlers>
   <remove verb="*" path="*.asmx"/>
   <add verb="*" path="*.asmx" type="Microsoft.Web.Services.ScriptHandlerFactory" validate="false"/>
   <add verb="*" path="atlasbatchcall.axd" type="Microsoft.Web.Services.MultiRequestHandler" validate="false"/>
   <add verb="*" path="atlasglob.axd" type="Microsoft.Web.Globalization.GlobalizationHandler" validate="false"/>
   <add verb="*" path="*.asbx" type="Microsoft.Web.Services.ScriptHandlerFactory" validate="false"/>
</httpHandlers>
<httpModules>
   <add name="ScriptModule" type="Microsoft.Web.Services.ScriptModule"/>
   <add name="BridgeModule" type="Microsoft.Web.Services.BridgeModule"/>
   <add name="WebResourceCompression" type="Microsoft.Web.Services.WebResourceCompressionModule"/>
</httpModules>

Note: If there is already an "<httpHandlers>" or "httpModules" node within your web.config file, be sure just add the verbs and names to your existing httpHandlers and httpModules nodes.

Your finished web.config file should look similar to the following:

<?xml version="1.0"?>
<configuration>
    <configSections>
        <sectionGroup name="microsoft.web" type="Microsoft.Web.Configuration.MicrosoftWebSectionGroup">
            <section name="converters" type="Microsoft.Web.Configuration.ConvertersSection" requirePermission="false" />
            <section name="webServices" type="Microsoft.Web.Configuration.WebServicesSection" requirePermission="false" />
            <section name="authenticationService" type="Microsoft.Web.Configuration.AuthenticationServiceSection" requirePermission="false" />
            <section name="profileService" type="Microsoft.Web.Configuration.ProfileServiceSection" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <microsoft.web>
        <converters>
            <add type="Microsoft.Web.Script.Serialization.Converters.DataSetConverter"/>
            <add type="Microsoft.Web.Script.Serialization.Converters.DataRowConverter"/>
            <add type="Microsoft.Web.Script.Serialization.Converters.DataTableConverter"/>
        </converters>
        <webServices enableBrowserAccess="true" />
    </microsoft.web>
   <appSettings/>
   <connectionStrings/>
   <system.web>
        <pages>
            <controls>
                <add namespace="Microsoft.Web.UI" assembly="Microsoft.Web.Atlas" tagPrefix="atlas"/>
                <add namespace="Microsoft.Web.UI.Controls" assembly="Microsoft.Web.Atlas" tagPrefix="atlas"/>
            </controls>
        </pages>

        <compilation debug="false">
            <buildProviders>
                <add extension=".asbx" type="Microsoft.Web.Services.BridgeBuildProvider" />
            </buildProviders>
        </compilation>

        <authentication mode="Windows" />

        <httpHandlers>
            <remove verb="*" path="*.asmx"/>
            <add verb="*" path="*.asmx" type="Microsoft.Web.Services.ScriptHandlerFactory" validate="false"/>
            <add verb="*" path="atlasbatchcall.axd" type="Microsoft.Web.Services.MultiRequestHandler" validate="false"/>
            <add verb="*" path="atlasglob.axd" type="Microsoft.Web.Globalization.GlobalizationHandler" validate="false"/>
            <add verb="*" path="*.asbx" type="Microsoft.Web.Services.ScriptHandlerFactory" validate="false"/>
        </httpHandlers>
        <httpModules>
            <add name="ScriptModule" type="Microsoft.Web.Services.ScriptModule"/>
            <add name="BridgeModule" type="Microsoft.Web.Services.BridgeModule"/>
            <add name="WebResourceCompression" type="Microsoft.Web.Services.WebResourceCompressionModule"/>
        </httpModules>
</system.web>
</configuration>

Congratulations!

Now, your ready to start throwing down some serious ATLAS powered AJAX radness in your ASP.NET 2.0 web application. Be sure to create your "<atlas:ScriptManager />" control in your web application on the pages where you want to use ATLAS and then you can start using ATLAS. As a suggestion, you may find it easier to drop your atlas:ScriptManager control into the appropriate MasterPage(s) if you are using these for your web application (which I strongly recommend).


 

ATLAS for the ASP.NET Developer

Lately it seems as though the rage in web development, across platforms and technology stacks, centers on the term AJAX. Asynchronous JavaScript And XML (AJAX) is a technology that enables users to interact with web based applications in a richer way. The very core of AJAX is essentially an array of DOM elements and JavaScript objects that enable browsers such as Internet Explorer and Mozilla FireFox to request content via HTTP in both synchronous and asynchronous fashions. ATLAS is a tool kit released by Microsoft that enables AJAX development in a more intuitive fashion for ASP.NET 2.0 developers.

A Quick History of AJAX Before ATLAS

In the early days of AJAX (consequently, this is before it was ever referred to as “AJAX”), developers were able to do simple asynchronous data loading by using hidden FRAME or IFRAME HTML elements. Combining these hidden frames with an onload event handler for the element allowed for JavaScript DOM manipulation of the newly loaded data. This mechanism was the core of AJAX in Netscape browsers prior to Mozilla’s Gecko project and the introduction of their XMLHttpRequest object. JavaScript object. At the dawn of IE 5, the XML element was introduced along with the MS XML Parser ActiveX Object which allowed for much finer control over the loading of content via HTTP. The MSXML.XMLHTTP and MSXML.DOMDocument (which is the object representation of the XML element) ActiveX Objects introduced with the MS XML Parser are still the core pieces of technology used for developing AJAX applications today in IE 6 and IE 7. 

Present Day Core of AJAX

Under the covers, the AJAX technology stack is enabled and primarily implemented using the XMLHttpRequest object in Gecko based browsers and the MSXML.XMLHTTP object in IE browsers. In order to abstract the implementation of these objects in a browser agnostic programming model, ATLAS was born. To be clear about what ATLAS actually is; developers should look at ATLAS as a Framework for AJAX development that integrates directly with Visual Studio. There are indeed other frameworks for AJAX development such as the Google Web Toolkit (GWT). The benefit of ATLAS, though, is the seamless integration with Visual Studio 2005 and the ability to declaratively implement AJAX in an ASP.NET 2.0 application.

Why Consider ATLAS for AJAX Development?

It’s fairly obvious that the implementation of AJAX in web applications requires the use of JavaScript code. Unfortunately, from an architect or dev lead’s perspective, it’s not usually a trivial matter to find or build experience in cross-browser compatible JavaScript DOM manipulation for a web development team. ATLAS introduces controls that abstract many of the complexities of client side cross-browser compatible JavaScript coding for HTTP content access and DOM manipulation. In fact, using ATLAS, you have the option, as a developer, of never writing a line of JavaScript code in any of your pages to build a fully functional, AJAX enabled web application. Ultimately, the payoff is faster turn around on the development of AJAX applications through easy implementation and potentially increased ease of maintenance down the road.

Controls Provided With ATLAS

ATLAS provides several controls to enhance ASP.NET 2.0 applications out of the box. It’s interesting and notable that each of these features can be implemented declaratively in the ASPX or ASCX code file. There is even an ATLAS Control Toolkit that provides additional AJAX controls that can be added to your pages declaratively. Here are a few of the controls and their descriptions from ATLAS and the ATLAS Control Toolkit (which are both available for free download at http://www.asp.net):

  • atlas:UpdatePanel – Allows you to specify a ContentTemplate that represents a panel in your ASP.NET web application that can be wholly replaced/updated using AJAX without browser flicker after PostBack.
  • atlas:UpdateProgress – This control allows you to display a loading image or loading text when an AJAX call is being performed in the background of the page.
  • atlas:TimerControl – Allows you to specify an interval at which content within a control or UpdatePanel is refreshed automatically using AJAX.
  • atlas:AutoCompleteExtender – Allows you to attach “word wheel” functionality to a server side textbox control in ASP.NET.
  • atlas:DragOverlayExtender – Allows you to add simple drag functionality to a control in ASP.NET
  • atlasToolKit:CascadingDropDown – Allows you to build a series of drop downs where a drop down select list’s values are dependent upon the value of a previous drop down select list.
  • atlasToolKit:CollapsiblePanel – Allows you to build a panel that expands and collapses dynamically.
  • atlasToolKit:ConfirmButton – Allows you to add a confirm dialog to any server side button control (i.e. asp:Button).
  • atlasToolKit:DragPanel – Allows you to turn any server side panel into a drag-able panel in the browser.
  • atlasToolKit:HoverMenu – Allows you to create a pop-up that hovers next to a control when the user puts their mouse over the control in the browser.
  • atlasToolKit:PopupControl – This allows you turn a server side panel into a popup in the browser.
  • atlasToolKit:ReorderList – This control allows you to drag items in a list to reposition them.
  • atlasToolKit:TextBoxWatermark – This control allows you to put prompt text over a textbox that disappears immediately after a user clicks on the control remains invisible after the user enters text.
  • atlasToolKit:ToggleButton – Using this, a user can effectively replace an asp:CheckBox control’s output with a pair of images, one that represents checked and another that represents unchecked.
  • atlasToolKit:AlwaysVisibleControl – When using this control, you can make a control float on the page in a specific spot so that when the user scrolls in the browser window, the control is still visible.
  • atlasToolKit:DropShadow – Allows you add a drop shadow to any control in a web page.
  • atlasToolKit:ModalPopup – Displays a popup in the screen that acts like a modal window. The rest of the page is effectively grayed out and the active item is the modal popup.
  • atlasToolKit:ToastedBreadExtender – Allows a user to asynchronously toast up to 2 slices of bread in the nearest located toaster.
  • atlasToolKit:RoundedCorners – This feature allows a user to added rounded corners to any panel displayed on the page.

Object-Oriented JavaScript

Many developers believe that JavaScript (ECMAScript) lacks object-oriented constructs, and as such they use it only as a procedural language. It is true that JavaScript lacks classes but it has some unique language features which provide support for inheritance and information hiding. This is a high-level view of those language features and how to effectively use them for encapsulation and code reuse.

Associative Arrays As Objects

Before writing OO JavaScript, one needs a clear understanding of what a JavaScript object is. Objects in JavaScript are essentially associative arrays. Most people are familiar with associative arrays from the the data structure HashTable, which is a collection of name/value pairs. JS Objects are essentially the same with language syntax to make them more natural to use. Essentially, all functions and variables attached to a class are stored in this associative array and indexed by their member name. For instance:

// public field
myObject.myPublicField = 6;
// is equivalent to
myObject["myPublicField"] = 6;
// usage
var timesThree = 3 * myObject.myPublicField;

// public method
myObject.myPublicMethod = function(param1) { return "Hello "+param1; };
// is equivalent to
myObject["myPublicMethod"] = function(param1) { return "Hello "+param1; };
// usage
var message = myObject.myPublicMethod("world!");

As you can see, objects aren't defined by a class but remain mutable throughout their lifecycle.

Constructors Instead Of Classes

In order to create a new object in JavaScript, you need to have a constructor. This constructor is essentially the closest you will get to having a class definition. The most common usage for a constructor is to set instance members, using the this keyword. For instance:

// MyClass constructor
function MyClass(initialValue) {
	this.myValue = initialValue;
	this.myValueTimesTwelve = 12*initialValue;
}
// MyClass instance
var myObject = new MyClass(6);

Prototypes Provide Inheritance

JavaScript enables inheritance through a mechanism referred to as a prototype chain. Prototypal inheritance allows objects to share their associative values (functions and variables), through a prototype. Variables and functions added to a prototype allow instantiated objects to not have to have an explicit definition to use them. The associative array for the object is first used to lookup the value, and if not defined then the prototype for that object is used for lookup. For example:

// MyClass public method
MyClass.prototype.sharedPublicMethod = function(param1){
	return param1 * this.myValue;
};

The chaining of prototypes allows an effect similar to n-level class inheritance. By explicitly setting the prototype to an object instance, the analogy of a base-class can be simulated. By default, new objects have Object as their prototype and Object has a null prototype. So using the same machanism for associative array lookup, a member is looked up through each successive prototype until the value is found or a null prototype is reached. An example of setting the prototype:

// MyOtherClass constructor
function MyOtherClass(otherValue) {
	this.myOtherValue = otherValue;
}
// set MyOtherClass prototype to a MyClass object
MyOtherClass.prototype = new MyClass(3);

// instantiate a new MyOtherClass
var myOtherObject = new MyOtherClass(4);
// myResult will be assigned 3*13
var myResult = myOtherObject.sharedPublicMethod(13);

As you can see this feels like inheritance that we are used to from more traditional object-oriented languages. Overriding a base implementation then becomes merely assigning a new value to a member of the prototype:

// MyOtherClass public method override
MyOtherClass.prototype.sharedPublicMethod = function(param1){
	return param1 + this.myValue;
};

Public Static Members

Static members are a bit of a gray area, but if a member is defined on the equivalent of the class then it is effectively a public static member:

// MyOtherClass public static member
MyOtherClass.staticMember = "static";

Note the absence of the prototype keyword, which allows this value to be shared among multiple instances, hence static. Adding prototype would effectively create an instance member.

Closures Hide Information

There are no language features which explicitly control information hiding in JavaScript. However, ECMA-262 specifies the concept of closures which are often misunderstood and rarely mentioned in JavaScript references. A working knowledge of JavaScript closures can provide information hiding and in some cases even prevent memory leaks (in IE JScript).

A closure is a mechanism by which a function reference prevents variables external to it from being garbage collected. JavaScript allows functions to be defined within other functions. When this takes place, the inner function's scope has access to everything in the outer function. If the outer function exposes a reference to the internal function then everything in scope is maintained and not garbage collected. For example:

// external function
function outerFunction(a) {
	// create internal variables
	var b = a;

	// inter function definition, stored as a reference
	var functionRef = function innerFunction(c) { return b+c; };

	// create a closure
	return functionRef;
}

// expose the inner function externally as a closure
var extFuncRef = outerFunction(25);

// b was never garbage collected so result1 will contain 25+2
var result1 = extFuncRef(2);

// b was never garbage collected so result2 will contain 25+10
var result2 = extFuncRef(10);

This may seem unintuitive as one would expect the inner variables to be allocated on the execution stack and be destroyed after the outerFunction context is left. Instead, all that memory is held onto and the effect is internal variables are maintained.

So combining this with the Object support mentioned earlier, a more complete object-oriented model may be used. This even enables Java/C#-style properties to be created:

// CSharpStylePropertyClass constructor
function CSharpStylePropertyClass(val) {
	// private field won't be garbage-collected due to the closures created through the getter/setter.
	var myValue = val;

	// C# style getter
	this.get_MyValue = function() {
		return myValue;
	}

	// C# style setter
	this.set_MyValue = function(value) {
		myValue = value;
	}
}
// instantiate a CSharpStylePropertyClass object
var myCSharpStyleProperty = new CSharpStylePropertyClass(111);
// myVal will contain null because there is no myValue member
var myVal = myCSharpStyleProperty.myValue;
// myVal will contain 111
var myVal = myCSharpStyleProperty.get_MyValue();
// change myVal
var myVal = myCSharpStyleProperty.set_MyValue(512);
// myVal will contain 512
var myVal = myCSharpStyleProperty.get_MyValue();

There is no way to get to the internal value except through the property methods. This means that validation can be performed and the internal value protected. Douglas Crockford coined the term "privileged methods" for these types of functions. The getter and setter are priviledged in the sense that they are publically accessible but have access to private members due to the closures created when they were defined.

Private methods also behave the same way. If a function were defined inside the constructor but not exposed through a public member or returned as a function reference then it would only be accessible from other private or privileged functions. Thus information hiding and encapsulation.

Private Static Members

The combination of static members and closures creates several oportunities for the creation of private static members. Unfortunately the technique involves nesting constructors to create closures around the constructor and in my opinion the usefulness is outweighed by the convoluted nature of the code. That being said, a good description of the process by Richard Cornford is found at: http://www.litotes.demon.co.uk/js_info/private_static.html

DOM Interaction Using Closures

Another powerful usage of JavaScript closures is when a function call with parameters is needed at a future point but the parameters are only available now. This comes into play primarily with window timers and DOM events.

// builder function creates the closure containing the parameters
function callLater(paramA, paramB, paramC){
	// return a reference to an inner function
	return function(){ paramA[paramB] = paramC; };
}
// create a reference which sets the display to none for an element
var funcRef = callLater(document.body.style, "backgroundColor", "red");
// pass function reference to be executed five seconds in future
window.setTimeout(funcRef, 5000);

The signature of the setTimeout function doesn't easily allow objects to be passed in. Passing in a function reference as a closure enables those parameters to be embedded. Other similar usages are DOM events like onload, onclick, onmouseover, etc.

Caveats With This

One final note is to understand the meaning of the keyword this. Traditional class-based object-oriented behavior is to have this refer to the current instance of the class. JavaScript is more loose with the definition and it refers to the current call-context. Most of the time it behaves as expected, but since functions are objects there are times when in a nested function situation where this isn't intuitive. Other times, when not in an object, this refers to the Global Object (e.g. window). Douglas Crockford, suggests the convention of creating a private member (self) in constructors for consistent usage:

// MySelfClass constructor
function MySelfClass(val) {
	var value = val;

	// private variable to hold reference to the instance
	var self = this;
	// use self instead of this to be certain
	this.getValue =  function() { return self.value; }
}


JavaScript References