Thursday, June 22, 2006

This JavaScript Code will cycle through all elements on a page and find the next one that should recieve the focus.  This worked well in IE6 but the results in FireFox where mixed.  I don't have time right now to clean it up but I wanted to post it as this is one of those gems that you know you will want in the future.

Original Source: http://www.codecomments.com/message290822.html

Original Author: Daniel Kirsch

// returns the next focusable object for a given one
function getNextFocusElement(elm,restart,dir,_looped) {
var allElm = document.getElementsByTagName('*');
var found = false; //(start == true);
var allowedElements = 'input,textarea,a,button';
if (!dir) dir = 1;
var start = dir > 0 ? 0 : allElm.length-1;
var end = dir > 0 ? allElm.length : -1;
jslog.info('start: ' + start + ' end: ' + end);

for (var i=start; i!=end; i+=dir) {
if (!found) {
if (allElm[i] == elm) {
if (_looped) return null;
found = true;
jslog.info('i: ' + i );
continue;
}
}
if (found || (restart && _looped)) {
if (allElm[i].focus && allElm[i] != elm) {
if (isInList(allElm[i].nodeName.toLowerCase(),allowedElements)
&& isVisible(allElm[i]))
jslog.info('i: ' + i);
return allElm[i];
}
}
}
jslog.info('starting next loop...');
return (_looped) ? null : getNextFocusElement(elm,true,dir,true);

}

function isVisible(elm) {
if (elm.style.visibility == 'hidden' || elm.style.display == 'none')
return false
else
return elm.parentNode && elm.parentNode.style ?
isVisible(elm.parentNode) : true;

}

function isInList(aItem,aList,aSep,aCaseSensitive) {
if (typeof aItem == 'undefined' || typeof aList == 'undefined')
return false;

// make sure, the element is a string.
aItem = String(aItem);
if (aCaseSensitive !== true && typeof aItem == 'string') {
if (typeof aList == 'string')
aList = aList.toLowerCase();
aItem = aItem.toLowerCase();
}
if (!aSep) aSep = ',';
var lString = aSep+aList+aSep;
return (lString.indexOf(aSep+aItem+aSep) > -1);

}

Thursday, June 22, 2006 1:19:21 PM (Central Standard Time, UTC-06:00)  #    Comments [1]

A new contender for the Pragmatic Toolkit is PDFCreator, a SourceForge project which allows you to print to a pdf file much like you would a normal printer.  This is useful if you want to need to capture output to a platform inpependant format.  For example, you have a web page that shows a reciept from an online purchase.  Use PDFCreator to print it to a PDF so you have a nice record of the purchase.  This also works for screen prints or any other capture operations where you have an applications that can print (basically any editor program like Word, StarOffice, PaintShop Pro, Photo Shop, etc). 

