jQuery ate my values

by Mikael Henriksson 22. July 2010 20:33
I wanted to clear some textboxes when it gets focus so that the user does not have to clear the textbox before they enter whatever text. I came up with the following pretty quickly.
$('input[type=text]').focus(function () {    
    $(this).val('');
});

This worked like a charm!

I clicked a textbox and it got cleared, perfect right? Wrong! The problem here is that no matter how the textbox gets focus the box will be cleared. While tabbing through the form I cleared it completely and had to reload the entire page to get the values back. I thought of implementing some sort of ctrl+z to undo changes but realized I am better of not going down that road.

If it isn't broken…

UPDATE (2010-07-26): As suggested in the comments it’s actually a great idea to store the value locally and if the textbox is empty when the user leaves it we just add the original value back. This can be done like follows:

$(document).ready(function() {
        $('input[type=text]').bind('focusin', function(e) {
            tbData = $(this).val();
            $(this).val('')   
        });
        $('input[type=text]').bind('focusout', function(e) {
            if ($(this).val() == '') {
                $(this).val(tbData);
            }
        });
});

 

I’d like to shorten this a little but can’t get it working as expected. I’d probably want to get rid of the global variable for instance. Expect another update sometime soon.

UPDATE (2010-08-05): I found another way of solving the exact same problem which sort of makes more sense even though I can’t get rid of the global parameter.

$('input[type=text]').live('focusin focusout', function (evt) {
    if (evt.type == 'focusin') {
        tbData = $(this).val();
        $(this).val('');
    } else {
        if ($(this).val() == '') {
            $(this).val(tbData);
        }
    }
});

Tags:

jQuery

Resharper NOT broken, MSpec R# runner IS

by Mikael Henriksson 15. July 2010 21:23

I have no idea what is going on over at jetbrains but youtrack is down and resharper is broken. I got the latest version of Resharper 5.1.1727.12 and I can’t use it. The renaming functionality is broken. I keep pressing F2 and nothing happens. Feels like going back to the stoneage. Obviously it’s one of the features I use the most and without the coding experience is terrible.

EDIT: I just discovered that intellisense also is broken both on my work VS2008 and at home VS2010.

Obviously they have to create a version 5.2 pretty rapidly but I can’t report the bug because youtrack is down! Sad smile

On a side-note I am happy with the latest version of windows live!

Thank you Hadi HaririI would probably be looking for a long time if you had not been there! I posted this to the mspec guys instead. http://github.com/machine/machine.specifications/issues/issue/18

Tags:

Using Powershell to perform ftp uploads

by Mikael Henriksson 11. July 2010 23:58

This is not so much for informational purposes as it is for safe keeping

