Wednesday, June 25, 2003

A Must have Mozilla Extension

PNH toolbar

Tuesday, June 10, 2003

Nice DHTML libraries


JavaScript: DHTML API,
Drag & Drop for Images and Layers


Javascript drawing library

Thursday, April 17, 2003

Forcing a file download

Everyone should know how to use cfcontent to get ColdFusion to dish up a file.

However, making the browser download it is often precarious. Many browsers have settings that tell them exactly how to handle a particular file. This is due to their mime-types.

Well, it was suggested earlier today, that to make the browser download a file, set the mime-type: "application/unknown". Presto! It forces the download.

Saturday, April 12, 2003

Some 'nifty' stuff

This site has some cool stuff: http://www.webweaver.org/dan/css/ I personally like the label on a checkmark makes the label clickable as well.

Wednesday, April 09, 2003

First (n-1) words in a string

This nifty little snippet will grab the first (n-1) words from a string and output them:

<cfset mystring = "Answeree(A) and Questioner(Q) agree that the work will lie solely with Q.A is not an agent of Q.A does not guarantee syntax & answers shall be delivered in psuedocode with intent for Q to RTFM and derive answers empiracally.##coldfusion reserves the right to slap Q with trouts, tampons & soggy objects. ##coldfusion are l33t bastages with good hearts & short on patience.">
<cfset x = REFind("([a-zA-Z.\(\)]*[[:space:]]){11}", myString, 1, true)>

<cfif ArrayLen(x.pos) EQ 2>
<cfoutput>#trim(Mid(myString, 1, x.pos[2]-1))#</cfoutput>
<cfelse>
<cfoutput>#myString#</cfoutput>
</cfif>


In this case, n = 11 . Therefore, it should show the first 10 words.

Wednesday, February 26, 2003

Search Engine Safe URLs in MX


URL formats that do not use the ? query string identifier result in page not found errors when using ColdFusion MX with either Microsoft IIS or Apache web servers. The problem is not evident when using the integrated ColdFusion MX web server, typically on port 8500.

Solution for Microsoft IIS web server

This is a known bug that was logged with Macromedia as a J-Run issue. As ColdFusion MX is built on J-Run the problem is now also evident in ColdFusion MX.

Add a servlet mapping to the web.xml file found in C:\CFusionMX\wwwroot\WEB-INF (for ColdFusion MX default installation).

<servlet-mapping>
<servlet-name>CfmServlet</servlet-name>
<url-pattern<*</url-pattern>
</servlet-mapping>

For additional information on this solution see
http://webforums.macromedia.com/coldfusion/messageview.cfm?catid=7&threadid=377954

Tuesday, February 11, 2003

Mozilla's Google toolbar

I might finally be able to use mozilla for real now.
mozdev.org - googlebar: index
The Googlebar project was initially created to address the widespread desire in the mozilla community for the Google toolbar to support Netscape 7/Mozilla, since many users of mozilla enjoy having all of Google's specialty searches in one convenient location. In the past, the Google toolbar was only available for IE on windows. While we are in no way affiliated with Google inc, our current release emulates all of the basic search functionality of the toolbar, allowing users to easily access a number of specialty searches from their browser, including: basic web search, site search, the "I'm Feeling Lucky" search, groups, directory, image search, and restricted searches in BSD, linux, Mac, Microsoft, catalog, news, and US government sites (some of which are not yet supported by the original Google toolbar!). Future plans call for the addition of support for highlighting all keywords, uninstall, and preference panel configurability for keyboard modifiers on a search, among other features (feel free to comment on our wishlist.

Neat Web tools

Porter's Workshop Yeah, it's a pretty bland-looking page, but it scores really high on the Doesn't-feel-like-sucking-a-pot-roast-through-a-garden-hose Bandwidth Scale. Please excuse any mess you run into; this is my development area, where I get to play. And I don't always put away my toys. Also, I make no guarantees as to what browsers support any of this.

Monday, February 10, 2003

Pure CSS

Welcome to the edge, css/edge

Noodle Incident CSS Designs


This is a Problem & Workaround Set for a series of CSS Boxes going from a simple single box, through 3 columns with a full width top box, all with variations.