I use it to screen capture protected web pages (on sites where you need to sign in) and send it to someone who doesn't have access to the site, like my wife.  It's useful if you are going for a paperless office as you could scan your paper items and then print them to PDF (if your scanning software doesn't support it natively).  You can also create product documentation by creating the document in Word and then printing it to PDF to create a manual for distribution to customers.

Here is the link:

http://sourceforge.net/projects/pdfcreator/

Thursday, June 22, 2006 10:10:39 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Monday, June 19, 2006

Do you want to limit the imput of a text input (textbox) to valid date characters?  Here you go:

// START SCRIPT

function runKeyFilter(e) {
 if (e.srcElement.readOnly) return;

 var key_code = e.keyCode;
 var oElement = e.srcElement;
 //alert (key_code);

 try {
  if (!window.event.shiftKey && !window.event.ctrlKey && !window.event.altKey) {
   if (
     (key_code > 47 && key_code < 58) ||  // numbers on top of keyboard
     (key_code > 95 && key_code < 106)  ||  // number on numpad at right of keyboard
     (key_code > 36 && key_code < 41) ||  // arrow keys
     (key_code == 35) || // end
     (key_code == 36) || // home
     (key_code == 45) || // dashes
     (key_code == 111) || // forward slash /
     (key_code == 191) || // forward slash /                      
     (key_code == 8) || // backspace
     (key_code == 46) || // delete
     (key_code == 9) || // tab
     (key_code == 16) //SHIFT TAB
      )
   {
    e.returnValue = true;
    return;
   }      
  } 
 }
 catch (ex) {
  alert('Error Message: ' + ex.message );
 
 }
 // if we get here then we didn't have a number
 e.returnValue = false;

}  // end runKeyFilter()

//using the helper functions from prototype.js
Event.observe('|CONTROL|', 'keydown', runKeyFilter, false);  

// END SCRIPT

Monday, June 19, 2006 1:22:50 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, June 15, 2006

I've had to go look for this more then once so here it is:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SchedulingAgent

MaxLogSizeKB - This is max size of the log in kilobytes (duh).  Make sure you edit this using Decimal values.  The default in Windows 2000 is hexadecimal. 

Default - Notice I changed the Base to Decimal in order to edit the value correctly:

Changed to reflect a 1 MB (1024KB) size:

You can also change other values like the location of the log (LogPath) but MaxLogSizeKB is the only one I've needed to change on almost every computer.

The task scheduler log file (located by default here at %SystemRoot%\SchedLgU.Txt) keeps track of the start and finish times of all scheduled tasks.  We use the task scheduler to run almost all of our services and batch processed simply because it is ubiquitous and reliable.  However, the 32k limit is a pain as a busy scheduler will quickly fill this up and the log will begin to overwrite itself.  You'll get one of these things:
[ ***** Most recent entry is above this line ***** ]

to indicate where the latest entry is.  I've found that with our schedule it overwrites itself within an hour or so.  Your mileage may vary but with today's huge harddrives it's often beneficial to trade a small amount of space for a large amount of history.  Keep in mind thought that this does open with notepad.exe to if it gets too large notepad may choke. 

You may also want to check out my article on using the task sceduler as a poor man's Windows Service:

 http://www.pragmaticprose.com/PermaLink,guid,5cc361e3-3940-43d9-8591-fb6f5dd00036.aspx

Thursday, June 15, 2006 2:40:18 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, June 09, 2006
I do a lot of web development.  Unfortunetely at work all the folks out on the floor have Internet Exploder oops I mean Explorer.  So I do most of my testing in IE6.  The problem comes in as we start to do more DHMTL (AJAX) on our sites.  Ofter you need to view source to see what is rendered.  Well of course IE just gives you little old notepad and calls it good.  Firefox does a better job by at least highlighting syntax.  Well, I've found a good solution for IE.

Notepad++.  Two big bonuses here.  Excellant syntax highlighting and code folding.  Code folding is the ability to expand and contract sections of code so it's out of your way when you don't want to look at it.  The syntax hightlighting is great plus Notepad++ is one great editor in general.  I use it for heavy duty JavaScript development because of the code folding and the lings that line up the beginning and ending tags and code blocks. 

Give it a try.  http://notepad-plus.sourceforge.net/uk/site.htm

I believe it promts you on the install to act as the view source client for IE.


Friday, June 09, 2006 10:53:26 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
If Jerry Seinfeld were a programmer he might ask "What's the deal with configuration files having to be in XML format?".  I just find them to be incredibly hard to read and decipher.  The problem with XML is that it's just so verbose.

Java has property files which may or may not be berrer. Ruby on Rails using YAML files.  These seem fairly reasonable.  One thing an XML file does however is let you show relationships and nesting of data.  So does the complexity of .NET require that the configuration files are also complex?  The configuration file seems to be a collection of serialized objects spat out at random into a file.  Is it a result of the everything must be XML crusades at the turn of the century?  Could the files be simplified?  Could we have seperate config files for seperate concerns.  Example, I go into the config file to change a setting and I typo.  My whole site (or server) goes down.  Is this expected behavior? 

So does the nature of .NET itself demand XML configuration or is this laziness on the programmers part to simply allow them to deserialize the configuration settings in the most convenient way (for them) possible? 

 |  | 
Friday, June 09, 2006 10:43:29 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, June 08, 2006

IF you have a server to monitor that has many different applications, for instance an intranet server, and you want one error logging/reporting solution to rule them all then you've come to the right place.  It took me forever to find this information so I'm going to explain it. 

ASP.NET 2.0 comes with a feature called health monitoring (healthMonitoring).  This feature allows us to configure the monitoring and reporting of information related to ASP.NET.  Almost anything useful can be monitored but I was most concerned about handling server wide exceptions in a consistent manner.  Of course you should handle all errors/exceptions in each application if possible but sometimes this gets overlooked.  In Classic ASP we would route the errors (500's) to a certain page and capture them with the Server.GetLastError which worked just fine in Classic ASP.  However, in ASP.NET this doesn't work so well.  You lose the exception when you transfer to another application.  So you either have to store the exception somewhere by using the application_error or use a solution involving health monitoring.  I chose the latter as a blanket solution just in case anything got through the cracks in an individual application.  I've included a file that will help you set this up. If you want server wide coverage then these settings need to go into the web.config located at C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\.  Once you apply these settings you should be able to receive emails and log events to the event log.  You can also set up a SQL provider that will log events to an SQL database instead. 

The important things to look at in the file is the mailSettings tag under the system.net group.  This sets up your SMTP server. 

Next you want to check out the settings in the healthMonitoring section.  This should give you a good idea how to set your server up.  I've noticed that the MSDN examples and documentation is riddled with errors and inconsistencies.  I don't know why they aren't shouting this stuff from the rooftops as it makes application and server administration so much easier.

I've attached the web.config file (web.config.txt (31.22 KB)) to this post.  Here are the relevant sections:

Setting up your SMTP server:

    <system.net>

       <defaultProxy>

            <proxy usesystemdefault="true" />

        </defaultProxy>

      <mailSettings>

        <smtp >

          <network

            defaultCredentials="true"

            host="EMAIL-SERVER-NAME-OR-IP"

           />

        </smtp>

      </mailSettings>

    </system.net>

Health Monitoring (Notice that we add a provider named CriticalMailEventProvider and have the All Errors Default rule use this provider):

<healthMonitoring enabled="true" heartbeatInterval="0">

            <bufferModes>

                <add name="Critical Notification" maxBufferSize="100" maxFlushSize="20"

                    urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:01:00"

                    maxBufferThreads="1" />

                <add name="Notification" maxBufferSize="300" maxFlushSize="20"

                    urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:01:00"

                    maxBufferThreads="1" />

                <add name="Analysis" maxBufferSize="1000" maxFlushSize="100"

                    urgentFlushThreshold="100" regularFlushInterval="00:05:00"

                    urgentFlushInterval="00:01:00" maxBufferThreads="1" />

                <add name="Logging" maxBufferSize="1000" maxFlushSize="200" urgentFlushThreshold="800"

                    regularFlushInterval="00:30:00" urgentFlushInterval="00:05:00"

                    maxBufferThreads="1" />

            </bufferModes>

 

            <providers>

                <add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />

                <add connectionStringName="LocalSqlServer" maxEventDetailsLength="1073741823"

                    buffer="false" bufferMode="Notification" name="SqlWebEventProvider"

                    type="System.Web.Management.SqlWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />

                <add name="WmiWebEventProvider" type="System.Web.Management.WmiWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />

             

                <add name="CriticalMailEventProvider"

                  type="System.Web.Management.SimpleMailWebEventProvider"

                  from="CHANGME@PRAGMATICLABS.COM"

                  to="CHANGME@PRAGMATICLABS.COM"

                  bodyHeader="Warning!"

                  bodyFooter="Please investigate ASAP."

                  subjectPrefix="Intranet Error "

                  buffer="true"

                  bufferMode="Critical Notification"

                  maxEventLength="4096"

                  maxMessagesPerNotification="1"

              />

         

            </providers>

 

            <profiles>

                <add name="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00"

                    custom="" />

                <add name="Critical" minInstances="1" maxLimit="Infinite" minInterval="00:00:00"

                    custom="" />

            </profiles>

 

            <rules>

                <add name="All Errors Event Log" eventName="All Errors" provider="EventLogProvider"

                    profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00"

                    custom="" />

                <add name="All Errors Default" eventName="All Errors" provider="CriticalMailEventProvider"

                  profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00"

                  custom="" />

                <add name="Failure Audits Default" eventName="Failure Audits"

                    provider="EventLogProvider" profile="Default" minInstances="1"

                    maxLimit="Infinite" minInterval="00:01:00" custom="" />

               

            </rules>

 

            <eventMappings>

                <add name="All Events" type="System.Web.Management.WebBaseEvent,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"

                    startEventCode="0" endEventCode="2147483647" />

                <add name="Heartbeats" type="System.Web.Management.WebHeartbeatEvent,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"

                    startEventCode="0" endEventCode="2147483647" />

                <add name="Application Lifetime Events" type="System.Web.Management.WebApplicationLifetimeEvent,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"

                    startEventCode="0" endEventCode="2147483647" />

                <add name="Request Processing Events" type="System.Web.Management.WebRequestEvent,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"

                    startEventCode="0" endEventCode="2147483647" />

                <add name="All Errors"