. 'x:\path-to\ftp-tools.ps1'
$server = 'ftp.domain.com'
$dir = 'C:\Users\Public\Pictures\Sample Pictures'
$pass = ConvertTo-SecureString "******" -AsPlainText -Force
$cred = new-object `
 	-typename System.Management.Automation.PSCredential -argumentlist "*******", $pass

upload-directory `
 -server $server `
 -dir $dir `
 -overwrite $true `
 -cred $cred
function upload-directory {
  param([string] $server = $( Throw "You must specify an FTP server to logon to."),
	 [string] $dir = $( Throw "You must specify a local directory to upload (ie, C:\Testing\FTPTest\)"),
	 [switch] $overwrite = $false,
	 [System.Management.Automation.PSCredential] $cred = $( Throw "You must provide credentials with which to logon to the FTP server.") ) 
        
  $files = (get-childitem $dir -r)

  foreach ($file in $files) {
    $remfilename = $file.FullName.Replace($dir, "")
    $remfilename = $remfilename.Replace("\", "/")
    if ($file.Attributes.ToString().IndexOf("Directory") -ge 0) {
  	  try
  	  {
      	send-ftp -server $server -cred $cred
      }
      catch {} #if the directory already exists, ignore the error
    }
    else {
      send-ftp `
	  	-Server $server `
		-LocalFile $file.FullName `
		-Path "/account/zoolutions.se/Test" `
		-RemoteFile $remfilename `
		-Credentials $cred `
		-Overwrite $true
    }
  }
}
function send-ftp {

	param([string] $server = $( Throw "You must specify an FTP server to logon to."),
		[string] $dir = $( Throw "You must specify a local directory to upload (ie, C:\Testing\FTPTest\)"),
		[switch] $overwrite = $(Throw "Must select wheter to overwrite existing files"),
		[System.Management.Automation.PSCredential] $credentials = $(Get-Credential),
		[Parameter(ValueFromPipeline=$true)] $LocalFile = $( Throw "You must specify an FTP server to logon to."),  
		[string] $path = $( Throw "You must specify an FTP server to logon to."),  
		[string] $remoteFile = $(Split-Path $LocalFile -Leaf), 
		[int] $parentProgressId = -1,
		[string] $progressActivity = "Uploading $LocalFile" )
	  
	## Assert the existence of the file in question
	if( -not (Test-Path $LocalFile) ) {
		Throw "File '$LocalFile' does not exist!"
	}

	## Create the server string (and make sure it uses forward slashes and ftp://)
	$upload = "ftp://" + $Server + ( Join-Path (Join-Path "//" $Path) $RemoteFile ) -replace "\\", "/"
	#$Upload = $upload
	$total = (gci $LocalFile).Length

	Write-Debug $upload
	## Create FTP request
	$request = [Net.FtpWebRequest]::Create($upload)

	## NOTE: we do not create a folder here...
	# [System.Net.WebRequestMethods+Ftp]::MakeDirectory
	$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
	$request.Credentials = $Credentials.GetNetworkCredential()
	$request.UsePassive = $true
	$request.UseBinary = $true
	$request.KeepAlive = $false

	try {
		## Load the file
		$read = [IO.File]::OpenRead( (Convert-Path $LocalFile) )
		$write = $request.GetRequestStream();
		
		$buffer = new-object byte[] 20KB
		$offset = 0
		$progress = 0

		do {
		$offset = $read.Read($buffer, 0, $buffer.Length)
		$progress += $offset
		$write.Write($buffer, 0, $offset);
		Write-Progress $ProgressActivity "Uploading" -Percent ([int]($progress/$total * 100)) -Parent $ParentProgressId
		} while($offset -gt 0)

	} finally {
		Write-Debug "Closing Handles"
		$read.Close()
		$write.Close()
	}
}

Tags:

PowerShell

All my current Fluent NHibernate Conventions

by Mikael Henriksson 5. July 2010 23:17

I have been working on these for a while now. It all started  when I had to adapt to DBA style naming conventions. I wanted to automate everything because 16 tables with almost the same number of columns becomes a lot of text to write . Yeah I have to override a column name every now and then but all in all it has served me pretty well. Later I added some conventions for invert many-to-many and some other conventions as well.

I’ll just add them here so let the games begin:

public class TableNameConvention : IClassConvention, IClassConventionAcceptance
{
	public void Apply(IClassInstance instance)
	{
		instance.Table("`" + Inflector.Underscore(instance.EntityType.Name) + "´");
	}

	public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
	{
		criteria.Expect(x => x.TableName, Is.Not.Set);
	}
}

I recently posted the Inflector class and this and much more is what I have been using it for. The method “Inflector.Underscore” makes SomeEntity into some_entity. It should be easy enough to understand :) Oh and the reason for the acceptance criteria is for those few times I got complaints about the table names and needed to set it in the mapping. It sets the table name if it has not been set from the mapping.

public class ManyToManyTableName : ManyToManyTableNameConvention
{
	protected override string GetBiDirectionalTableName(IManyToManyCollectionInspector collection,
	                                                    IManyToManyCollectionInspector otherSide)
	{
		return Inflector.Underscore(collection.EntityType.Name + "_" + otherSide.EntityType.Name);
	}

	protected override string GetUniDirectionalTableName(IManyToManyCollectionInspector collection)
	{
		return Inflector.Underscore(collection.EntityType.Name + "_" + collection.ChildType.Name);
	}
}

This one was a bit difficult for me to get right, had to do a few trials before I got it correct.

public class EnumConvention : IPropertyConvention, IPropertyConventionAcceptance
{
	public void Apply(IPropertyInstance instance)
	{
		instance.CustomType(instance.Property.PropertyType);
	}

	public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
	{
		criteria.Expect(x => x.Property.PropertyType.IsEnum);
	}
}

My trusty old EnumConvention, it has made developing against a RDBMS a lot nicer. Enums are a powerful addition to the model.

public class IdColumnConvention : IIdConvention
{
	public void Apply(IIdentityInstance instance)
	{
		instance.Column(Inflector.Underscore(instance.EntityType.Name) + "_id");
		instance.GeneratedBy.Identity();
	}
}

The IdColumnConvention is the only one that changes between projects and it’s the generated by that is subject to change. You might want to throw in a IIdConventionAcceptance if you have more than one type of Id column.

public class PropertyConvention : IPropertyConvention
{
	public void Apply(IPropertyInstance instance)
	{
		instance.Column(Inflector.Underscore(instance.Property.Name));
	}
}

