Blog of Steve Savage A blog for business analysts and architects, and fellow user's of Sparx's EA

12Jun/083

CFSelect: getting ‘bind’ to work with selected values

Problem addressed

This article provides a workaround allowing you to specify the selected items for cfselect when using the new AJAX bind function.

Solution

My example is a modification of the cfselect example taken from livedocs:

Upload fixColdfusionAjax.js to your site, and call the file using the script tag

<head>
 <title>your page</title>
 <script src="/{path}/fixColdfusionAjax.js></script>
</head>
<cffunction name="getValues" access="remote">
 <cfscript>
  VAR LOCAL = structNew();
  LOCAL.array = arrayNew(2);
  LOCAL.array[1][1] = "0";
  LOCAL.array[1][2] = "-- relationships --";
  LOCAL.array[1][3] = false; // not selected
  LOCAL.array[2][1] = "1";
  LOCAL.array[2][2] = "author";
  LOCAL.array[2][3] = true; // selected
  LOCAL.array[3][1] = "2";
  LOCAL.array[3][2] = "publisher";
  LOCAL.array[3][3] = true; // selected (can have multiple values selected)
  return LOCAL.array;
 </cfscript>
</cffunction>

I will show a live example once I migrate this site to CF 8

Background

I've been slowly working on a new version of this site, and as part of the back end I wanted to use Coldfusion's new AJAX features for <CFForm>.

I quickly discovered that for some really bizarre reason, when you use the "bind" attribute to get the values for an option list <CFSELECT>
you can't indicate which options are selected.

I searched the net and found some work around's by Todd Sharp
and Ray Camdem but they seemed a bit awkward to me.

So, I decided to take a look at Coldfusion's AJAX javascript. After some digging I found out the problem was really simple to fix.

I've created the file fixColdfusionAjax.js, that contains JavaScript that over-rides a function from Coldfusion's cfajax.js code library to add support for selecting options

4Apr/080

Browser Specific Stylesheets

Problems addressed

  • How to Use Different CSS Style Sheets For Different Browsers
  • Dealing with Inconsistencies in how Cascading Stylesheets are rendered by different browsers
  • Older browsers crashing when trying to load and render modern stylesheets

Solution

I have used conditional comments and avoided CSS hacks as much as possible to prevent future compatible issues.

I have found that the majority of browsers support font, colour, and absolute positioning fairly consistently,
so I created a shared.css that contains features that will work with all browsers,
with style sheets below extending the shared stylesheet as required (@include:url...).

00 <style type="text/css">
	@import url('/_site/basic.css'); // must be single quotes
	</style>
01 <!-- WIN IE Style Sheets -->
02 <!--[if IE]>
03  <![if gte IE 5.5]>
04   <![if gte IE 7]><link rel="stylesheet"
	type="text/css" media="screen,projection"
	href="/_site/ie_win_7x.css" />
	<![endif]>
05   <![if lt IE 7]><link rel="stylesheet"
	type="text/css" media="screen,projection"
	href="/_site/ie_win_5.5x_6x.css" />
	<![endif]>
06  <![endif]>
07  <![if lt IE 5.5]>
08   <link rel="stylesheet"
	type="text/css" media="screen,projection"
	href="/_site/ie_win.css" />
    <![endif]>
09 <![endif]-->
10 <!-- Everything else -->
11 <!--[if IE]><![if !IE]><![endif]-->
12  <!-- standard : Sam Foster's comment hack (hide from MAC IE) -->
	<style type="text/css" media="screen,projection">
	/*\*/ @import url("/_site/standard.css") all; /**/
	</style>
13  <!-- MAC IE : Tantek &##xC7;elik comment hack (only for MAC IE) -->
	<style type="text/css" media="screen,projection">
	/*\*//*/ @import url("/_site/ie_mac.css"); /**/
	</style>
