Saturday, July 4, 2009

Changing Default Download Folder for Internet Explorer 6

How to Change the Default Download Folder for Internet Explorer 6

I just had the pleaser to use a computer that had IE6 still installed on it. I needed to change the default download directory, which ended up being a "home-made hack" I figured out on my own.

I know this information is a bit useless/out of date inasmuch ad Microsoft is about to release IE8, but there may be someone out there who needs this information.

So here is how to change the default downosd folder for IE6.

1. START/Run/Regedit
2. Navigate to this key: HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer
3. Right click on the right pane.
4. Choose New / String Value (REG_SZ)
5. Name the new key "Download Directory"
6. For the string value, enter the folder you want, in my case "C:\Dropzone"

Make sure to close all instances of IE that may be running for the change to take effect.

Shannon Norrell

Monday, May 18, 2009

Badass Javascript Date Validator.
Useful for Rails.

Haven't posted for a while. I should remember to post cool routines like the one below after I write them as they are useful to many.
I have seen quite a lot of good examples of folks using (and expanding upon) routines I wrote for some of the Gadgets that ship with Vista (to be found in library.js if you have a Vista Box) and for some of AOL's (apparently deprecated) Mac OSX Widgets.
Functions like showOrHide, getLocalizedString, getSpinner (emulates Vista-like spinner image) I have seen in use all over the place.

Here is a somewhat badass Date Validator routine I wrote today that takes in either a string date value or an <INPUT> Element Object and validates the date to be formatted as DD-MM-YYYY.

I wrote it for use by a Ruby on Rails application, but it's pretty handy as a general library function.

Using this (simple) Regex:
var DATE_REGEX = /^(\d{2})-(\d{2})-(\d{4})$/

////////////////////////////////////////////////////////////////////////////////
// //
// validateDate([object|string] oHTMLInputElement) - Validates a date value //
// =============================================== //
// You can pass in the id to an <input> Element, an actual //
// oHTMLInputElement or an actual date value in the form of a string //
// //
////////////////////////////////////////////////////////////////////////////////
function validateDate(oHTMLInputElementOrDateValue) {
var theDateValueToValidate = "";
var theValidatedDateValue = false;
var bIsInputElement = false;
if (typeof(oHTMLInputElementOrDateValue)=="string") {
var oHTMLInputElement = document.getElementById(oHTMLInputElementOrDateValue);
if (oHTMLInputElement && typeof(oHTMLInputElement=="object") && (oHTMLInputElement.tagName=="INPUT")) {
theDateValueToValidate = oHTMLInputElement.value;
bIsInputElement = true;
} else {
// Presumably they just passed in a date string
theDateValueToValidate = oHTMLInputElementOrDateValue;
bIsInputElement = false;
}
} else {
// They have passed in an Object
if (typeof(oHTMLInputElementOrDateValue=="object") && (oHTMLInputElementOrDateValue.tagName=="INPUT")) {
var oHTMLInputElement = oHTMLInputElementOrDateValue;
theDateValueToValidate = oHTMLInputElement.value;
bIsInputElement = true;
}
}
// If we have a date value to actually validate, let's get started
if (theDateValueToValidate != "") {
var theDateValue = theDateValueToValidate.replace(/\//g,"-"); // Ruby-side only accepts hyphens
if (DATE_REGEX.test(theDateValue)) {
theValidatedDateValue = theDateValue;
} else {
if (theDateValue.indexOf('-') > -1) {
var theMonth = theDateValue.split('-')[0];
var theDay = theDateValue.split('-')[1];
var theYear = theDateValue.split('-')[2];
theMonth = parseInt(theMonth).PadWithZero(); // If they've entered a single digit for either Day or Month, pad with zero accordingly
theDay = parseInt(theDay).PadWithZero();
if (theYear.length==2) { theYear = "20" + theYear; } // If they've entered a two-digit year, assume it's in the 21st century
theDateValue = theMonth + "-" + theDay + "-" + theYear; // Rebuild the date. Hopefully this will work
if (DATE_REGEX.test(theDateValue)) {
theValidatedDateValue = theDateValue;
}
}
// If we get to this point and none of our efforts have worked to format the date as "required", throw an error (if they are using an INPUT element)
if (!theValidatedDateValue && bIsInputElement) {
alert("ERROR: Date must be formatted as follows:\n\n\tDD-MM-YYYY\n\nPlease correct before continuing");
oHTMLInputElement.focus();
}
}
}
if (bIsInputElement && theValidatedDateValue) {
oHTMLInputElement.value = theValidatedDateValue;
}
return theValidatedDateValue;
}

Hope you find this one useful as well.

Shannon Norrell


Now on GitHub as well

Monday, April 13, 2009

Rnadom Flex Note - Event handlers Nightmares

It is onerous to say the least to determine which events to handle for many objects.

 

For instance today, I was trying to get an <mx:HSLIDER> control to change the size of something in real time (as the thumb drags around)..

 

Let me explain how I figured out which one to use.

 

Here is how I started out:

 

<mx:HSlider id="mySlider" />

<mx:Text id="foo" text="{mySlider.value}"/>           

 

With this setup, there is some magic that occurs so that when you stop dragging the little thumb, the binding takes into effect and the value in the text box updates.  Easy enough, right?

 

So now, what if I want the value in “foo” to update AS I DRAG THE THUMB.  Should be possible (it is).

 

I counted, and there are no less than 63 events that an HSLIDER control can fire.  Which one to trap?

 

Well, not finding an obvious answer on the internet, I began attaching handlers to events that seemed to make sense:

 

So here is my first iteration:

 

<mx:HSlider id="mySlider" change="sliderChange(event)"/>

 

Notice that with Flex, you always have to pass in the (event) object. 

 

Now in your handler, you have to “handle” the specific type of event that has fired.

 

So let’s say I wrote my handler as follows:

 

    internal function sliderChange(event:StateChangeEvent) : void {

      var theSlider:Slider=Slider(event.currentTarget);

      foo.text = String(theSlider.value);

    }

 

THIS WILL NOT WORK AS I HAVE NOT USED THE RIGHT EVENT TYPE.

 

There are two ways to determine what type of event to put in your handler.

 

1)       put *something* and let the IDE tell you:

     “Error implicit coercion of a value of type mx.Events.SliderEvent to an unrelated type mx.Events.StateChangeEvent”