Nothing too exciting here either, just the naming of the columns.

public class CustomForeignKeyConvention : ForeignKeyConvention
{
	protected override string GetKeyName(Member property, Type type)
	{
		if (property == null)
			return Inflector.Underscore(type.Name) + "_id"; 

		return Inflector.Underscore(property.DeclaringType.Name) + "_id";
	}
}

This one on the other hand is a different story. Here is where conventions become convenient (and difficult). It’s really nice to be able to set the foreign key but figuring out the correct variable to put in took some time. The last return is for  many-to-one and the top one is for all the others.

public class HasManyConvention : IHasManyConvention
{
	public void Apply(IOneToManyCollectionInstance instance)
	{
		instance.Cascade.All();
		instance.Inverse();
		instance.Key.Column(Inflector.Underscore(instance.EntityType.Name + "_id"));
		instance.Key.ForeignKey(string.Format("fk_{0}_{1}",
		                                      Inflector.Underscore(instance.EntityType.Name).ToLower(),
		                                      Inflector.Underscore(instance.ChildType.Name).ToLower()));
	}
}

I set cascade and inverse here as well as the names of the foreign key and the column name. I probably don’t need the column name though. If you want to customize the inverse and cascading you would be better of moving that over to a second convention so you can pass in a convention acceptance criteria to decide whether to set it or not.

public class ReferenceConvention : IReferenceConvention
{
	public void Apply(IManyToOneInstance instance)
	{
		instance.Cascade.None();

		instance.Column(Inflector.Underscore(instance.Property.PropertyType.Name) + "_id");

		instance.ForeignKey(
			string.Format("fk_{0}_{1}",
				Inflector.Underscore(instance.Property.PropertyType.Name).ToLower(),
				Inflector.Underscore(instance.EntityType.Name).ToLower()));
	}
}

The last one for today is pretty similar to the HasMany convention. When working with ASP.NET MVC it’s really important to set the cascading to none in the following scenario:

Let’s say you have and order that holds products. You retrieve the order from the database. Then you add a product to the order and want to use the cascading inverse functionality in the Order mapping. However if your product holds a reference to the Order in your View (you use your data model in your presentation layer) you could end up with the following message “a different object with the same identifier value was already associated with the session”. What this means is that you have cascading on the wrong end. Cascading from the wrong side of things is as bad as leaving your aggregate members as publicly accessible as the aggregate root.

Tags: ,

Fluent NHibernate | NHibernate

Inflector – renaming utilities

by Mikael Henriksson 3. July 2010 11:04