Box lessons

Monday, February 03, 2003

XSL:FO - Formatting Objects

In MX, you can actually make use of formatting objects thanks to nice integration of Java.

Look at Apache's FOP for more information.

Javascript to limit text area size

Since there is no built in mechanism to limit text area sizes, this page tells you how to use javascript to do just that, limit text area.

Note: right-click paste gets around this script. You'll probably need to append an "onchange" event as well.

Sunday, February 02, 2003

CSS designs

This site as a list of 16 common site layouts and includes the bare CSS for each, Little Boxes

Inlined lists

Per djuggler's request, I figured out two ways to show inlined lists.

<style>
ul {
padding: 0px;
margin: 0px;
position: static;
display: inline;
width: 70px;
}
li {
padding: 0px;
top: 0px;
position: absolute;
display: inline;
}
</style>
this is <ul><li>choice1</li><li style="top:15px;">choice 2</li><li style="top:30px;">choice3</li></ul> this is fun

This is hardly a perfect method, but does have the desired effect.

Here's my second attempt, which basically uses an inline div:
<style>
div.list {
display: inline;
}
ul {
padding: 0px;
margin: 0px;
position: static;
width: 70px;
display:inline;
}
</style>
this is <ul><li>choice1</li><li style="top:15px;">choice 2</li><li style="top:30px;">choice3</li></ul> this is fun

Thursday, January 30, 2003

Looping over lists


I've discussed it before, but I'll do it again for giggles. Lists are not the most efficient data structure. They, more often then not, are better used if they are first converted to arrays.

However, sometimes its just better to use them and get them out of the way, like in the case of forms.

Here's a faster way, in script to loop through a list:
<cfscript>
tempList = yourlist;
while(len(tempList)){
    value = ListFirst(tempList);
    tempList = ListRest(tempList);
}
</cfscript>

CFC's done a better way

One of the most annoying things about CFC's is their inability to handle errors very well. In fact, a calling page may never realize an error was generated at all. However, that does not mean you have to live with it.

In fact, I propose that every method within a CFC be written only to return a structure. That structure contains three (perhaps more in the future) elements: .value, .error, and .message.

.value

The value portion returns what you would have normally returned anyway. That is, it can be a query, a number, string, etc. There are no restrictions on what gets returned in .value. If a method executes completely, value would contain what would have normally been returned.

If an error was generated, .value may contain some sort of return value or even, perhaps garbage.

.error

The error key is always of type boolean. This is a signalling mechanism for your CFC. It tells the calling page (or application) that the result contained within .value may actually be meaningless. This means that some sort of catch mechanism must be written into the application itself. For example:

x = yourCFC.method();
if (x.error){
writeOutput(x.message);
yourCFC.abort();
}
x = x.value;


This example moves us right into the third key.

.message

The message key basically returns error information. Most of my .messages, on error, return something "An error occurred in method(): #cfcatch.message". If a function was successful, however, I just simply supply the message: "Successfully executed method()".

Piece of cake.

To make things even easier, consider that you could probably make a private method that does the structure building for you:
<cffunction name="returnVal" access="private" hint="Returns a struct to the invoking page with the result and error information." output="no" returntype="struct">
<cfargument name="value" required="yes" type="any">
<cfargument name="message" required="no" default="success!" type="string">
<cfargument name="error" required="no" default="false" type="boolean">

<cfscript>
theStruct = structnew();
theStruct.error = arguments.error;
theStruct.message = arguments.message;
theStruct.value = arguments.value;
</cfscript>

<cfreturn theStruct>
</cffunction>


You can thus use the function to do the following: return returnVal(value);

Beer's rules for CSS versus Tables


  1. If it's part of the presentation, then there's no question: use CSS ** do not go on **

  2. If you are unsure of where to place <thead>, <tbody>, or <th> tags, you're probably not dealing with a table

  3. If it looks like a table, make it a table. (i.e. does tabular layout really matter?)

Saturday, January 11, 2003

Right-click - Command prompt here

Cmdhere.inf: Command Prompt Here This shell extension adds a CMD Prompt Here command to the context menu that is available when you right-click in the Folders (left) pane of Windows Explorer. Selecting this option from the context menu creates a new command-prompt session with the same path as that of the object that is right-clicked.

