cftopper.com

Form Wizard launched

Yesterday I released version 1.1 of Form Wizard for ColdFusion.

It will save your hours and hours of tedious work designing forms for your website, and then doing the javascript validation, database store, email notifications etc.

And the look and feel can be extended to integrate with any website design.


Form Wizard for ColdFusion


It's the shanizzle.
Tags: My Work | Tools | WebDev

Supporting Multiple Languages

The Translation engine at work
Google API Translation at work
Over the weekend, I wrote a resuable script that converts snippets of English text to 20 other languages using the new Google translate Ajax API for our Teamwork Project Manager software.

The script was hacked together quickly and isn't the best most structred code in the world but it works well - it cycles through any strings in the languages table that haven't been converted yet and one by one, converts them to a foreign language. Every time, the script has 20 results, it saves the changes to the database.

Watching it at work is pretty cool with strings coming back in Arabic, Chinese, Russian etc.

The strings are stored in the following table MySQL table:

CREATE TABLE `languagestrings` (
  `languageStringId` int(10) unsigned NOT NULL auto_increment,
  `languageStringRef` varchar(255) collate utf8_bin NOT NULL,
  `languageCode` char(2) character set utf8 NOT NULL,
  `languageString` text character set utf8 NOT NULL,
  `languageStringUsageCount` int(10) NOT NULL default '0',
  PRIMARY KEY  (`languageStringId`),
  UNIQUE KEY `langStringRef` (`languageStringRef`,`languageCode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

And translating the strings is done with the function
translate( ref, english_default, bUpdateNow, language ) which works like so:

#APPLICATION.teamworkpm.translate( "Your Projects", "Your Projects", false, "ES" )# gives "Su Proyectos".

Here is the translate function code:

<cffunction name="translate" returnType="string" output="No">
<cfargument name="ref" type="string" required="yes">
<cfargument name="englishDefault" type="string" required="Yes">
<cfargument name="updateNow" type="boolean" default="no">
<cfargument name="lang" type="string" default="#SESSION.lang#">
<cfset var getLangString = "">
<cfset var insLangString = "">
 
<!--- Ensure there is a structure for the currency language code --->
<cfif NOT StructKeyExists( APPLICATION.langStrings, ARGUMENTS.lang )>
	<cfset APPLICATION.langStrings[ ARGUMENTS.lang ] = StructNew()>
</cfif>
 
<cfif NOT StructKeyExists( APPLICATION.langStrings[ ARGUMENTS.lang ], ref )>
	<cfset ARGUMENTS.updateNow = true>
</cfif>
 
<cfif ARGUMENTS.updateNow>
 
	<!--- Check to see if the value is in the database --->
	<cfquery name="getLangString" datasource="teamworkpm_master">
	SELECT	languageString
	FROM	languagestrings
	WHERE	languageStringRef = <cfqueryparam value="#ref#" cfsqltype="CF_SQL_VARCHAR">
			AND languageCode = <cfqueryparam value="#ARGUMENTS.lang#" cfsqltype="CF_SQL_VARCHAR">
	</cfquery>
	
	<cfif getLangString.recordCount>
 
		<cfset APPLICATION.langStrings[ ARGUMENTS.lang ][ ref ] = getLangString.languageString>
		
		<cfquery name="updateLangStringCount" datasource="teamworkpm_master">
		UPDATE	languagestrings
		SET		languageStringUsageCount = languageStringUsageCount + 1
		WHERE	languageStringRef = <cfqueryparam value="#Left(ref,80)#" cfsqltype="CF_SQL_VARCHAR">
				AND languageCode = <cfqueryparam value="#ARGUMENTS.lang#" cfsqltype="CF_SQL_VARCHAR">
		</cfquery>
		
	<cfelse>
		
		<!--- Store the value in the field --->
		<cfset APPLICATION.langStrings[ ARGUMENTS.lang ][ ref ] = ARGUMENTS.englishDefault>
 
		<!--- Insert the default english value into the database --->
		<cfquery name="insLangString" datasource="teamworkpm_master">
		INSERT INTO languagestrings( languageStringRef, languageCode,
		languageString, languageStringUsageCount )
		VALUES( <cfqueryparam value="#ARGUMENTS.ref#" cfsqltype="CF_SQL_VARCHAR">,
		<cfqueryparam value="#ARGUMENTS.lang#" cfsqltype="CF_SQL_VARCHAR">,
		<cfqueryparam value="#ARGUMENTS.englishDefault#" cfsqltype="CF_SQL_VARCHAR">, 1 )
		ON DUPLICATE KEY UPDATE languageString =
		<cfqueryparam value="#ARGUMENTS.englishDefault#" cfsqltype="CF_SQL_VARCHAR">
		</cfquery>
 
	</cfif>
 
</cfif>
 
<cfreturn TRIM(APPLICATION.langStrings[ ARGUMENTS.lang ][ ref ])>
 
</cffunction>


You can see that if the string has already been looked up, the result is returned immediately so that this function is nice and fast.

If a string doesn't exist for a given language, the default english version is inserted for that language, so that it can be translated later.

The languageStringUsageCount is updated whenever a string has to be looked up, usually after a server reboot. This will be useful when we want to strip the database of strings that are no longer used in a few months.

The "update now" argument allows programmers to quickly change the value of english strings directly from the code base during development.

Hopefully this will help you get your own multi-language systems up and running in ColdFusion.
Tags: ColdFusion | Tips | WebDev

Backup Software Recommendations

I'm going to tell you a secret, but don't tell anyone. Shhhhsss.
About 3 weeks ago on a quiet Tuesday evening I installed the latest version of subversion client TortoiseSVN on one of our website hosting servers in Dublin - I had to reboot the server after the install. This is when it all went wrong...

I usually wait maybe 2 minutes and the server is backup serving a plethora of client websites and a few small web apps. I waited and waited, repeatedly pinging the server, searching for the first sign of life.

The server was apparently lifeless. Nada. Nothing. Zip. "No reply from server"...

We called our hosting company. No I lied ... we didn't. We actually had to use their brutal support chat program and bludgeon English into a pigeon-English speaking Polish guy to request that the server be manually restarted.

I guessed that I had hit the "shutdown" option instead of the "restart" option and that the technicians would reboot the server in a jiffy and that all would be well.. so I tottered off home.

Some time later I got a frantic phone call from Dan informing me that the technicians said the server's hard drive was fried. I turned visibly white and raced back to the office for damage assessment.

Hours later, the technicians in Dublin had managed to salvage some data by plugging the hard drive into another PC and running a Linux program to do a sector by sector copy where possible. We recovered a lot of data but we had still lost a fair amount. Luckily we had most, but not all, of the website databases backed up to a PC in my office thanks to Navicat and scheduled tasks.

The technicians reinstalled a blank Windows 2003 server installation along with the data they managed to recover and Dan and I spent the entire night working feverishly to get all the websites and applications working before our clients got to work and started screaming.

In the end, the only thing we lost was a very small website. We recovered the page content from Google page cache (isn't Google great) and then gave the client a new, much better website for free to make up for the down time which was 1 day while Dan knocked the new site out.

And here's my point: disasters will happen, so plan for them.

Our New Backup Plan


We have since installed Carbonite Backup on all our servers. Everywhere. It's an absolutely bargain for only $30 a year per server for unlimited data. I thought there must be a catch at first, but no, it's a steal, easy-to-setup and works great.

That's the files sorted. But what about the databases. Well, we use MySQL on all our servers (if you use anything else you are a stupid Microsoft whore or Oracle slut, sorry) and it's difficult to restore MySQL from just the raw data files. I wanted something that could backup an entire server of MySQL databases automatically including new databases without any additional configuration - the reason we lost that one website was because each website had to be manually configured with our old database backup system and we had missed a few.

Eventually, after a serous amount of poking about ye olde internet, I found exactly what I was looking for in Auto Backup for MySQL from Swordsky SoftWare. This is the only program I could find that would run as a service and backup multiple entire servers reliably without needing additional configuration as each new website is added.

It also has a thoughtful array of options such as automatic removal of old backups after so-many days - something that I used to have to do manually in the past. The SwordSky team, whoever they are, have done a fantastic job here and I encourage you to give it a go. It's a bargain at only $100 or so too.

So there you have it, two cheap, easy-to-setup products that may one day save your ass.
Tags: Tips | Tools | WebDev

Another reason to hate IE

Like we need another reason to hate IE. But here it is.

I recently implemented rounded edges throughout Teamwork Project Manager and it's a painful process involving nested divs and workarounds for IE6 glitches.

Today I was procrastinating on Digg.com and I stopped to admire the rounded edges on their notification bar.

Digg.com - nice rounded edges

I decided to look at the page source to to see their nested divs - are they using 4 nested divs for maximum flexibility bar with rounded edges - 1 div for each corner, or, where they using just 2 divs - one for each side with a height limitation?

The answer perplexed me - They just had something like <div id="announce"><p>Check out...</p></div>.

I thought "they must be using the <P> tag as a container with a background image" so I download their CSS source code and was confounded to see this:

     -moz-border-radius: 1em;
border-radius: 1em;

What in the blazes is that? CSS supports rounded edges? My pain was for nought? Could I have just shoved these 2 lines of code in and saved myself hours of work?

In a perfect world, a world without Internet Explorer, then yes, I could. If you are using FireFox, this entire post will have rounded edges. If you are using IE, you'll just see a plain box.

Here you see the same announcement banner in IE - notice anything different?

Digg.com - no rounded edges in IE

Here is another example.

Rounded edges browser comparison
I hereby confirm, IE sucks.
Tags: CSS | Rant | WebDev

We have launched!

We have finally launched!!

And what a wild ride it has been getting everything ready.

Check out Teamwork Project Manager at www.teamworkpm.net

The Website - Final Days

About a 5 days ago we had this marketing website almost complete. We stood back and looked at what we had created... and we decided... it sucked. Against the pressure of the looming launch date chiseled in stone on the preview website, we started again. We threw away the old website and said to our designer, Adam, "Hey Buddy, um... we don't like the site. Can you cook us up something prettier?".

Lo and behold, he disappeared off the face of the Earth for 2 days and returned with the new website design. And we saw that it was good. We worked round the clock slicing and dicing, XHTMLizing and CSSing, content-managing, tweaking and testing.

A few hours behind the intended launch time, we made the critial change to the IIS web server and set the new site live, flying open the doors allowing all to sign up for the shiny new kid on the block - Teamwork Project Manager.

Here we are in my office seconds after putting the website live. We are tired, we are hungry, we have sore backs and aching asses... but we're happy. That's me, Topper, on the left and Dan on the right.
We are holding the camera in our out-stretched hands (attempt number 10 to take a photo with both of us in the frame. The bad quality reflects that this was taken on my trusty K750i camera phone.)



We still have a lot to work to do on this website of course but we are proud of what we have created.

Teamwork Project Manager - Final Days

We started making some important changes with just days left to launch.

For example, our testing had revealed that user were getting confused between project view and top-level/dashboard view. They would just blink wildly and we've have to explain that you have to click-into a project. Also in project view they wondered where all the other projects had gone.

We fixed this by redesigning the navigation system into two bands of tabs in stead of just one with and extra "Project View" tab at the top level to make it obvious that the user was now indeed, in project view. It's so much more intuitive this way.

What else - oh yes, Dan whinged on about the need for starring of projects for so long that I finally relented. I didn't plan on getting this done for launch but I'm very glad I did now. Now, when you are members of a whole host of projects and the dashboard is getting a little busy, the user can switch to custom view where he will only see the projects he has starred.

Also when there are loads of active projects such as here at Digital Crew, we now only list the projects that have been active in the last 14 days on the sidebar. Other projects can then be shown by clicking "All projects". It looks so simple but we had a good 10 minute discussion over the best way to present this to the user. We considered tabs for "Recent Projects" and "All Projects"  but in the end, I think the way we have it now is much better.

TeamworkPM is launched at last and Dan is a happy little camper

Après Launch

This morning I woke up and eagerly turned on the computer, anxious to see if we got any sign-ups or feedback. I was delighted to see a very positive email - " I have started playing with the app and am incredibly impressed with the ui and the streamlined approach to project management.". He then asked us to provide a roadmap and listed a few more features he would love to see.

This type of feedback just hours after launch is great motivation for me. I'm going to get busy cooking up the extra feature this guy wants and serve it hot! Stay tuned.

TeamworkPM Launched - Topper has his legs up! A job well done.

PS. I will be adding a roadmap page to the Teamwork site before the end of the day,
PSS. I just added a "Chat Now" link in the footer of this website so feel free to get in touch.

Check out Teamwork Project Manager at www.teamworkpm.net

Secret Project Revealed

I've been working on a secretish project for a while now. Featuring all the ajax stuff you know and love.

More at: www.teamworkpm.net
Tags: WebDev

Google Video: MySQL Performance Tuning Best Practices

I stumbled upon this last night and it's excellent.



If your too lazy to watch this, just take this one tip from me - use the MySQL Administrator tool to increase the Cache Size setting under the Performance tab. You will notice immediate speed-up on heavily-loaded servers where the 32Mb cache just wasn't enough.

Increase you MySQL Cache size
Tags: MySQL | Tips | WebDev

My Lastest Masterpiece: ProFlashDownload

Cue Drumroll... my latest ColdFusion component is complete!

ProFlashDownload allows developers to make a list of files available for download to a user. These files will download with a progress bar and the developer can have a page called in the background when a file has completed downloading.

ProFlashDownload - Click for real demo

I was specifically asked to develop this component based on my existing work on ProFlashUpload.

Just like ProFlashUpload, ProFlashDownload is highly customizable, easy-to-use and easy-to-program.

Sidenote: You would think that Flash programming is browser-independent, but with this sucker, I had a bunch of issues with Internet Explorer causing all sorts of strange behaviour that I had to tediously program around.

Sidenote 2: It has been suggested that I combine ProFlashDownload and ProFlashUpload to make the mother of all web based file management utilities... and i'm considering it.

I'll be making this tag available for purchase at $50 on www.cftagstore.com in the coming days.

GZip Encode your CFML

There is an excellent article in the latest ColdFusion Developers Journal on how to enable GZip compression on your ColdFusion pages for free.
First, HTTP Compression is a great way to speed up your Website and lower bandwidth utilization all at the same time. In this example, your ColdFusion server (6.1 and above) will encode CFML output using GZIP and have the browser decompress this data on the fly. In a corporate environment, Webmasters may choose to go with third-party software such as Port80 Software's httpZip, which can compress other files as well, including .js, .css, and your HTML files. In this example, we are only compressing the generated HTML output from a .cfm template execution.

I just implemented it on one of our servers in 2 minutes. It reduced a 7Kb page to only 2306 bytes.
Date: Wed, 28 Mar 2007 23:01:45 GMT
Server: Microsoft-IIS/6.0
Content-Type: text/html; charset=UTF-8
Content-Encoding: gzip
Content-Length: 2306

200 OK
Tags: ColdFusion | Tips | WebDev

Image Gallery in 30 Seconds

How long would it take you to create an image gallery on your client's website?

Even using off-the-shelve scripts or purchased components, your probably still looking at an hours work, minimum, right? Maybe even a half-day or days work when you take into consideration the development of the administration section for the gallery.

How about reducing that time to 30 seconds?

With the plug-in architecture we developed for our in-house content management system, TeamworkCMS, you can! See for yourself...




Complete with administration. The database tables are created for you automatically when you install your first gallery. All aspects of the gallery including image size, thumbnail size and the CSS can be easily tweaked to suit your client's website.

This is just one of a myriad of page add-ons that we have developed.
Plug-n-play web development = saved time = money.

We will be releasing TeamworkCMS to the ColdFusion community FOR FREE in the coming weeks. BETA Testers wanted. Comments, feedback and suggestions would be great.

Topper Contributes to Open Source

I *think* this is the first time I have ever actually contributed to an Open Source project. Sure, I've given out free code, but I've never actually contributed to a community based software project until today.

I didn't want to have to use a CFX tag for image resizing anymore (even If I did make CFX_Jimage) so I tracked down Rick Root's ImageCFC.

In the project I was working on, I needed to create thumbnails that were exactly 90x90 with no whitespace from any size of source image. The source image could be any size.

To do this correctly, you need to figure out whether to resize on the X or Y axis, do so, then and clip off the remaining bit.

Figuring out the Axis to Resize on


You have to get the scale of the destination width over the current width and compare it to the destination height over the current height:

if( deltaX/currX < deltaY/currY ) then Resize on X Axis
else Resize on Y Axis

Then you have to clip the center piece of the remaining image:

        <cfset cropOffsetX = max( Int( (imgInfo.width/2) - (newWidth/2) ), 0 )>
        <cfset cropOffsetY = max( Int( (imgInfo.height/2) - (newHeight/2) ), 0 )>

It was a little tricky to get right (mainly because my brain was refusing to cooperate yesterday), but eventually I cracked it and it work's perfectly.

I submitted my new resizeBestFit function to Rick. Within a few short hours, he has integrated it nicely into the existing resize function and added an extra option, cropToExact.

ImageCFC Version 2.14 is available now. Cudos Rick.
Tags: ColdFusion | Tools | WebDev

I feel like crying

So I go away and create a lovely new website for the client. I use class sub-selectors and relative positioning to achieve some of the complex dynamic layouts. The project is just about finished and I put a preview version online for the client. The website works perfectly in Firefox and IE7.

Inevitably, the client calls:

"Peter, why are all the links blue? That's not what we want!".

"No, the links (on page X, section Y) are white. What do you mean? Try refreshing.. Hit control-F5..."

"No, they are still blue... and another thing...".

At this point I realize that they are using IE 5.5... my heart sinks.

I fire up IE 5.5, which barely works now that I've got IE 7 installed, and am treated to a plethora of ugly.

I can't tell the client to upgrade. What to do? We need to wrap up this project asap.
I have to undo all my CSS-niceness, and create complex layouts using logic and tables instead of intelligent CSS. I have to redo CSS first element sub-selectors and painfully hack the stylesheet with IE only hacks.

This is the state of the web today and this is what makes web design such a difficult business to operate in. This is what sucks the joy out of being a web developer.

Update


I stopped Whining, got stuck in and got it all working with IE6. Painful, but it was easier than I thought it would be. Here's what I did:

  1. <cfif Find("MSIE 6",CGI.HTTP_USER_AGENT) OR Find("MSIE 5",CGI.HTTP_USER_AGENT)>
  2.         <cfabort>
  3. </cfif>


Only messing! Messing
Tags: WebDev

Teamwork CMS Demo Online!

This weekend I got the thumb out and put the documentation website we build for our own documentation portal up on CFTagStore.com as a full product complete with CMS. As part of putting the product online, I also setup a working demo of the Portal and CMS.

 This is the first time that we have put a complete working demo of the latest version of our Teamwork Content Management System online for the general public to play with.

I invite you to log in and mess around with TeamworkCMS and then to let us know what you think:

The TeamworkCMS Demo is available here:
http://demos.digital-crew.com/documentationportal/cms/

Login with "admin" and password "admin".

You can view the pages you add or edit on the Demo Website here:
http://demos.digital-crew.com/documentationportal/

The database and codebase will reset automatically every 2 days (or when we get complaints that some Ejit has messed it up too much).

I Propose an Extension to CSS

We all know that CSS is absolutely fantastic. But it is far from perfect. To achieve many effects, the programmer has to add divs around existing elements and layout the order of divs on the page in a format that will suit his intended design.

Wouldn't it be great if you could just write out loads of elements such as divs, UL/OL lists etc un-nested on the page, then the stylesheet would be responsible for the nesting and element order.

The would completely, separate the code and layout, for once and for all!

How to do this?


How about adding a elementOrder CSS attribute? Maybe there is a better way. Hell, maybe it's planned already for the next version of CSS.

It would be used to specify the order that elements should be considered to appear on the page and the nesting structure of elements.

It could also insert new div elements into the page.

For example:

body{
        elementOrder: h1, #search, #mainarea
}
#mainarea{
        elementOrder: #nav, #main
}

In this example, mainarea could be a new imaginary holder for the navigation and main body.


A More Practical Example


Instead of:
<div id="container">

    <div id="header">
        <h1><a href="index.cfm">My Site</a></h1>
        <div id="search">
            <div><h2>Search</h2></div>
            <div><form><input type="text" name="p"><input type="submit"></form></div>
        </div>
    </div>

    <div id="mainarea">

          <ul id="nav"><li>NAV HERE</li></ul>
          <div id="copy">Page content here</div>

    </div>

</div>

Use:

<h1 id="sitename"><a href="index.cfm">My Site</a></h1>
<div id="search">
    <div><h2>Search</h2></div>
    <div><form><input type="text" name="p"><input type="submit"></form></div>
</div>
<ul id="nav"><li>NAV HERE</li></ul>
<div id="copy">Page content here</div>

These 4 elements could be in any order.
This stylesheet would control the order and nesting:

#body{
    elementOrder: #container;
}
#container{
    elementOrder: #header, #mainarea;
}
#header{
    elementOrder: h1#sitename, #search;
}
#mainarea{
    elementOrder: #nav, #copy
}



What would all this mean?


Well, you could COMPLETELY change a site with no limits just by modifying the CSS. You would never have to worry about the actual code layout again.

Am I completely mad or is this a good idea?
Tags: Ideas | WebDev

Navicat - Top Dog MySQL Manager

Here at Digital Crew, we use MySQL for just about everything only using other database types when clients force us to... yeuck. MySQL Rocks. But you know that.

What you mightn't know is that there is an absolutely awesome program for managing MySQl called Navicat. I have just been saved hours of work of tedious syncronising data between two databases using one of Navicat's many excellent features.

Navicat

This program is simply excellent - it will pay for itself in no time and has my highest endorsement.
Tags: My Work | Tools | WebDev

How to Beat Form Spam-bots

...without resorting to an annoying CAPTCHA.

Those bloody form spam bots were driving our clients crazy with hundred of bs emails arriving every day. I came up with this simple but effective method to beat these form spam-bots.

Part 1 - Duping New Bots


Warning: This method assumes needs JavaScript enabled and is thus not blah-blah compliant.

  1. Change the action of your form to "about:blank". (Remember the real action for later.) Robots indexing this will now go to "about:blank" instead of your action handler page.
  2. If your form has a JavaScript validation function, add this line just before the form is OKed or submitted:

    document.[form name].action = "[path to form handler page]"

    Otherwise just stick in something like this in the form:

    onsubmit="this.action='[Path to handler page here]'"

It's pretty simple, but since implementing this at the crew, we haven't encountered any robots smart enough to figure out that we are duping them with the about:blank. If the robots evolve, then so will we.

Part 2 - Blocking Old Bots (they're using Form Caching!)


Part 1 will prevent robots indexing your form action URL; but what about the robots who have already indexed your form and are storing the form details in their database? Here's how to block them:

  1. Add this line to your form:

    <input type="hidden" name="formSecurity" value="<cfoutput>#Hash( DateFormat( now(), "dd/mm/yyyy" ) & "YOUR_SECRET_KEY" )#</cfoutput>"/>

  2. In your handler page insert the following at the start:

    <!--- FORM SECURITY --->
    <cfif NOT isdefined( "FORM.formSecurity" ) OR ( FORM.formSecurity IS NOT Hash( DateFormat( now(), "dd/mm/yyyy" ) & "YOUR_SECRET_KEY" ) )>
        <cfabort>
    </cfif>

Tada! Your done. Welcome to zero-spam.
Alternative method: Cut the internet cable running out of Nigeria.

The GoogleBot is retarded.

Stupid GoogleBot The Googlebot is retarded.

Why? Because it has absolutely no idea what a base href tag is for.

I use a base href on all my sites to make internal linking much easier - no matter what the URL for the page on the site looks like, the link to another page will remain the same.

For those who don't know a base href looks like this <base href="">. When you use a base href on your site, all relative links are from that URL. So a link to "index.cfm" from the URL "page/somesubfolder/" will go to "index.cfm" instead of "page/somesubfolder/index.cfm".

But Mr. G, I-control-the-world, A. Bottie chooses to plough right on throught my base href scoffing at my pityful attempt to direct it to the content.

This is why I am continually getting error reports from sites where I have something like <cfparam name="URL.id" type="numeric">

Instead of getting a normal link like index.cfm/page/viewproduct/id/34, the bot is interpreting URLs like index.cfm/page/viewcat/index.cfm/viewproduct/34 and this is generating an error report which is automatically emailed to me every time the Googlebot goes into action on one of our client sites.

For FS, how hard is it for the Google engineers to intrerpret that there is a standard base href on the page. Or is it that the Googlebot is hedging it bets and checking to see if the base href was a mistake and there IS a valid page at it's conjured link URL.

ps. I'll probably get a permanent thumbs down in the Google ranking for this - Mr G.Bot tie knows when hes being insulted and he doesn't like it. You don't fuck with the bot - he controls the Internet, he can break you like that Messing.
Tags: Rant | WebDev

Good Linking

Never use words like "here" as a link. The link should have context.

Links should be written is this format:


...instead of this format:

Download a copy of Details of Irish Windfarms in pdf format here.
Download a copy of Details of Irish Windfarms in excel format here. 

This is more than my opinion... W3C content authoring guide.
Tags: WebDev

IE7 Javascript Error Reporting Still Sucks

Don't get me wrong, I like Internet Explorer 7 and I applaud the effort made by the IE team but guys could you not have improved the shoddy error reporting.

Not long ago, I used Internet Explorer almost exclusively and one of the reasons Firefox has stolen my soul is down to it's developer-friendly error reporting and debugging.

What prompted this rant was an error I encountered first thing this morning on my current project. Internet Explorer simply said, "Hey dipship, you have an error, go figure". Also IE seems to displays the exact same error message, 'Object missing', for a myriad of different scenarios.

IE7 Error Message


In Contrast

Firefox on the other hand, says "Yo! Little problem on line 1. There's no init() method.". It tells me exactly what the problem is! No thinking involved. Time saved. And it also provides a link to bring up the code, be in in the current file or on some dynamically generated JavaScript file. Very handy.

Firefox Error Message


Appeal to the IE7 Team

IE Team, please help us developers. Is there some developer extension for IE7 I don't know about? I just searched and installed the developer toolbar for IE7; it's good but alas, it doesn't provide better debugging services.

Final IE Rant

One final rant: IE7 should lose the annoying Error on Page message in the bottom left of the browser.

IE7 - Error On Page

It only advertises how crummy some developers are (notice I didn't say we) and frightens little children Messing.

 

Tags: Rant | WebDev

Good coding style #1: Use Whitespace

Coding readability is important! But only to to a degree - when people get religious on this issue I just zone out.

IMHO, if you have decided that you are a professional programmer, why not be the best programmer you can be. Try to evolve everyday. Look for things to learn. Improve, improve, improve. Get faster, learn the shortcuts. Every little time saver adds up.

#1 Use Whitespace

Which is easier to read, the first SQL statement or the second. Also most editors will allow the use of control-left, control-right to skip keywords with spaces between them but without the spaces, it skips the entire line.

There are basic examples, and as-such probably bad examples, when more code is involved the readability gets much harder when spaces aren't used.

SELECT moduletitle,modulelongtitle,moduleStatus,modulelevel
FROM modules
WHERE moduleId=#moduleId#
or
SELECT moduletitle, modulelongtitle, moduleStatus, modulelevel
FROM modules
WHERE moduleId = #moduleId#
 
Example 2:
html+='<option value="'+this.freqOptionVals[i]+'">'+this.freqOptions[i];

or

html += '<option value="' + this.freqOptionVals[i] + '">' + this.freqOptions[i];

You decide.

Tags: ColdFusion | WebDev

HTML Lists have always pissed me off

HTML lists have always pissed me off in 'both' browsers. I figured out for myself that Mozilla uses padding for the default indentation and IE uses margin for this same indentation.

So padding:0; will do nothing to the indent in IE.
And margin:0; will do nothing in Mozilla.

To dump the excessive indent in all browsers and still keep the bullet, use:

    margin:0;
    padding:0 0 0 1em;

I found an article on A List Apart on this just now:

http://alistapart.com/articles/taminglists/
Tags: Tips | WebDev

MySQL error on rename 150

If you ever run into the error message "MySQL error on rename 150" when making changes to your MySQL table, the easiest thing to do to fix this is:

  1. Backup the database
  2. Delete it
  3. Recreate it
  4. Restore it

Basically MySQL has temporary files interfering with the ALTER TABLE process. I has done a load of googling and found comments but no solution - this is posted here to save others some stress.

Update

Be careful with the above advise - you could be getting this error just because you are doing something like trying to link an unsigned int to a signed int. Use the advise above only after you have carefully determined that MySQL is acting the maggot.

Tags: MySQL | Tips | WebDev

..Not the best 'Pages' Design in the World...

..oh no, this is just a tribute! This is the latest Digital Crew database design for storing website pages.

I have evolved this design over the years and I'm pretty happy with this result - this design supports multiple sites, page redirection, page short name (for navigation) and page long name, page HTML (for basic pages or intro text on complex pages), meta information, visibility, security, published status, alternative URLs, alternative files, making page for special (dynamic) processing and the ability to open the page in a new window.

Use it, if you like.

Design view of MySQL 'Pages' table

CREATE TABLE `pages` (
  `pageid` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `siteId` int(11) UNSIGNED NOT NULL DEFAULT '1',
  `pageparentid` int(10) UNSIGNED DEFAULT '0',
  `pageCode` varchar(50) character SET latin1 NOT NULL,
  `pageNavName` varchar(100) character SET latin1 NOT NULL DEFAULT '',
  `pageName` varchar(150) character SET latin1 NOT NULL DEFAULT '',
  `pageHTML` text character SET latin1 NOT NULL,
  `pageDisplayOrder` smallint(5) UNSIGNED NOT NULL DEFAULT '2000',
  `pageIsPublished` tinyint(1) NOT NULL DEFAULT '1',
  `pageDescription` varchar(255) character SET latin1 DEFAULT NULL,
  `pageKeywords` varchar(255) character SET latin1 DEFAULT NULL,
  `pageIsFolder` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
  `pageIsDynamic` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
  `pageIsVisible` tinyint(3) UNSIGNED NOT NULL DEFAULT '1',
  `pageIsLocked` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
  `pageAccess` enum('O','I','A') character SET latin1 NOT NULL DEFAULT 'A' COMMENT 'A=All, I=Logged In, O = Logged Out',
  `pageRedirectPage` varchar(50) character SET latin1 DEFAULT NULL,
  `pageAltFile` varchar(255) character SET latin1 DEFAULT NULL,
  `pageAltURL` varchar(255) character SET latin1 DEFAULT NULL,
  `pageOpenNewWin` tinyint(3) UNSIGNED DEFAULT '0',
  `pageShowOnInPageNav` tinyint(3) UNSIGNED DEFAULT '1'
  PRIMARY KEY  (`pageid`),
  KEY `pageparendId-pageId` (`pageparentid`),
  CONSTRAINT `pageparendId-pageId` FOREIGN KEY (`pageparentid`) REFERENCES `pages` (`pageid`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Source Control - 3 months later

For years we knew that we should be using source control. But we weren't. We didn't want the hassle of using source control.

But here's the thing: We make software components for ColdFusion. Some of these components are the cornerstones of our content management solutions which are in turn the cornerstone of our successful website and Intranet development business. In the past, when I made a change to UDI, a component for managing database content, I'd manually copy the code back to a central location. Then I would get the code again when starting a new project. The current version and change log were stored within the main.cfm file of each component. Painful.

What were we thinking?! About 3 months ago, I decided to take the bull by the horns and investigate the incredible complex, tedium world of source control. I got some manuals on Subversion and read a lot about CVS and source control systems. All pretty scary stuff to begin with.

But in truth, with the most excellent amazing fantastically brilliant TortoiseSNV extension for windows, source control is absolutely painless. Made changes? Just right click on the directory and select check-in, provide a short message and your done. Need the latest version, just right click and choose SVN Update. Wow, painless and simple.

And here is the thing I've come to notice, and it's a compelling reason to use source control - and not just because you should. You will be one hundred times more productive. How? You see, with the hassle of maintenance gone, I find myself making hundreds of little fixes and improvements all-the-time now.

If you make software and your not using some sort of proper source control, your officially living in the dark ages.

Tags: ColdFusion | Tips | Tools | WebDev

QueryWizard Version 1.1

Today I made a number of important improvements to the QueryWizard that I started yesterday. Already the QueryWizard is proving to be a useful tool for me. Just unzip this and execute <cf_queryWizard>.

The Query Wizard

I've tried to make the Query Wizard as intelligent as possible.

  • Matching Field Names
    It automatically links up any URL or FORM variables to matching fields. But database fields are often prefixed with the name of the table (at least at DCHQ they always are) so it matches the right hand side of the column name against the variables names.
  • Preview of Field Values
    As you see in the drop down for matching fields I now display a preview of the data that was held in the field when <cf_queryWizard> was executed.
  • Query Name Selection
    The wizard does it best to pick a suitable name for the generated query. If you are INSERTing into the "Monkeys" table, the query will be called "InsertMonkey".
  • Matching indentation level
    You can place <cf_queryWizard> anywhere in your CFM template and the query that is generated in its place will match your indentation keeping everything nice and neat.

Road-map

  • Ability to specify SORT ORDER when doing SELECT
  • Ability to SELECT from multiple tables and specify the join type and clause - this is going to be tricky Messing
  • General improvements to interface including have the generated query not scroll

And with that I'm out of ideas so please download the query wizard and hit me with your suggestions.

Tags: My Work | Tools | WebDev

Javascript: Date.getYear() Gotcha

Working with some older code using firefox whereas during development I would have used IE. It took me a while to track a problem down where a selected date was returning 106 instead of 2006 for the year.

Date.getYear() returns 2006 in IE and 106 in Firefox.

Thats sucks but just use Date.getFullYear() to get around this.

Tags: Tips | WebDev

Fixing the Min-Height Problem

If your a web developer, no doubt your ran into the height/min-height problem. The problem is basically that Internet Explorer treats the CSS height property like the min-height property and doesn't not support the min-height property.

So you can get the behaviour you want in IE, but it looks like shit in Firefox. Or vice-versa.

But Dustin Diaz came up with a solution:

selector {
  min-height:500px;
  height:auto !important;
  height:500px;
}

Tags: WebDev

CF_ProFlashUpload - Live at Last

I've finally released the flash upload component - the development of which I was blogging about here. Took a while for myself and Dan to come up with a good name. We were throwing all sorts of crazy ideas out there. Anyhow, please please go ahead and try it out. The demo is fully functional apart from a banner that asks you to purchase it.

I'm selling this baby for $50 per website - a fair price I think given the amount of work that went into this sucker.

What Is CF_ProFlashUpload? This widget creates a interface that allows your site user to easily upload multiple, even hundreds of files to your server. Each file has an individual progress bar and there is also an overall progress bar. The upload rate is also displayed.

 

The component allows you to use a multiple file upload component of any size as part of any ColdFusion application. It is extremely easy-to-use. You can call the component passing in just the upload directory and nothing else. Or you can use any of the advanced options to customise security options, file-type options and the look-and-feel of the component.

One of the nicest features of this component are per-file progress bars. The upload rate is also displayed along with the overall progress.

The demo is completely functional - just download it and you'll be up and running in minutes.

Accessibility Audit

I just got a professional accessibility audit report on a website I recently developed. I didn't fare too badly - an average score.

What really impressed me was the thoroughness of the report - wherever there was a red flag, there was a very good suggestion on how to fix this as well as notes on why this is an issue.

I've learnt a lot about how to make a website truly accessible and look forward to moving the websites score from average to excellent. It's important to keep learning and strive to be the best developer you can be.

Tags: My Work | WebDev

Heading to Boston

I'm at Dublin airport and I'm just after paying Eircom's extravagant fee of €5 for 1 hour of wireless Internet access - the thieving bastards. I'm on my way to Boston for 4 weeks. The flight leaves in 2 hours time.

One of the highlights of my trip to Boston will no doubt be attending the Boston CFUG meet tomorrow night. I've been in touch with Brian Rinaldi and he says I welcome. He might even be able to arrange 5 minutes for me to show off the multiple file upload component I recently developed.

Aside from all that, I'm wrecked after Ireland's biggest festival, Oxegen, at the weekend. The Red Hot Chilly Peppers rocked. I was also impressed by Feeder.

Saturday was a mud-ridden wash-out but Sunday was great. We were camping and it was hilarious to intermittently see tents take-off in the strong gale with 2 screaming girls jogging after them.

Update

Dan I KNOW you'll get a kick out of this. Some goth style Linux nerds just came up and said "here ya go" and gave me an Ubuntu Linux installation disk. Looks like there are walking through the airport giving them out to anybody with a laptop. I got a strange look from the cute girls across the way when I took the CD. Reminds me of the sandals - you'll know what I mean. Messing

Tags: Musings | My Trips | WebDev

New Digital Crew Showcase Site

At Digital Crew we are busy. So busy our own website is badly neglected. Hell, it's so old, it uses font tags! And it uses our original CMS solution so its pretty hard to manage also.

We've wanted to make the mother-of-all websites for over 2 years now and last year we couldn't settle on a mother-of-all design and so the project stagnated. And eventually was forgotten under our heavy workload.

Recently we made the decision to put up a simple showcase site in place of the current embarrassment. Anything is better that what's there now. Our top priority is to showcase our recent work which I think (somewhat biasedly of courseMessing) is pretty good.

Aside: I'm watching Portugal Vs France right now.... Portugal is losing 1-0 and they just missed a sitter.

Preview of New Digital Crew websiteAdam, our graphic designer has put together the temporary showcase website design for Digital Crew and its not too bad at all for a temporary site. I'm looking forward to putting it up. Here is a tiny preview.

Aside: Update: The match is over. Well done France for getting to the Final.

Aside: Can somebody tell me why Firefox is putting a load of whitespace at the end of the first blog post on this site?

Tags: My Work | WebDev

Google Checkout is US Only

Shit - It looks like we won't get a chance to use Google Checkout after-all. You must have a US Address and bank account. And apparently getting a US bank account is a difficult ordeal these days.
Tags: WebDev

Google Checkout is here!

Google Checkout is here! Google Checkout is here! Google Checkout is here!

For every $1 you spend on AdWords, you can process $10 in sales for free through Google Checkout. For example, if you spent $1,000 on AdWords last month, this month you can process $10,000 in sales at no cost. The more you spend to promote your business through AdWords, the more you save on transaction processing fees with Google Checkout.

If you exceed your free transaction processing for the month, or you don't advertise with AdWords at all, you'll only be charged 2% plus $.20 per transaction.

https://checkout.google.com/sell

Happy Days - they are only charging 2% + $.20 per transaction! I can't wait to change CFTagStore.com over to using this. At the moment we are using WorldPay and are simply being raped on the transaction costs.

Tags: Online | WebDev

InfinityCMS Button for Google Toolbar

I'm just finished another small website project and it should be launched within a matter of days:

WebWorks Cork

But that's not the reason I'm posting this. Yesterday, I was searching for something completely different when I came across some pages on Google's site describing how to add your own custom buttons to the new Google BETA toolbar.

My imagination was captured (=all real work ceased Messing). An hour later (OK to be honest, about 3 hours later) and I had my very own icon for our own InfinityCMS Content Management System. Check it out:

Simply click this icon and it launches InfinityCMS

Installation: I added a page to our CMS system where the user can click a link to install this button in his/her Google Toolbar.

What Happens? Once clicked, the button sends the current URL to infinitycms.digital-crew.com. A ColdFusion page there checks the URL and performs a test to see if InfinityCMS is installed on that website.

If it isn't, the user gets a quick message displayed and is returned to where he/she was with history.back().

But if InfinityCMS is detected, a new window launches InfinityCMS and in the old window the user is again returned to where he was with history.back().

The Cool Bit: InfinityCMS is passed the URL of the page you were on when you clicked the icon... There are a series of regular expressions in the database (which can easily be updated in InfinityCMS by an administrator) that handle the request in a smart way...

For example, if the user was on the home page and clicks the icon, a window will appear allowing the user to quickly edit just the home page without all the other elements of the CMS solution:

InfinityCMS Quick Eidt Mode

And if there are several corresponding 'Quick Edit' options for a page, then the user will get a list of options. For example, on the following Quick Edit of the "Contact Us" page, the user can choose to edit the page or review messages from the contact form which have been logged in the database:

InfinityCMS Quick Edit of Contact Page - Options

Now that I've been using it for a bit, I find this little icon invaluable for making quick changes here and there. Of course if the user isn't logged into the CMS system, the login page appears first. I must add on the ability for the user to switch from Quick Edit more to full edit mode which looks like this:

InfinityCMS for WebWorks in Full Mode

Would love to know what you think of this little hack?

Update

I was giving a demo of this to Cormac and his popup blocker (Google Toobar - haha - the irony) was preventing the Quick Edit window from opening.

I remembered when the other day, GMail popped up a message for me saying that a popup blocker was blocking a window from opening so I knew it was possible to detect this. I did a bit of googling and it turns out it's pretty easy to detect:

<script language='JavaScript'>
<!-- <![CDATA[
function userHasPopupBlocker() {
var oWin = window.open('','child','width=50,height=50,status=no,resizable=yes');
if( oWin==null || typeof(oWin)=="undefined" ) return true;
else oWin.close();
return false;
}
//    ]]> -->
</script>

So now my script displays a friendly message asking to user to disable the popup blocker for the redirect site and "click here to try again". All working as it should again.

Aardvark'd Review

This morning, Dan and I were planning, scheming and arguing about the forthcoming application we are planning to develop when Cormac marched into my office with a priority mail package from Fog Creek.

It had arrived! The long awaited package contained Aardvark'd - a documentary of the development of Co-Pilot by a group of interns at Fog Creek software last Summer.

We did a bit of rescheduling so that we could have our Geek Night in and thoroughly enjoy this movie at Dan's house later. We were looking forward to watching the code-monkeys plan, structure, project manage, make decisions, argue, debate and code their way to success.

Interlude

Well, I'm just back from Dan's house after watching the DVD and I have to say that I'm a little disappointed.

Certainly there were a few interesting bits and it was good to see inside the organisation, their environment and so on. But I had wanted to see software development at it's finest. I didn't. Instead I got 90 minutes of utter tedium.

Seriously! - I don't care about the ledge, your tomato plant, your birthday hat, your misfired party, your apartments, your bike or even the fucking cockroach (I could go on).

I had wanted to see the team work together, choosing the correct platform, the decision to go with VNC, the frustrations, the long hours, the code, the mistakes, the tools, the database design, the server setup... everything.

But alas, it seems that this wasn't aimed at developers. If not, then who was this aimed at? Certainly nobody other than developers would give a shit about something subtitled "12 weeks with Geeks". It could be that they were sick of discussing the development process they went through forums and such online and wanted to show the lighter side of software development. Or it could be that the production company behind the video just don't get it.

For me, it's a misfire, a wasted opportunity.

Tags: Musings | WebDev

Flash Security Wrecking My Head

FFS, all I want to do is ask the license server if this component is OK to run on this website. My code was working perfectly from localhost - cummunicating perfectly with the licensing server but when I put it out in the real world, it couldn't get a connection.

Turns out Flash's security model is preventing loading data from another domain.

There are three methods (I've found so far) to allow the communication, but all of these require that the license server know who the requesting server is, in advance. So not too good for my needs then.

I think the WebService API might be able to get around this restriction... It's 2.18am however and that's another days work. This article looks positive...

http://www.adobe.com/devnet/flash/articles/flmxpro_webservices_03.html

MultiUpload Demo - 171 Files

Interesting to see that, since yesterday, users of this site have uploaded 171 files messing around with the Multiple Upload Demo.

Among the files are a plethora of interesting MP3s, excel sheets, PSD files and of course some porno - thanks Guys.

Whomever uploaded "film_ze_mucha_nie_siada.mpg" - that's just weird.

Updated Demo

I've updated the demo with a few more options and started updating the descriptions. I haven't tested all these options yet, so please let me know if you find a bug.

IE users, you may want to reset you cache as I updated the flash control and IE is brutal for not updating the cached version flash movies.

Some Minor Updates

I changed the names of some attributes such as "color" which is now "statusTextColor".

I also re-jigged some of the internal Flash default parameter coding to make the flash control smaller and more robust in that it can handle color codes in any of the following formats, "0xFF4466", "#FF4466" or just "FF4466".

It's all these little things that are delaying the launch but will ultimately make this incredibly easy-to-use and dummy-proof.

Multiple Upload Demo Updated.

Last night, I added some options and fixed one of the last remaining bugs in the Multiple File Upload Widget Demo.

Tonight I'll add more options to the demo.

I was thinking of add a 'tic' sound as each file uploads. Also don't you think the default text for the select files button should be "Select Files" and not "Browse".

One of the last things we want to add to the Flash control is licence control. From the top of my head, here's an overview of how the licensing might work:

  1. The flash component will have a secret key and the licensing server will also have this same secret key.
  2. When the component is called on a commercial website, the component will ask the server if the current website has a licence registered using its secret key to build a hash of the domain and time-stamp. The server will respond yes or no.
  3. Once the flash gets the response, it will be able to authenticate that it was the real server it was talking to based on the hash.
  4. If the server responded 'no', the "unregistered version, click here to register" text will display.
  5. The website will be sent a unique license hash for the current website that it will store and pass into the flash control for instant authentication in the future without the need to communicate with the licensing server.
  6. It will also be possible for users to download licence files for their website that prevent the need to communicate with the licensing server.

Of course all the falls flat on it's face if somebody cracks open the SWF file and obtains the secret key; and understands the licensing mechanism; and goes to extreme lengths to replica the licensing server or rebuild the licence key. But it's going to sell for $50, so so I don't think anybody would be bothered going to those lengths.

Flash Upload Demo is Up

I know some of you are looking forward to checking out the demo of the flash file uploader component for ColdFusion so without further ado, here you go:

ps. I haven't got around to adding the licence management code yet so for security I've just slapped "demo" on it for now. This demo uses exactly the following code and also shows how javascript callbacks can be used. C&C very welcome.

<cf_dccom component="dcFlashUpload" folder="#folder#"

width="500"
height="400"

jsOnFileUpload="onFileUpload"
jsOnComplete="onComplete"

color="0xFFFFFF"

themeColor="haloGreen"

blockExtensions="cfm,cfml,exe,cgi,php,php3"

></cf_dccom>

Configuring Firewall for Passive FTP

Access to our web servers has been wanky since we installed a new firewall in the hosting center a while back. The firewall was configured to allow full access on port 21 so that should be fine, right?

Wrong. I thought "FTP uses port 21" and that was that, but FTP only uses port 21 for commands and uses a random port for the communication.

I did some reading about how both modes, Active and Passive FTP, work. Basically using Active will prevent any firewall issues but the clients firewall may think the server connecting to the client on a random port to send data is an intruder. So enforcing Active Mode may create problems for some clients.

But if you use Passive mode, the client will try to create a connection with the server for data transfer on any port over 1024. The problem is that could be any port and you don't want to have to tell the firewall to leave access open on all ports over 1024.

The solution is to configure the FTP servers themselves to use a narrow range of potential port numbers for the Passive mode data transfer, say 51000 to 52000, and then configure the firewall to allow access on these ports. Our servers are now working with Passive mode FTP again - Happy Days.

Tags: My Work | WebDev

Drunken Programming

I was happily programming in my room when one of the lads dragged me out drinking a few hours ago. Now I'm back happily drunk programming, back listening to good music and enjoying finishing off the multiple upload control. I'll be glad to put this multiple upload control to rest and get some feedback.

Drunken programming rocks. I probably won't understand any of the code tomorrow but what the hell, I'm getting things done.

I just added the code that prevents a user selecting a file he has already chosen a second time. Unfortunately the Flash-heads don't let us know where on the user's hard drive a selected file comes from so I have to base the analysis on the file name and file size. That means that if some user tries to upload 2 different files with the same name and same file size that they simply won't be able to. Know what I'm on about? Anyhow it was a bit of a dumb decision from the Macromedia heads... I mean the Adobe heads. They should have at least provided a hash to represent the file so we could distinguish between 2 similar files. For some user, somewhere, this will cause slight confusion but what can I do.

I have just 2 tasks remaining on the control. 1 - Get the maxTotalFileSize limit working. And 2, Fix the sorting of the columns.

Then I just have testing and tweaking. I've added a shit load of customisation options to the control so all that has to be documented as well. I'm glad that I can just hand this masterpiece (ahem sorry) off to Dan and that he has to do all the packaging. There's some amount of work gone into this thing, but most of it is behind-the-scenes and optional stuff that most people won't appreciate.

OK, I'll stop here, I'm ranting. Maybe I'm just pissed. Hic.

Here's the latest screenshot, notice the customisation of the column headers, the button icons, the highlighted text effect and the overall file size. This will be the best multiple file upload widget on the market. Smile

Oh yes, sell baby sell

Tags: My Work | WebDev

Flash Multiple File Upload Widget Preview Part II

I've been working on the Flash Multiple File Upload Widget - I think it's really getting there now that I've added in a few neat features. Here is an updated screenshot.
 
Oh Yeah, it's gonna rock
 
I'm learning a lot of advanced flash on this project; I had no idea what a CellRenderer class was just a few days ago. If I know it can be done, and I want it done bad enough, I'll bloody well keep at it until I get it done.

I managed to get the file type icons loading dynamically and I just had to put in the per-file progress bar (I was up till 3.30am last night at that).

Dan and I have agreed a final list of changes to make to this before we release it to the world. Here are the remaining work items:

  • Allow per-file callback through variable jsOnFileUpload(success,fileNo,fileName)
  • Allow user to set the nameConflict - default is "overwrite"
  • Put the stylish per-file progress bar at the bottom of the control - dump the built-in one
  • Change footer text to something like "Uploading file 1 of 20, Upload Rate: 20KB/s"
  • Allow user to turn on/off the size column through showSizeColumn="no"
  • Prevent duplicate selection for uploading of the same file
  • Add and implement maxTotalFileSize limit
  • Put striped background colours in
  • Change style on header of columns to glass effect, if thats possible
  • Put icons in for the buttons
  • Fix the sorting of the columns
  • implement stopOnError="yes"

Since I'm doing the Flash programming, Dan has agreed to make a masterpiece of the packaging and marketing of this baby. I'm hoping this baby will sell like cupcakes.

Now back to it...

Flash MultiUpload Control in the Works

On our site, CFTagStore.com, we have a ColdFusion widget called CF_MultiUpload Advanced which was programmed by Dan and I.

The advanced part of the widget uses an activeX control in a pop-up window to allow the user to easily select and upload hundreds of files.

However because Flash 8 now has powerful support for selecting and uploading multiple files, I spent Tuesday and Wednesday working on a sexual flash replacement for our old CF_MultiUpload Advanced widget. Here is a preview:

Flash Multi Upload Preview

The Flash version will mean that this will work on all platforms and browsers without the need to install an activeX control.

As you can see, I only have icons in for JPG images so far - I was to try to dynamically load the needed icons to keep the controls load-size minimal.

Also I plan to add in a second progress bar for the current file along with some stats on the current upload rate and possibly the average upload rate.

Have a few bugs to fix also before I add any more features.

Dan assures me this will sell like cupcakes.

IE7 Beta 2

I have just finally got around to testing IE7. I'm about 1 minute into it and so far I'm loving the clean easy-to-use interface. What was all the fuss about. So far all my sites I've checked work perfectly, no CSS issues.

Stay tuned...

Tags: WebDev

The Last Form

Can you imagine the luxury of never having to program a form again! Well. I am here adding some functionality to a 5 year old website (the programming behind of which is so... awkward; that it really highlights how much we, Digital Crew, have developed as CF programmers over the years) and...

I was just about to program another "input form, validation, update database, send emails" combination when I sighed and thought fuck this.

I've been comtemplating updating my UDI project to be able to work standalone with single forms so that I never have to do this shit. Just pop UDI onto a page, mess with the wizard that appears and bingo - job is done.

Stay tuned, I'm about an hour into this upgrade - the time invested will reap major rewards.

Tags: ColdFusion | WebDev

Advanced Caching wit' dcCache

So it's been a week since my last post. That's pretty bad - I made a rule for myself that I'd post at least once every 2 working days. Guess I didn't have anything of note. So what have I been up to? Advanced caching for one thing...

Last Monday I decided to finally get around to adding content-caching to the Digital Crew site engine. With proper advanced caching, a single server could host up to 10 times the amount of websites, leading to cost savings and an overall improvement in website speeds. So I pulled out my old dcCache tag. I then re-factored (to use some bullshitty programming jargon) the tag bringing the code into the CFMX age. The tag works like so:

<dcCom component="dcCache" key="stuff"> CONTENT HERE </dcCom>

If the tag detects a cached version of "stuff", it just loads up that HTML page and spits it out, then exits the tag using <cfexit method="exittag">.

By the way, I had an old note in the tag saying that there was a bug with <cfexit> in which if the exittag option was called, it would still execute the content nested with the tag. I tested and this bug seems to be gone so I reimplemented the <cfexit> code.

This tag is used to cache various items around a web page. A "Top 10 Movies" content snippet could be cached for example so that it only updates when the database behind it is updated saving the execution of a query and parsing of result on every page of the site. Also an entire page could be cached. That entire page might contain the "Top 10 Movies" cached item. I got thinking about this and wanted a way so that if the "Top 10 Movies" snippet is reset, the parent cached item, the full page in this example is also reset.... I won't bored you with the details but with a REQUEST.dcCacheCurrentList variable I was able to make this magic happen.

I'm a little concerned that repeated loading the cached content from disk might be slow - it might be better to cache the most popular content in memory, but then again the operating system should know that certain disk items are being repeated accessed and make them easily available.

To reset the cache, the dcCache component is called using

<dcCom component="dcCache" action="resetlist" resetList="Top10Movies">

I used all this caching milarchy for Digital Warehouse and after some teething problem, the site now seems to be nice and fast - it's basically just spitting out pre-rendered HTML code for 90% of the web page. That's the beauty of dcCache, it can be used for just parts of a web page.

In our implementation of www.digitalwarehouse.ie, the CMS is one application and the website is another so I use CFHTTP to send a request from one app to the other to reset items when an update is made in the CMS. So far, it works pretty well. Anyone have a better idea for inter-application communication than CFHTTP and I don't want to hear about using SERVER variables - that's a no-no on a server that could host hundred of sites. :D

Oops, this post is way too long. Way to rant. I was going to give an overview of my entire week but that explanation of one days work has done me in. Stay tuned for another post later today.

Tags: ColdFusion | WebDev

Battle of the WYSIWYGs

Dan told me the other day that he stumbled upon an online WYSIWYG that is much better that FCKEditor which we use in UDI and in turn use in all our content management systems as the main editor.

I was a bit reluctant. Why?

  1. When I went looking for the best editor a year ago, I thought I had found it in FCKEditor. I honesty thought FCKEditor was the best out there.
  2. I had put so much effect into the integration of FCKEditor with UDI, hacking FCKEditor to death until it fit my needs, that the thought of change was dismaying.

But an hour ago I asked Dan to show me that Editor... the editor is TinyMCE.

TinyMCE Kicks FCKEditor about

Yip. I admit it, I was wrong, FCKEditor has been delivered a heart-stopping fist-of-death by TinyMCE. The loading seems faster. The integration seems better. The toolbars are easily modified (wasn't easy in FCK). But what really made me wet what the advanced image editing... images can be resized and clipped online! It's just what dummy clients need. Hell, even the documentation is better.

What really convinced me was when Cormac chipped in with a link to this excellent online WYSIWYG comparison which places TinyMCE above FCK and names it as the best open-source solution.

It remains to be seen if TinyMCE is flexible enough to allow me to do some advanced things; like allowing the user to easily link to existing web pages from a tree menu of available site pages when adding a link.

Anyhow, I've downloaded TinyMCE and all going well, I'm determined to have it an integral part of UDI by this day next week.

Tags: My Work | Online | WebDev

Stupid MySQL -> CounterStrike

Check this out for a bizarre bug in MySQL (or else I'm way too tired). I have this setup, what do you think the query will return, 2 rows right?

The Setup

Alas no - it returns NADA, nothing, blank, no data! No matter what I try the shippingcostWeight will not match any decimal value. See this screenshot of the results:

The Problem

I've tried changing the float column to decimal and double but it makes no difference. I tried putting the float value in single quotes and no luck. I'm sure its either a bug in MySQL 5, a bug in the driver or that i'm being completely stupid. Anyhow i'm nearly finished the ecommerce site I'm working on so I think it's time to call it a night and play some CounterStrike - the best game ever made!! :)

Counterstrike - the best game ever!

 

Tags: My Work | WebDev

The 160,000,000 Euro Website

Wow. I just read about a failed website project that although forecast to cost only (*cough*) €65M ended up costing €165M. From theDailyWTF.com:

German readers may be familiar with the story of Arbeitsagentur.de, the official website of the Bundesagentur für Arbeit (Federal Labour Office). It's a fairly typical "big business" story: government wants a job portal website, large consulting company (Accenture) bids €65.5M, government accepts, consultants start it but say they need another €100M to complete it, government becomes outraged, news stories are written (like this one), and eventually a horribly slow low-functionality website gets built.

But there's something I just can't wrap my mind around with stories like this. Why do people get outraged with a job portal website costing 160,000,000+ euros? Don't they realise how much enterprise is bundled with a price like that? Can't they understand that the slowness and poor usability is key part of enterpriseness and, that this is actually a good thing?

Well I hope that I can set the record straight today and give Accenture the credit they are due. It's impossible to explain the value behind a €160M+ website in such a small space, but I think that Wladimir Palant found the perfect example that you can actually check and see for yourself (view source on arbeitsagentur.de). It's a 714-byte session identifier that's unique enough to represent all sessions across all websites across all the Internets across all galaxies throughout all of time ... four times over. Now that's enterprisey ...

 

<a href="/berufe/search/alpha/index.jsp;jsessionid=000000000000001a49444c
3a687474702f52657150726f636573736f723a312e3000000000000001000000000000012400
0102000000000973303230323032310000eb460000004d00504d43000000000000001a49444c
3a687474702f52657150726f636573736f723a312e300020200000000f6265727566655f636c
757374657200200000000d2f746f6d636174345f706f61000000000000000456495303000000
05000507017f0000000000000000000008000000005649530000000001000000180000000000
0100010000000105010001000101090000000000000021000000700001000000000001000000
0000000022000000000040000000000008060667810201010100000019040100080606678102
01010100000009557365725265616c6d00040000000000000000015642210100000007426f72
6c616e6400000000010000000806066781020101010000000f_1CA157F9330F6E6F373F6BE19
C19812C" tabindex="600" class="mainmenu">

 

It pisses me off more that I can say. Look at the example code from the project above - obviously the developers at Accenture are a talented bunch. It's far from the first example of a hot-shot consulting company making a dogs balls of a project leading to massive overruns. If you gave our company, Digital Crew, this contract, we'd make a masterpiece of it for a lot less that €65M. I hope the day will come when the idiots awarding these contracts learn to look beyond the image and spiel dished out by these uber-consulting companies and award the job to a company who actually walk the talk.

Tags: WebDev

My Work: NMCI

NMCII've spent the last 2 weeks working on the website for the new National Maritime College of Ireland (NMCI). It was a bit of a struggle to meet a tight deadline for their launch but we did it.

The website itself ain't bad but the CMS behind it is another evolution of our custom built InfinityCMS content management system and is pretty sweet (if I do say so myself).

One neat feature is this ability for the user to type [include:subnav] in the WYSIWYG and the website will automagically spit out an in-page navigation. Other options are [include:date], [include:datetime] etc.

Also an editor can choose up to 5 image and write [include:image1] in their text to get a nicely rounded captioned image on the page. The rounded edges are done using the nifty corners flash I showed here last week.

Then theres the right hand side items - editors can create and assign right hand side items for any page and the images are automatically scaled and rounded for them.

Oh and the site also uses the useful script I wrote to extract URL variables from the pathe path so the site is more search engine friendly with URLs like http://www.nmci.ie/index.cfm/page/undergraduatecourses as opposed to http://www.nmci.ie/index.cfm?page=undergraduatecourses

All in all, I think I did well to add all these features and still get the job done on-time.
Check out the site and hit me back, comments appreciated (Keith, this time round, please try to say something positive before you unleash hell's fury).

A Better Way

Just bored here in AREA51 doing my usual Friday night stint, browsing the web, considering doing some work. Was just filling out a form...

On just about every HTML sign-up form, when you make a mistake or something like your desired username is taken, you have to re-enter your desired password and password confirmation because writing out the users password in the HTML is a breech of security.

There is a better way.

Developers should ask the user if they want to use the password they already provided or supply another one i.e. the server should remember that the user put in the first time.

Grant it most of us just are too busy for that added effort. Guess I'm just a lazy idealist.

 

Tags: Musings | WebDev

Code: Friendly URLs

Ever notice the way some sites would write a URl like:

index.cfm?page=somepage&x=1

as something a little more URL friendly like:

index.cfm/page/somepage/x/1

To get this, simply include the following code in your application.cfm file!:

<cfif ListLast(CGI.PATH_INFO,".") NEQ "cfm">
  <cfif Find(".cfm",CGI.PATH_INFO)>
      <cfset lenRHSofDotCFM = Len(CGI.PATH_INFO) - (Find(".cfm",CGI.PATH_INFO)+4)>
  <cfelse>
      <cfset lenRHSofDotCFM = Len(CGI.PATH_INFO)>
  </cfif>
  <cfif lenRHSofDotCFM GT 0>
      <cfset RHSofDotCFM = Right( CGI.PATH_INFO, lenRHSofDotCFM )>
      <cfset numURLItems = listLen(RHSofDotCFM,'/')>
      <cfset numURLItems = numURLItems - (numURLItems mod 2)>
      <cfloop from="1" to="#numURLItems#" index="i" step="2">
          <cfset URL[ GetToken(RHSofDotCFM,i,'/') ] = GetToken(RHSofDotCFM,i+1,'/')>
      </cfloop>
  </cfif>
</cfif>

PS. I made this site wider since I figure that anybody reading this site must be working with at least a 1024x768 resolution and the text is easier to read this way, don'tcha think.  If the site looks a little odd, try deleting your browser cache - the flash headers on the blog posts are caching big time. I've deleted Internet Explorers cache a few times now and its still cached. Looks fine in Firefox though so I guess it'll sort itself out.

Tags: ColdFusion | Tips | WebDev

About Topper on ColdFusion

Peter Coppinger aka Topper is a neurotic web monster who spends most of his chaotic life developing ColdFusion web applications when not drinking himself into a stupor and scheming his plans for world dominance.

Peter founded Digital Crew way back in 1999. Digital Crew run CFTagStore.com and have also produced lots of powerful ColdFusion tools like ProFlashUpload and CFMyAdmin.

I made this site to share my thoughts, tips and tools with fellow ColdFusion developers.

If your a ColdFusion developer, go ahead and subscribe to this site and in exchange i'll try to provide quality content to make it worth your while.
RSS Feed for Topper on ColdFusion

    I'm speaking at CF-United Europe!

    CFDevCon I'm going to be speaking at CFDevCon08! It's my second time speaking in front of more than 10 people so please lend your support.

    The topic is:
    Introducting TeamworkCMS and Site Engine - Building better websites in half the time or something like that..

    Digging

    My Work - Just Finished

    • modules.cit.ie
      Web-=based modules/programmes designer tool and database system for Cork institute of technology.
    • Teamwork Project Manager
      The top secret project is finally released. The project management app will rock your world - give it a go.
    • PMG
      New website for Project Management Group website.
    • Digital Warehouse Wholesale
      Added wholesale products to existing client website.
    • New Digital Crew documentation website
      New version of documentation.digital-crew.com using new InfinityCMS site engine. It's done now. Just add content.
    • PFH Company Webite
      New website/CMS/Newsletter System for prestigious Irish IT company.
    • Module Manager for CIT
      CIT is switching to module based courses. We are making an application for managing/submitting these modules. Gettig there.
    • Bons Secours Cork Hospital Intranet
      New Intranet for Bons Secours hospital in Cork. Considering turning this Intranet system into stand-alone product.
    • Revamping InfinityCMS
      I'm making major improvements to our content management solution, InfinityCMS. Making it faster, more powerful and easier to check into/out-of source control. Done but it's always going to be evolving.
    • BPC Update
      Minor functionality update for internal Pfizer Best Process Chemistry project.