cfGrid – use full document width

One of the pains of using cfgrid is that the width has to be hard-coded in. As a developer, you can’t assume the user’s screen width, even if they are admins with directions/instructions. Fortunately, to get around this shortcoming is not too difficult.

First we’ll use javascript on the back office welcome page to get the screen width and save that as a cookie. In application.cfc we’ll test for that value first in the session scope, then in cookies, and take action appropriately. Finally in the template with a cfgrid we’ll insert that value as the width.

CMS Welcome Page

When the client signs in successfully, add some javascript to the <head> of the welcome page. Lets load jQuery to make this a bit simpler. Then add some nice cookie functions. At the end of the javascript, save a cookie ‘bodyWidth’ with value of the window’s width – minus 20 just for breathing room. This works within a frame, too, by the way. After that, you want to make sure that the previous (and perhaps incorrect) bodyWidth saved in the session is erased.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
function createCookie(name, value, days) {
 if (days) {
  var date = new Date();
  date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
  var expires = "; expires=" + date.toGMTString();
 } else var expires = "";
  document.cookie = escape(name) + "=" + escape(value) + expires + "; path=/";
}

function readCookie(name) {
 var nameEQ = escape(name) + "=";
 var ca = document.cookie.split(';');
 for (var i = 0; i < ca.length; i++) {
  var c = ca[i];
  while (c.charAt(0) == ' ') c = c.substring(1, c.length);
  if (c.indexOf(nameEQ) == 0) return unescape(c.substring(nameEQ.length, c.length));
 }
 return null;
}

function eraseCookie(name) {
 createCookie(name, "", -1);
}

$(document).ready(function(){
 createCookie("bodyWidth", $(document).width()-20, 14);
});
</script>
<cfset structDelete(session, 'bodyWidth') />

Application.cfc

In the ‘OnRequestStart’ function of application.cfc you’ll need this snippet. It checks to see if there is a session variable of ‘bodyWidth’. If not, it looks for the cookie. If no cookie, default to 1067. Of course you can set that default to whatever you’d like.

<!--- GRID WIDTHS --->
<cfif not isDefined("session.bodyWidth")>
 <cfif isDefined("cookie.bodyWidth")>
  <cfset session.bodyWidth = cookie.bodyWidth>
 <cfelse>
  <cfset session.bodyWidth = 1067>
 </cfif>
</cfif>

Template with cfGrid

Now the easy part. In your cfGrid tag simply use the width stored in session.

...
width="#session.bodyWidth#"
...

Custom scrollbars in Adium – ‘Elegant Simple’ Message Style

Visually based on the “Pretty Simple” Message Style by Piotrek Marciniak, I’ve created a new breed of Adium Message Style – which boasts a completely custom scrollbar.

This message style is a working proof of concept. It is a prototype for the talented folks that create¬† wonderful message styles. I’m a developer, not an artist. I hope that others will use it as a spring board for rapid development of a whole new breed of message styles with custom scrollbars.

Since Adium Message Styles are really web pages, it only seemed right to mash up Prototype JS, LivePipe UI and Scriptaculous!

Features

  • Fade-in of messages
  • Auto smooth scrolling when new message is received
  • Custom styled scrollbar
  • Dynamic height scrollbar handle
  • Header and Footer objects of scrollbar handle
  • Auto-hiding and fading scrollbar (mouse in/out of window)
  • Mouse wheel support

[media id=11 width=600 height=470]

( View full size 800×600 MP4 3.7MB )

Go and get it!

Compressed Prototype 1.6.1 and Scriptaculous 1.8.3

I created a new compressed file for Prototype 1.6.1 and Scriptaculous 1.8.3. Included is my modified sound.js.

The combined file is 268KB. The load order is as follows:

  • prototype
  • builder
  • effects
  • dragdrop
  • controls
  • slider
  • sound

It includes all comments and credits. I gzipped it down to 60KB.

For your convenience in the attached zip contains both versions and a ColdFusion file to serve the correct one. You’d load it like so:

<script type="text/javascript" charset="ISO-8859-1" src="/includes/js/scriptaculous/scriptaculous.cfm"></script>

Well, what are you waiting for? ūüôā wv-scripty-183.zip

A better Fix for IE6 and gzip compressed javascripts

In previous posts I found a fix for an intermittent problem with IE6 not loading compressed javascripts. IE was loading the first zero bytes of the gzipped javascripts. But if you copy-paste the url of the javascript it loads fine. And then the pages with those javascripts work just fine from there on. That fix was to exclude IE6 from receiving the compressed version.

Well, this fix is much better. Just add blank Pragma and Cache-control headers. No need to exclude IE6 from receiving the compressed js.