Saturday, January 04, 2003

CFMX Sleep...

I found this while I was actually looking for something else, ColdFusion, Java, and Web Development Blog
<cfset thread = CreateObject("java", "java.lang.Thread")>
About to sleep for 5 seconds...<cfflush>
<cfset thread.sleep(5000)>
Done sleeping.

Thursday, December 12, 2002

Shameless Promotion


A shameless ColdFusion site promotion, Book a hotel in Europe and the United Kingdom.

Monday, October 07, 2002

Dereferencing Queries by structures and arrays

I recently came across an instance when I really wanted to return a single row from a query. It made things just look nicer when it was wrapped up in a CFComponent.

So, to make it dynamic, I took advantage of the fact that I could get the column list from the original query (literally query.columnlist), and that I could use a query's array property to gather the row. In earlier versions, this method would have posed a huge problem. In part because #Evaluate("query.#column#[#row#]") throws an error. Of course, there has always been a way around it, query["column"][row], but I took this as an opportunity to explore whether or not MX had resolved the Evaluate problem. Indeed it had.

Here's my code for returning a row of a query, using the evaluate method:
<cfscript>
    q = QueryNew("id, name");
    temp = QueryAddRow(q, 1);
    temp = QuerySetCell(q, "id", "1");
    temp = QuerySetCell(q, "name", "Mike");
    temp = QueryAddRow(q, 1);
    temp = QuerySetCell(q, "id", "2");
    temp = QuerySetCell(q, "name", "Kevin");


    row = 2;

    ReturnQuery = QueryNew(q.columnlist);
    if (row LTE q.recordcount and row GT 0){
        temp = QueryAddRow(ReturnQuery, 1);
        for(i=1; i LTE listlen(q.columnlist); i = i + 1){
            item = ListGetAt(q.columnlist, i);
            temp = QuerySetCell(ReturnQuery, item, Evaluate("q.#item#[row]"), 1);
        }
    }
</cfscript>
<cfoutput query="ReturnQuery">
    #id# #name#
</cfoutput>

Great fun.

Here's the code as I have implemented as a Function:
<cffunction name="QueryRow" returntype="query" access="private">
    <cfargument name="q" type="query" required="yes">
    <cfargument name="row" type="numeric" required="no" default="1">

    <cfscript>
        ReturnQuery = QueryNew(arguments.q.columnlist);
        if (arguments.row LTE arguments.q.recordcount and row GT 0){
            temp = QueryAddRow(ReturnQuery, 1);
            for(i=1; i LTE listlen(arguments.q.columnlist); i = i + 1){
                item = ListGetAt(arguments.q.columnlist, i);
                temp = QuerySetCell(ReturnQuery, item, arguments.q.["#item#"][arguments.row], 1);
            }
        }
   
   
</cffunction>

CFScript Looping Faster than CFLOOP in CFMX

I did a test on my MX server, and unlike previous versions, CFMX's CFSCRIPT loop actually kicks 's butt in performance.

I ran the following code:
<cfset a = GetTickCount()>
<cfloop from="1" to="10000" index="i">
</cfloop>
<cfset b = GetTickCount()>
<cfscript>
c = GetTickCount();
for (i = 1; i LTE 10000; i = i+1) ;
d = GetTickCount();

</cfscript>

<cfoutput>#b-a# vs. #d-c#</cfoutput>


The CFSCRIPT code was, consistently, at least 3 times faster. Yay!

Undocumented CFMX code

ColdFusion MX Un-Documentation - undocumented features in ColdFusion MX
ColdFusion's Move to java has opened up a host of new possibilities, several of these possibilities are not documented.
Because all variables in ColdFusion are now Java Objects, we can use Java Reflection to find out hidden methods or functions.

Saturday, October 05, 2002

Using Flash Remoting with Google

flash Remoting with Google #include "NetServices.as"
#include "NetDebug.as"

//settings for google query
var params = new Object();
params.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXX"; //enter your own google key here
params.q = "Macromedia MX"; //this is the search term