So, in this case, it’s telling you to use “SliderEvent”, not “StateChangeEvent”

2)       The second (preferred) way is to simply hover over the “event” part in your line:

<mx:HSlider id="mySlider" change="sliderChange(event)"/>

      *sometimes* a tooltip will appear telling you what event handler type to use

   3) A third way is to launch in debug mode, get an error and then you can hover over stuff and figure out what type of event handler to use:  See Screenshot:

 

 

One would think that this tells me the event type is SliderChange.

 

The actual event handler type is “SliderEvent”

 

The reason I am telling you all of this is that it is extremely frustrating to do some simply shit in the Flex IDE at the moment. Surely there must be a better way.

 

Anyway, moving on.

 

So now we have:

 

<mx:HSlider id="mySlider" change="sliderChange(event)"/>

 

And an event handler

    internal function sliderChange(event:SliderEvent) : void {

      trace(“sliderChange eventg fired”);

      var theSlider:Slider=Slider(event.currentTarget);

      foo.text = String(theSlider.value);

    }

By adding “trace” calls, when you run in debug mode, the text dumps to the console.

 

So, in this case, guess what?  This event does not fire until the user has released the thumbdrag handle!

 

So I try another event han dler

 

<mx:HSlider id="mySlider" currentStateChange="sliderStateChange(event)"/>

 

Notice I have to use a different handler because (you guessed it), the event fired is different.  So, going through the same agony as before, I determine that the event type being fired is, in fact, called “StateChangeEvent”. (Bascically by trying to run the app, letting it error out and reading the error message.

 

    internal function sliderStageChange(event:StateChangeEvent) : void {

      trace("sliderStageChange");

    }

 

Near as I can tell, this event does not fire.

 

So, thinking that it is not really the “slider” that is changing but the thumbdrag handle, I thought to add an event handler to that one as well:

 

Now, iteration #4:

 

        <mx:HSlider id="mySlider" thumbDrag="thumbDrag(event)" />

        <mx:Text id="foo" text="{mySlider.value}"/>           

 

And writing another event handler:

 

    internal function thumbDrag(event:SliderEvent) : void {

       trace("thumbDrag");

    }

 

 

I can see in my debug window that this is, in fact, the event that fires as you move the thumbDrag thingie around.

 

Therefore, I fix the event handler to read As follows:

    internal function thumbDrag(event:SliderEvent) : void {

       trace("thumbDrag");

      var theSlider:Slider=Slider(event.currentTarget);

      foo.text = String(theSlider.value);

    }

 

 

GUESS WHAT?  IT STILL DOESN’T WORK!

 

Turns out all you have to do is add “livedragging=”true” to the HSlider control and you do not have to write any event handlers.

 

 

So,

        <mx:HSlider id="mySlider" liveDragging="true"/>

        <mx:Text id="foo" text="{mySlider.value}"/>           

 

Does the trick..

 

 

Why do I tell you all about this?  So hopefully you can share in my pain and perhaps to learn something from my stupidity.

Flex is cool, but there is a pretty steep learning curve.

 

-shannon norrell

 

 

Wednesday, February 25, 2009

Fast JavaScript Max/Min on an Array Taking Arbitrary Number of Arguments

What's the fastest way to find the largest, or smallest, number in an array?

Array.max = function( array ){
return Math.max.apply( Math, array );
};
Array.min = function( array ){
return Math.min.apply( Math, array );
};

By using JavaScript's .apply() method on a built-in function you can pass in an array of unlimited arguments.

Shannon Norrell

Friday, September 5, 2008

Line 0 Object Required Internet Explorer Javascript error - aka the dangers of using CSS Expressions

One of my favorite mechanisms to do IE-specific CSS is to use the so-called dynamic properties available to IE5+ browsers. Firefox and Opera ignore these tags, so if, for instance you need a div of id "foo" to be 110 pixels in IE and 100 pixels in all other browsers, you would just do this:

#foo {
width: 100px;
width: expression('110px');
}

