Designing the Moment

Cover of Designing the Moment by Rober Hoekman, Jr.

I've finished reading Designing the Moment byRobert Hoekman, Jr., and it was an excellent book to follow up Web Design for ROI. I'd read Robert's other book, Designing the Obvious as well, and this book is no less impressive. Since I spend most of my time in back-end developer land, its awesome to read books which offer not only great advice, but great advice that says that the user experience flows from the beginning to the end of the project; its not the job of just a front end developer or designer.

Check it out for great advice on how to analyze your apps to make them more usable, and thus increase conversions.

 

BlogCFC Tweaks: Easier Category Selection

I've talked about it before, but I find classic multi-selects in HTML to be really hard to use. You invariably have to end up putting some explanation text to let a user know how to select more then one, and its easy to clear your selections everything while trying to select an additional item. I put these ideas into practice in BlogCFC to help with category selection. I replaced the following code in admin/entry.cfm starting at line 391:

<cfif allCats.recordCount>
    <select name="categories" multiple size=4 class="txtDropdown">
    <cfloop query="allCats">
        <option value="#categoryID#" <cfif isDefined("form.categories") and listFind(form.categories,categoryID)>selected</cfif>>#categoryName#</option>
    </cfloop>
    </select><br>
</cfif>

With this code:

<cfif allCats.recordCount>
    <ul class="multiselect">
        <cfloop query="allCats">
            <li><input id="cat_#categoryID#" type="checkbox" name="categories" value="#categoryID#"<cfif isDefined("form.categories") and listFind(form.categories,categoryID)> checked="checked"</cfif>/><label for="cat_#categoryID#">#categoryName#</label></li>
        </cfloop>
    </ul>
</cfif>

I also added the following code the admin style sheet ( /includes/admin.css ):


ul.multiselect {
    height: 100px;
    width: 225px;
    border: 1px solid silver;
    list-style-type: none;
    padding-left: 3px;
    overflow: auto;
}
ul.multiselect li label {
    display: inline;
    padding-left: 2px;
}

That makes it a lot easier to keep track of categories without messing something up.

 

Utility Function: PermanentRedirect()

I really can't take any credit for this one. The idea and the core code come from Pete Freitag's blog post "What CFLOCATION Does". Its probably not even original to wrap it in a function, but here it is any way.


<cffunction name="PermanentRedirect" output="false" returntype="void">
    <cfargument name="url" type="string" required="false" />
    
    <cfheader statuscode="301" statustext="Moved Permanently" />
    <cfheader name="Location" value="#arguments.url#" />
    
    <cfabort />
    
    <cfreturn />
</cffunction>

 

Utility Function: ArrayElementIsDefined()

The other day I was trying to be clever and use a multi dimensional array as a kind of look up table for cached results based on two values. For example:


<cfset array = ArrayNew(2) />

<cfif NOT (ArrayIsDefined(array, x) AND NOT ArrayIsDefined(array[x], y))>
<cfset array[x][y] = someFunction(x, y) />
</cfif>

<cfset result = array[x][y] />

And what did I discover? The system bulks and throws an error... apparently even though ArrayIsDefined() is supposed to tell you if values exist in an array, it can't do that until at least 1 value has entered the array.

While I could have just done something like set array[1][1] = 0, it wouldn't have been quite right (what if x and y are 1 for real?), and it didn't sit right with me that ArrayIsDefined() didn't work in this situation. Here is my stand in for ArrayIsDefined().


<cffunction name="ArrayElementIsDefined" output="false" returntype="boolean">
    <cfargument name="array" type="array" required="true" />
    <cfargument name="index" type="numeric" required="true" />
    
    <cfset var returnValue = false />
    
    <cftry>
        <cfset returnValue = ArrayIsDefined(arguments.array, arguments.index) />
        
        <cfcatch type="any">
            <!--- Do nothing, the return value is already false --->
        </cfcatch>
    </cftry>
    
    <cfreturn returnValue />
</cffunction>

 

BlogCFC Tweaks: Post Releaser Scheduled Task

I've been slowly accumulating a few tweaks to BlogCFC that make my life a little easier. The first is a schedule task I created to help me with my problem of writing 10 posts one day, but then none for a week.


<cfquery name="qryEntries" datasource="myblogds">
    SELECT TOP 1 id
    FROM tblBlogEntries
    WHERE blog = 'myblogname'
    AND released = 0
    ORDER BY posted ASC
</cfquery>

<cfif qryEntries.recordCount>
    <cfquery name="qryUpdateEntries" datasource="myblogds">
        UPDATE tblBlogEntries
        SET released = 1,
            posted = GETDATE()
        WHERE id = <cfqueryparam value="#qryEntries.id#" cfsqltype="cf_sql_varchar" />
    </cfquery>
</cfif>

I set this up to run once a day, fairly early in the morning. With this setup, all I have to do is make sure that I mark my posts as not released, and they will be parceled out one at a time to help keep my blog fresh.

 

Utility Function: DirectoryCopy()

I was kind of surprized when I found that ColdFusion has no built in ability to recursively copy the contents of a whole directory. In order to do that, I whipped up this function.


<cffunction name="DirectoryCopy" access="public" output="false" returntype="void">
    <cfargument name="source" type="string" required="true" />
    <cfargument name="destination" type="string" required="true" />
    
    <cfset var local = StructNew() />
    
    <!--- Get the contents of this directory --->
    <cfdirectory action="list" directory="#arguments.source#" name="local.contents" />
    
    <!--- If the destination doesn't exist, create it --->
    <cfif NOT DirectoryExists(arguments.destination)>
        <cfdirectory action="create" directory="#arguments.destination#" />
    </cfif>
    
    <!--- loop over everything in the directory --->
    <cfloop query="local.contents">
        <!--- Figure out source and desitnation --->
        <cfset local.destination = "#arguments.destination#\#local.contents.name#" />
        <cfset local.source = "#arguments.source#\#local.contents.name#" />
        
        <!--- If this is a folder, call this on that folder --->
        <cfif local.contents.type eq "dir">
            <cfset DirectoryCopy(
                source        = local.source,
                destination    = local.destination
            ) /
>

        
        <!--- If this is a file, copy it over --->
        <cfelse>
            <cffile action="copy" source="#local.source#" destination="#local.destination#" />
        </cfif>
    </cfloop>
    
    <cfreturn />
</cffunction>

 

More Entries

Jon Hartmann, July 2011

I'm Jon Hartmann and I'm a Javascript fanatic, UX/UI evangelist and former ColdFusion master. I blog about mysterious error messages, user interface design questions, and all things baffling and irksome about programming for the web.

Learn more about me on LinkedIn.