//the rest are required, but you can leave them at their defaults
params.start = 0;
params.maxResults = 10;
params.filter = true;
params.restrict = "";
params.safesearch = true;
params.lr = "lang_en";
params.ie = "latin1";
params.oe = "latin1";


/* This object will be used to catch any responses from server / web service */
Result = function()
{
/*
onResult is called when data is loaded

data is a GoogleSearchResult object.
*/
this.onResult = function(data)
{
trace("Estimated Total Results : " data.estimatedTotalResultsCount);
trace("Search Time : " data.searchTime);

/* resultElements is ResultElementArray object containing ResultElement objects */
trace("Results : " data.resultElements);

/*
We can either pass the ResultElementArray to a component
*/
lBox.setDataProvider(data.resultElements);

/*
Or print out the search results one by one.

Here we just print the first result to the output window.
*/
trace("----------First Result Data --------");

var fResult = data.resultElements[0];
for(var x in fResult)
{
trace(x + " : " + fResult[x]);
}
}

/* onStatus is called if an error occurs */
this.onStatus = function(error)
{
trace("Error : " + error.description);
}
}

NetServices.setDefaultGatewayUrl("http://localhost:8500/flashservices/gateway/");
var gw = NetServices.createGatewayConnection();
var google = gw.GetService("http://localhost:8500/google/GoogleSearch.wsdl",new Result());

/* This is where the google web service is actually called */
google.doGoogleSearch(params);

Thursday, September 19, 2002

Really Good Javascript Browser Detection

This page has a very thorough browser detection script.Determining Browser Type and Version with JavaScript
// convert all characters to lowercase to simplify testing
var agt=navigator.userAgent.toLowerCase();

// *** BROWSER VERSION ***
// Note: On IE5, these return 4, so use is_ie5up to detect IE5.
var is_major = parseInt(navigator.appVersion);
var is_minor = parseFloat(navigator.appVersion);