I spent the better part of the day trying to track down a Line 0. Object Required Javascript bug that, when hit, required me to close IE using Task Manager. I could not figure this one out and finally resorted to reconstructing the entire page, line-by-line until I found the problem.

I finally determined it occurred only when I added a <textarea> tag to the page. My current project is a Ruby on Rails app, which necessarily indludes the Prototype Library, so I initally wrote off this weirdity to the vagaries of Prototype and its many tens of thousands of lines of code.

In this context, an input type=text tag would do fine, so I switched to that and moved on.

Quite by accident, I stumbled across this section in my CSS file:

.WordBubble textarea {
overflow:hidden;
border:solid 1px lightBlue;
height:30px;
width:expression(document.getElementById('WordBubble').offsetWidth-66);
}

And WHALA, the answer!

Thinking to reuse a WordBalloon construct I had developed, I had modified this CSS to play off of .WordBubble the className vs the original #WordBubble the ID. Therefore, when I used the original:

<div id="WordBubble" class="WordBubble">
<textarea>
</div>

things worked as expected.

However, when using:

<div id="AnotherWordBubble" class="WordBubble">
<textarea>
</div>

The CSS, when evaluating the dynamic property, could not find "WordBubble" as it did not exist.

Although I realize this posting is somewhat confusing (I barely understand it myself), what I am trying to say is "When you get a Line 0, Object Expected" Javascript error and can't figure out where it comes from, check your CSS for Expression use.

Shannon

Tuesday, March 18, 2008

parseInt Bug in Firefox, IE6 and IE7

Quick Entry:

There is a bug in shipping versions of Internet Explorer and Firefox wherein if you attempt to use parseInt on a number with leading zeros, the value returned will be incorrect for "08" and for "09" due to the Javascript interpreter thinking these are, in fact, Octal numbers (and there being no "Octal" value greater than 7, the value returned is "0").

Try it.  Copy/Paste the following Javascript into your browser's url:

javascript:alert(parseInt("08"))

Anyway, a somewhat esoteric bug perhaps but it did cause an infinite loop today when I was attempting to scan over a date range where the dates were stored with leading zeroes.

The fix?

USE parseInt( var, 10) instead.

The second parameter ensures that the parseInt operation will be done using base10

Tuesday, March 11, 2008

fetchNVPValue - routine to extract a value from a querystring

There are probably more efficient - and more bullet-proof - ways to do this, but figured I had better capture this before I forgot that I wrote it.

Shannon Norrell

////////////////////////////////////////////////////////////////////////////////
//
// fetchNVPValue( string aNVPName, string aURL )
//           Extracts the value of a Named Value Pair (NVP) from a URL
//       eg: fetchNVPValue( "name", "http://mypage.com?id=123&name=Shannon&foo=bar" ) returns "Shannon"
//
////////////////////////////////////////////////////////////////////////////////
function fetchNVPValue( aNVPName, aURL ) {
  var retVal = "";
  var bItsInThereSomeWhere = (aURL.toLowerCase().indexOf(aNVPName) > -1);
  // If we have a URL, a name to look for and it's in there somewhere ...
  if ( aNVPName && aURL && bItsInThereSomeWhere ) {
    var theURL = aURL.toLowerCase().replace(/\+/g, ' ');    // Turn all '+' signs back into spaces, if applicable
    var args = theURL.split("&");
    for (var i=0;i<args.length;i++) {
      var nvp = args[i].split("="); // Break out each argument out into a NVP
      var name  = unescape(nvp[0]);
      if (name==aNVPName) {
        retVal = nvp[1];
        break;
      }
    }
  }
  // If we still haven't extracted it and it's in there somewhere, the Named value follows a "?" in the URL, rather than a &
  if (( retVal == "") && bItsInThereSomeWhere) {
    if (aURL.toLowerCase().indexOf("?" + aNVPName) > -1) {
      retVal = aURL.split("?")[1].split("=")[1];
    }
  }
  return retVal;
}