Monday, June 21, 2010

Using jQuery and Templating to Pull and Display Your Twitter Updates

A while back, I wrote a blog post on how to pull in your last three twitter posts into your web page via jQuery and JSON. It's still today a very popular post.

A lot has happened since that post and I wanted to re-address it and show you an alternative way of pulling in your Twitter feed via jQuery and the new Templating plugin developed by Microsoft. On the right is a new Twitter widget I put together using the new jQuery templating plugin.

Microsoft's Templating Plugin

During MIX10, John Resig and Microsoft announced that Microsoft would be contributing code back to the jQuery Project. One of their first contributions was the Templating plugin. Microsoft created templates for jQuery so that JavaScript developers could use jQuery to easily display a set of data.

The source code for the plugin can be found in the jQuery-tmpl GitHub repository. The plugin requires jQuery 1.4.2 or higher.

Getting Setup

Before we start you'll need the following:

Create a html page, and include jQuery, the template plugin and the supporting_methods.js. Then include the style.css doc so that your code from the demo we do looks nice.

The HTML

Since each tweet will be listed as a list item in an unordered list the only required HTML we need is an empty ul:

		<ul id="renderTweets"></ul>
	

In our demo though we want to make it a complete widget. We need some extra layout html to be able to provide a heading and a link to take you to more tweets. Here is the full html we'll use:

		<div id="Tweets">
			<h3>@RedWolves Tweets</h3>
		  	<ul id="renderTweets"></ul>
			<div id="more">
				<a href="http://twitter.com/redwolves">More &gt;</a>
			</div>
		</div>
	

Make sure you replace my twitter name, RedWolves, with yours.

Making the Ajax request

Now let's get the data from Twitter. We'll use a JSONP ajax call to get back the JSON data of the last three tweets from Twitter. To get the JSON data we will use the user timeline of the Twitter API.

		$("document").ready(function(){
			var url = "http://api.twitter.com/1/statuses/user_timeline.json?id=RedWolves&count=3&callback=?"
			$.ajax({
				dataType: 'jsonp',
				url: url,
				jsonpCallback: "renderTweets" 
			});
		});
	

At the end of the Twitter API url that we declare we attach the user id of the user timeline we want to see, in this case mine, RedWolves, so make sure to update with the username you wish to see. We then declare the url and call the .ajax() method and provide it with the dataType 'jsonp' so that we can pull the data via cross-domain. We set the url and then tell it which function we will call after the data is loaded. After the data is loaded we will call the function 'renderTweets', defined below, which will run the data through the template.

Defining the Template

Now let's define the template that will display the data we get back from the Ajax request. We define the template in a script tag and we provide it with a type of "text/template" and a unique ID.

		<script type="text/template" id="twitterTemplate">
			<li>
					<img src="${ user['profile_image_url'] }" /> 
					${ text.linkify().atify() } 
					<span class="created_at">
						${ relative_time(created_at) } via ${ source }
					</span>
			</li>
		</script>
	

On each JSON item we will run it through the template and create an li element with the profile photo, tweet text, when it was created and what source the tweet came from (e.g. Twitter for iPhone, web, etc.).

We are using a couple of supporting methods to help us in formatting. .linkify which will make any link a hyper link, atify which will link up any @screenname to their twitter profile and relative_time which will turn the created time into Twitter style time. You can find these methods in the supporting_methods.js file.

Putting it all together

The last bit of jQuery code we need to do is to actually call the plugin and combine the template with the data and put it into the DOM. Here we will define the renderTweets callback function.

		function renderTweets(data) {
			$("#twitterTemplate")
				.render(data)
				.appendTo("#renderTweets");
		}
	

What we do is select our template, call the template plugin method, .render, which takes in the data from the Ajax call and renders the results against the template, and then append the results to the desired element in the HTML, the ul with id of renderTweets.

The whole HTML

		<!DOCTYPE html>
		<html>
			<head>
				<meta charset=utf-8 />
				<title>twitter</title>
				<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
				<script src="jquery.tmpl.js"></script>
				<script src="supporting_methods.js"></script>
				<link rel="stylesheet" href="style.css" type="text/css" media="screen" title="no title" charset="utf-8">
				<script type="text/template" id="twitterTemplate">
					<li>
							<img src="${ user['profile_image_url'] }" /> 
							${ text.linkify().atify() } 
							<span class="created_at">
								${ relative_time(created_at) } via ${ source }
							</span>
					</li>
				</script>
				<script type="text/javascript">
					$("document").ready(function(){
						var url = "http://api.twitter.com/1/statuses/user_timeline.json?id=RedWolves&count=3&callback=?"
						$.ajax({
							dataType: 'jsonp',
							url: url,
							jsonpCallback: "renderTweets" 
						});
					});

					function renderTweets(data) {
						$("#twitterTemplate")
							.render(data)
							.appendTo("#renderTweets");
					}
				</script>
			</head>
		<body>
		  <div id="Tweets">
			<h3>@RedWolves Tweets</h3>
		  	<ul id="renderTweets"></ul>
			<div id="more">
				<a href="http://twitter.com/redwolves">More ></a>
			</div>
		  </div>
		</body>
		</html>​
		
	



Source Code Demo

Friday, January 22, 2010

jQuery 1.4 Give Us a New Way to Zebra Stripe

In jQuery 1.4 all setter methods have been extended to take in a setter function.  Before only .attr() had the ability to use a function to return the value to set. Now you can pass a setter function to .css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .before(), .after(), .replaceWith(), .wrap(), .wrapInner(), .offset(), .addClass(), .removeClass(), and .toggleClass().

The setter function can take two arguments, the index position of the element in the set and the old value of the element.

.css( propertyName, function(index, value))

With setter functions now available we can use this in a new way to zebra stripe a set of elements.  In this example we'll stripe a unordered list:

HTML:

<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
<li>item 6</li>
<li>item 7</li>
</ul>
jQuery 1.4:

$(document).ready(function(){
$("li").css("background-color", function(i){
return (i % 2 === 0) ? "#cccccc": "#FFFFFF";
});
});

We select all the LIs and call the .css() setter method. We give it the property name we want to update, background-image and we pass a function that will return the value we want to set.

The function tests if the index that we passed in i is MOD 2 (simply is it even or odd), if even set the color to #cccccc else set it to #FFFFFF.

Demo: (jsbin)

Note: Obviously, this isn't the best way to do zebra stripping with jQuery but I like to explore different ways to do the same thing to learn the techniques.

Saturday, January 02, 2010

Getting "Up-to-speed"

I was looking over my blog this week while I was out on holiday vacation and noticed I haven't posted a blog post since October.  So much has happened since then I think perhaps a "getting the reader up-to-speed" post is in order.  

So here we go...

jQuery Team member

Early last year, I made it a goal to blog, tweet and personally evangelize jQuery to better myself and the project.  My efforts got noticed by jQuery Evangelist Rey Bango and he brought me in as a advisor to the jQuery team.  While I was an advisor I took advantage of my situation and jumped in on projects the team was working on.  Mainly, the jQuery Conference in September and the Stack Overflow Dev Days talk in Toronto.

In November, it was voted on by the jQuery team to bring me on as a jQuery Team Member and I was added to the evangelism team.  I was truly surprised and honored by this action as I wasn't expecting it at the time. 

Being a team member made it easier for me to launch my new project...

The Official jQuery Podcast

I announced in October, at Stack Overflow Dev Days in Toronto, that I would be starting the Official jQuery Podcast in November.  I worked with the jQuery team to get infrastructure support and found a cohost, in Elijah Manor, that could give an outsiders perspective on topics.

We initially started with streaming the shows live on uStream.  But I think I am finding that to be too stressful and am reevaluating whether that is still viable.  Maybe at a later date.

Our first show, with guest John Resig, got the show ranked to #2 on the top Technology podcasts for the day which was very exciting.

We've since had guests Richard D. Worth, Paul Irish, Cody Lindley and Rey Bango.

Our planned shows for January will sure to be very exciting. We are planning to travel to Washington DC to do some shows live in person with the people we are going to interview.

You can find our show on iTunes or you can subscribe to the show with the raw RSS feed.

My plans for now are to do a weekly show as long as I can sustain them throughout 2010.

Coming up in 2010

I don't have many plans for 2010 at this point but there are a few things I am planning on.

We are currently in the middle of planning something huge for jQuery this month.  I'll be travelling with Elijah to cover the "something huge" for the Official jQuery Podcast.

In addition, there will be physical conferences in San Francisco, London and Boston.  I am hoping to at least attend the conferences that won't require a passport.
I am currently scheduled to give a talk on jQuery at LUGOR (Linux User Group of Rochester) on May 20th at RIT.

So there you go you should now be sufficiently "up-to-speed."

Tuesday, August 04, 2009

PHP 101: Uploading a file

I am doing some freelance work with PHP and I am posting these for my future reference.  This is basic PHP 101 stuff here.

The HTML Form:

<form enctype="multipart/form-data" action="upload.php" method="post">     Please upload your file:     <div>         <input id="fileUpload" name="fileUpload" type="file">         <input id="submit" name="submit" value="Submit" type="submit">     </div> </form>

The key part to the form is enctype="multipart/form-data" which tells the server to expect a file on postback. 

The upload php file to process the file:

<?php     $target_path = "uploads/";
    $target_path = $target_path . basename( $_FILES['fileUpload']['name']);     if (isset($_FILES['fileUpload']))     {         if(move_uploaded_file($_FILES['fileUpload']['tmp_name'], $target_path)) {             echo "The file ".  basename( $_FILES['fileUpload']['name']).             " has been uploaded";               } else {                   echo "There was an error uploading the file, please try again!";               }         } ?>


First we test to see if fileUpload has a value if so it attempts to save the file to the target path.  If all goes well we get a message that the upload passed.  If not a message that there was a problem.

Sunday, July 12, 2009

Apples Developer Connection Documentation is buggy

I was working this morning on setting up a LAMP environment in OSX.  I found this tutorial  from Apple's Developer Connection. As I haven't set up PHP on a Mac in quite a while i felt I needed a refresher.

It was going good till I got to the section "Enabling PHP in Apache."  They outline a script you need to run but to a new Mac user this isn't readily apparent how to do.  Obviously this is geared towards the advanced Mac Developer even though the topic is for a beginner.  I finally deduce from past experience that this needs to be run like a batch script on Windows.   I do a search on Google for "shell scripting in osx" and found that I needed to run "sh filename.sh" in the terminal window.  So I created a file and copy/pasted the script into the file, saved and switched to the terminal.  Here is the script I pasted, DO NOT RUN THIS:

set admin_email to (do shell script "defaults read AddressBookMe ExistingEmailAddress")
user_www=$HOME/Sites
filename=php-test
user_index=${user_www}/${filename}.php
user_db=${user_www}/${filename}-db.sqlite3
# NOTE: Having a writeable database in your home directory can be a security risk!

conf=`apachectl -V | awk -F= '/SERVER_CONFIG/ {print \$2}'| sed 's/"//g'`
conf_old=$conf.$$
conf_new=/tmp/php_conf.new

touch $user_db
chmod a+r $user_index
chmod a+w $user_db
chmod a+w $user_www

echo "Enabling PHP in $conf ..."
sed '/#LoadModule php5_module/s/#LoadModule/LoadModule/' $conf | sed
"s^you@example.com^<b>\$admin_email</b>^" > $conf_new

echo "(Re)Starting Apache ..."
osascript <<EOF
do shell script "/bin/mv -f $conf $conf_old; /bin/mv $conf_new $conf;
/usr/sbin/apachectl restart" with administrator privileges

EOF
The first time I run it I am asked for the administrative password which I provide.  After I see that the script had a few errors.  But the instructions on the tutorial say I should be able to create phpinfo page and see the phpinfo data.  I create the file try to run it and the web server isn't running.

I do some troubleshooting and eventually figure out that httpd.conf has not no data in it anymore.  There is an older file with a version number attached but I can't copy or write to httpd.conf cause I don't have su priv on this computer.

I go back to the script file and try to figure out what happened. First I need to fix my apache.  I hack together a shell script to fix my httpd.conf and I come up with this:

osascript <<EOF

do shell script "/bin/mv -f /private/etc/apache2/httpd.conf.9002 /private/etc/apache2/httpd.conf" with administrator privileges

EOF

This restores the original httpd.conf that was made as a back up.  Retry to access a file in apache and it serves it.  Success!  At this point I want to make my own backup file of httpd.conf in case the script screws it up more. 

osascript <<EOF

do shell script "/bin/cp -f /private/etc/apache2/httpd.conf /private/etc/apache2/httpd.conf.bak" with administrator privileges

EOF

So why did httpd.conf have no data in it?  Looking over the script it seems that it is uncommenting the line for the PHP module and sending the output to conf_new.  But it seems the file specified in conf_new is never created in the script.  So when the final line is called to copy the new file over httpd.conf there is nothing to copy.  I solve this by adding another line: touch $conf_new

Now let's tackle the script, the first error I see is that a file doesn't exist: chmod: /Users/ralph/Sites/php-test.php: No such file or directory

The file doesn't exist apparently touch $user_index isn't included in the script.  Which is funny cause nothing else in the script requires the $user_index.  The script is basically just trying to create a php file.  I also add touch $user_index to the script.

Next error is: s^you@example.com^<b>$admin_email</b>^: No such file or directory

I wasn't quite sure what was causing this error and I couldn't solve fixing it but I determined that it was trying to replace the default admin e-mail with the one I specified earlier.  I took out that part of the command.  So the new line now looks like: sed '/#LoadModule php5_module/s/#LoadModule/LoadModule/' $conf > $conf_new

The final script looks like this:

user_www=$HOME/Sites
filename=php-test
user_index=${user_www}/${filename}.php
user_db=${user_www}/${filename}-db.sqlite3
# NOTE: Having a writeable database in your home directory can be a security risk!

conf=`apachectl -V | awk -F= '/SERVER_CONFIG/ {print \$2}'| sed 's/"//g'`
conf_old=$conf.$$
conf_new=/tmp/php_conf.new

touch $user_index
touch $user_db
touch $conf_new
chmod a+r $user_index
chmod a+w $user_db
chmod a+w $user_www
chmod a+w $conf_new

echo "Enabling PHP in $conf ..."
sed '/#LoadModule php5_module/s/#LoadModule/LoadModule/' $conf > $conf_new

echo "(Re)Starting Apache ..."
osascript <<EOF
do shell script "/bin/mv -f $conf $conf_old; /bin/mv $conf_new $conf;
/usr/sbin/apachectl restart" with administrator privileges

EOF

I feel like the script written in the Developers Connection article was just written and not tested.  But what is really concerning is there is no way to provide feedback on the article on the page.  MSDN provides a way on every page asking if the tutorial was helpful and provides an area to comment. 

Needless to say I did not finish the tutorial. 


Monday, June 22, 2009

Transparent PNG's and IE 6

IE 6 doesn't have native support for the Alpha channel that make PNG's transparent.  This can make PNG's look very ugly in IE6 when they are transparent.

Asking around the office today, I got a cool solution that uses IE's proprietary behavior css attribute to call a Compiled HTML document that applies filters to the PNG to behave correctly.