// Note: Opera and WebTV spoof Navigator. We do strict client detection.
// If you want to allow spoofing, take out the tests for opera and webtv.
var is_nav = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
&& (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
&& (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
var is_nav2 = (is_nav && (is_major == 2));
var is_nav3 = (is_nav && (is_major == 3));
var is_nav4 = (is_nav && (is_major == 4));
var is_nav4up = (is_nav && (is_major >= 4));
var is_navonly = (is_nav && ((agt.indexOf(";nav") != -1) ||
(agt.indexOf("; nav") != -1)) );
var is_nav6 = (is_nav && (is_major == 5));
var is_nav6up = (is_nav && (is_major >= 5));
var is_gecko = (agt.indexOf('gecko') != -1);


var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
var is_ie3 = (is_ie && (is_major < 4));
var is_ie4 = (is_ie && (is_major == 4) && (agt.indexOf("msie 4")!=-1) );
var is_ie4up = (is_ie && (is_major >= 4));
var is_ie5 = (is_ie && (is_major == 4) && (agt.indexOf("msie 5.0")!=-1) );
var is_ie5_5 = (is_ie && (is_major == 4) && (agt.indexOf("msie 5.5") !=-1));
var is_ie5up = (is_ie && !is_ie3 && !is_ie4);
var is_ie5_5up =(is_ie && !is_ie3 && !is_ie4 && !is_ie5);
var is_ie6 = (is_ie && (is_major == 4) && (agt.indexOf("msie 6.")!=-1) );
var is_ie6up = (is_ie && !is_ie3 && !is_ie4 && !is_ie5 && !is_ie5_5);

// KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
// or if this is the first browser window opened. Thus the
// variables is_aol, is_aol3, and is_aol4 aren't 100% reliable.
var is_aol = (agt.indexOf("aol") != -1);
var is_aol3 = (is_aol && is_ie3);
var is_aol4 = (is_aol && is_ie4);
var is_aol5 = (agt.indexOf("aol 5") != -1);
var is_aol6 = (agt.indexOf("aol 6") != -1);

var is_opera = (agt.indexOf("opera") != -1);
var is_opera2 = (agt.indexOf("opera 2") != -1 || agt.indexOf("opera/2") != -1);
var is_opera3 = (agt.indexOf("opera 3") != -1 || agt.indexOf("opera/3") != -1);
var is_opera4 = (agt.indexOf("opera 4") != -1 || agt.indexOf("opera/4") != -1);
var is_opera5 = (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1);
var is_opera5up = (is_opera && !is_opera2 && !is_opera3 && !is_opera4);

var is_webtv = (agt.indexOf("webtv") != -1);

var is_TVNavigator = ((agt.indexOf("navio") != -1) || (agt.indexOf("navio_aoltv") != -1));
var is_AOLTV = is_TVNavigator;

var is_hotjava = (agt.indexOf("hotjava") != -1);
var is_hotjava3 = (is_hotjava && (is_major == 3));
var is_hotjava3up = (is_hotjava && (is_major >= 3));

// *** JAVASCRIPT VERSION CHECK ***
var is_js;
if (is_nav2 || is_ie3) is_js = 1.0;
else if (is_nav3) is_js = 1.1;
else if (is_opera5up) is_js = 1.3;
else if (is_opera) is_js = 1.1;
else if ((is_nav4 && (is_minor <= 4.05)) || is_ie4) is_js = 1.2;
else if ((is_nav4 && (is_minor > 4.05)) || is_ie5) is_js = 1.3;
else if (is_hotjava3up) is_js = 1.4;
else if (is_nav6 || is_gecko) is_js = 1.5;
// NOTE: In the future, update this code when newer versions of JS
// are released. For now, we try to provide some upward compatibility
// so that future versions of Nav and IE will show they are at
// *least* JS 1.x capable. Always check for JS version compatibility
// with > or >=.
else if (is_nav6up) is_js = 1.5;
// NOTE: ie5up on mac is 1.4
else if (is_ie5up) is_js = 1.3

// HACK: no idea for other browsers; always check for JS version with > or >=
else is_js = 0.0;

// *** PLATFORM ***
var is_win = ( (agt.indexOf("win")!=-1) || (agt.indexOf("16bit")!=-1) );
// NOTE: On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all
// Win32, so you can't distinguish between Win95 and WinNT.
var is_win95 = ((agt.indexOf("win95")!=-1) || (agt.indexOf("windows 95")!=-1));

// is this a 16 bit compiled version?
var is_win16 = ((agt.indexOf("win16")!=-1) ||
(agt.indexOf("16bit")!=-1) || (agt.indexOf("windows 3.1")!=-1) ||
(agt.indexOf("windows 16-bit")!=-1) );

var is_win31 = ((agt.indexOf("windows 3.1")!=-1) || (agt.indexOf("win16")!=-1) ||
(agt.indexOf("windows 16-bit")!=-1));

var is_winme = ((agt.indexOf("win 9x 4.90")!=-1));
var is_win2k = ((agt.indexOf("windows nt 5.0")!=-1));

// NOTE: Reliable detection of Win98 may not be possible. It appears that:
// - On Nav 4.x and before you'll get plain "Windows" in userAgent.
// - On Mercury client, the 32-bit version will return "Win98", but
// the 16-bit version running on Win98 will still return "Win95".
var is_win98 = ((agt.indexOf("win98")!=-1) || (agt.indexOf("windows 98")!=-1));
var is_winnt = ((agt.indexOf("winnt")!=-1) || (agt.indexOf("windows nt")!=-1));
var is_win32 = (is_win95 || is_winnt || is_win98 ||
((is_major >= 4) && (navigator.platform == "Win32")) ||
(agt.indexOf("win32")!=-1) || (agt.indexOf("32bit")!=-1));

var is_os2 = ((agt.indexOf("os/2")!=-1) ||
(navigator.appVersion.indexOf("OS/2")!=-1) ||
(agt.indexOf("ibm-webexplorer")!=-1));

var is_mac = (agt.indexOf("mac")!=-1);
// hack ie5 js version for mac
if (is_mac && is_ie5up) is_js = 1.4;
var is_mac68k = (is_mac && ((agt.indexOf("68k")!=-1) ||
(agt.indexOf("68000")!=-1)));
var is_macppc = (is_mac && ((agt.indexOf("ppc")!=-1) ||
(agt.indexOf("powerpc")!=-1)));

var is_sun = (agt.indexOf("sunos")!=-1);
var is_sun4 = (agt.indexOf("sunos 4")!=-1);
var is_sun5 = (agt.indexOf("sunos 5")!=-1);
var is_suni86= (is_sun && (agt.indexOf("i86")!=-1));
var is_irix = (agt.indexOf("irix") !=-1); // SGI
var is_irix5 = (agt.indexOf("irix 5") !=-1);
var is_irix6 = ((agt.indexOf("irix 6") !=-1) || (agt.indexOf("irix6") !=-1));
var is_hpux = (agt.indexOf("hp-ux")!=-1);
var is_hpux9 = (is_hpux && (agt.indexOf("09.")!=-1));
var is_hpux10= (is_hpux && (agt.indexOf("10.")!=-1));
var is_aix = (agt.indexOf("aix") !=-1); // IBM
var is_aix1 = (agt.indexOf("aix 1") !=-1);
var is_aix2 = (agt.indexOf("aix 2") !=-1);
var is_aix3 = (agt.indexOf("aix 3") !=-1);
var is_aix4 = (agt.indexOf("aix 4") !=-1);
var is_linux = (agt.indexOf("inux")!=-1);
var is_sco = (agt.indexOf("sco")!=-1) || (agt.indexOf("unix_sv")!=-1);
var is_unixware = (agt.indexOf("unix_system_v")!=-1);
var is_mpras = (agt.indexOf("ncr")!=-1);
var is_reliant = (agt.indexOf("reliantunix")!=-1);
var is_dec = ((agt.indexOf("dec")!=-1) || (agt.indexOf("osf1")!=-1) ||
(agt.indexOf("dec_alpha")!=-1) || (agt.indexOf("alphaserver")!=-1) ||
(agt.indexOf("ultrix")!=-1) || (agt.indexOf("alphastation")!=-1));
var is_sinix = (agt.indexOf("sinix")!=-1);
var is_freebsd = (agt.indexOf("freebsd")!=-1);
var is_bsd = (agt.indexOf("bsd")!=-1);
var is_unix = ((agt.indexOf("x11")!=-1) || is_sun || is_irix || is_hpux ||
is_sco ||is_unixware || is_mpras || is_reliant ||
is_dec || is_sinix || is_aix || is_linux || is_bsd || is_freebsd);

var is_vms = ((agt.indexOf("vax")!=-1) || (agt.indexOf("openvms")!=-1));

Wednesday, August 28, 2002

ColdFusion Structure to XML

There isn't a very good way to turn a structure into its xml equivalent.

So I wrote a simple, recursive UDF to do it. Simply pass this function the structure and whether or not you want the header information included.

This is a highly modified version of a UDF found on CFLIB that only allowed basic structures:
<cfscript>

// This is a recursive function

function StructToXML(structHandle){
      var includeXMLHeader = 1;
      var depth = 1;
      var padding = chr(9);
      var output = '';
      if(arrayLen(arguments) gte 2)
            includeXMLHeader = arguments[2];
      if(arrayLen(arguments) gte 3)
            padding = arguments[3];
      if(arrayLen(arguments) EQ 4)
            depth = arguments[4];

      if(isStruct(structHandle)){
            //if struct is a form handle, reduce clutter
            if(structkeyexists(structHandle,'fieldnames') ){
                  fieldnames= StructFind(structHandle,'fieldnames');
                  StructDelete(structHandle, 'fieldnames',0);
      }
      if(includeXMLHeader){output = "" & chr(13)& chr(10);}
      for(thisKey in structHandle){
            thisKey=lcase(thisKey);
            if(IsStruct(structHandle[thisKey])){
                  "key#depth#"=trim(thiskey);
                  output = output & "<" & Evaluate("key#depth#") & ">" & chr(13)& chr(10) & StructToXML(structHandle[thisKey], false, padding&chr(9), depth+1) & "" & chr(13)& chr(10);
            }
            else{
                  safeVal=XMLFormat(structHandle[thiskey]);
                  output = output & padding & "<#Trim(thisKey)#>#trim(safeVal)#" & chr(13)& chr(10);
            }
      }
      if(includeXMLHeader){output = output & "
";
      }
      return output;
      }else return '';
}
</cfscript>

Friday, July 26, 2002

Grabbing the Text Between to Strings

I was looking for a simple way to grab all the text between two tags (in the case it was <b></b>).

And because this was a fairly simple task, wasting execution time on REGEX was unnecessary.

And, instead of writing a closed function to work with only one kind of tag, I made it a general function that will return the contents between any two strings (not necessarily HTML tags):

    function stripInBetween(tagA, tagB, string, pos){
        start = FindNoCase(tagA, string, pos);
        stop = FindNoCase(tagB, string, start+(len(tagA)));

        toReturn = StructNew();
        if (Not (start AND stop)){
            toReturn.found = false;
            toReturn.start = 0;
            toReturn.stop = 0;
            toReturn.string = "";
        }else{
            start = start + +len(tagA);
            toReturn.found = true;
            toReturn.string = Mid(string, start, stop-start);
            toReturn.start = start;
            toReturn.stop = stop;
        }
        return toReturn;
    }

This function returns a structure containing the a flag about whether or not it was found, the start position, the stop position, and the text in between the two tags.

Easy enough to use.

Wednesday, July 24, 2002

Even More Javascript: List to DropDown Options

This little snippet is handy for two reasons:
1) It shows you formally how to take a list and create options for your dropdown
2) It shows a very good way to loop over lists in Javascript