14 <!--[if IE]><![endif]><![endif]-->
15 <!-- Netscape 4.x Style Sheets (because I can) -->
	<script type="text/javascript">
	<!--//--><![CDATA[//><!--
16 if(document.layers) {
	document.write(unescape('%3CLINK%20href%3D%22
	/_site/netscape-4x.css%22%20rel%3D%22
	stylesheet%22%20type%3D%22text/css%22%20/%3E')); }
17 //--><!]]></script>
  • Basic CSS: line 0
    • uses the @import to hide the style sheet from Netscape 4.x browsers
    • this is the only stylesheet loaded by WIN IE 4.x and MAC IE 4.x
  • Windows IE: lines 1 to 9
    • used downlevel-hidden conditional comments to hide WIN IE style sheets from non-WIN IE browsers and WIN IE 4.x or less
    • used link instead of @import to prevent the IE rendering issue (annoying flash of unformatted content)
    • Lines 3 to 5. I like to use PNGs with alpha transparencies in my layouts and support for PNGs in WIN IE has be 'unique' to put it mildly.
      Before WIN IE 5.5 there was no support, WIN IE 5.5 and 6.x provided support using proprietary 'filters', and WIN 7.x finally provided native support,
      so I had to create seperate stylesheets for these 3 ranges, e.g. pre 5.5, 5.5 to 6.x, and 7.x
  • Other Browsers: lines 10 to 14
    • used downlevel-revealed conditional comments to hide all non-WIN IE stylesheets from WIN IE 5.x + browsers. (lines 11 to 14)
    • used CSS hacks to filter for MAC IE 4.x/5.x and WIN IE 4.x, luckily these are dead browsers, so this isn't going to be fixed, but there may be an issue with one of these hacks if a new browser is release with the same bug, but the risk is low
  • Standard: line 12
    • used Sam Foster's comment hack to hide my standard style sheet from IE Mac,
    • used the media 'all' hack to hide from WIN IE 4.x.
    • used the url double quote bug to hide from IE MAC 4.x.
  • MAC IE: line 13
  • Netscape 4.x: line 15 to 17
    • used @import to hide non-WIN IE stylesheets from Netscape 4.x
    • used Javascript to load the stylesheet for Netscape 4.x (Netscape 4.x only renders stylesheets when Javascript is turned on).

Background

Fortunately browsers are moving to more consistent implimentation of standards (e.g. IE 7), unfortunately not everone has updated to the latest versions.

The browser wars are ending, but there are still the old browsers of the 90s and early 2000s that some people still use,
and the bane of my existence IE for the Mac (come on Mac people, switch to Safari or Firefox already).

This all started when for the weatheroffice website I had to find a way to use CSS for layouts, avoid javascript, provide static pages (no server side detection of browsers allowed due to load on the servers), and pass W3C CSS, and XHTML strict verification.

The end result is that my standard.css stylesheet is the default stylesheet for my site, with the other non-standards browsers recieving what they need to deal with their 'quirks'.

27Mar/060

Portable Network Graphics (PNG)

Problem addressed

Using Portable Network Graphics (PNG) as content in IE

One of the most annoying problems designers run in to for Win IE is it's apparent lack of
support for PNG Alpha transparencies. I say "apparent" because there is a way to display
PNG's properly in WIN IE 5.5+, it's just not quite automatic.

Solution

For this I rely on JavaScript to modify the page's Document Object Model (DOM) to replace <img> tags
with <span> tags with the above AlphaImageLoader filter applied as an inline style, with
the original PNG file as the source. The width and heigth defaults to the files actually width and height unless set in the style sheet.

01 function sf_applyPNGFilter() {
02  if(document.all&&document.getElementById
	&&(navigator.userAgent.lastIndexOf('mac')==-1)) {
03   for(var i=0; i<document.images.length; i++) {
04 	// loop through all the images on the page looking for PNG files.
05    o_image = document.images[i];
06    $imageName = o_image.src.toUpperCase();
07    if ($imageName.substring($imageName.length-3, $imageName.length)
	=="PNG") {
08	/* if the image ends in PNG convert it
09	You will need to re-apply the filter any
10	time you dynamically add content that contains a PNG file,
11 	so if the PNG filter has not already been applied to an image, then apply it.
12	*/
13     if(o_image.style.cssText.indexOf('AlphaImageLoader') == -1){
14      $imageID = (o_image.id) ? 'id="'
	+ o_image.id + '" ' : '';
15      $imageClass = (o_image.className) ? 'class="'
	+ o_image.className + '" ' : '';
16      $imageTitle = (o_image.title) ? 'title="'
	+ o_image.title + '" ' : 'title="' + o_image.alt + '" ';
17      $imageStyle = (o_image.style.cssText) ? o_image.style.cssText + ';' : '';
18      o_image.outerHTML = '<span ' + $imageID + $imageClass + $imageTitle
	+ ' style="' + $imageStyle
	+ ' width:' + o_image.width
	+ 'px; height:' + o_image.height + 'px; '
	+ 'filter:progid:DXImageTransform.Microsoft.'
	+ 'AlphaImageLoader(src=\'' + o_image.src + '\');">'
 	+ '</span>';
19      i = i - 1;
20     } //if
21    } //if($imageName...)
22   } //for
23  } //if(document.all...)
24 } //sf_applyPNGFilter
25 // only run this on IE Win,
	put script call inside of an IE
	Downlevel-hidden conditional comment for extra security
if(document.all&&document.getElementById&
&(navigator.userAgent.lastIndexOf('mac')==-1))
window.attachEvent("onload", sf_applyPNGFilter);

To make sure this is only runs on WIN IE 5.5+, I place the calling <script> tag inside of a
Downlevel-hidden conditional comment statement.

<!--[if gte IE 5.5]>
  <script src="/_interface/_javascripts/imageobjectpng.js"
		type="text/javascript" defer></script>
<![endif]-->
27Mar/060

Portable Network Graphics (PNG) in IE”

Problem addressed

Supporting Alpha chanel transparency in IE using CSS

Solution

As of IE 7.x you no longer need to use filters to support PNG Alpha Channels.

01 div##wantfancypngbackground {
02 /* turn off any current background image in place
	for other browsers, typically the png */
03  background-image:none;
04 /* reload the image using WIN IE's proprietary filter */
05  filter: progid:DXImageTransform.Microsoft.AlphaImageLoader
		(src="image.png",
		sizingMethod="crop|image|scale");}
06 /* sizingMethod:
07  crop: clips the image to fit the dimessions of the object.
08  image: Default.  Enlarges or reduces the
	border of the object to fit the dimensions of the image.
09  scale: Stretches or shrinks the image to
	fill the borders of the object */

Background

One of the most annoying problems designers run in to for Win IE is it's apparent lack of
support for PNG Alpha transparencies. I say "apparent" because there is a way to display
PNG's properly in WIN IE 5.5+, it's just not quite automatic.

For PNG images that are part of the sites content, I rely on JavaScript to modify the page's Document Object Model (DOM) to replace <img> tags
with <span> tags with the above AlphaImageLoader filter applied as an inline style, with
the original PNG file as the source. The width and heigth defaults to the files actually width and height unless set in the style sheet.

20Mar/060

‘Streaming’ Flash FLV video using Coldfusion, PHP or ASP

Problem Addressed

Allowing users to jump to any point in a movie without having to wait for the entire movie to download and without purchasing expensive media server software

Solution

  1. Convert you movie file to an FLV file
  2. Run Buraks - FLV MetaData Injector on the file. This will 'inject' the byte position of the videos 'keyframes' as additional information in the FLV.
  3. Install either:
  4. Select a player:
<cfsetting enablecfoutputonly="NO">
<!--- the function that sends the feed --->
<cfscript>
 function f_StreamFLV(s_file,i_seek) {
 // i_seek = the byte position of a key frame in the video
 var i_position = i_seek;
 var i_buffer = 10000;
 var byteClass = createObject("java",
 	"java.lang.Byte");
 var byteArray = createObject("java",
 	"java.lang.reflect.Array")
	.newInstance(byteClass.TYPE, i_buffer);
 var context = getPageContext();
 var response = context.getResponse().getResponse();
 var flvinstream = createObject("java",
 	"java.io.FileInputStream");
 // take over control of the feed to the browser
 var flvoutstream = response.getOutputStream();
 byteClass.Init(1);
 flvinstream.init(s_file);
 context.setFlushOutput(false);
 try {
  if(i_seek GT 0) {
   // jump to a location of a key frame
   flvinstream.skip(i_seek);
   // output the header bytes
   flvoutstream.write(toBinary('RkxWAQEAAAAJAAAACQ=='));
  }
  do {
   i_length = flvinstream.read(byteArray,0,i_buffer);
   if (i_length neq -1) {
   flvoutstream.write(byteArray);
   flvoutstream.flush();
  }
  }
	while (i_length neq -1);
	// keep going until there's nothing left to read.
 }
 catch(any excpt) {}
 flvoutstream.flush(); // send any remaining bytes
 response.reset(); // reset the feed to the browser
 flvoutstream.close(); // close the stream to flash
 flvinstream.close(); // close the file stream
}
</cfscript>

<!--- set to false to allow the file name
	to be passed, true for a numeric ID --->
<cfset b_secure = true>

<!--- path for the movie --->
<cfset s_path = ...>
<!--- must use the extended path either in the
	form c:/path/file.flv or c:\\path\\file.flv. --->
<!--- the application.root variable is set
	in my application.cfc file,
and gives the absolute path to the root of my site --->

<cfparam name="position" default="0">
<cfif isNumeric(position)>
 <cfset i_seek = position><cfelse><cfset i_seek = 0>
</cfif>

<!--- create an array for possible movies,
or this could read an XML file, or the vidID
could be used to reference a database record --->
<cfset a_movies=ArrayNew(1)>
<cfset a_movies[1] = "##s_path##movie1.flv">
<cfset a_movies[2] = "##s_path##movie2.flv">
<cfset s_file = a_movies[1]> <!--- set the default movie ---> 

<cfif b_secure>
 <!--- I decided to use a file ID instead
	of a file name to make the script more secure --->
 <cfif isDefined("url.vidID")
 	and isNumeric(url.vidID) and url.vidID LTE arrayLen(a_movies)>
  <cfset s_file = a_movies[url.vidID]>
 </cfif>
<cfelseif isDefined("url.vidFile")>
 <cfset s_file = "##s_path####url.vidFile##">
</cfif>
<cfset f_StreamFLV(s_file,i_seek)>
<cfsetting enablecfoutputonly="NOS">

How this works

When you 'seek' to a new position in the movie, the player will determine the location of the nearest key frame (as a byte position) and passes that number to the server.

The server opens a file stream to the video, and seeks to the specified position, outputs the standard FLV header bytes, and then starts sending the file starting at that point.

Background

This is the result of a major geekout weekend, the code works, but could probably use some refactoring.

I was trying to figure out a way to stream video for a hobby site I was planning, and I came across an article on streaming flash FLV files using PHP, great I thought, but I use Coldfusion hosting services (no PHP support), I took a look at the PHP script, and it seemed fairly straight forward, but I wasn't sure how to do a binary stream in coldfusion, some more research and I found Christian Cantrell's site, with entries on Byte Arrays and Writing Binary Data to Browser putting this together with some java that I know I managed to create a script for Streaming FLV video via ColdFusion.

For the video, I compressed an AVI file (Space Quest promo video) using sorensen Squeeze 3.5, and injected the key-frame position metadata using Buraks - FLV MetaData Injector

18Apr/040

Hiding javascript from older browsers

Problem addressed

Hiding JavaScript from older browsers to prevent browser errors, and browser crashes using Google Analytics JavaScript as an example.

Solution

There are several possible approaches, but the only one I trust is object/function detection combined with try and catch:

  1. use if(functionName) to determine if the browser supports the function. Please not that function names are case sensitive (e.g. getElementByID is not the same as getElementById)
  2. unfortunately Netscape 4.x will return true even if the function doesn't exist, so you need to explictily check to see if the browser is Netscape 4.x using if(document.layer). Luckily Netscape 4.x is the only browser that supports this function.
  3. use a try {} catch {} statement to determine if a built in constant (e.g. undefined) is supported.
  4. unfortunately not all browsers support try / catch, but any browser that supports getElementById() does, so you can use if(getElmenentById) as your check before your try and catch statement.
  5. unfortunately IE 4.x doesn't support try / catch and parses all JavaScript event if it doesn't execute it (IE 4.x doesn't support getElementById), so it will
    throw an error when it reaches the try / catch statements, so you need to hide the try / catch statements from IE 4.x inside the eval() function

The following example shows how I put the above techniques in place to hide Google Analytics JavaScript from older browsers (crashed Netscape 4.x, threw an error for IE 4.x and 5.x):

01 <script type="text/javascript">
02 //<![CDATA[
03	var b_undefined_keyword_supported = false;
04  if(document.getElementById&&!document.layer) {
05   b_undefined_keyword_supported = true;
06   eval("try { var b_test = undefined; }
	catch (err)
	{ b_undefined_keyword_supported = false;}");
07  }
08  // google scripts
09  if(b_undefined_keyword_supported) {
10   var gaJsHost = (("https:" ==
	document.location.protocol) ? "https://ssl."
	: "http://www.");
11   document.write(unescape("%3Cscript src='"
	+ gaJsHost + "google-analytics.com/ga.js'
	type='text/javascript'%3E%3C/script%3E"));
12  }
13 //]]>
14 </script>
15 <script type="text/javascript">
16 //<![CDATA[
17  if(b_undefined_keyword_supported) {
18   var pageTracker = _gat._getTracker("UA-4725824-1");
19   pageTracker._initData();
20   pageTracker._trackPageview();
21  }
22 //]]>
23 </script>
  • 02: CData - see using XHTML with older browsers for details
  • 03: the main problem is googles use of the keyword undefined that isn't supported by older browsers
  • 04: use the document.getElementById check to see if the browser supports the try / catch statement, combined with the !document.layer check to make sure the current browser isn't Netscape 4.x
  • 05: the majority of browsers that support getElementById also support the undefined keyword with the known exception of IE 5.x
  • 06: use the try / catch statement hidden inside of an eval function to see if the browser supports the keyword
  • 07: if the keyword is supported load the script
  • 09: if the keyword is supported run the script

Background

As part of redeveloping my site I decided to install
Google Analytics to gather addtional information about the users accessing my site.

Based on my analysis of the browsers still used on the net I decided to test my site under Netscape 4.x+ and IE 4.x+, and found that the Google scripts crashed Netscape 4.x and caused JavaScript errors in IE 4.x and IE 5.x,
so I dug up my old page on using object detection in JavaScript, and updated it to the current page.

4Apr/040

IE Wierdness: Box Model problem in Windows Internet Explorer (IE)

Problem addressed

The handling of borders and margins in Windows Internet Explorer (IE), known as the Box Model Problem

Solution

This problem has been fixed for Windows IE 7.0

  1. Include <?xml version="1.0" encoding="UTF-8"?> as the first line in your documents. This is recommended by the W3C and will force IE 6 in to
    quirksmode, so that it will behave the same way as previous versions of IE (reducing the amount of work you need to do).
  2. Create a stylesheet for IE 4.x to 6.x browsers modifing the width and height of boxes to include the width of margins and borders.
  3. Use my browser specific stylesheets method to target the quirky stylesheets to the supported browsers.

What is Quirks Mode?

Holly Bergevin and John Gallant have written an excellent article explaining Doctypes, Standards, and Quirks mode

Background

This one drove me crazy when I was first learning CSS.
WIN IE 4.x, 5.x and 6.x in quirksmode
places borders and margins on the inside of an elements "box", where "Standard"
browsers (basically everything else) place them on the outside.

So an element set to 100px wide with a margin, and border stays 100px wide with the margin and borders placed inside the box.
Everything else gets a width of: 100px + margin width * 2 + border width *2.
Same goes for height. You can see the problem.

I decided to use conditional comments in my browser specific stylesheets method instead of
relying on css hacks to minimize future compatibility issues.

23Nov/030

Creating XHTML complient downlevel-revealed conditional comments

Problem addressed

Downlevel-revealed conditional comments do not validate

Solution

Wrap the downlevel-revealed tags (visible to non-WIN IE browsers) in downlevel-hidden start and end tags (treated as comments by non-WIN IE browsers) to hide them from validators

<!--[if IE]><![if !IE]><![endif]-->
	Hidden from IE
<!--[if IE]><![endif]><![endif]-->

Treated the same in IE as:

<![if !IE]>
	Hidden from IE
<![endif]>

Background

Supported by WIN IE 5.x +,
I mainly use this to target code/css to specific versions of WIN IE.

I currently use
downlevel-hidden conditional comments
for my browser specific style sheets.

I prefer conditional comments to the popular but
problematic css hack filters that
rely on browser bugs that may or may not get fixed.

6Sep/030

Fixed Positioning in IE

Problem addressed

Fixed positioning is not supported in WIN IE

Solution

This has been fixed in IE 7, so this solution is only necessary if you need/wish to support older versions of WIN IE.

CSS

/* turn off scrolling for the body of the document */
	html, body {overflow:hidden;height:100%;}

/* create a document box to allow the
	fixed positioning of the layers, you don't have
	to follow my naming convention */
  div##sltDocument{position:absolute;
	top:0px;left:0px;
	height:100%;width:100%;
	overflow:auto;z-index:1;}
/* create the fixed layer that will sit
	on top of or underneath the document box */
  div##sltFixed{position:absolute;
	top:0px;left:0px;
	height:40px;width:50px;z-index:2;}

HTML

<body>
  <sltDocument>
    Content and non-fixed portion of the layout goes here.
  </sltDocument>
  <sltFixed>
    This layer will stay "fixed" in place.
  </sltFixed>
</body>

Known Issues

The "fixed" layer will cover your pages scroll bars, if you align it right, or width 100%.

Background

There are five values for positioning using CSS2:
position:inherit, position:static,
position:relative, position:absolute, and position:fixed.

Unfortunately IE 6.x does not support position:fixed,
in fact WIN IE 5.0 will choke if you use position:fixed in a style sheet it can read.
But there is a way to emulate the effect of position:fixed using WIN IE proprietary features inside a
WIN IE specific style sheet:

17Jul/030

Display of unformatted html in Internet Explorer

Problem addressed

Flash of unformated content when WIN IE is loading a page

Solution

  1. Use <link href="..." rel="stylesheet" type="text/css" /> instead of
    @import in the head of your document.
    Using @import within an external stylesheet
    to import additional stylesheets does not seem to cause any problems.

  2. The existence of a <script> element (empty will do) inside of the document's
    head will prevent the flash of unstyled content.

I prefer the first option with the additional use of IE conditional comments to prevent the flash,
and to provide a browser specific stylesheet for WIN IE 5+.

Background

WIN IE has an annoying bug that causes the browser to start displaying a document before it has finished
loading all the applicable CSS, causing the page to start being displayed, before it has been formatted.
But there are a few simple ways to stop that flashed display of unformatted content.