<cfif cgi.HTTP_ACCEPT_ENCODING contains "gzip">
	<cfheader name="Content-Encoding" value="gzip" >
	<cfheader name="Content-Disposition" value="inline; filename=""protoaculous182min.jgz""">
	<cfheader name="Content-Type" value="application/x-javascript; charset=ISO-8859-1">
	<cfif cgi.HTTP_USER_AGENT contains 'MSIE 6.0; Windows'>
		<cfheader name="Pragma" value="">
		<cfheader name="Cache-control" value="">
	</cfif>
	<cfcontent deletefile="no" file="#expandpath('./protoaculous182min.jgz')#" type="application/x-javascript; charset=ISO-8859-1">
<cfelse>
	<cfheader name="Content-Disposition" value="inline; filename=""protoaculous182min.js""">
	<cfheader name="Content-Type" value="application/x-javascript; charset=ISO-8859-1">
	<cfinclude template="protoaculous182min.js">
</cfif>

Fix for Safari and gzip compressed javascripts

Yesterday I showed how to use¬†cgi.HTTP_USER_AGENT to not push gzipped javascripts to IE6. After fixing that guess who starts choking? IE’s bastard stepchild: Safari. I don’t trust Safari any more than I do IE.¬†Unfortunately¬†my client base uses it all the time: Designers!

After some digging around I learned that you cannot send compressed javascripts to Safari with the extension of “gz”. It must be “jgz”. Steve, you have got to be kidding me.

So here it is fixed… notice the modified filename in the Content-Disposition:

<cfif cgi.HTTP_ACCEPT_ENCODING contains "gzip" and cgi.HTTP_USER_AGENT does not contain 'MSIE 6.0; Windows'>
	<cfheader name="Content-Encoding" value="gzip" >
	<cfheader name="Content-Disposition" value="inline; filename=""protoaculous182min.jgz""">
	<cfheader name="Content-Type" value="application/x-javascript; charset=ISO-8859-1">
	<cfcontent deletefile="no" file="#expandpath('./protoaculous182min.gz')#" type="application/x-javascript; charset=ISO-8859-1">
<cfelse>
	<cfheader name="Content-Disposition" value="inline; filename=""protoaculous182min.js""">
	<cfheader name="Content-Type" value="application/x-javascript; charset=ISO-8859-1">
	<cfinclude template="protoaculous182min.js">
</cfif>

Work flawless in Safari3, IE6, IE7, IE8, and Firefox3.

Fix for IE6 and gzip compressed javascripts

For the past two weeks I’ve been struggling with a website. In particular, IE bugs. Of course.

What I had the most problem with is an intermittent problem with IE6 not loading compressed javascripts. It spews out cryptic javascript errors. The debugger is a joke. If you hit reload, sometimes it works. Sometimes it does not. Then it works fine for quite a while. Then the client emails ‘broken’ messages. Argh what a mess.

It turns out to be a bug in IE that has been around since version 5.5 until version 7. Yes that’s right, 6 years! IE loads the first zero bytes of the gzipped javascripts. But if you copy-paste the url of the javascript it loads fine. And then the pages with those javascripts work just fine from there on (probably cached at that point). Wow. Nice work Redmond!

After figuring this out I quickly made a fix. I’ve been using prototype and scriptaculous compressed for quite some time. Since 99% of my work is on shared hosting I just use ColdFusion to server the gzipped version if the browser allows it (keep in mind this is the old code that can have problems in IE6):

<cfif cgi.HTTP_ACCEPT_ENCODING contains "gzip">
	<cfheader name="Content-Encoding" value="gzip" >
	<cfheader name="Content-Type" value="text/javascript" >
	<cfcontent deletefile="no" file="#expandpath('./protoaculous182min.gz')#" type="text/javascript">
<cfelse>
	<cfinclude template="protoaculous182min.js">
</cfif>

The fix then is to exclude IE6, too, from receiving the compressed version. I also added some other bits to make it nicer and more proper:

<cfif cgi.HTTP_ACCEPT_ENCODING contains "gzip" and cgi.HTTP_USER_AGENT does not contain 'MSIE 6.0; Windows'>
	<cfheader name="Content-Encoding" value="gzip" >
	<cfheader name="Content-Disposition" value="inline; filename=""protoaculous182min.gz""">
	<cfheader name="Content-Type" value="application/x-javascript; charset=ISO-8859-1">
	<cfcontent deletefile="no" file="#expandpath('./protoaculous182min.gz')#" type="application/x-javascript; charset=ISO-8859-1">
<cfelse>
	<cfheader name="Content-Disposition" value="inline; filename=""protoaculous182min.js""">
	<cfheader name="Content-Type" value="application/x-javascript; charset=ISO-8859-1">
	<cfinclude template="protoaculous182min.js">
</cfif>

That seems to work flawless in IE6, IE7, IE8, and Firefox3.

Whew. Hope someone out there finds this helpful!

bd