So, enough jibber-jabber, here's the code:
<script language="javascript"> function appendToDropDown(item, dropdown){
if (item.length != 0)
dropdown[dropdown.options.length] = new Option('');
dropdown[dropdown.options.length-1].value = item;
dropdown[dropdown.options.length-1].text = item;
}

function appendListToDropDown(list, dropdown, delimiter){

pos_old = 0;
pos = 0;
while ( (pos = list.indexOf(delimiter, pos)) != -1){

pos += delimiter.length;
new_item = list.substr(pos_old, pos-(pos_old+(delimiter.length)));
pos_old = pos;
appendToDropDown(new_item, dropdown);
}
new_item = list.substr(pos_old, list.length);
appendToDropDown(new_item, dropdown);

}

</script><form name="myform">
<input type="text" name="myTextField"><input type="button" value="add list to dropdown" onclick="javascript:appendListToDropDown(document.myform.myTextField.value, document.myform.mySelectBox, ', ');"><br>
<select name="mySelectBox"></select></form>

Notice again that this code allows you to specify your own delimiter. It might be handy to use just spaces, or a less common character delimiter.

It would also be possible to use '\n' and a textarea to add individual lines to a select box. Anything is possible.

One interesting line, at least I find it interesting, is the while statement. This actually combines an assignment and a comparison in the same line. Although, this looks complex, it simply gets the next occurrence of a string, stores it into pos, and then checks to make sure pos is a for real value.