It's pretty easy to install:

How To Use

Follow these simple steps to add this to your page:

  1. Copy and paste iepngfix.htc and blank.gif into your website folder.
  2. Copy and paste this into your website's CSS or HTML:
    <style type="text/css">
    img, div { behavior: url(iepngfix.htc) }
    </style>
    That CSS selector must include the tags/elements on which you want PNG support -- basically, give it a comma-separated list of tags you use. It must also include the correct path to the .HTC relative to the HTML document location (not relative to the CSS document!). For instance, yours may look like this:
    <style type="text/css">
    img, div, a, input { behavior: url(/css/resources/iepngfix.htc) }
    </style>
  3. If your site uses subfolders, open the .HTC file in a text editor like Windows Notepad and change the blankImg variable to include a correct path to blank.gif like so:
    var blankImg = '/images/blank.gif';
    Again the path is relative to the HTML file. Otherwise, you will see a "broken image" graphic!

Tuesday, June 16, 2009

Selecting the fastest selector for jQuery using Firebug Profile

Today I needed to select all the h3's within a div and set a margin-top property on all items in the returned set except the first.

I came up with a few ways to return the results I was looking for (here are some jQuery examples):

$("#div h3").slice(1);

$("#div h3:not(:first)");

$("#div h3:gt(0)");

I've been reading a lot about how your selection can be optimized based on how you structure your query. So I ran each query through Firebug Profile to see which selector query was the fastest. Load the page, click on the "Profile" button at the top, run your query in the console, click the "Profile" button again to stop the profile.  You'll get the time it took to execute that statement.  Here are the results for each:

$("#div h3").slice(1); 3.305ms

$("#div h3:not(:first)"); 0.705ms

$("#div h3:gt(0)"); 2.347ms

It's clear from my testing that the second query is 2-3 times faster then the rest for my page and my specific uses.  Your specific profile times may vary based on HTML structure and selector query. So it's always good practice to test the speed of your selector if there is more then one way to get your results so that you are using the most efficient selector for your situation. 

Sunday, June 07, 2009

Hidden C# Feature: Using Alias Directive

You can create an alias to a long namespace or a type like so:

using Project = SolutionName.Data.Project;

Then you use the Alias in place of the namespace:

Project p = new Project();

I wish I would of known about this last summer, probably could of shaved a month off my project just from not having to type in the long namespaces to our data layer.

Related Links:

using Directive (C# Reference)
Hidden Features of C#

Thursday, May 21, 2009

New Features of .NET 4.0

Microsoft recently released Visual Studio 2010 and .NET 4.0 beta.  I'd like to highlight some of the key new features available to .NET 4.0.

Web Forms

  • Developers can manage control IDs that affect rendered client ID
  • Remove ID bloat, and 'mangling'
  • CSS:
    • Ideally remove the need to use CSS adapters
    • Defer to CSS styles and bypass existing style properties
      • non-inline style attributes
    • Support non-table-based HTML rendering
  • URL-routing for web forms
    • Friendly url handling for web forms
    • configuration model for url routing
  • View state
    • Disable on the page, enable on specific controls - they will provide granular control of viewstate - today it is backwards
    • Disable on control, enable on child controls
    • GridView/ListView work better without viewstate
  • ASP.NET dynamic-data

Ajax

  • Continue ASP.NET Ajax innovation : RIA
  • Appeal to JavaScript Developers
  • Provide support for the page developer
  • jQuery including Intellisense
  • Templates and data binding
    • Client side handling, REST or Web Services
    • Covers page developer and component developer scenarios
  • DOM manipulation, selectors ...
  • Ajax higher-level components
    • Ajax Control Toolkit is a part of the strategy - they will make the toolkit part of the overall ASP.NET package
    • New controls
  • Centralized script libraries and break-up for performance

ASP.NET MVC

  • Appeal to those wanting separation of concerns, TDD, full control
  • Ruby on Rails, Django, PHP
  • Building on from ASP.NET MVC 1.0
  • ASP.NET MVC (Model View Controller)
  • Asynchronous controllers
  • Sub-controllers & Views
  • Declarative controls

ASP.NET Dynamic Data

  • Making building data-driven web apps easily
  • Attacking the Ruby on Rails crowd
  • Building on from FX3.5 SP1
  • Dynamic-data and MVC
    • Scaffolding, templates and data validation
  • Support for abstract data layer
    • Removes need for specific DL (SQL, entities ...)
    • Allows scaffolding of objects
  • Support for many to many relationships
  • Dynamic data on MVC -- this is on codeplex today
  • Built around something called field templates
  • Enhanced filtering:
    • Auto-complete, search filters

ASP.NET Core

  • Address customer pain points
  • Improve scale and performance
  • Cache extensibility and performance:
    • Enable caching like Velocity

There's a couple of videos on Mircosoft's Channel 9 that talk specifically about the points mentioned above:

Tuesday, March 10, 2009

The Future of Programming Languages is Now

As I was commuting home from work tonight I was listening to StackOverflow #44 where Jeff Atwood and Joel Spolsky were discussing how the future of programming languages will gradually get smaller and more precise in their function. Jeff explains:

"I see the future of languages as a lot of small languages that are good in specific things. And you'd switch between them in a fluid way, to when you are like "Oh, this is a set-based problem" or "Oh, this is a database problem" or "Oh, this is a text manipulation problem" and you sort of drop in a language that is good in that thing."

That statement resonated with me for a little while and I got to thinking the future of languages that Jeff perceives is already here.  Let me share what I mean from my experiences in programming during my career.

Let's first take a step back and look at programming languages back when I first started in 1996.  For me there was HTML and that was it.  For me PHP really hadn't taken off, classic ASP was just coming out and so everything was HTML even the formatting was done within the HTML *shudder*.

Move a head some to 1999 and I got into Classic ASP.  Still a language that was self contained.  You could hook it up to a database either Access or SQL Server being the popular choices but SQL statements were done inline in the spaghetti code mess.  In one ASP file you had the dynamic code the presentation and the data integration.

Let's move now to 2003, ASP.NET 1.0 is prevalant.  SQL Server 2000 is out and you could now separate your data integration into stored procedures with T-SQL on your SQL Server.  You would use ASP.NET to separate your busniess logic and your presentation.  CSS was making headway as the way to separate your presentation code from your markup code. 

In 2006 I feel is the start of segmenting ASP.NET out further.  Why? jQuery was released to the world.  And as the world grew more and more used to working with jQuery we were able to hand off some of the tasks that ASP.NET would of handled dynamically, like form validation, DOM manipulation and page interactions.  So we now have CSS to handle presentation, jQuery to handle DOM manipulation, ASP.NET to handle business logic, HTML to handle page structure and finally T-SQL to handle data manipulation and retrival. 

Seems to me that we've made it to the future.  I would hate becoming a web developer today.  You need to learn at least 5 languages to be able to create a respectable web page.  It's also my experience that colleges aren't teaching students all these languages.  They either learn them on their own or they learn on the job. 

Look at what Microsoft is doing to ASP.NET.  .NET 2.0 is the core which then 3.0 and 3.5 are loaded on top.  These versions of .NET include smaller subsets of the language that you may or may not use WFS, Silverlight, WCF, MVC, Dynamic Data, etc.  The burden on the programmer to keep up is ridiculous.

The question I have, does the future continue to segment languages even further as Jeff predicts or will there be a time where we start merging languages together and come back to one super language? When does the segmentation of languages start to hinder us instead of help us?

Tuesday, March 03, 2009

My BarCamp Buffalo Slides - Intro to jQuery



Update:

Video of my presentation. 


My BarCamp Buffalo Presentation - Intro to jQuery from Ralph Whitbeck on Vimeo.

Presentation to BarCamp Buffalo on 3/3/09. My slides can be found http://ralphwhitbeck.com/2009/03/03/MyBarCampBuffaloSlidesIntroToJQuery.aspx

Thursday, February 12, 2009

Where to find help for your jQuery questions?

One of the most common questions I see on twitter from people is "I need help with jQuery, any experts around?"

While this is definitely a fair use of twitter.  Being an "expert" in jQuery I don't want to reply back with "Yes, I can help" without knowing what I am getting involved in.

But not to fear there are plenty of places one can go to get help online.


My favorite place to get help is Stack Overflow (http://stackoverflow.com). Stack Overflow is the Yahoo Answers, Experts Exchange for programmers.  And the great thing for jQuery programmers is that there are a ton of jQuery experts hanging out there.  jQuery questions seem to get answered almost immediately.



For more official help try the jQuery Group on Google Groups (http://groups.google.com/group/jquery-en?hl=en).  This is a great place to get help as most of the plugin authors and jQuery core programmers are hanging out in here to help.


IRC Channels

If you require more one-on-one help you can jump in to the jQuery IRC room where at any given time there are 400+ jQuery developers hanging out and talking jQuery.  Use the following information to connect to the channel.

For general discussion and jQuery development, please visit:

Server: irc.freenode.net
Room: #jquery

For jQuery UI discussion, please visit:

Server: irc.freenode.net
Room: #jquery-ui


Good luck!


Tuesday, February 03, 2009

In case you Missed it: #jQuery Twitter posts

My #jQuery related twitter posts for the week of January 27th - February 2nd:

Friday, January 30, 2009

Selecting a ASP.NET Generated ID with jQuery

I was looking at some of the questions on Stack Overflow this evening and I came across one that had a great tip for selecting a tag whose ID was generated by ASP.NET.  So say you have a label control on your page:
<asp:label id="label1" runat="server"></asp>

The generated output of the html and the ID of that control might look like this:

<span id="ctl00_ContentPlaceHolder1_Label1"></span>

Unfortunately the generated ID of ct100_ContentPlaceHolder1_Label1 isn't always going to be the same from build to build.  So trying to select it like this:

$("#ct100_ContentPlaceHolder1_Label1").hide();
will eventually break and it won't hide the label control.

The trick is to use ASP.NET inside the jQuery selector. Label1.ClientID will return the generated ID everytime. We combine ASP.NET and jQuery into one line like this:
$("#<%= Label1.ClientID %>").hide();

This will get the generated ID of the Label control everytime.



Thursday, January 29, 2009

Building a jQuery-Powered Tag-Cloud with an ASP.NET MVC backend

NETTUTS had a great tutorial by Dan Wellman called "Building a jQuery-Powered Tag-Cloud" The problem for me was that the tutorial showed you how to connect to the database and pull tags and frequencies via PHP.

Because I am currently learning ASP.NET MVC I thought I would try to duplicate the results of the tutorial but with using ASP.NET MVC RC instread of PHP.  Here is how I did it.

I started by creating a Home Controller class.

HomeController.cs

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Web.Mvc;
   6:  using System.Web.Mvc.Ajax;
   7:   
   8:  namespace MvcApplication5.Controllers
   9:  {
  10:      public class HomeController : Controller
  11:      {
  12:          //
  13:          // GET: /Home/
  14:          public ActionResult TagCloud()
  15:          {
  16:              return View();
  17:          }
  18:   
  19:          public JsonResult JSON()
  20:          {
  21:              List<object> tagcloud = new List<object>
  22:              {
  23:                      new { tag = "jQuery", freq = "10" },
  24:                      new { tag = "asp.net", freq = "3"},
  25:                      new { tag = "programming", freq = "183"},
  26:                      new { tag = "code", freq = "34" },
  27:                      new { tag = "HTML", freq = "58"},
  28:                      new { tag = "javascript", freq = "23"},
  29:                      new { tag = "people", freq = "43" },
  30:                      new { tag = "Google", freq = "3"},
  31:                      new { tag = "Microsoft", freq = "1"},
  32:                      new { tag = "Apple", freq = "10" },
  33:                      new { tag = "iPhone", freq = "38"},
  34:                      new { tag = "MVC", freq = "1"}
  35:              };
  36:              return Json(tagcloud); 
  37:          }
  38:   
  39:      }
  40:  }

What's happening here is that we are making a action for the View we will create and I am calling it TagCloud.  This action isn't going to provide us any data so it's a stub action.  The next Action we create is to provide TagCloud the JSON data.  In here I am creating a static List to send back serialized as JSON.  You could also tie it to a model and use Linq to SQL to build the List.

Our URL for the .getJSON method will be: /Home/JSON

This will return JSON data that looks like this:



Notice the difference in the JSON I am bringing back and the one Dan was bringing back.  I don't have a tags: with the rest of the data nested under it.  We'll need to update a line in the jQuery to make this work now.

Let's create the View for TagCloud.


TagCloud.aspx

   1:  <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
   2:   
   3:      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">  
   4:      <html>  
   5:        <head>  
   6:          <link rel="stylesheet" type="text/css" href="/content/tagcloud.css" />  
   7:          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
   8:          <title>jQuery Tag Cloud</title>  
   9:        </head>  
  10:       <body>  
  11:         <div id="tagCloud">  
  12:           <h2>Tag Cloud</h2>  
  13:         </div>  
  14:         <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>  
  15:         <script type="text/javascript">
  16:             $(function() {
  17:                 //get tag feed  
  18:                 $.getJSON("/Home/JSON",null, function(data) {
  19:                     //create list for tag links  
  20:                     $("<ul>").attr("id", "tagList").appendTo("#tagCloud");
  21:   
  22:                     //create tags  
  23:                     $.each(data, function(i, val) {
  24:   
  25:                         //create item  
  26:                         var li = $("<li>");
  27:   
  28:                         //create link  
  29:                         $("<a>").text(val.tag).attr({ title: "See all pages tagged with " + val.tag, href: "http://localhost/tags/" + val.tag + ".html" }).appendTo(li);
  30:   
  31:                         //add to list
  32:                         li.appendTo("#tagList");
  33:                         //set tag size  
  34:                         li.children().css("fontSize", (val.freq / 10 < 1) ? val.freq / 10 + 1 + "em" : (val.freq / 10 > 2) ? "2em" : val.freq / 10 + "em");  
  35:            
  36:                     });
  37:                 });
  38:             });  
  39:         </script>  
  40:       </body>  
  41:    </html>  

As we start to loop through the JSON data Dan was telling jQuery to start inside tags with data.tags, since we don't have tags we can just use the variable data like so: $.each(data, function(i, val) {

The rest of setting this up is the same as NETTUTS article.  All that remains is the css.




Download the Source

jQuery-TagCloud_source.zip (44.82 KB)



Wednesday, January 28, 2009

ASP.NET MVC Release Candidate - No Codebehinds on Views

Check out Scott Guthrie's mammoth blog post on what's changed in this release of the ASP.NET MVC RC that was pushed to the public today.  A lot has changed in my opinion.  One change that I wasn't expecting was that Views and View User Controls do not have code-behinds any more.

The problem was the only way to have strongly typed Views was to inherit in the code behind.  This caused an issue with intellisense in the aspx/ascx pages. You would need to create and immediately build in order to have intellisense work.

No one was using the code-behinds anyways.  The code should be in the Controllers.

Here is the write up from Scotts Blog:

Views without Code-Behind Files

Based on feedback we’ve changed view-templates to not have a code-behind file by default.  This change helps reinforce the purpose of views in a MVC application (which are intended to be purely about rendering and to not contain any non-rendering related code), and for most people eliminates unused files in the project.

The RC build now adds C# and VB syntax support for inheriting view templates from base classes that use generics.  For example, below we are using this with the Edit.aspx view template – whose “inherits” attribute derives from the ViewPage<Product> type:

One nice benefit of not using a code-behind file is that you'll now get immediate intellisense within view template files when you add them to the project.  With previous builds you had to do a build/compile immediately after creating a view in order to get code intellisense within it.  The RC makes the workflow of adding and immediately editing a view compile-free and much more seamless.

Important: If you are upgrading a ASP.NET MVC project that was created with an earlier build make sure to follow the steps in the release notes – the web.config file under the \Views directory needs to be updated with some settings in order for the above generics based syntax to work.

Monday, January 26, 2009

BarCamp Rochester 4

BarCamp Rochester 4 has been announced for April 18th at RIT.  I missed last years and wish I could of attended.  This year I kicked myself in the butt and signed up to present on ASP.NET MVC.  This will force me to do a couple of things.  It'll force me to really understand MVC and it'll force me to be prepared.

Now if it'll force me to rewrite my blog in ASP.NET MVC by then who knows. Would be a good talking point.

Anyway, here is an initial structure of my presentation I am thinking about:

  • Introduction
  • MVC
    • Current uses (ruby on rails, CakePHP, etc.)
    • MVC in the wild (StackOverflow)
    • Status of MVC
  • MVC vs Web Forms
  • Demo (perhaps build a simple blog)
Any suggestions?

Friday, January 23, 2009

jQuery vs Prototype and jQuery.noConflict()

While helping people out on twitter with jQuery lately I've found one of the most common asked questions is, "why won't jQuery work when I include prototype as well?" Well the answer to the why is simple.  jQuery and prototype are both competing for how $() is going to be used.

I set out to understand how this would break and how to call jQuery.noConflict(); and make both work.

noConflict_test.html (2.41 KB)

If you look at my code you'll see that I was having a hard time just trying to get a single line of prototype to work as it should.  I tried to display a div that was hidden with css.  A very simple task in jQuery.  Unfortunately, it states right on the Element.show documentation page that prototype is not capable of displaying elements that are hidden with css. 

Next I tried to color the text of the other element on the page.  Which to my bad luck I was injecting into the DOM and I was finding that this is impossible to do in both jQuery and Prototype.

In the end all I wanted to do was fire one prototype command and have it update the DOM in some way.  Needless to say this gave me a bad taste in my mouth for prototype.

Tuesday, January 20, 2009

In Case you Missed it: #jQuery Twitter posts

My #jQuery related twitter posts for the week of January 13th - January 19th:

Follow me to see what I'll twitter next about jQuery.

Tuesday, December 02, 2008

Finally Launched www.stjohns.edu

Yesterday, we launched the project I've been working on since April.  We've redesigned and upgraded St. John's Universities web site http://www.stjohns.edu

I sent out a note to my fellow team members today thanking them for a job well done I felt like sharing that note.

Team,

I just wanted to say thank you to everyone that put in long hours and maximum effort to see st. john's redesign to go live.  It was a long and crater filled road.  This is by far one of the biggest and longest projects I have ever worked on and it has provided me with a lot of new knowledge, skills and experience. 

Some major accomplishments we were able to push through:

Went live with 4 sites. http://www.stjohns.edu, http://digest.stjohns.edu, we upgraded their Intranet to the latest ASP.NET framework and ported over and upgraded what is left of their old RedStormSports.com site that we are hosting as an archive.

4GB of data or 40,000 content pages had to be ported and or massaged into the new database schema.  News and Events had to be striped out of EDU, Intranet and Digest and merged into one database.

10GB of images, PDF's and Video's had to be brought over and inserted into the 40,000 pages with their new designs.

Set-up 3 physical servers with 10 virtual machines running 4 web servers, 2 file servers, 2 database servers, domain controller and a Web Trends server.  These were coordinated with IT, set-up, tested, stressed and verified to work before we put our code on and after.

The set-up of 25 themes (for the various colleges, schools and departments) that wanted to have their own unique presence in the site.

The set-up of 683 templates which are variations of 64 unique templates which display Home pages, landing pages, content, photo gallery, etc. in the www.stjohns.edu site alone.  I haven't even done a count for the new News Engine Portal (digest).

3 designers all working together and in parallel to provide a fresh look and feel for every department, school and college.

5 developers working together to port, build, upgrade and maintain the code to make Brand Ensemble better for not only St. John's but for our future clients.  Already [redacted], [redacted] and [redacted] are seeing some of these benefits.

There are many accomplishments, too many to name or remember in one sitting. But the most important accomplishment is that we came together as a team:

Larry, Anne-Marie, Katje: Thanks for being there for support and taking the brunt of the clients calls.  I am thankful to have you in-between the client and the rest of the team.

Cheryl, Mary, Susan: Thanks for coming up with a fresh web 2.0 look and feel and something I am proud to show others and tell them I helped build.  I hope the development team was able to bring your designs to light.

Ernie, Travis, Ravi, Anna:  Ernie, Travis you guys were always there when I needed extra hands.  You were willing to jump in and help out when needed even pulling a couple of all nighters with me and coming in on weekends.  I am lucky to work with two talented programmers that I can go to when I am stuck on a problem with the knowledge that one of you will know the answer and if not will help me figure it out.  You guys push me to be a better programmer.

Ravi, you really impressed me with your dedication and your SQL knowledge.  Being able to assign you the data porting script and having to minimally oversee you was a great burden off my shoulders.  You put in more off hour time then anyone on the team to get the project accomplished.  I am still impressed at what you were able to accomplish.

Anna, you came into the project at just the right time.  Having you work with us as an intern has been very refreshing.  Your ability to pick this project up quickly and run with it was hugely beneficial.  I am amazed at how dedicated you are at constantly nagging me for the next thing to work on and your ability to take what you were assigned and complete it with high quality and completeness. You are a huge asset to the team and I hope we are able to keep you around well after your co-op has ended.  

Chuck, Brad: Chuck I think I've learned the most by working with you.  You are very detailed oriented and thorough.  I've learned many new skills in working on setting up the servers.  I feel more experienced in working with SQL Server 2005 especially.  I also have a new appreciation for Virtual Environments that we've begun to implement into our development environment.  You are also a very dedicated person being available at all hours of the day and night.

Brad,  you've helped me more then you know.  You have this uncanny ability to keep everyone sane.  You are very supportive and willing to jump in and get your hands dirty and help the team any way you can.  This is very much appreciative and was in no way overlooked by your team members. 

In the end this project wasn't perfect.  There are many areas that could use reflection upon to improve the process going forward.  We've already started this reflection by starting the discussion of standardizing the design specs that are created.   Even though we've gone live the job isn't done yet as we need to polish and maintain. 

Again, thank you all for your hard work and effort from one team member to the team.

Wednesday, November 19, 2008

System.Net.WebException: The operation has timed-out.

If you open more than a few connections to the same website using HttpWebRequest, then you'll likely get this misleading exception. You can fix the problem by making sure you close your HTTP connections.

HttpWebRequest r = WebRequest.Create("http://xyz");
HttpWebResponse w = r.GetResponse()
... // << do stuff here
w.Close(); // << frees the connection

This was causing some fun debugging issues for me. Just needed to close my connection.

Sunday, October 12, 2008

Database Mirroring with SQL Server 2005

    Database mirroring is a software solution, provided by SQL Server 2005, that gives you the ability to replicate your data in real-time.  Mirroring allows for increased database availability and data protection and works at the database level on databases that are set to full recovery mode.  You need two instances ofSQL Server to set up mirroring because it maintains separate copies of data of a single database across both servers.

    Let's look at a common scenario for database mirroring. Take a company that has their customer database in a data center in New York City.  They also have a backup data center in Houston. The database in NY is mirroring the data to the database in Houston.  Let's say the data center in NY loses power and they need to shut the server down.  With a "flip of a switch" they can move the database to Houston and continue as if nothing happened.  When the data center gets power again they can switch to the NY city database as soon as it's resynchronized.

Benefits

    One benefit of database mirroring is the increased data protection of your data.  As each transaction is being written to your principle database it is sending that exact transaction to the mirror database.  This provides complete or almost complete (depending on which mode you set up; I'll get into this later) data redundancy in real time.

    High-availability, this is a huge benefit for mission critical data.  Hardware failures happen and network issues arise, with a "flip of a switch' you can send the responsibility to the mirrored server to become the principled server at any time.  You can also set up automatic failover with the addition of a witness server to monitor the servers.

    Another benefit is that you have the flexibility to install updates on your server without data disruption.  Because you can manually failover to the mirror server at any time you can failover, install the updates and reboot if necessary. When you are done you can then have the new principle server failover again to restore the principle on to the primary server without any data loss or downtime and upgrade the mirror server.

    Finally, you can set up mirroring to sync in synchronous or asynchronous modes.  Synchronous or high-safety mode will write a transaction to the principle database and send that exact transaction to the mirror and then wait for it to finish committing that transaction before moving on. With high-safety you are assured that the data that is on the principle is on the mirror at the exact same time. In that you trade some latency waiting for the transaction for the true redundancy of the data.  Automatic and manualfailovers, explained more below, require the use of high-safety mode.

    Asynchronous or high-performance mode will send the stream of transactions at the mirror server and the mirror will try to keep up.  With high-performance there can be a gap where the mirror has a back log of transactions to complete that the principle already has completed.  This gap can become pretty big with heavy loads on the principle. 

Requirements

    Database mirroring requires two servers. With SQL Server 2005 you can set up mirroring with Standard or Enterprise editions.  It's very important that both servers are running the same edition.  It is also recommended that the hardware for both servers be near identical and have the ability to handle the same load.

Setting up a Database Mirror

    Let's start with some simple preparation:

  1. Make sure that you have the proper logins created on the mirror server.
  2. Create the mirror database by restoring with NORECOVERY a recent full backup of the principle database. The principle database must have been set-up with full recovery when the backup was created.
  3. You must also restore all log backups since the full backup was made. Create a backup of the transaction logs and restore on the mirror server.  You'll want to start the mirror session as soon as you can after taking the log backup.

    Configuring Database mirroring:

  1. Connect to the principle database. Select the database you wish to mirror.
  2. Right-click > Tasks > Mirror; this will bring you to the Mirror tab on the database properties pop-up.
  3. Select the Configure Security button to configure the mirror session through the Configure Database Mirroring Security Wizard (only in this wizard you can add or change the witness server instance).
  4. Upon completion of the security wizard and you are still connected to the principle server click on Start Mirroring.

Client Connections (Connection Strings)

    I am going to assume that you as the reader already know how to connect to a database in your application code in order to access it.  What I'll cover here are the required key strings needed in the connection string to handle connecting to both database servers in a mirror session depending on which one is acting as the principle at the moment.

    Just as you would with a normal connection string you need to provide a initial partner name.  This will be the principle server.  If you are usingTCP/IP then enter in the IP, if you are using named pipes then enter in the name of your server. Additionally, if your SQL Server is using a Instance Name then you will need to add that as well (example: 10.10.2.1\InstanceName.  Now we need to provide the failover partner.  This will be the mirror server.  Add this information similarly as you would for the initial partner name.

    The other item you will need to provide in your connection string is the network attribute.  This will specify the network protocol to be used and ensures that the proper network protocol persists between connections to different partners. ForTCP/IP use the following:

Network=dbmssocn;

    Named Pipes use:

Network=dbnmpntw;

    Putting it all together in a sample connection string, you can get more info on connection string keywords here:

Data Source = 10.10.2.10/InstanceName; Failover partner = 10.10.2.11\InstanceName; Initial Catalog = databaseName; User ID = sa; Password = 12345; Network = dbmssocn;

Failover

    There are three types of failover: automatic, manual and forced.  Automatic requires a witness server and the mirror set-up in high-safety mode.  Manual failover does not use a witness server and also requires the mirror set-up to be in high-safety mode. Forced is usually used because the principle server has been disconnected somehow.  Using forced service may result in data lose as all transactions may not have made it to the mirrored server.  Forced service is supported on high-availability and high-safety mirrored set-up modes.

Automatic Failover

    For automatic failover to occur the following conditions are required:

  • Mirroring sessions must be running high-safety mode and posses a witness server.
  • The mirror database must be synchronised.
  • The principle server has lost communication with the witness and mirror servers but the witness and mirror server are still online.  Note: If all servers lose connectivity but then the witness and mirror server comes online automatic failover does not occur.
  • The mirror server detects the loss of the principle server.

    How it works

  • If the principle server is still online and changes it's state to DISCONNECTED and disconnects all clients.
  • The mirror and witness server both register that the principle server is unavailable.
  • The mirror server waits for all logs to be written from the redo queue before rolling forward the mirror database.
  • The former mirror server now moves online to be the principle. Recovery will roll back any uncommitted transactions, locks isolate those transactions.
  • When the former principle server comes back online and sees that the mirror has moved to principle the former principle server will become the new mirror and start synchronising. Once synchronising is complete failover is possible again.

Manual Failover

    With manual failover it's possible to failover to the mirror server so that updates and upgrades can be performed on the principle server. Manual failover requires the mirror set-up to be in high-safety mode (transaction safety set to FULL). The partners need to be connected and synchronised.

    How it works:

  • Principle server disconnects, sends the last log message to the mirror and switches to be the mirror server.
  • The mirror server records the last log message as the failover log.
  • The mirror server waits for all logs to be written from the redo queue before rolling forward the mirror database.
  • The mirror server becomes the principle server and the principle becomes the new mirror.
  • The new mirror server quickly resynchronizes with the new principle server. Once complete failover is possible again.

    Initiate Manual failover:

  1. Connect to the principle server. Choose your database.
  2. Right-click > Tasks > Mirror; this will bring you to the Mirror tab on the database properties pop-up.
  3. Click Failover.  Confirm that you want to failover to the mirror server.

Note: The client will need to see that the connection to the primary has failed before it will try to connect to the failover partner.

Forced Service

    If the Principle server goes down due to hardware issues or is unreachable you can use forced service to bring the mirror to principle state.  Doing this may cause data loss as the mirror may not have received all of the transaction logs from the principle. Read this Microsoft TechNet article for more information on forced service.

    Initiate Forced Service

  1. Connect to the mirror server.
  2. Run the following T-SQL:
    ALTER DATABASE <database_name> SET PARTNER FORCE_SERVICE_ALLOW_DATA_LOSS

    The mirror will take over as principle and mirroring will be suspended.

Summary and Online Resources

    Database mirroring has many options and ways to be effective in maintaining a high-availability database.  This article is my collected research as I was learning how to set up mirroring. If you would like more information on setting up database mirroring please look at the following resources:


Wednesday, October 08, 2008

Gaining Exclusive Access to database in SQL Server 2005 via T-SQL

Usually, whenever I restore a backup of my database in SQL Server I am presented with the following error:

Msg 3101, Level 16, State 1, Line 1
Exclusive access could not be obtained because the database is in use.
Msg 3013, Level 16, State 1, Line 1
RESTORE DATABASE is terminating abnormally.

Usually, to get around this I just restart the server. This was fine when we were developing on our local server instance on our development machines. But we have a few programmers that need to make changes to the database and the logistics of having everyone script their changes and drop them into Subversion was becoming a nightmare. Regardless our simple solution was to put it on a shared server in the office and backup the server occasionally, in case someone screwed up the data.

Well I screwed up some data and needed to restore. Unfortunately, I have another co-worker in the office who is working on another project and is using the same database server (different database) for development. To be nice I'd want to restore without restarting the SQL Server and possibly disrupting his work.

What I need to do is find all the connection processes to the database and kill them:

Use Master
Go

Declare @dbname sysname

Set @dbname = 'databaseName'

Declare @spid int
Select @spid = min(spid) from master.dbo.sysprocesses
where dbid = db_id(@dbname)
While @spid Is Not Null
Begin
        Execute ('Kill ' + @spid)
        Select @spid = min(spid) from master.dbo.sysprocesses
        where dbid = db_id(@dbname) and spid > @spid
End

Now I can immediately restore:

USE Master
GO
RESTORE DATABASE [databaseName]
FROM  DISK = N'physical disk path to the backup file.bak' --example path: c:\program files\microsoft sql server\mssql\backup\databaseName.bak
WITH  FILE = 1,  NOUNLOADREPLACESTATS = 10
GO

This method works best in a development environment with minimum developer connections. In production/staging environments refer to your database administrator for best practices.


Related Links

How to Gain Exclusive Access to SQL Server 2005 DB to restore?

Thursday, September 25, 2008

Light at the End of the Tunnel

I've had my head down and focused on this project at work since April/May.  I've been working long hours and most weekends throughout the summer.  This project has had it's ups and downs.

For instance, I am managing three other programmers right now who are all smarter then me and can focus on one thing at a time and crank out great code.  I am also coordinating with two other designers to put together the final details that are needed in the design and to be able to deliver photoshop templates for the client to use to make content assets in the future.  Finally, I am working with a outside vendor to coordinate the set up of the hardware the virtual server environment and the installed code base and database for the four sites we are migrating.  Again, people that are way smarter then I to handle these tasks are making these taks more manageable.

That is the ups.  The downs?  Well I hit burn out back in July.  I am on auto-pilot here. It's taking me a little longer to make decisions for people and don't even get me started on how long it takes me to program a simple template or control.  Again, one of the major ups is that I have three great programmers that can focus.  Right now my mind is mush.

I feel that the project is coming together nicely.  We need to have the programming part done by October 1st and have it installed on the hardware then.  Right now it's worrying about the details, testing the data port from the old schema and 2000 database to the new schema and the 2005 database, again another smart programmer worked part-time throughout the summer to build us the most complex SQL package I every seen to be able to port the data to our new database.

As we are getting towards the end I keep thinking about the vacation time I haven't used yet.  I can't wait to be able to take them.  I am also excited to start another project.  It's been so long since I last worked on another project it'll be nice.

Any tips on how to survive long projects that are actually short on deadline deliverables?  What about burn-out?  Any tips for pushing through till a vacation can be had?

Tuesday, August 26, 2008

jQuery Plugin - Simple Shadow

UPDATE: Simple Shadow has been set up on Google Code.  You can get the latest here.

We've been researching and trying out javascript shadow solutions for quite sometime.  Our designers are really liking to add subtle dropshadows to elements in their designs.  jQuery UI had a shadow plugin and it looked promising.  I even submitted some bug reports to help it along.  But it's been officially removed from the project for the time being.

We've been using RUZEE.shadedborder to handle our shadow needs.  It works but adds a lot of undesired div tags to make the gradient color.  But the biggest problem was it was really slow and caused IE to crash when I had six items on a page RUZZEEIFIED.

I finally gave in and decided to write my own shadow plugin to handle my specific needs which were to display a shadow of 10px width on the right and bottom sides.  I needed it to be easy as well so it uses graphics to accomplish the shadow.

This will work on any element that has a width and height specified in css.  It requires three image files that are included in the complete zip file below. See demo.

Here is the code to make the shadow:

$(document).ready(function() {     $("div").shadow(); });

Download


UPDATE: Simple Shadow has been set up on Google Code.  You can get the latest here.

Monday, July 14, 2008

Adding link separators to a unordered list using jQuery

I figured out how to easily add a separator to a inline displayed unordered list of links using jQuery and so I'd thought I share.

So for a list like so:



I wanted it to display like this:

Ralph Whitbeck | jQuery | BrandEnsemble

Notice that the separator (|) is only between the links and not at either the beginning or end.  I should also note that when I was rendering the list it was coming from a dynamic source so I didn't have a set list to work from.

I wrote this jQuery:

$(document).ready(function(){
   $(".subnavigation li:lt(" + ($(".subnavigation li").length - 1) + ")").append(" | ");
});


So basically I used the :lt(index) selector to match against all the matches that were less then the index value.  I do that by figuring out the length of how many are selected and subtracting one.  Then finally I append my selector to all of my matches.


Update: John Resig (creator of jQuery) chimes in with an easier way to do the same thing in the comments.

$(document).ready(function(){
   $(".subnavigation li:not(:last-child)").append(" | ");
});

This works by selecting all the li's except the last child (or the last li) in the container. This will work with multiple containers on a page if there are more then one.  Thanks John for the tip.

Saturday, June 28, 2008

How to target="_blank" a link while keeping it XHTML compliant with jQuery

I had to make a bunch of links for a site I am working on for a client at work open in a new window.  It's not ideal but it was what was requested.

So I set up my links like such:

http://ralphwhitbeck.com

I run my page though a HTML validator and am quickly reminded that the target attibute is not allowed in the XHTML 1.0 Strict standard.  I do a quick Google Search and the first couple of results bring back the following function to make it compliant:

function externalLinks() {
 if (!document.getElementsByTagName) return;
 var anchors = document.getElementsByTagName("a");
 for (var i=0; i    var anchor = anchors[i];
   if (anchor.getAttribute("href") &&
       anchor.getAttribute("rel") == "external")
     anchor.target = "_blank";
 }
}
window.onload = externalLinks;

This function expects there to be a rel="external" attribute inside the links you want to open in a new window.

That function to me looks scary and ugly.  jQuery to the rescue.

$(document).ready(function(){
    $("a[rel='external']").attr("target","_blank");
});

I was able to shrink all that down to one line of jQuery.  And it's a lot easier to read and more importantly it now makes the document XHTML compliant.

Note: I did notice a huge argument/discussion on if this is really truely standards compliant.  As when you take the generated html code and run that through the validator you still get the same compliance error.  While others say that you are separating the action from the presentation and that satisfies the standard.  Thirdly others say that target was depricated and as such we should never use it because the standards people think we shouldn't open new windows on people.   I don't know whose right or whose wrong but I did find the discussion interesting.  Thoughts?

Sunday, June 15, 2008

Book Review: "Smart & Gets Things Done" by Joel Spolsky

I went into Borders the other night to look at books that I wanted to buy.  I wasn't actually going to buy them but just wanted to see what books looked good and would pick them up on Amazon.  Cause let's face it Borders charges full price for it's books Amazon doesn't.

Anyways, I ran across a book by Joel Spolsky called "Smart & Get Things Done".  Now I know of Joel from the Stackoverflow podcast he is doing with Jeff Atwood.  He is the founder of Fog Creek Software that makes the project management software FogBugz. Before that he worked for Microsoft and Juno Online Services.  He was even a paratrooper in the Israeli Defense Forces (an interesting fact that I learned from the book).

The book is pretty small and short. It's 182 pages and I was able to read it cover-to-cover in a few hours in one sitting.  This book is aimed at those who hire technical talent to their organization (aka Programmers).  This affects me as I have recently been tasked with hiring co-ops for 6 month positions at BrandLogic.  I have hired three people so far but I feel that I could learn quite a bit in the interview and selection process.  I actually purchased the book from Borders that day because it was less the $20 ($16.99 at Borders, $11.55 at Amazon) and because I found it to be an easy read and it would be a great help to me going forward.  I think this book would also be great to programmers who are about to head into the job market.  This is a great insight into what hiring managers are looking for.

Joel goes through the whole gamut in hiring a developer.  He starts out by outlining how one measures a great developer, defines where to find great developers, to what makes a developer happy.  He then goes through the selection process with how to sort through the resumes to weeding out candidates with a phone interview. He gets into the details of the interview once you have a candidate that has passed through the selection process before it.  Finally, Joel takes through the hiring process and talks briefly on how to fix suboptimal  teams.

I felt that the book was direct and outlined the issues with hiring developers and talked about how the great developers are not on the market.  Advertising for jobs in traditional job boards (Monster.com, Craigslist, etc.) is only going to bring out the desperate job seekers the great developers are going to seek out the exact job that they want.  Getting resumes from the traditional methods is only going to bring in a lot of noise and lot of resumes that just don't fit.

So where do you find great developers? Joel states three ways to finding great developers: 1. Go to the mountain- Go to conferences where great developers will hang out and start conversations.  WWDC for Apple Devs, PDC for Microsoft Devs, etc. Go to conferences where early adopters might hang out (Ruby on Rails, etc) and talk to them.  2. Internships - This is the method that BrandLogic employs.  Being that 100% of our office is RIT graduates we also feel our duty to help fellow RIT students with achieving their credits to graduate.  Anyways Joel's philosophy is that if you can bring in a student one, two years before they graduate and have them working in a summer internship it's like 6 months of an interview at the end of which you can thank them for their work and send them on their way or give them a offer in which you know exactly how they are going to work for you without anymore risk. And Finally the third way is to Build your own Community.  Basically if you start a blog or are known to people in the blogosphere and have a community following then when it comes down to needing to fill a position and you post a comment on your blog about that you will seem to get a higher quality selection of resumes to pick from.  Of course this is all easier said then done.  The how to build a community and being able to attract people is all hit or miss and Joel alludes to that.  It's not the easiest thing to do but if you can build a community it's a great resource to draw from.

Joel tries to define a developer in terms of how to make them happy and egger to work and thus more productive or be hired.  He stats each  developer needs his own private office.  This will make them more productive.  He goes into the reasons behind all of this.  One point is that developers seem to get into a zone when developing and a private office will help them stay in that zone longer.  Additionally he goes into the physical office, big monitors, Areon chairs, etc.   But the important part and the piece I think we've really tried hard to encompass at BrandLogic is that the personality of developers has to be inline with everyone else.  You can't hire jerks and think that people are going to be happy to work with jerks, even though he states Microsoft does just that.  Ha!

Sorting out the resumes.  Joel lays out his criteria for sorting out the good from the bad.  Don't hire someone based on a resume but eliminate people based on their resume.  Some criteria to look for Passion (look for evidence for passion to work with computers), Pickiness (look at their resume for glaring errors), English (can they communicate effectively in their resume, if not probably aren't going to communicate effectively in a team), Brains (high GPA or some other high honors [I disagree with this as it relates to our selection process at BrandLogic]), Selectivity (Has the applicant been though another selection process meaning did he make it into a school that only accepts 30% of it's applicants or something similar [again at BrandLogic we favor RIT and usually only advertise at RIT that this isn't an issue for us]), Hard-Core (ability to work in hard-core languages like Assembler etc. is seen as being better then working with Java or PHP [again I don't entirely agree with this statement, we look for someone with web programming experience so hard-core languages don't usually add to the experience desired for our needs]) and finally diversity (ability for new people to bring new ideas and ways of thinking to the table [I whole-heartily agree with this statement]).

After you've sorted through the resumes you need to weed through the resumes with a phone interview.  This will save money as you can probably get eliminate many people by just talking to them.  One example Joel gives is that after ten minutes he felt he couldn't stand listening to a candidate any longer. He was able to weed that person out and saved money on not having to bring him out.  The benefits to a phone interview is that you can listen to what someone is saying without visual prejudices getting in the way.

The Interview.  Joel works in NYC so for him he uses the city to entice his potential hires or if they don't work out in the interview at least use that experience to still leave an impression on that person. When they go home and tell their friends how awesome the place was and how awesome the interview was, their friends will apply next summer for that chance for the trip. This all goes back to how to find great developers.  By using your interview as a way to get known virally it's another way to draw them in. 

The interview needs to be a conversation and needs to have the applicant writing some kind of code.  It doesn't matter what language the code is in or if it's right or wrong the purpose is to get the person talking to find out how they think, how are they going to solve a problem.  If they make mistakes see if they catch them, ask them "Are you happy with this code?" and see if they catch their mistake.  Even if they don't make a mistake it'll be great to see if they are confident to say yes it's perfect when you ask them if they are happy with their code. Don't dwell on the technicalities you should base your decision on whether the person is 1. smart and 2. can get things done. 

Joel's company has many developers interview a person and usually has them come back with a HIRE or NO HIRE verdict within 15 minutes of the interview.  One person usually can't decide their fate but once a certain number of people come back with NO HIRE the interview is over and they won't be hired.

The rest of the book goes into how to hire someone and how to deal with a team that might be poisoning the rest of the team.  I'll leave those chapters to you to read.  I think the dealing with a team chapter is just a brief insight into management but Joel gives his recommendation into other books you can pick up to help with project/team management.

I really enjoyed this book. It was easy to read and was clear and to the point.  I have many ideas on how I can update and tweak our interview process at BrandLogic for future hires.

Help support this blog by purchasing this book from my Amazon link.

Monday, June 09, 2008

My first JSON Implementation

I wanted to share my first real use of JSON (JavaScript Object Notation) I created today at work.  The reason I find this exciting is cause I never really understood the use of JSON or how to create and use it.  I found a simple use when I wrote about pulling in twitter updated into my blog using jQuery and the Twitter API using the JSON data, but I didn't create the JSON and was just consumming it.

Well today I was tasked with creating a JavaScript array that could be easily updated by an administrator of a web site and the data would be used to populate a dropdown box.  Yes there are probably better solutions to populate a dropdown box but this was what I was tasked with. 

Now a year ago, I would have probably created an XML file to hold onto this data but a recent blog post from Jeff Atwood over at Coding Horror made me realize that XML is ugly.  From that article JSON seemed like a cleaner choice.

So basically my data needed to hold geographical regions of the US with sections or cities for each region.  Each region/city would have a url associated with it.  So in a separate js file I created this:

{ regions: [
                    {
                        text: "NorthEast",
                        value: "http://ralphwhitbeck.com/northeast",
                        sections: [
                                         {
                                            text: "New York",
                                            value: "http://ralphwhitbeck.com/newyork"
                                         },
                                        {
                                            text: "Boston",
                                            value: "http://ralphwhitbeck.com/boston"
                                         }
                                     ]
                   },
                    {
                        text: "South East",
                        value: "http://ralphwhitbeck.com/southeast",
                        sections: [
                                        {
                                            text: "Orlando",
                                            value: "http://ralphwhitbeck.com/southeast"
                                        }
                                      ]
                    }

                ]

}

So looking at this you can see that it's very clean and easy to read.  We can see that it's two levels deep and we can see which sections are related to which regions at a quick glance.

Now I needed to take this JSON data and consume it and populate a dropdown.  I turn to jQuery to help me out (which was very slow today due to the 1.5 release of the UI plugin).  Here is the code to consume display it:

$(document).ready(function(){
    $.getJSON("sections.js",function(json){
        $.each(json.regions, function(i,ritem){
            $("#select_dropdown").append("");
            $.each(ritem.sections, function(i,sitem){
                $("#select_dropdown").append("");
            });
        });
    });
});

This requires a select element on the page with an id of select_dropdown. 

Download the example code JSON_Example-DamnRalph.zip (1.24 KB)

Update: So an interesting problem came up at work today where we needed to validate the JSON because the data we entered had a syntax error (we figure this was the case cause it wasn't working as expected) and so we needed a validator to validate the JSON data.  Unfortunately the way we are consumming the JSON if it tries to parse it and it's not valid then the user doesn't get an error (is this the desired choice in jQuery's getJSON method?) so there is no feedback to what the sytax problem might be.  We found this online JSON Validator that worked to help us identify the syntax errors.

Wednesday, May 28, 2008

Google I/O 2008 - Day 1

Google IO is a two day developer conference in San Francisco which is held in the Moscone Center.  This year the conference is focusing on technologies like Android (mobile phone OS), Gears (ability to extend the browser to make your site work offline and sync when your online again), Gdata (API to work with Google Services like Calendar, Gmail, etc.) and finally a look into OpenID, OAuth and OpenSocial.

Since this was in San Fran it was fairly heavily covered and TechCrunch has a good write up with live blogging, video demo's (embedded below) and many pics. James Hamilton provides some rough notes from various talks from throughout the day. Update: Andy O posted his blog in the comments which has a well written detailed thoughts of the conference.

Some interesting announcements from the keynote.  MySpace is going to work with GearsGears officially changed it name to Gears dropping Google from the previous name of Google Gears.  The reasoning is that Google wants to strongly urge that Gears is Open Source and is for the community.AOL officially joins OpenSocial.

Here is a video demo of Android:


Finally, Scoble gives an idea of what the hot topics are at the Google Party:


(Photo from flickr user Nancy-. Used undeer the Creative Commons License)

Tuesday, May 27, 2008

Kings of Code 2008

Last month I first heard of ROFLCon from a coworker who asked for a couple of days off to go to Boston to attend this convention.  Well when he went I was doing some searching on Flickr and watched blogs to see if I could see any pictures of him from the uploaded pics.  Needless to say we didn't see any pictures of him.  I did however see 10 or more pics of John Resig and 100+ images of Jay Maynard (the Tron Guy).  So needless to say we are on the verge of firing our employee for lying to us about attending a convention he obviously didn't attend (I am only joking about firing him...or am I?).

Anyways, the point I am trying to make is that I felt that I in some way experienced the convention through the eyes of everyone that attended.  There were countless photos, video's, blog posts and twitter was huge as well.

So today I heard about the Kings of Code conference that is happening in the Netherlands today.  I only heard about it because John Resig is a speaker.  So I try the normal routine of doing flickr searches and blog searches on Kings of Code.  Sure enough I got enough info from people that posted on it that I felt like I truly experienced a part of it.

First I started out with the conferences web site (which is translated via Google Translate) and I got a sense of who the speakers are and what the schedule is like.

I then went to Flickr to see if there are people there that are posting pics.  This usually tells me if there are people there who are willing to post info on the conference.  Sure enough there are people posting pics.  And there is a picture of John speaking.  So that's cool I get the feel of how big the conference is and what the stage and stuff look like.

Now let's see if I can dig up what the speakers are actually talking about.  I go to Google Blogs (or Technorati) and do a search for Kings of Code and sort by date added.  Jackpot, I stumble on to Gijs van Zon's blog who live blogged the whole thing. He broke it up by per break.  We need to use Google Translate again and the translation isn't 100% perfect but you still get a lot of the information that was presented. Here are his live blogs:


I found some of the info in these talks useful and I wanted to share.  Thanks to those who posted pics and took the time to live blog the conference for those of us on the other side of the world to enjoy.

Update: With a little more digging I found some live streams of John Resig's talk.





(Photo from flickr user Inferis. Used under Creative Commons license.)

Monday, November 19, 2007

Pulling twitter updates with JSON and jQuery

I wrote a little script tonight to pull in my latest 3 tweets from twitter and display them on my blog.  You can see it in action on the right.

Here is how I did it.  I used the Twitter's API and called my timeline with a JSON call and comsummed it with jQuery and outputted it to a blank div.

       var url = "http://twitter.com/status/user_timeline/RedWolves.json?count=3&callback=?";        $.getJSON(url,         function(data){             $.each(data, function(i, item) {                 $("img#profile").attr("src", item.user["profile_image_url"]);                 $("#tweets ul").append("
  • "                       + item.text.linkify()                       + " "                       + relative_time(item.created_at)                       + " via "                       + item.source                       + "
  • ");             });         });

    Basically what this does is pulls in the data from twitter and makes them available as objects.  I then loop through each item and pull out the data I want and write it out to a unordered list. Update: make sure to look at the complete working example below as it has the two functions this code block is using (linkify and relative_time) to transform the JSON data into how I'd like it to look.

    Here is the HTML stub it's going to:

       

                   
         

      You can download a working example here: twitter-json-jquery.html (1.79 KB)

      Wednesday, November 14, 2007

      Update on my jQuery bug

      Last month I posted about my problems with the jQuery UI shadow plugin where it wasn't working with absolute positioned divs.

      I was looking at the Development jQuery UI forum this morning and came across this post by Brandon Aaron detailing how he cleaned up the shadow plugin.

      I politely mentioned my bug I submitted and he politely told me that the latest version in SVN will now solve my problem.

      And it does:



      Yay, open source!

      Interesting fact, when they release the next version there will now be a UI branch and a FX branch. Shadow was moved and will be in the FX branch.

      Monday, November 05, 2007

      VS.NET IDE Issue - ASPX gets separated from codebehind

      Sometimes in VS.NET 2005 the codebehind for the aspx file show up in the solution explorer not connected.

      To Solve this problem:

      1. Close Visual Studio
      2. Open up the proj file with a text/XML editor.
      3. Scroll down till you find the <EmbeddedResource> section.
      4. Find around where you need to enter in a new resource in relation to the file you're having issues with.
      5. add this for each file except the aspx file:
          <EmbeddedResource Include="Admin\Author\MassUpload\upload.aspx.cs">
      <DependentUpon>upload.aspx</DependentUpon>
      </EmbeddedResource>
      <EmbeddedResource Include="Admin\Author\MassUpload\upload.aspx.resx">
      <DependentUpon>upload.aspx.cs</DependentUpon>
      </EmbeddedResource>

      Related Links

      Form & Designer File Becoming Separated


      Saturday, October 27, 2007

      Installing Rails on Ubuntu using VMWare Server

      I installed Ruby on Rails,I think ;), on a VMWare Server installation of Ubuntu 7.10 using the following tutorials.

      To install VMWare Server and Ubuntu: http://cmsproducer.com/Ubuntu-Linux-Windows-VMware-Server

      To install Ruby on Rails on Ubuntu: http://paulgoscicki.com/archives/2005/09/ruby-on-rails-on-ubuntu/

      Total installation time took me about two hours from the start of downloading Ubuntu to finishing the last step.

      Now let's see if I can figure out how to program Ruby on Rails.

      My first jQuery bug

      Update: Bug has been fixed/closed.

      I submitted my first jQuery bug today,  I am pretty sure that it's a bug and not something I am doing wrong, but hey it wouldn't be the first time.

      I was trying to use the new jQuery UI to add a drop shadow to a floating DIV. Unfortunately, I was not getting the results I was expecting.

      Here is the test HTML I was using to recreate the bug:


      <html xmlns="http://www.w3.org/1999/xhtml" >
      <head>
      <title>Shadow Page Test</title>
      <script src="jquery.js" type="text/javascript" language="javascript"></script>
      <script src="jquery.dimensions.js" type="text/javascript" language="javascript"></script>
      <script src="ui.shadow.js" type="text/javascript" language="javascript"></script>
      <style type="text/css">
      #Alert
      {
      position: absolute;
      top: 200px;
      left: 200px;
      background-color: #ffffff;
      width: 200px;
      height: 200px;
      padding: 10px;
      font-weight: bold;
      border: 2px solid #ff0000;
      }
      </style>
      <script type="text/javascript" language="javascript">
      $(document).ready(function () {
      $(
      "#Alert").shadow({ offset: 5, color: "#000000" });

      });
      </script>
      </head>
      <body>

      <div id="Alert">
      This is some Alert text!
      </div>

      </body>
      </html>
      Again I was using the Shadow pluggin from http://ui.jQuery.com but this is what I was getting:



      Notice how the three different colored shadow layers line up under the div instead of stacked so it looks like a shadow?

      Anyway I sent it into the bug tracker in jQuery, I am ticket number 1853.

      Here are the files to recreate this bug. ui.shadow_bug.zip (17.71 KB)

      Friday, October 12, 2007

      A Visual Explaination of SQL Joins

      Jeff Atwood over at Coding Horror explains with visual Venn diagrams how joins work.  Even if you know how joins work it is still nice to see it in visual form.

      Click here to see the joins.

      Thursday, October 11, 2007

      Click on your own Google Adsense links without breaking policy

      Laurent Kempé writes:

      If you are developing a site containing Google Adsense you might know that clicking on your own ad is not allowed.

      To be able to test and click on your own ad and still follow Google AdSense Program Policies, just add following to your pages:

      <script type="text/javascript">google_adtest = 'on';</script>

      Don't forget to remove it on your production server! ;)

      That's cool! The biggest worry of any Google Adsense participant is getting dropped from the program for clicking on your own links.

      Thursday, February 01, 2007

      Case sensitivity, SVN and Windows is a recipe for disaster

      We are working on a project at work that has four developers working against the SVN repository in Visual Studio.NET 2005.  The other day I had to create a new project in the solution.  I got it all set up and committed the project into the repository using Ankh, great.  I started to close down for the day and in explorer I noticed that there were still files that were flagged that they needed to be committed.  Looking at it, it was the project file that needed to be committed. So I right clicked and committed it with Tortoise.

      Yesterday another developer was trying to checkout the repository to his computer and they ran into an error trying to load the project I had committed.  I was roughly told that it was my project file was missing.  They were able to work around it because the project I committed wasn't needed to work on what they needed.  So I took note of it and would look into it when I had a chance.

      Fast forward to this morning.  Based on the feedback I had been given I went into explorer to see if the project file was indeed the one that needed to be added to the repository.  But it showed that it was already committed.  Hmm...so I went to the developer and asked him to forward me the error messages he was getting when updating.

      Here was ankh's message:
      NSvn.Core.SvnClientException:
      Failed to add file '[Path to file]\Web.config': object of the same name already exists
      at NSvn.Core.Client.Update(String[] paths, Revision revision, Recurse recurse, Boolean ignoreExternals) in d:\tmp\build-2\src\nsvn.core\client.cpp:line 356
      at Ankh.Commands.UpdateItem.UpdateRunner.Work(IContext context) in D:\tmp\build-2\src\Ankh\Commands\UpdateItemCommand.cs:line 131
      at Ankh.ProgressRunner.Run() in D:\tmp\build-2\src\Ankh\ProgressRunner.cs:line 95
      Same file conflict?  That didn't make any sense.  We started speculating.  I run different a different version of Tortoise on my machine then everyone else and thus my client version of Subversion is newer then the server and everyone else.  But I've been running like this for weeks with no problems up to this point.

      I have the developer try checking out a project that only I worked on for another client in the past couple of days.  He said he had no problems getting those files.

      He then went back and tried to update the original problem project from Tortoise and pasted the errors he got:
      Error: In directory '[Directory Path Specified]'
      Error: Can't copy '[Path Specified]\.svn\tmp\text-base\web.config.svn-base' to '[Path specified]\web.config.tmp': The system cannot find the file specified.
      I went and googled for "Can't copy '': The system cannot find the file specified." the results led me to this explaination.
      There are actually 2 different files in the repository whose names differ only in case. This cannot work on a Windows checkout, because the Windows file system is not case-sensitive. It is likely that one of the files got added by mistake, so you need to find out which one, make sure there are no changes committed to the wrong file, then delete it.
      I went to our Trac site and looked at the source files and sure enough there was web.config and Web.config files listed.  Going back to Visual Studio.Net and Explorer I noticed that Visual Studio.NET had the Web.config and Explorer had the web.config. 

      Here is the solution I came up with, there's probably a better way of doing this and I'd love to hear about them in the comments but this solution did work.  I made a backup of the Web.config file and then I deleted the Web.config in VS.NET and committed my changes. Looking in Trac again I see that I am down to just web.config in the repository.  I figure at this point I can just update and use that single version of web.config but I got the same error as above.

      I close Visual Studio and open up Tortoises Repository Browser and I delete web.config. I then delete the whole project folder out of explorer (you have to do this because the svn folders have the web.config still listed in it's cache and you'll get the same errors). 

      After the folder had been deleted I reopened Visual Studio.NET and opened the solution.  After I updated the solution from the repository I added my backed up copy of web.config (with the proper case that I am looking for) into the project and committed it.  Everything now had the right case, Visual Studio, Explorer and trac (which is the SVN Repository version). 

      I went to the other developers and after they committed all the work they were doing they closed out of Visual Studio. Deleted the problem project folder in Explorer.  Reopened the solution in VS and updated and refreshed the project with a now working copy.

      So make sure if you're working with a SVN client in Windows against a Linux based SVN repository that you have the same case throughout or you'll need to fix it.  And so far the only way to fix it is a manual process.

      Saturday, January 27, 2007

      Redesigned BrandLogic.com Launches

      We've spent quite sometime recently getting BrandLogic.com ported over to our BrandEnsemble product.  It's pretty exciting to actually have our website using our product.  Before we did it in JSP because it was a great selling feature for some companies that we were multi talented (which we are by the way). 

      I think though that we were never really proud of our site before.  But now, I think this is the best version of our website, and we are really proud of going live with it.

      It runs on ASP.NET 1.1 and SQL Server 2000.  It runs on our BrandLogic BrandEnsemble Content Management System. 

      Here are some screen shots of the site (click to enlarge).

        

      And some of our admin tools which our CEO states are "the best admin tools I have ever seen."

           

      These shots show how our pages can be edited inline so you get a feel for what the page will look like before you're ready to publish, version control history of a page with the ability to revert a page back to a previous version and how a typical view of a group (our terminology of a directory) looks within the system.

      BrandEnsemble has been used in many of our clients sites as well:
      Of course BrandEnsemble is only a piece of the overall branding puzzle that BrandLogic services offer to clients.  BrandEnsemble is what I am close to as I have contributed to it's development over these past eight years.

      Here are some of BrandLogics other services we offer:
      And who we did it for.

      Feel free to contact BrandLogic for your branding needs.

      Friday, January 19, 2007

      What does the future hold?

      Where is the future heading with web programming/technologies?  I have considered myself Microsoft programmer since I graduated college.  I learned Classic ASP on the job, eventually I learned ASP.NET with VB.NET first then realized the power of C#.  I love C# I really do.  It makes programming a complex web site simple and straight forward.

      We at BrandLogic would of never been able to program a complete CMS system for St. John's University in 3 weeks if it had not been for the robust framework that .NET offers.  Hell I am still to this day maintaining that code.

      We've taken that code base and improved upon it and created the BrandEnsemble suite out of it.  Many clients are enjoying the benefits of the ease of programming C# provided us to be able to make a robust versioned CMS system.

      So why do I feel uneasy?  Why do I feel like I am going down the wrong path?

      It might be because ASP.NET 2.0 and Visual Studio.NET 2005 doesn't excite me like VS.NET 2003 did.  It doesn't excite me like the promise of what Ruby on Rails can provide.

      But I think the most important part is it doesn't wow me in the wallet.  As a freelance web developer paying $1000 for a copy of Visual Studio.NET is a huge chunk of my annual freelance salary.  So upgrading to the next release isn't on the top of my lists of things to do right away.  Plus there is the cost of SQL Server, Windows, etc. etc. Basically I need a MSDN subscription.  What are they up to now?  $3000?  I stopped caring, I guess, the last time I looked at the new MSDN offerings and I thought I needed a lawyer to explain it to me.

      So that brings me back to my original question: Where is the future?  Lately, I have been seriously thinking that the future, as is the present, is in open source software and the technologies that support it, programming languages like PHP and Ruby on Rails (there is a reason why they are so popular now).  If you own a PC (and if you don't save a paycheck and go out and get a barebones computer) everything else is free, free as in beer. 

      So you got an idea for a cool web site? Get a computer, download a linux distro for your operating system, install the packages you need, get programming IDE's for PHP or Ruby free off of sites like SourceForge.  Get a Enterprise level database like MySql or Postgres free again by downloading it off the internet.  Download TheGimp for image processing.  Bam! You're up and running on the simple cost of the hardware.  And best of all your legal too!  Plus there is a community of starving programmer that are on the web willing to help you out.

      But PHP is Old

      Yeah, PHP has been around a long long time, but it's robust and again it's free.  And as I've highlighted before, Chris Prillio nailed it on the head once when he was stating the reasons why he was using PHP on his CMS Publishing project: PHP is prevailant on most if not all hosts that are out there right now.  So make a PHP site and chances are the majority of webmasters can install your software on their site.   Try to do that with an ASP.NET site with a SQL Server 2000 backend.

      If you look around Silicon Valley now most Web 2.0 companies are using LAMP  (Linux + Apache + MySQL + PHP) partly due to the low cost in a market where the revenue stream is still up in the air for most.  But they need the appeal of the masses to get the word out.

      Scoble said something tonight that got me to write this post tonight, even though I been thinking it for the past couple of weeks.  He said, "
      LAMP is sure getting traction — I’ve stopped asking entrepreneurs what infrastructure they are using since the answer was so consistently LAMP."

      A couple of days ago I saw a sponsor on TechCrunch post job listings for web developers/designers and it got me thinking if I all of a sudden found myself out in the mix again fighting for a job, I think my resume would fall to the bottom of the pile for most places that I think I would find fun to work at (although I have a family, which means the fun places are too risky for me).  My resume is very impressive I think.  My strengths are meeting the needs of our clients in a productive and efficient manner, providing the best customer service and experience with our clients, maintaining a long lasting and trusting relationship with our clients (in the 8 years I've worked at BrandLogic I can probably count the number of clients I've worked with on my one hand, not because we don't get clients but because I help maintain the longest lasting clients.  Which I think is a testiment of the quality of service I as well as the rest of the team provide.)  And last but not least are my Microsoft skills.  Which in my opinion is a technology that is becoming more and more obsolete.

      I guess I'll add a new resolution to the New Year.  Learn Web 2.0 technologies!

      Saturday, January 06, 2007

      Sending HTML E-Mails

      I spent most of this week figuring out how to send out a HTML e-mail for our company.  I started thinking I could just craft a HTML page and then send it out.  Well that's not the case at all.  GMail was a huge pain in the butt.  It was striping tags left and right.

      I found this page from One NorthWest with the do's and don'ts of HTML E-mail and CSS.

      The Don'ts
      1. Do not rely on external (<link rel="stylesheet">) or embedded style sheets (those contained within the <style> tag above the <body> tag). This is the most important thing to avoid. Many email services cut everything above the body tag and disable external style sheets.
      2. Don't use javascript in an email newsletter. Ever. There's no better way to have your newsletter marked as spam.
      3. Don't use the <body> or <html> tag. Most email services will ignore them. You can try putting your whole newsletter inside a <div> and apply inline styles to it. Results may vary.
      The Do's
      1. Use tables. Lots of them. You're welcome to try <div> tags for positioning and layout, but my research shows that tables are more consistently supported. C'mon now. Get over your table-phobia.

      2. Use inline styles liberally in tables. In fact, you'll find you can get the best millage out of inline styles in <td> tags. That way you are setting up little style regions within each table. Think of these inline styles as miniture style sheets. This allows non-technical users to swap content in and out of pre-formatted cells in a modular fashion.

      3. Define the background color in a td cell or table tag with bgcolor=, not the CSS style. This works in all email services I tested.

      4. Test your newsletter by sending to yourself or colleagues. This will give you the chance to catch any problems before your whole subscriber list does!
      Images
      1. Define background images using background= instead of the inline background-image call. Gmail, among others, will ignore any url() attribute in an inline style. Keep in mind, though that if the background image is ignored, the default color is going to be white. Sooooo your white on black text will disappear! Don't do it! Stick with text colors that are visible against a white background.

      2. Don’t use images for important content like calls to action, headlines and links to your web site. Outlook, Gmail and others turn images off until allowed by the user. If your entire newsletter is graphical, all your recipients are going to see is a lot of broken images.

      3. Use alt text for all images.

      4. Declare BOTH height AND width parameters for images. Poor old Outlook Web Access especially needs this for your table layout to display properly.


      Monday, November 13, 2006

      Today's Big News: Sun to release Java under the GPLv2

      The internet is abuzz today about Sun's announcement to release Java to the open source community.  So what does this mean?  Is it an admission from Sun that Java is a dying technology and this is a ploy to get developers re-enthused about working with Java again?

      "Sun is hoping that this step will attract more developers, as well as extend the lifespan of Java." -Slashdot.

      It'll be interesting to see how this works out for them as this may force other companies like Microsoft to open up more of their source in an attempt to drive participation from the developer community.  Isn't that why Ruby on Rails is the hot language?  Will we see Java on Rails in the near future? 

      Related Links:


      Sun Open Sources Java Under GPL (Slashdot)
      Sun to Opensource Java and GPL it (Scoble)
      Sun to Open-Source Java Under GPL v2 (digg)

      Sunday, October 08, 2006

      A Slick CSS Solution to Image Rollovers

      Here is a simple and elegant solution to doing image rollovers using one image and css to position the image to the rollover state.

      Tuesday, September 12, 2006

      New Dialog box in VS.NET 2003

      When I load up a web project in VS.NET now that I have Subversion installed I get this dialog box that says:
      Refreshing the project failed. Unable to retrieve folder information from the server.
      Thankfully this isn't a real problem just a nuisance as after you click ok (the only choice given) the project loads just fine.

      So what's going on?

      Well a bug is happening.  VS.NET refuses to read/load directory names that start with a "." and guess what new directory in my web project now starts with a "."?  .svn

      I do not have VS.NET SP1 installed yet...I'll install that tomorrow and let you know if it contains a fix for this particular issue.  But digging around the net Microsoft has known about this issue back in 2003 when people first started to complain about it.

      Update (1/30/2007): I see alot of people finding this post via google having the same error above.  I found a better way around this.  So instead of starting a new post I'll just add it here.

      You can set up Subversion to use _svn instrad of .svn here's how, if you set an environment path variable SVN_ASP_DOT_NET_HACK to true and then restart your computer (you must restart to have tools like Tortoise and Ankh recognize the _svn folder).  You will need to recheck out your repository and then VS.NET 2003 will work as expected with no error messages.   The problem lies in VS.NET 2003 only 2005 will read .svn folders fine.  But the good thing is 2005 will also run _svn folders with no problems. 

      So rule of thumb if your on windows and using Subversion with any version of VS.NET just add the path variable.  Also very important...make sure you commit everything before you do the variable cause you won't be able to after it's added, you'll have to undo the variable and commit and then add the variable back.

      Monday, August 21, 2006

      SVN Source Control in Windows

      At work we started exploring using SVN for source control with Visual Studio as Visual Source Safe is still living in 1999 and Visual Studio 2005 doesn't seem to be anymore promising (Jeff Atwood recommends "Anything but SourceSafe").  AnkhSVN was made to integrate with Visual Studio but wasn't the easiest to set-up...Scott Hanselman says there is a new version out but it's still in Release Candidate and requires you to upgrade to a release candidate version of subversion too.

      Anyway with SVN being open source I was looking at setting up a version control solution for my personal projects.

      Lifehacker recently ran a two part series (part 1, part 2) in it's weekly Hack Attack column about setting up Subversion and TortoiseSVN for Windows.  It also includes an optional Apache install to access files from other computers.

      I followed the Lifehacker articles and installed Subversion and TortoiseSVN and created a couple of repositories for projects I am working on. I elected to skip the Apache install on my machine as I only develop from my laptop.

      I'll tell you that it already saved my butt once this weekend...in a rare act of stupidity (OK it really wasn't that rare) I copied files into the wrong directory...it only overwrote one file.  But with version control I just right clicked on the file and hit revert and pulled up the original file I overwrote...without source control I would of had to recreate that file.

      I still need to figure out a backup solution that is easy and unobtrusive.  I am thinking about one of those one-click backup external hard-drives.  Maybe for my birthday ;)


      Thursday, August 03, 2006

      Suckerfish Menu with jQuery

      Me on jQuery's blog

      I think we all have heard of or used Suckerfish CSS Menu's before, written by Pattrick Griffiths and Dan Webb for A List Apart. If not, it's a cool way to make drop down menu's using standards based semantic HTML and CSS. Unfortunately, with IE still dominating the browser marketplace we still need a way to handle the hover state in IE. To do that we need a little bit of JavaScript to attach mouseover and mouseout events to HTML elements.

      Myles Angell decided to rewrite Suckerfish's JavaScript with jQuery. Myles uses jQuery's Basic Effects to show and hide the submenus and jQuery's BaseStyle Base module methods to highlight the current moused over menu item. Pretty slick.

      Check out some of Myles other experiments with jQuery. For the jQuery beginner these are good examples to start out with. The treeview is another experiment that caught my eye.

      Sunday, July 30, 2006

      I am now blogging for jQuery

      Check out my first blog on jquery.com about Aptana IDE now including jQuery as a imported JavaScript Library.

      How to run Ubuntu and Kbuntu in VMware Player

      I had an itch today to run Ubuntu.  I actually wanted to see how Konqueror compared to Safari in rendering as I needed a way to test since I don't own a Mac. Since Safari is a descendent of Konqueror it makes sense that they render the same for the most part.

      I started by downloading and installing the free VMware Player.


      I then downloaded the Ubuntu iso (disk image) from Ubuntu's site.  I had the best luck with the torrent files.  I was able to download the 696mb iso in 20 minutes.  Since I'll be touching on it later you can also get the Kbuntu iso from the Kbuntu site.

      Now that I have VMware and the iso's I need to make a Virtual Hard Disk.  I found directions online here

      First I needed to download and install QEMU because you need the qemu-image.exe to emulate/create the virtual hard disk.

      After you installed QEMU open a command window and change directories to c:\program files\QEMU or whatever the directory name you put the files.  Once you are in the directory run the following command which will allowcate 3GB for a Ubuntu virtual hard drive.

      qemu-img.exe create -f vmdk Ubuntu.vmdk 3G Formating 'Ubuntu.vmdk', fmt=vmdk, size=3097152 kB

      For Kbuntu:

      qemu-img.exe create -f vmdk Kbuntu.vmdk 3G Formating 'Kbuntu.vmdk', fmt=vmdk, size=3097152 kB

      This will create a file Ubuntu.vmdk or Kbuntu.vmdk in the QEMU folder.

      Create a folder called Ubuntu or Kbuntu in My Documents > My Virtual Machines and move the vmdk file you just created in there. Also copy the iso file to this folder. Finally, create a blank text file and name it either Ubuntu.vmx or Kbuntu.vmx which are VMware Configuration files.

      In the Ubunti.vmx files paste this:

      config.version = "8"
      virtualHW.version = "3"
      ide0:0.present = "TRUE"
      ide0:0.filename = "Ubuntu.vmdk"
      memsize = "256"
      MemAllowAutoScaleDown = "FALSE"
      ide1:0.present = "TRUE"

      #ide1:0.fileName = "auto detect"
      #ide1:0.deviceType = "cdrom-raw"

      ide1:0.fileName = "ubuntu-6.06-desktop-i386.iso"
      ide1:0.deviceType = "cdrom-image"

      ide1:0.autodetect = "TRUE"
      floppy0.present = "FALSE"
      ethernet0.present = "TRUE"
      usb.present = "TRUE"
      sound.present = "TRUE"
      sound.virtualDev = "es1371"
      displayName = "Ubuntu"
      guestOS = "Ubuntu"
      nvram = "Ubuntu.nvram"
      MemTrimRate = "-1"

      ide0:0.redo = ""
      ethernet0.addressType = "generated"
      uuid.location = "56 4d 5c cc 3d 4a 43 29-55 89 5c 28 1e 7e 06 58"
      uuid.bios = "56 4d 5c cc 3d 4a 43 29-55 89 5c 28 1e 7e 06 58"
      ethernet0.generatedAddress = "00:0c:29:7e:06:58"
      ethernet0.generatedAddressOffset = "0"

      tools.syncTime = "TRUE"
      ide1:0.startConnected = "TRUE"

      uuid.action = "create"

      checkpoint.vmState = ""

      For Kbuntu.vmx paste this:

      config.version = "8"
      virtualHW.version = "3"
      ide0:0.present = "TRUE"
      ide0:0.filename = "Kbuntu.vmdk"
      memsize = "256"
      MemAllowAutoScaleDown = "FALSE"
      ide1:0.present = "TRUE"

      #ide1:0.fileName = "auto detect"
      #ide1:0.deviceType = "cdrom-raw"

      ide1:0.fileName = "kubuntu-6.06-desktop-i386.iso"
      ide1:0.deviceType = "cdrom-image"

      ide1:0.autodetect = "TRUE"
      floppy0.present = "FALSE"
      ethernet0.present = "TRUE"
      usb.present = "TRUE"
      sound.present = "TRUE"
      sound.virtualDev = "es1371"
      displayName = "Kbuntu"
      guestOS = "ubuntu"
      nvram = "Kbuntu.nvram"
      MemTrimRate = "-1"

      ide0:0.redo = ""
      ethernet0.addressType = "generated"
      uuid.location = "56 4d cf a0 97 ef 95 ad-c2 6a 6e 62 5b f2 78 ff"
      uuid.bios = "56 4d cf a0 97 ef 95 ad-c2 6a 6e 62 5b f2 78 ff"
      ethernet0.generatedAddress = "00:0c:29:f2:78:ff"
      ethernet0.generatedAddressOffset = "0"

      tools.syncTime = "TRUE"
      ide1:0.startConnected = "TRUE"

      uuid.action = "create"

      checkpoint.vmState = ""
      Save the file and close it.  All you have to do now is double-click the vmx file and it will launch VMware Player and boot with the iso image as the Boot CD (you don't need to even burn a CD).

      If you decide to install Ubuntu, at the end of the installation you will be prompted to reboot, before the system starts up go in and modify the vmx configuration file so that it boots off the virtual drive instead of the iso by modifying these four lines

      Find:
      #ide1:0.fileName = "auto detect"
      #ide1:0.deviceType = "cdrom-raw"

      ide1:0.fileName = "ubuntu-6.06-desktop-i386.iso"
      ide1:0.deviceType = "cdrom-image"
      Replace with:
      ide1:0.fileName = "auto detect"
      ide1:0.deviceType = "cdrom-raw"

      #ide1:0.fileName = "ubuntu-6.06-desktop-i386.iso"
      #ide1:0.deviceType = "cdrom-image"
      The great thing about Ubuntu is that it runs live right off the CD you don't even need to install it if you don't want to.  The differences between Ubuntu and Kbuntu is Ubuntu uses Gnome as it's Desktop and Kbuntu uses KDE.  Like I said at the beginning I wanted to test sites against Konqueror and with Konqueror being a KDE application it was installed by default in Kbuntu and ran perfectly right off the live CD without installation.  It can run off Ubuntu but you'll need to install Ubuntu then install Konqueror from the Synaptics Package Manager.

      Sunday, July 16, 2006

      Ruby on Rails Tutorials

      After I asked about tutorials on Ruby on Rails I went searching for a few. Here are about 30 tutorials on Ruby on Rails.


      Friday, July 14, 2006

      What's hot now?

      Obviously Web 2.0 apps are hot and all the rage.  I posted some examples of popular and up and coming apps.

      But what I think is surprising to me is that Ruby and Ruby on Rails is the hottest programming language out there right now.

      myBillq.com was done in Ruby on Rails.  It was done for two reasons. One, it gave the developers and the company something to program to show off their talents plus gave them experience with writing an application in Ruby on Rails.

      OK it seems like it might make web 2.0 easier to program? Is that a fair statement?  What's a good resource to start understanding Ruby?

      Wednesday, July 12, 2006

      jQuery

      I used to work with John Resig and Julia West before they moved on to become big wigs on their own.  They are on their way too, making waves in the JavaScript community with a new way to work with Javascript.  They are in the mist of developing a javascript API called jQuery that makes a developers life easier once you understand how it works. 

      What is jQuery?

      jQuery is a Javascript library that takes this motto to heart: Writing Javascript code should be fun. jQuery acheives this goal by taking common, repetitive, tasks, stripping out all the unnecessary markup, and leaving them short, smart and understandable.

      I finally used jQuery last night because I needed to make rounded corners on a div. all I needed to do was include the jquery.js file, include the rounded corners jQuery plugin js file then I included these three lines of code:

      $(document).ready(function(){
           $("#learn-more-container").corner("round bottom 15px");
      });

      which finds the div with id learn-more-container and sets the bottom corners to round with a radius of 15px.

      Just that easy.  Definitely check out jQuery and see how easy it is for yourself.

      Monday, June 26, 2006

      Domain Specific Class Selector

      This is pretty cool...we stumbled across this syntax in a Digg Article about putting the menu back on the right.

      docrule ::= "@-moz-document" S+ url-list "{" S* ruleset* "}"

      url-list ::= url-item ( "," S* url-item )*

      url-item ::= ( "url(" | "url-prefix(" | "domain(" ) URL ")" S*

      where S is from the CSS2 tokenization, ruleset is from the CSS2 grammar,
      and URL is like the production URI in the CSS2 tokenization except
      without the 'url(' and ')'.

      To define the three functions by example:

      @-moz-document url(http://www.w3.org/),
      url-prefix(http://www.w3.org/Style/),
      domain(mozilla.org)
      {
      /* CSS rules here apply to:
      + The page "http://www.w3.org/".
      + Any page whose URL begins with "http://www.w3.org/Style/"
      + Any page whose URL's host is "mozilla.org" or ends with
      ".mozilla.org"
      */
      }

      It basically allows you to have a class that only works on a specific domain. Of course it only works in Mozilla. Good use for the userContent.css file in FireFox.

      Sunday, June 25, 2006

      Interesting the people you meet at the most unusual times

      Yesterday was my nephews high school graduation party.  Yep my nephew graduated and my oldest son is going into middle school...I am getting old.

      At the party my dad said I had to meet my nephews uncle that runs his own business doing what I do...I ask "oh what's that?" "COMPUTERS" I always get a kick out of that.  They never realize that that could mean anything.

      A couple hours later after my wife had handed me my 8th Crown Royal and coke my nephews grandfather bring him over to meet me.

      Turns out he runs pokerdream.com a for pay online poker site.  He told me the site was written in VB.NET and the poker rooms were written in C++.

      I visited the site this morning and was really impressed with the design and layout of the site...very professional looking.

      He's looking for someone to build an affiliate program for the site.  I told him about my experience with building banner ads tracker on MediaGab and how I thought that should work...now that I think about it I should of told him about RedStorm Sports and the Ad system we build for that as well...I guess I can thank my wife and the 8 cups of Crown Royal and coke for that.

      We exchanged cards and talked about our nephew and his choice of college and his decision to go into Computer Science.  I was telling him I think he'll switch to IT eventually because I don't see him have the geekiness to like Computer Science once you get into the Science of it...I know I couldn't handle it and switched to IT in my third year....it's just more satisfying to make things work from existing software and applications then it is to build it from scratch.

      MySpace hiring ASP.NET Developers

      Speaking of MySpace.  I got a bulletin today from Tom (the founder) looking to hire more MySpace Developers.

      i want to hire some more .net developers to work on myspace. do you have experience? here's what i need:

      Required Skills/Experience:
      - 3+ years of solid C Sharp experience
      - 3+ years of ASP.NET (and the .NET 1.1 Framework) experience
      - 4+ years of experience developing with SQL Server 2000 (including stored procedures)
      - Strong knowledge of several protocols (including HTTP, TCP/IP, and UDP)
      - a solid foundation in n-tier, Business Objects, Design Patterns, and general OOP
      - Strong knowledge (and wisdom) of IIS6 and its internals
      - Experience on sites under heavy loads that require meticulous attention to coding practices as they relate to performance and scalability

      go here to upload a resume:
      myspace developers

      please dont upload anything about any other job at myspace. i'm only posting this to find .NET developers!

      oh yah, you've got to live in, or move to LOS ANGELES, CALIFORNIA! yeehaw!


      If I was single and didn't have a family and a house I would totally have jumped all over this.  Not because I like MySpace and want to make it better.  I would do it for the experience and jump into another company in the "Valley" that would be impressed to see a big name like MySpace on my resume.

      But I have a great job here in Rochester, NY.  Even if I am stuck in Maintenance Programming....thank God Coding Horror says it's pretty complex and challenging stuff. Thank god since I am challenged everyday with it.

      Tuesday, June 06, 2006

      LinkButton doesn't print out a name attribute

      When you use a LinkButton Control in ASP.NET 1.1 there is one difference compared to a Button Control.  A LinkButton does not print out a name attribute in the Generated HTML.

      I was trying to write some javascript from a textbox to press the LinkButton if the enter key is pressed as this is not done automatically in .NET.

      I was having the worst time debugging this stipping it all down to bare javascript calls. But I kept coming up with this.form.elements.somenameattibute has no properties.  Obviously I was getting at the LinkButton control but for some reason could not figure out why.  I switched over to document.getElementById("someIDattribute").click() and this worked great in IE but did not work in Firefox.  So back to debugging I went.

      After looking at the code and the example code that I lifted this with I noticed that the code had a name attibute and my code did not.  I switch my Link button over to a button control and everything worked fine.

      So in case you need to know this information at a later time a LinkButton control does not print out a name attribute, at least by default.

      Wednesday, May 03, 2006

      ASP.NET 1.1 Web.configs Inheritance Feature but to me it's a Bug

      I was working on a project on Saturday when I ran into a problem. I spent a good four hours trying to find a solution for it. When I finally did I still am not sure why it works but works it does.

      I was working on this web site that was written in .NET. I needed to dupe that site and make a new site in a sub directory. I made the subdirectory a virtual directory as I didn't want to make the new application conflict with the root site.

      Well that didn't happen. Conflict it did. I was getting an error (similar to this) that one of my declarations in my web.config was already declared. The declaration was in the Configuration part of the config file.

      I went and did a little research and found many other programmers just as frustrated that they were having the same issues. On their development machine it worked fine but when they put it onto the site it would throw this same sort of error. Turns out they develop the way they are advised too by creating a subdirectory for each project so they don't inherit from each other. But when they tried to put the files on the server one project was the root and one was the Virtual Directory. Bam!

      I was able to recreate this error on my machine by setting the project that was the root on the site as the root on my development machine. I could at least try and debug it.

      In my research I found that even though the app is in a virtual directory it STILL inherits from the root on up.

      Basically the hierarchy starts with the machine.config -> machine web.config -> app web.config -> subdirectory web.config and so on.

      Technically a virtual directory is a subdirectory but the point of making it a virtual directory is to separate the app from other apps in your site. This works for everything except web.config files. Why? Microsoft says this is a feature and not a bug...I on the other hand beg to differ.  Here are some configuration scenarios Microsoft details they get into the virtual directory configuration at the bottom.

      I finally got around the problem but it took some work. One of my class libraries in the project I created as a IConfigurationHandler and has set it up in the web.config but because both projects used different name spaced the declaration line was slightly different. I tried everything to try to override it. I read you could override the web.config by using <clear> or <remove> tags but then I found that the web.config schema doesn't allow those tags in the configuration element.

      In the end I took the class file and made into it's own DLL and referenced it in both projects and the configuration element became identical in both projects allowing me to see the virtual directory without an error.

      So does this “feature” still work like this in ASP.NET 2.0? I am told that Microsoft fixed this. But frankly I am not sure if it truly does or not. I do know there are more tags in the web.config to allow you to lock or override elements in the web.config. So until I see it for my own eyes it's a hope that it is fixed.

      I haven't even touched how ASP.NET 2.0 and a ASP.NET 1.1 web.config files don't like each other...but I haven't gotten to that point yet.

      Subserviant Programmer

      Kind of cool ASP.NET 2.0 Example project that mimics the Subserviant Chicken from a few years ago.

      http://www.subservientprogrammer.com/

      Some commands:

      Channel 9
      Get a drink


      Tuesday, April 25, 2006

      Nested Repeater Control Update

      Back in January I posted about a Expanding Nested Repeater control I had developed.  Well I ran into some difficulties with it right after I launched it...actually the problem was always there I just didn't realize it.

      For some reason that was unknown to me at the time the sub menu was skipping every other row of data that was getting returned from the database.  I spent hours looking at it and was literally beating my head trying to figure it out.

      I left it alone for a while.  And I looked at it again last night.  Stepping through the code for the first time it hit me right in the face.  As I was going through the repSubMenu_ItemDataBound method I realized that I was not testing for e.Item.ItemType == 'AlternateItem' I was only testing for e.Item.ItemType == 'Item'.

      I just needed to alter my if statement to check to see if Item OR AlternateItem.  I am glad I finally fixed it but holy crap that frustrated the hell out of me.

      It's funny though how fast I found the bug after I set it aside for a while.   That always seems to happens.

      Saturday, April 08, 2006

      Some interesting links from the week

      I have been so busy at work this past week I havn't had a chance to even think about my blog.  But it hasn't stopped me from finding some cool and/or interesting links on the web.

      I have been looking into resources for AJAX.  I went to Borders yesterday and was looking through "Professional AJAX" from WROX.  It looked good but I found better resource from Rushi Vishavadia, AJAX Resources for Beginners.

      Getting Started with AJAX - Author Aaron Gustafson takes you through writing a basic AJAX application (An address book). Lots of code there.

      Mastering AJAX - This is a pretty good tutorial which gives you the nitty gritty basics, talks about cross browser compatibility which is really important with XmlHTTPRequest object in IE (stupid MSFT :-p) What I like about this tutorial is that it explains info in a very easy to understand manner and it also says why you need it. (Part 1 (introduction) of the tutorial is here)

      Using AJAX with PHP and mySQL - Being a PHP Developer myself, this tutorial is really well written and very complete. Step by step instructions on how to go about working with the XMLHttpRequest object too.

      XAJAX - Xajax is an open source PHP Library for building ajax based applications. xajax is very easy to use and damn powerful, allowing you to use php where you wouldnt unneccesarily use JavaScript. They have a very good tutorial here called Learn Xajax in 10 Minutes.

      Another good tutorial by John Wiseman on Creating a mySQL connection with PHP and Ajax.(If the code seems too small copy and paste it intoyour favorite editor, or hit Ctrl + '+' on Firefox to increase font size)

      Ajax Loading Indicators & Icons - You can make up your own indicator icons, but the ones provided are really nice and fancy.

      Lastly, Max Keisler has a very comprehensive list Ajax tutorials, resources - from beginner to advanced.

      Scott Hanselman had a couple of interesting articles about debugging/troubleshooting.

      To go along with the interesting links category Travis sent me this link the other day to a LASIK @ Home Kit.  I posted it on my forum with some "observations."

      Remember that How to be a Rockstar Programmer post?  Well apparently there is some difference of opinion that is going around.

      Lastly, and certainly not least Apple announced that they will ship a program called Boot Camp in their next release, Leopard, but a beta was pushed out earlier this week.  This really has alot of people excited.  Apple listened to "Bloggers" and provided them a way to dual-boot Windows and OSX on a Intel Mac.

      Paul Thurrot has many many posts detailing his thoughts and experiences with Boot Camp.  I do agree with him that they should of made a boot loader menu show up on default rather then having to push and hold a option key to bring up the menu.

      Still though didn't someone already do this with a IBM Laptop?

      Wednesday, March 22, 2006

      Top Ten Tips to become a Rock Star Programmer

      On Digg they had this article about the top ten tips to become a Rock Star Programmer:

      Here are some of the tips I liked or related the most to me and what I should work towards.

      #7 Go back and enhance your old code

      Not that it is sound from an economical point of view but because you learn oodles of things reading you own crap, which old code always is. Code gets rotten after a couple of years, it really does, since you evolve. If you can't find bad things in your old code you either already are a rock star programmer, or maybe more probable, hasn't evolved much lately.

      This is good advice and something I never do.  I am of the mindset if it ain't broke don't fix it.  But then like he says it'll never evolve.

      #9 Don't ask people for advice

      Learn how to get that answer yourself instead, it is way more useful. Finding out how to get information about something is a value in itself and may pay you back more than the solution to the problem in the first place. Ask only if you must or if the question in itself is more a discussion and you are actually spreading information. Of course you shouldn't take this too literally, but I see lots of people asking pointless questions they could have found out faster by ten seconds of googling.

      I am so guilty of this.  I am always going to my co-workers for questions.  Mostly though it's because I don't know what to search for.  But if I would follow this tip:

      #6 Read books

      You might be good at what you do, but knowing only that, whatever it may be, is seldom enough to really shine. Knowing enough about more fields than the field you are about to shine in is golden. Take for instance a GUI coder that knows nothing about databases. He might be almost useless since he can't interact with the guy doing the backing store, and so on. It takes as much effort to be 90% good in five fields than to be 99% good one one.
      Maybe I would know more about what I need to know.

      Anyways there are some good tips in the article...some common sense tips and others that should make you reevaluate yourself.

      Monday, February 20, 2006

      IE 6, XHTML and the image space

      OK IE 6 has a great little bug/feature where if you set your page type to XHTML and you put an image on the page let's say a logo in your header, most times you want your image to be flush with the bottom element, perhaps a border of the container div the image is in.  If you leave the image unprocessed then you'll run into the problem where a 1px space shows up under your image.  This is very frustrating when your looking for a clean layout.

      I googled for an answer and either I wasn't searching right or there really isn't an answer on the topic but I couldn't find a solution to the problem.

      Asked my friend Travis and he gave me the simple solution to this problem.

      img
      {
          display: block;
      }

      That's it.  This will butt everything up on all sides.

      Wednesday, February 01, 2006

      Stylizing a Quote box with CSS

      I had to create a quote box the other day and decided I would try the nifty little CSS quote boxes you see on all those fancy CSS designers sites.  So I went googling for a tutorial and found one by Simon Willison called Quick top: Styling blockquotes with CSS.

      Basically his tutorial has you create a blockquote and then nest a div inside of it.  The reason for this is because in the Blockquote you put a background image (your left quote) to stick in the upper left.  Within the div you stick a background image (your right ending quote) to the lower right.

      His use of Blockquote as the container wasn't ideal in my opinion so replacing that with a div and giving it it's own class work just the same for me.

      Here is my mark I used for the quote box.

      <div class="quote">
          <div>
              The numbers vindicate&#8230;that children who are given clear behavioral 
      standards and social skills, allowing them to feel safe, valued, confident, and
      challenged, will exhibit better school behavior and learn more to boot.<br/> <span class="quotesource">-NY TIMES Op-Ed, August 16, 2005</span> </div> </div>
      The CSS to add the background images.
      .quote 
      {
      background: transparent url(images/leftquote.png) left top no-repeat;

      }
      .quote div
      {
      background: transparent url(images/rightquote.png) right bottom no-repeat;
      }
      That'll give you a box with your quote images on both side and your quote in the middle.  All you need now is to give it your personal touch.

      Here are my end results.


      [image] Smiling Kid in class
      The numbers vindicate…that children who are given clear behavioral standards and social skills, allowing them to feel safe, valued, confident, and challenged, will exhibit better school behavior and learn more to boot.
      -NY TIMES Op-Ed, August 16, 2005

      Monday, January 23, 2006

      More Nested Repeater Control

      I spent some time on Saturday working on my new navigation system.  The one the required the use of Nested Repeater Controls.  While working with them a little more I found it rather challenging to write to a Literal control that was in the Header Template of the nested repeater control.  The problem I was having was figuring out how/when the ItemDataBound event got fired.  The typical place to put the event declaration is in the InitializeComponent method but this would cause a runtime error as the nested Repeater wasn't in scope just yet.

      I found through some frustrating trial and error that if you put the event declaration in the main repeaters ItemDataBound event and set it before you bound the nested repeater, the event would fire correctly.

      Here is the code:

         1:      private void repMenu_ItemDataBound(object sender, RepeaterItemEventArgs e)
         2:          {
         3:              repSubMenu.ItemDataBound += new RepeaterItemEventHandler(repSubMenu_ItemDataBound);
         4:              repSubMenu.DataSource = page.SelectAllWSectionIDLogic();;
         5:              repSubMenu.DataBind();
         6:          }
         7:   
         8:          private void repSubMenu_ItemDataBound(object sender, RepeaterItemEventArgs e)
         9:          {
        10:              
        11:              if (e.Item.ItemType == ListItemType.Header)
        12:              {
        13:                  litSpan = (Literal)e.Item.FindControl("litSpan");
        14:                  litSpan.Text = "<span class=\"submenu\" id=\"sub" + _count.ToString() + "\">";
        15:              }
        16:          }

      Oh and if you want to see the finished Navigation you can see it here.  Used two nested Repeaters, LLBLGen Data code generation and some expanding javascript.  I am waiting on the go ahead to drop that control into the site.

      Thursday, January 19, 2006

      Nested Repeater Controls

      I am working on this variation of a main menu navigation where the submenu will display below the main navigational element once it is clicked.  Basically I was struggling with how I was going to databind the submenu to the main menu item it was related too.

      I went about solving this problem by using nested repeater controls.

         1:  <asp:repeater id="repMenu" runat="server">
         2:        <itemtemplate>
         3:          <%#  DataBinder.Eval(Container.DataItem, "Name") %><br>
         4:          <asp:repeater id="repSubMenu" runat="server">
         5:               <itemtemplate>
         6:                    <%# DataBinder.Eval(Container.DataItem, "MenuTitle") %>
         7:               </itemtemplate>
         8:          </asp:repeater>
         9:       </itemtemplate>
        10:   </asp:repeater>


      The above HTML defines two Repeater Controls.  The first one will display my DataBound Column Name from a Table in SQL Server. The second Repeater will display a column called Menu Title from a second DataBound Column.

      Looking at the C# Code:

         1:          /// <summary>
         2:          /// Repeater Control
         3:          /// </summary>
         4:          protected System.Web.UI.WebControls.Repeater repMenu, repSubMenu;
         5:   
         6:          private void Page_Load(object sender, System.EventArgs e)
         7:          {
         8:              Section section = new Section();
         9:              repMenu.DataSource = section.SelectAll();
        10:              repMenu.DataBind();
        11:          }
        12:   
        13:          #region Web Form Designer generated code
        14:          override protected void OnInit(EventArgs e)
        15:          {
        16:              //
        17:              // CODEGEN: This call is required by the ASP.NET Web Form Designer.
        18:              //
        19:              InitializeComponent();
        20:              base.OnInit(e);
        21:          }
        22:          
        23:          /// <summary>
        24:          ///        Required method for Designer support - do not modify
        25:          ///        the contents of this method with the code editor.
        26:          /// </summary>
        27:          private void InitializeComponent()
        28:          {
        29:              this.Load += new System.EventHandler(this.Page_Load);
        30:              this.repMenu.ItemDataBound +=new RepeaterItemEventHandler(repMenu_ItemDataBound);
        31:          }
        32:          #endregion
        33:   
        34:          private void repMenu_ItemDataBound(object sender, RepeaterItemEventArgs e)
        35:          {
        36:              RepeaterItem item = e.Item;
        37:              repSubMenu = (Repeater) item.FindControl("repSubMenu");
        38:              DataRowView drv = (DataRowView) item.DataItem;
        39:              Page page = new Page();
        40:              page.SectionID = (int)drv.Row.ItemArray[0];
        41:              repSubMenu.DataSource = page.SelectAllWSectionIDLogic();;
        42:              repSubMenu.DataBind();
        43:   
        44:          }

      I use LLBLGen to generate DataLayer Code automatically, your code may use DataTables, DataSets, XML, etc. The key to the code, however, is the ItemDataBound function (Lines 34-44).  Within this function is where the magic happens.  The first line (line 36) sets the line item that we are on in the first Repeater so that we can work with the data.  In the second line (line 37) we need to find the Second Repeater so we know how to work with it.  Line 38 we need to move the DataItem Row into a DataRowView so that we can access the columns.  I then initialize my datalayer class from LLBLGen and assign the sectionID from the DataRowView from the first Repeater into it. SectionID is specific to my database and tables.  I use the methods/Properties Row.ItemArray from the DataRowView class.  What ItemArray does is return the columns and the data that is bound in the first Repeater as an array.  I found from debugging and looking at the variables while stepping through the code that the column I needed SectionID was at the 0 index of the array.

      I then call the method again within the LLBLGen class and methods to bring back a DataTable of all the pages that relate to the section that I am in.  I DataBind the repeater and I set the databound column I want to display MenuTitle in the HTML within the second Repeaters ItemTemplate.

      The output of the nested table above would look something like this:

      Section
      Page
      page
      Page
      Section
      Page
      Page
      Page

      I need to do more work to get the navigation menu to be useful like making the Section Name a linkbutton that hides/shows the nested Repeater.  I'll blog on that when I figure that part out.


      Update: based on comments from Travis I was able to update my code to streamline it a little better. Instead of this line:
        40:              page.SectionID = (int)drv.Row.ItemArray[0];
      I was able to replace it with:
        40:              page.SectionID = (int)drv["ID"];
      Thus making it easier to get at the columns needed from the parent repeater. Thanks Travis.

      Tuesday, January 03, 2006

      Web Developer Extension Toolbar releases 1.0 version

      Web Developer  Extension Toolbar releases the official 1.0 version.


      Get it here



      UPDATE: Version 1.0.1 was just released.






      Sunday, January 01, 2006

      AJAX for dummies

      AJAX is the latest buzz word going around the internet.  But what is it?  Well it's basically a way to send data with Javascript with XML calls.  But for some reason it sounds complicated and hard.  But here is a 30 second AJAX Tutorial I found that gets you up and going quick.  Here is the article posted below.


      I find a lot of this AJAX stuff a bit of a hype.  Lots of people have
      been using similar things long before it became "AJAX". And it really
      isn't as complicated as a lot of people make it out to be. Here is a
      simple example from one of my apps. First the Javascript:

      function createRequestObject() {
      var ro;
      var browser = navigator.appName;
      if(browser == "Microsoft Internet Explorer"){
      ro = new ActiveXObject("Microsoft.XMLHTTP");
      }else{
      ro = new XMLHttpRequest();
      }
      return ro;
      }

      var http = createRequestObject();

      function sndReq(action) {
      http.open('get', 'rpc.php?action='+action);
      http.onreadystatechange = handleResponse;
      http.send(null);
      }

      function handleResponse() {
      if(http.readyState == 4){
      var response = http.responseText;
      var update = new Array();

      if(response.indexOf('|' != -1)) {
      update = response.split('|');
      document.getElementById(update[0]).innerHTML = update[1];
      }
      }
      }

      This creates a request object along with a send request and handle
      response function. So to actually use it, you could include this js in
      your page. Then to make one of these backend requests you would tie it
      to something. Like an onclick event or a straight href like this:

      <a href="javascript:sndReq('foo')">[foo]</a>

      That means that when someone clicks on that link what actually happens
      is that a backend request to rpc.php?action=foo will be sent.

      In rpc.php you might have something like this:

      switch($_REQUEST['action']) {
      case 'foo':
      / do something /
      echo "foo|foo done";
      break;
      ...
      }

      Now, look at handleResponse. It parses the "foo|foo done" string and
      splits it on the '|' and uses whatever is before the '|' as the dom
      element id in your page and the part after as the new innerHTML of that
      element. That means if you have a div tag like this in your page:

      <div id="foo">
      </div>

      Once you click on that link, that will dynamically be changed to:

      <div id="foo">
      foo done
      </div>

      That's all there is to it. Everything else is just building on top of
      this. Replacing my simple response "id|text" syntax with a richer XML
      format and makine the request much more complicated as well. Before you
      blindly install large "AJAX" libraries, have a go at rolling your own
      functionality so you know exactly how it works and you only make it as
      complicated as you need. Often you don't need much more than what I
      have shown here.

      Expanding this approach a bit to send multiple parameters in the
      request, for example, would be really simple. Something like:

      function sndReqArg(action,arg) {
      http.open('get', 'rpc.php?action='+action+'&arg='+arg);
      http.onreadystatechange = handleResponse;
      http.send(null);
      }

      And your handleResponse can easily be expanded to do much more
      interesting things than just replacing the contents of a div.


      Blog Posts by:

      Currently Viewable:

      Using jQuery and Templating to Pull and Display Yo...
      jQuery 1.4 Give Us a New Way to Zebra Stripe
      Getting "Up-to-speed"
      PHP 101: Uploading a file
      Apples Developer Connection Documentation is buggy...
      Transparent PNG's and IE 6
      Selecting the fastest selector for jQuery using Fi...
      Hidden C# Feature: Using Alias Directive
      New Features of .NET 4.0
      The Future of Programming Languages is Now
      My BarCamp Buffalo Slides - Intro to jQuery
      Where to find help for your jQuery questions?
      In case you Missed it: #jQuery Twitter posts
      Selecting a ASP.NET Generated ID with jQuery
      Building a jQuery-Powered Tag-Cloud with an ASP.NE...
      ASP.NET MVC Release Candidate - No Codebehinds on ...
      BarCamp Rochester 4
      jQuery vs Prototype and jQuery.noConflict()
      In Case you Missed it: #jQuery Twitter posts
      Finally Launched www.stjohns.edu
      System.Net.WebException: The operation has timed-o...
      Database Mirroring with SQL Server 2005
      Gaining Exclusive Access to database in SQL Server...
      Light at the End of the Tunnel
      jQuery Plugin - Simple Shadow
      Adding link separators to a unordered list using j...
      How to target="_blank" a link while keeping it XHT...
      Book Review: "Smart & Gets Things Done" by Joel Sp...
      My first JSON Implementation
      Google I/O 2008 - Day 1
      Kings of Code 2008
      Pulling twitter updates with JSON and jQuery
      Update on my jQuery bug
      VS.NET IDE Issue - ASPX gets separated from codebe...
      Installing Rails on Ubuntu using VMWare Server
      My first jQuery bug
      A Visual Explaination of SQL Joins
      Click on your own Google Adsense links without bre...
      Case sensitivity, SVN and Windows is a recipe for ...
      Redesigned BrandLogic.com Launches
      What does the future hold?
      Sending HTML E-Mails
      Today's Big News: Sun to release Java under the GP...
      A Slick CSS Solution to Image Rollovers
      New Dialog box in VS.NET 2003
      SVN Source Control in Windows
      Suckerfish Menu with jQuery
      I am now blogging for jQuery
      How to run Ubuntu and Kbuntu in VMware Player
      Ruby on Rails Tutorials
      What's hot now?
      jQuery
      Domain Specific Class Selector
      Interesting the people you meet at the most unusua...
      MySpace hiring ASP.NET Developers
      LinkButton doesn't print out a name attribute
      ASP.NET 1.1 Web.configs Inheritance Feature but to...
      Subserviant Programmer
      Nested Repeater Control Update
      Some interesting links from the week
      Top Ten Tips to become a Rock Star Programmer
      IE 6, XHTML and the image space
      Stylizing a Quote box with CSS
      More Nested Repeater Control
      Nested Repeater Controls
      Web Developer Extension Toolbar releases 1.0 versi...
      AJAX for dummies

      The Official jQuery Podcast

      with Ralph Whitbeck & Rey Bango

      You can subscribe to the show in iTunes or via the raw RSS feed

      My Twitter Updates

      View Twitter Page