JS Audio – update to scriptaculous sound

I’ve made a fork of scriptaculous at github and put in an important edit to sounds.js. The pull request is in but if you don’t want to wait, you can grab the updated sound.js below¬†.

Problem

While working on a website for design firm, they noticed the problem. When navigating to another page then back, lots of sounds would fire off. Weird!

In my original JS Audio Engine I was killing the element that played the sound after a set amount of time. That cleaned up the page. However when it was folded into scriptaculous so long ago, that code was removed/changed. So it made perfect sense that when you leave the page and come back, the browser sees all those elements and plays them. I’ve never noticed it because I’ve only used sounds in one-load-websites (ajax). There was never any web page navigation involved.

Solution

Not to undo any work done when incorporated into scripty, I came up with a self cleaning solution. When the js file is loaded it creates a random number ID:

randID = 'scriptaculous-soundboard-'+Math.floor(Math.random()*1000000000);

I know there is a way to create a UUID with prototype, but I don’t know it. Anyway… upon the first sound being played a hidden div with an ID of that random number is created:

// Is the soundboard created yet?
if (!$(randID)) {
	$$('body')[0].insert(
		new Element('div',{
			id: randID,
			style: 'visibility:hidden;'
		})
	);
	// All sounds will play from this soundboard
}

All sounds are now created within that div, instead of at the end of the BODY. When the page is left (onbeforeunload) that div is removed.

// Remove the soundboard when leaving
window.onbeforeunload = function() {
	if ($(randID)) {
		document.body.removeChild($(randID));
	}
}

So when you navigate back, no sounds play.

Download sound.js.zip
Follow github project

ColdFusion file upload progress

While working on the File Manager, and the upload function in particular, I had in mind to create a nice upload progress indicator. And I don’t want to use Flash, Java, or anything special installed on the server. So this is what I came up with:

[media id=9 width=547 height=444]

It seems pretty magical at first. But after I break it down here, you might think “oh yeah… easy!”. Here are the steps it takes to pull it off:

  1. Reset all variables and labels.
  2. Ask CF for the list of files in the temp dir.
  3. Start the upload, and start the timer.
  4. Using the list of files above, ask CF if the list has changed yet. Do this every second until a change is noticed. When a difference is reported, that is our upload-in-progress file. For this I used a CF function called ListDiff by Ivan Rodriguez. It compares lists (in this case, our initial and current dir) and returns the difference.
  5.  Every second, ask CF for the size of that file.
  6. Update the labels with the information every second (size, time, size/time). Use prototype to tween the size in 0.8s.
  7. On the upload action page use a JS to stop the timer and report the success.

There is a bunch of optimization to be had. Mostly in the ajax calls which, although they have fault tolerance, aren’t to smart about it. And also in the management of when ajax calls are made (there is a chance they can step on each others’ toes).

The final product to be entered into the file manager will of course be much more subtle than this. Simply displaying the Size and Speed. When the upload is done, everything goes away.

For your convenience, I updated Visual Code Editor to have TinyMCE accept iframes and I put the live demo in one below. But if you prefer, here is a direct link: ColdFusion file upload progress.

So… what should I call this thing? CFup?

WVFM (WebVeteran’s ColdFusion File Manager) build 081014

I was able to give more hours to the wvfm. As planned, I started to incorporate Finder-like column navigation:

When clicking a dir the contents load on the right by an ajax function. The view automatically slides left to the new column.

Its sloppy looking right now. But the final omelet should be tasty.

WVFM (WebVeteran File Manager) build 081008

I haven't come across any ColdFusion file manager that is good, free, and can be used with TinyMCE. Even the commercial products don't impress me. And  don't like relying on PHP in my CF applications. So I'm writing my own File Manager, WVFM. Sounds like an oldies station ūüôā I plan on releasing it as open source for free.

The following are my main goals for WVFM:

  • Speed
  • Aethetics
  • Easy to install
  • Easy to use

I plan to accomplish those goals with:

  • Optimized code (CFML and HTML/CSS)
  • FamFamFam Silk Icons, and a designer willing to help for free
  • AJAX w/ Scriptaculous web2.0 javascript library
  • Mimics Mac OSX Finder's column view navigation
  • Extra information for webmasters and content editors

Right now it's pretty much a drag and drop CFC. It runs immediately by navigating to its loader (index.cfm) with good default settings.

It figures out the root dir of the website, and if you're navigating within it, allows you to click on files to view/listen/download.

Every attribute of a file/dir is sortable. Sorting is prioritzed automatically as you sort by attribute. That sorting is saved as a cookie for when you return.

You can specify which attributes of the objects you need to see. The code is optimized to not bother asking the file system for those attributes. Good optimization for a large number of objects in a directory.

WebVeteran File Manager 081008

More to come! Next is making navigation like Finder's column view.