The substr() function allows me to grab everything between the previous delimiter (or the start) and the current delimiter (or possibly the end of the string).

More Javascript: Fun with Dropdowns

Here's a couple functions that will help you learn to use Drop Down boxes.

These first two functions have the same effect, build a list (in another field) or values from a drop down box:
<script language="javascript">
function ListAppend(field, item){
if (field.value.length == 0)
field.value = item;
else
field.value = field.value + ', ' + item;
}
function ListAppend(field, item, delimiter){
if (field.value.length == 0)
field.value = item;
else
field.value = field.value + delimiter + item;
}
<script>
<select name="mySelectBox" onchange="javascript:ListAppend(document.myform.myTextField, this.options[this.selectedIndex].value);">

This function is called on the "onchange" portion of the select field. It basically passes a text field and the currently selected value to one of two function, depending on the number of attributes.

The first function (without delimiter) automagically appends an item to a list using a hard coded delimiter. The second allows a programmer to specify the delimiter as part of the javascript.

The following function does virtually the opposite: take a value from a text box and add it to the drop down box:
><script language="javascript">function appendToDropDown(item, dropdown){
if (item.length != 0)
dropdown[dropdown.options.length] = new Option('');
dropdown[dropdown.options.length-1].value = item;
dropdown[dropdown.options.length-1].text = item;
}
</script>
<input type="button" value="add list to dropdown" onclick="javascript:appendToDropDown(document.myform.myTextField.value, document.myform.mySelectBox);">