One of my favorite utilities when working with 1. C#, 2. ORM, 3. DBA has been and will always be Inflector.  It takes any string input and changes ist’s form. For instance it can make your "some_table" in the database become "SomeTable" in C# by calling the right method. This is not my work, I take no credit for it. It originally belongs to some Andrew Peters guy. He seems to have vanished from the surface. It can still be found in a various places but this is where I store “my” stuff so:)

	public static class Inflector
	{
		#region Default Rules

		static Inflector() {
			AddPlural("$", "s");
			AddPlural("s$", "s");
			AddPlural("(ax|test)is$", "$1es");
			AddPlural("(octop|vir)us$", "$1i");
			AddPlural("(alias|status)$", "$1es");
			AddPlural("(bu)s$", "$1ses");
			AddPlural("(buffal|tomat)o$", "$1oes");
			AddPlural("([ti])um$", "$1a");
			AddPlural("sis$", "ses");
			AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves");
			AddPlural("(hive)$", "$1s");
			AddPlural("([^aeiouy]|qu)y$", "$1ies");
			AddPlural("(x|ch|ss|sh)$", "$1es");
			AddPlural("(matr|vert|ind)ix|ex$", "$1ices");
			AddPlural("([m|l])ouse$", "$1ice");
			AddPlural("^(ox)$", "$1en");
			AddPlural("(quiz)$", "$1zes");

			AddSingular("s$", "");
			AddSingular("(n)ews$", "$1ews");
			AddSingular("([ti])a$", "$1um");
			AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
			AddSingular("(^analy)ses$", "$1sis");
			AddSingular("([^f])ves$", "$1fe");
			AddSingular("(hive)s$", "$1");
			AddSingular("(tive)s$", "$1");
			AddSingular("([lr])ves$", "$1f");
			AddSingular("([^aeiouy]|qu)ies$", "$1y");
			AddSingular("(s)eries$", "$1eries");
			AddSingular("(m)ovies$", "$1ovie");
			AddSingular("(x|ch|ss|sh)es$", "$1");
			AddSingular("([m|l])ice$", "$1ouse");
			AddSingular("(bus)es$", "$1");
			AddSingular("(o)es$", "$1");
			AddSingular("(shoe)s$", "$1");
			AddSingular("(cris|ax|test)es$", "$1is");
			AddSingular("(octop|vir)i$", "$1us");
			AddSingular("(alias|status)es$", "$1");
			AddSingular("^(ox)en", "$1");
			AddSingular("(vert|ind)ices$", "$1ex");
			AddSingular("(matr)ices$", "$1ix");
			AddSingular("(quiz)zes$", "$1");

			AddIrregular("person", "people");
			AddIrregular("man", "men");
			AddIrregular("child", "children");
			AddIrregular("sex", "sexes");
			AddIrregular("move", "moves");

			AddUncountable("equipment");
			AddUncountable("information");
			AddUncountable("rice");
			AddUncountable("money");
			AddUncountable("species");
			AddUncountable("series");
			AddUncountable("fish");
			AddUncountable("sheep");
		}

		#endregion

		private static readonly List<Rule> _plurals = new List<Rule>();
		private static readonly List<Rule> _singulars = new List<Rule>();
		private static readonly List<string> _uncountables = new List<string>();

		internal static void AddIrregular(string singular, string plural) {
			AddPlural("(" + singular[0] + ")" + singular.Substring(1) + "$", "$1" + plural.Substring(1));
			AddSingular("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + singular.Substring(1));
		}

		internal static void AddUncountable(string word) {
			_uncountables.Add(word.ToLower());
		}

		internal static void AddPlural(string rule, string replacement) {
			_plurals.Add(new Rule(rule, replacement));
		}

		internal static void AddSingular(string rule, string replacement) {
			_singulars.Add(new Rule(rule, replacement));
		}

		public static string Pluralize(string word) {
			return ApplyRules(_plurals, word);
		}

		public static string Singularize(string word) {
			return ApplyRules(_singulars, word);
		}

		private static string ApplyRules(List<Rule> rules, string word) {
			string result = word;

			if (!_uncountables.Contains(word.ToLower())) {
				for (int i = rules.Count - 1; i >= 0; i--) {
					if ((result = rules[i].Apply(word)) != null) {
						break;
					}
				}
			}

			return result;
		}

		public static string Titleize(string word) {
			return Regex.Replace(Humanize(Underscore(word)), @"\b([a-z])",
			                     match => match.Captures[0].Value.ToUpper());
		}

		public static string Humanize(string lowercaseAndUnderscoredWord) {
			return Capitalize(Regex.Replace(lowercaseAndUnderscoredWord, @"_", " "));
		}

		public static string Pascalize(string lowercaseAndUnderscoredWord) {
			return Regex.Replace(lowercaseAndUnderscoredWord, "(?:^|_)(.)",
			                     match => match.Groups[1].Value.ToUpper());
		}

		public static string Camelize(string lowercaseAndUnderscoredWord) {
			return Uncapitalize(Pascalize(lowercaseAndUnderscoredWord));
		}

		public static string Underscore(string pascalCasedWord) {
			return Regex.Replace(
				Regex.Replace(
					Regex.Replace(pascalCasedWord, @"([A-Z]+)([A-Z][a-z])", "$1_$2"), @"([a-z\d])([A-Z])",
					"$1_$2"), @"[-\s]", "_").ToLower();
		}

		public static string Capitalize(string word) {
			return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower();
		}

		public static string Uncapitalize(string word) {
			return word.Substring(0, 1).ToLower() + word.Substring(1);
		}

		public static string Ordinalize(string number) {
			int n = int.Parse(number);
			int nMod100 = n%100;

			if (nMod100 >= 11 && nMod100 <= 13) {
				return number + "th";
			}

			switch (n%10) {
				case 1:
					return number + "st";
				case 2:
					return number + "nd";
				case 3:
					return number + "rd";
				default:
					return number + "th";
			}
		}

		public static string Dasherize(string underscoredWord) {
			return underscoredWord.Replace('_', '-');
		}

		#region Nested type: Rule

		private class Rule
		{
			private readonly Regex _regex;
			private readonly string _replacement;

			public Rule(string pattern, string replacement) {
				_regex = new Regex(pattern, RegexOptions.IgnoreCase);
				_replacement = replacement;
			}

			public string Apply(string word) {
				if (!_regex.IsMatch(word)) {
					return null;
				}

				return _regex.Replace(word, _replacement);
			}
		}

		#endregion
	}

Tags:

C# | Tools

About the author

Life architect specialized in programming