As you can see, it passes a text field's value (or any string for that matter) and the location of a select box. The code the creates another "option" tag and appends the new information.

Fun, isn't it?

Monday, July 22, 2002

Javascript With Checkboxes

An interesting thing about javascript is how it deals with checkboxes. Normally, with many like-named checkboxes, it creates an array. This makes dealing with them fairly simple. However, in the event of only a single checkbox of a particular name, it does not recognize the checkbox as an array.

As we, ColdFusion programmers, are big on dynamic pages, this bit of code will create an array, when appropriate, for checkboxes.

<form name="test">
    <input type="Checkbox" name="hi" value="blah blah">
    <input type="Checkbox" name="hi">
</form>
<script language="javascript">
    if (document.test.hi.length)
        k = document.test.hi;
    else{
        k = new Array(1);
        k[0] = document.test.hi;
    }
</script>

All the checkboxes are from there on available via k[index]. You can also use all the array functions now too.

Friday, July 19, 2002

Understanding Error 500 with CFMX

Macromedia has dropped returning 200 OK messages when errors are thrown. So now they are following standardized rules by throwing 500 errors, however, as such, there is definitely a problem reporting errors back to a developer.

Basically, this is going to force everyone to be much better at using CFTRY and CFCATCH.

Wednesday, July 10, 2002

From Time To Seconds and Back

These two function are extensions of the limited Time functions in ColdFusion. The first takes seconds and return Hours, Minutes and Seconds. The second takes Hours, Minutes and Seconds and just returns the number of seconds.
<cfscript>
    function fromSecondsToTime(seconds){
        hours = int(seconds / 60 / 60);
        minutes = int( ( seconds - ( hours * 3600 ) ) / 60);
        seconds = ( seconds - ( hours * 3600 ) - ( minutes * 60 ) );
        return hours & ":" & minutes & ":" & seconds;
    }
    function getSecondsFromTime(time){
        seconds = DatePart('H', time)*60*60;
        seconds = seconds + DatePart('N',time)*60;
        seconds = seconds + DatePart('S', time);
        return seconds;
    }</cfscript>
<cfset x = now()>
<cfset y = getSecondsFromTime(TimeFormat(x, 'HH:MM:SS'))>
<cfoutput>#x# #y#
#fromSecondsToTime(y)#</cfoutput>

Changing CFMX's debugging template


I found the file which lets you optimize your "classic" debugging output. Check out this file: CFMX_Install_Directory\wwwroot\web-inf\debug\classic.cfm

Hope that helps.

Tuesday, June 25, 2002

A Better "DateAdd" Function

Let's face it, DateAdd sucks when it comes to adding more than just one date or time element. The code ends up getting strung out in a series of DateAdds.

My solution, write a UDF to do it for me.
<cfscript>
function TimeAdd(hours, minutes, seconds, usedate){
complete_time = DateAdd('H', hours, usedate);
complete_time = DateAdd('N', minutes, complete_time);
complete_time = DateAdd('S', seconds, complete_time);
return complete_time;
}
function DAdd(years, months, days, usedate){
complete_time = DateAdd('Y', years, usedate);
complete_time = DateAdd('M', months, complete_time);
complete_time = DateAdd('D', days, complete_time);
return complete_time;
}
</cfscript>


The two above function perform 4 parameter Time Additions and Date Additions. I broke them out simply because it seems to be the case that I am only do "time operations" or "day operations." To use, for example, the Time add:
<cfoutput>#TimeAdd(2,4, 0, Now())#</cfoutput>


Thursday, June 06, 2002

Alternate Version for Alternating Row Colors

Although the aforementioned version works, it actually needlessly consumes extra lines. Granted, the below version is a step up from many other forms and it is very, very easy to read, but it is still not the best.

This code here, is actually, the shortest one yet:
<cfoutput query="dummy">
    <tr><td class="row#Iif(((CurrentRow MOD 2)),de('_alt'),de(''))#">#query_column#</td></tr>
</cfoutput>


The above code requires that a style sheet be set with two different styles: row and row_alt. This is a classic inliner.