Using other plug-ins with the JQuery Carousel Plug-in and event issues

This entry examines how the JQuery Carousel object interacts with other Plug-ins, and how to combine those plug-ins with the Carousel functionality. I also cover an issue where the jCarousel plug-in does not apply functionality to non visible elements on load.

I have been using two different JQuery Carousel plugins for a while now. The slightly older jCarousel ( http://sorgalla.com/jcarousel/) and the jCarousellite plug-in ( http://www.gmarwaha.com/jquery/jcarousellite/ ). Both work well, and both allow you to scroll through content in 'Rich' manner.

The problem

What I also want to combine with these is a lightbox ( FancyBox ). A user scrolls through the Carousel and clicks on one of the items, the item click invokes the lightbox script and the lightbox 'pops up'. This works for the items that are actually on display when the page loads. For all the other items it does not work. Clicking them simply takes you to their URL, and does not invoke the lighbox.

Debugging

It appears that the Carousel code that hides the off screen elements also causes them to be skipped in the DOM when the lighbox is applied. When you view their source they appear to have the right class, but they simply don't work.

The solution

Moving the position of the call to the lightbox will fix this. Usually you specify that a JQuery function loads when the document is ready, like this:

<s/cript type="text/javascript">
$(document).ready(function(){
//my function code goes here
});
</script>

Instead we have to move our lightbox code to a position where it will be triggered on each Carousel movement. In that way the JQuery is applied to each newly visible element.

The code looks something like this:

<s/cript type="text/javascript">

// build an Array of data for the carousel
var mycarousel_itemList = [
{url: "http://static.flickr.com/66/199481236_dc98b5abb3_s.jpg", title: "Flower1"},
{url: "http://static.flickr.com/60/199480111_87d4cb3e38_s.jpg", title: "Flower2"},
{url: "http://static.flickr.com/70/229228324_08223b70fa_s.jpg", title: "Flower3"}
];

// run as each item loads
function mycarousel_itemLoadCallback(carousel, state)
{
for (var i = carousel.first; i <= carousel.last; i++) {
if (carousel.has(i)) {
continue;
}

if (i >
mycarousel_itemList.length) {
break;
}

// Create an object from HTML
var item = jQuery(mycarousel_getItemHTML(mycarousel_itemList[i-1])).get(0);

        // this runs whenever an item comes into focus
        alert(i);

// this adds all the newly formed elements to the div
carousel.add(i, item);

// apply our lightbox effect to each of the new elements
$("a.iframe").fancybox({
        'speedIn'        :    600,
        'speedOut'        :    200,
        'overlayShow'    :    true});

}
};

/**
* Item html creation helper.
*/

function mycarousel_getItemHTML(item)
{
var url_m = item.url.replace(/_s.jpg/g, '_m.jpg');
return '<a href="' + url_m + '" title="' + item.title + '" class="iframe"><img src="' + item.url + '" width="75" height="75" border="0" alt="' + item.title + '" /></a>';
};

// apply the carousel script to the correct div
jQuery(document).ready(function() {
jQuery('#mycarousel').jcarousel({
size: mycarousel_itemList.length,
itemLoadCallback: {onBeforeAnimation: mycarousel_itemLoadCallback}
});
});

</script>

By positioning the lightbox code inside the call back function it is applied to each element as they gain visibility.

An demo of this is here.

Integrating Google search into your site using ColdFusion and XML

Rather than writing a custom search, and indexing service for your sites you can use Google to do the leg work for you.

This article examines how you can create and integrate a Google site search into your site. We will query Google and return an XML packet, which we will translate and display within our sites framework.

I am using XML as I must parse the result myself for Accessability. There are a few different ways of returning result, including some really nice AJAX stuff. None of them are Accessable for disabled users though.

To start with go here: http://www.google.co.uk/sitesearch

You can setup a free or Business account. This allows you to specify which sites the search will index, and any exclusions or filtering rules you want. The main difference between the free and Business accounts is the control you have over advertising.

The first step to create a simply search form, the simple form below will submit a form value to a processing template that we will build below.

<form name="gSearch" action="page.cfm" method="post">
<label for="q">Search:</label> <input type="text" name="q" id="q">
</form>

Next we need to create the template that will handle the form value, and process the results (page.cfm from the form above). The first step is to create a url string that we will use in a cfhttp request. This fires your form value to Google. We also specify that we want the return in an XML format. The http request is parsed using xmlParse.

<cfparam name="attributes.q" default="">
<h1>Search results</h1>

<cfif not len(attributes.q)>
Please enter some search text
<cfelse>

<cfset variables.url = "http://www.google.com/cse?cx=YOUR_ACCOUNT_NUMBER&client=google-csbe&output=xml_no_dtd&q=">
<cfset variables.url = variables.url & attributes.q>

<cfhttp url="#arguments.url#" method="get" result="variables.response"></cfhttp>

<cfscript>
    xmlfile = xmlparse(variables.response.filecontent);
</cfscript>

<cftry>
<cfset arrEntries = variables.response.gsp.res.r>
<cfcatch>
<!--- no response --->
<cfset variables.noResults = true>
</cfcatch>
</cftry>

In the next block of code we check that we successfully parsed the XML and that we have a valid Array. Then we loop over the results Array setting the values we want. Then display them on the page.

<cfif variables.noResults>
<p>There were no results for your search using <strong>#attributes.q#</strong></p>
<cfelse>
<p>Below are the results for your search on '<strong>#attributes.q#</strong>'</p>
<p></p>

<cfloop index="i" from="1" to="#ArrayLen(arrEntries)#">
<cfset properties["searchTitle"]    = arrEntries[i].XmlChildren[3].XmlText>
<cfset properties["searchString"]    = arrEntries[i].XmlChildren[5].XmlText>
<cfset properties["searchUrl"]        = arrEntries[i].XmlChildren[1].XmlText>

<h3 class="search-header"><a href="#properties.searchUrl#" title="#properties.searchTitle#" target="_blank">#properties.searchTitle#</a></h3>

<div>#properties.searchString#</div>
<br>
</cfloop>
</cfif>
</cfif>

The returned XML packet has a lot more data in it than just the three values I am using, so you could expand on this.

JavaScript Library conflicts when using more than one at the same time

Whilst building a new piece of functionality I have been trying to combine a JQuery carousel plug-in and the lightview prototype plug-in. This threw up an unexpected issue. Both libraries map the dollar ($) as their shortcut indicator. JQuery uses "$" as a shortcut as a replacement for "jQuery" and Prototype uses "$" as well.

It turns out that there is a JQuery command for exactly this issue. Wherever you include the JQuery library reference add another script code. The noConflict function maps which character you tell it as the short name for "JQuery".

<s/cript src="http://www.google.com/jsapi" type="text/javascript"></script>
<s/cript type="text/javascript" charset="utf-8">
    google.load("jquery", "1.3");
</script>

<s/cript>
    jQuery.noConflict();
    var J = jQuery;
</script>

Just remember to change your references to JQuery from "$" to "J", or whatever you assign it to.

J(document).ready(function(){
code
});

Now both the Libraries can load into different namespaces.

Tracking single page sites with Google analytics code

If you have a framework that controls the URL in some way then you may have an issue when it comes to Google Analytics tracking. In this blog entry I will examine how to alter your GA tracking so that you can specify custom URL values to track. I will then apply this to a FuseBox framework.

Traditionally Google Analytics code tracks each page impression by capturing the URL and all values of the Query string, storing it in a cookie and sending it back to the Google search engine through a JavaScript call. When all your site / applications pages are "index.cfm" it may prove difficult to generate useful Analytics information.

In this example I am using a FuseBox framework. If you are unfamiliar with this, the premise is that all the templates use "index.cfm" and then pass through two parameters. The first is the component to use as a controller (we will use public.cfc) and the second value is the function name to call within that controller. So our URL may look like this:

www.mysite.com/index.cfm?go=public.login

In this case our framework will go to the controller/public.cfc and find the function "login". Google analytics will log this hit as "/index.cfm?go=public.login". This is not at all user friendly, and would be very difficult to represent usefully to a client in a report.

Instead we alter the Google Analytics code so that it is logging a pseudo URL, rather than the actual URL.

The Google Analytics code resides just before the end body html tag, at the end of your page. In the FuseBox example I am using one layout template, "lay_template.cfm" so I only need add it there.

Firstly call the Google Analytics code.

<s/cript type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>

Next we will call the Google Analytics JavaScript that builds and sends the request. The pageTracker variable is created, and your Google Analytics code is added to it. Next we call the initData function. There seems to be confliction information online about whether this is required or not. Essentially it tells the Google Logging mechanism to prepare for a request. Next we will add a line that remove the need for a Fully Qualified Domain Name (FQDN). This has a negative impact on the next line of code, and must be run before the trackPageview code.

The trackPageview code is usually left empty, but in this case we are inserting the fuseaction that has been requested. So if we are following our example above this will read as "/login". You can have as long a string here as you require. IE it could be "campaign5/landingpage2". In this way Google will log the hit as you specify as this overwrites the URL cookie that Google normally creates.

<s/cript type="text/javascript">
var pageTracker = _gat._getTracker("UA-XXXXXX-XX");
pageTracker._initData();
pageTracker._setDomainName("none");
pageTracker._trackPageview('/#variables.myFuseBox.originalFuseaction#');
</script>

This principle can also be used to track AJAX URL requests, as they do not create a unique page impression.

Returning values from mySQL in a select query as Yes/No rather than 1/0

Whilst writing a ColdFusion based query to create a JSON response I thought I'd look up returning data values as a "Yes/No" string rather than "1/0". Then I wouldn't have to transform it in any way to use in the JSON build script.

The mySQL version allows you to do this by evaluating the value, and matching a string if the condition is met, like this:

SQL version:
SELECT intid,varuserfname,varusersname, IF(intactive<>0, "Yes", "No")
FROM     table.users

This does not work in ColdFusion at all. An error is thrown:

After a little tweaking it seems that if you alias the field it does work. In the example code below I've simply aliased the field with its own name.

I'm not exactly clear why, as the error message above isn't all that helpful.

CF version:
SELECT intid,varuserfname,varusersname, IF(intactive<>0, 'Yes', 'No') as intactive
FROM     table.users

Changing the 404 template handler in IIS

You could use a 404 ColdFusion template to handle missing templates, or the onmissingtemplate Application CFC function. Luckily I have a client with half a dozen sites all on the same server, with nothing else on it, so it makes more sense to do this in Internet Information Services.

404 templates are a handy way of masking any site errors or missing templates. Not only are they a cosmetic fix to nasty display errors but they can also seriously help your server security.

A recent incident where I was helping a friend setup a custom tag path on his server demonstrated this. He couldn't remember where the webroot was to point ColdFusion server at his custom tags directory. The default IIS 404 message will quite happily serve up a template telling anyone who cares to look where your webroot is, and half the other details of your server.

Begin by opening the IIS management console. Expand the list of websites in the left-hand pane of the console, and right-click on the icon for the website you want to customize. Choose "Properties" from the popup menu, and click the "Custom Errors" tab in the configuration window.

IIS screenshot

Enter the URL for the error template. At this point I was getting an error message "The path is not a local absolute path". The error is that windows is looking for a UNC path, so it needs a proceeding forward slash.

Specify a 404 location

A few points to note in your custom 404 templates.

  • Keep it simple. It isn't part of your site, its an error handler and should not really feature any functionality.
  • 404 might mean something to us, but it probably wont to most users. Is there really any reason to display 404 all over the page?
  • The url will be relative from where the error was thrown so hard code any url values used. IE CSS images or links to anywhere.
  • Add logging. Either Google Analytics tracking, or what ever tracker you use. I also like to drop a cfmail request in there so that I know its gone wrong.

My Software Development platform specifications - whats yours?

I've been experiencing issues with my development setup, so I thought I'd write a blog entry to wrap up my findings, and try and gauge what the community is running. In this article I will detail what I use in my development environment, and how it is set up.

I've recently had errors occurring in my Eclipse IDE. There have been some very frustrating SVN client version incompatibilities, so I thought I would re install it. It turns out this was a common error (menu options in subclipse were not available) based on an incompatibility between the subclipse plug-in and the Aptana studio.

A detailed fix is in this blog entry: https://radrails.tenderapp.com/discussions/problems/173-synchronize-view-broken-after-upgrading-to-radrails-203

Software setup

I use the Eclipse Java IDE as my primary development application. Alongside this I use the CFEclipse plug-in for ColdFusion functionality, the Aptana Studio plug-in for CSS and JavaScript functionality. I also use the subclipse plug-in for SVN integration.

For Flex/AIR I use a standalone FLEX studio installation. This is pretty much a custom workspace in an Eclipse IDE. I only do this as I have had several issues trying to get FLEX installed into the regular Eclipse IDE.

I recently tried to switch to the 64 bit version of Eclipse, but it would not recognise my Java install, and from what I've read online you need to install a 64 bit version of Java. The only version of this I can find is flagged as "experimental" so I think I'll leave it well alone.

I've found it quite good to increase the default 256mb heap space in Eclipse to 512mb, there e is an article detailing how to edit the Eclipse ini file here: http://wiki.eclipse.org/FAQ_How_do_I_increase_the_heap_size_available_to_Eclipse%3F

Download links

Eclipse downloads: http://www.eclipse.org/downloads/

CFEclipse downloads: http://trac.cfeclipse.org/wiki/InstallingCfeclipse

Aptana downloads: http://www.aptana.org/studio/plugin

Subclipse downloads: http://subclipse.tigris.org/servlets/ProjectProcess?pageID=p4wYuA

Combining persistent server side (ColdFusion) variables with client side (JQuery) values

I stumbled upon an interested dilemma recently whilst building a search engine. The results of a search are returned, and can be viewed in a list or thumbnail view. The view toggle is a uses a JQuery function, so no persistent data is stored concerning a users current viewing option. The dilemma is how do you maintain the viewing mode across page reloads, such as for pagination, or filtering of the search results?

The views are both built, and toggled between using a JQuery function, like this:

sgSreilde'c)t. tFoigeglldes(
4f0r0o)m;
T
ab l e
    W h e}re) ;
(    C    o    nrdeitutrion nfsa)
lsReE;T
U    R    N }@)@;E
R    RO}R
);G
O

PRINT 'Creating< p/rsoccreidputr>e

This code will hide one of two div's based on a session variable. It also includes the code to toggle the div's with a link, like this:

<a href="javascript:void(0);" id="search-toggle">Toggle display</a>

The only way I could think of to persist the JQuery display selection was to store it as a server based session variable. I created a simple AJAX call and attached it to the toggle function, so that after each toggle the session variable was updated, like this:

$.ajax({
type: "POST",
url: "changedisplay.cfm",
dataType: "html",
cache: false,

In the template 'changedisplay.cfm' I simply update the session value to the opposite of its current value.

<cfif session.displaytype EQ "list">
    <cfset session.displaytype = "thumb">
<cfelse>
    <cfset session.displaytype = "list">
</cfif>

In this way the user can refresh or page through the result set and still maintain the same display. I'm really interested to see if anyone has done anything similar to this, or maybe taken a different angle.

Using the JQuery dataTables plugin to display dynamic data in tables: part 1

Rather than writing out long winded table code to display your data in a tabulated fashion why not use the dataTables JQuery plugin to do it for you?

In this blog entry I'll be generating tables using a JQuery plugin, but I will also be generating the JQuery code from an XML document.

The theory behind the dataTables JQuery plugin is that when the template loads it makes an AJAX request to a remotely specified template. That template returns a JSON object of data which is formatted and used in a tabular display. This means that you can perfom filtering and sort functions inline, and the JQuery simply re submits the AJAX request, receiving new JSON each time. So no refreshing.

I'll be dealing with the auto generation of the JSON back end in the second part of this article. Here is how I setup the tabular display.

Build a standard html template, including the CSS and JQuery plugins.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/transitional.dtd">
<html lang="en-GB">
<head>
<InvalidTag http-equiv="Content-Type" content="text/html; charset=iso-8859-1" lang="en">
<InvalidTag name="language" content="en-GB">

<style type="text/css" title="currentStyle">
    @import "demo_page.css";
    @import "demo_table.css";
</style>

<s/cript type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<s/cript type="text/javascript" language="javascript" src="jquery.dataTables.js"></script>

Next we build our JQuery function. I wont go into massive detail about all the parameters and values being passed in here, but it is well documented on http://www.datatables.net/.

<s/cript type="text/javascript" charset="utf-8">
$(document).ready(function() {
                $('#example').dataTable( {
                    "bProcessing": true,
                    "bServerSide": true,
                    "sAjaxSource": "content.cfm",
                    "aoColumns": [
{ "sName": "Edit", "sTitle": "Edit", "sWidth":"10%"} ,
{ "sName": "Band", "sTitle": "Band"} ,
{ "sName": "Genre","sTitle": "Genre"} ,
{ "sTitle": "Fake Column"}
],
                    "sPaginationType": "full_numbers",
                    "aaSorting": [[1,'asc']],
                    "oLanguage": {
                        "sLengthMenu": "Page length: _MENU_",
                        "sSearch": "Filter:"
                    }
                } );
            } );
</script>

The really important column here is the "aoColumns" JSON data block. This specifies what fields are returned from your AJAX call, and parameters they must adhere to.

In this example we are anticipating that we will receive four columns of data back (Edit,Band,Genre and Fake Column).

Lastly we create a table with an ID of "example", as this is what the JQuery is looking for. This table must be formatted in a certain way, as the JQuery plugin will re write the specified elements.

<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
<thead>
<tr>
<th>Edit</th>
<th>Band</th>
<th>Genre</th>
<th>Fake Column</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="3" class="dataTables_empty">Loading data from server</td>
</tr>
</tbody>
</table>

The code also contains the header elements that will match the returned column values from the AJAX request. The last part of the table is displayed when the data is loading.

This all works well, but to extend it further I have altered the code to read from an XML document. The XML document Is loaded when the template starts, and the data fields and attributes are read, and looped over to create the JQuery code and table headers. In this way it is a generic table display template, driven from an XML document.

The XML doc:

* History < ? x:m lv evresrisoin onnu=m"b1e.r0 " ? >
< f o r m >
*/
/* < f i e l d s N a m e = " E d i t " s o u r c e = " d a t a " s T i t l e = " E d i t " s W i d t h =*"1/0
%">/*Ed**i*t****************<**/f**ie**l*d*>*
* * * * * *****************<*f*i*e*l*d* *s*N*a*m*e*=*"*B*a*n*d*"* *s*o*u*r*c*e*=*"*d*at/
a
" sTitle="Band">Band</field>
<field sName="Genre" source="data" sTitle="Genre">Genre</field>
<field sName="fake column" source="" sTitle="Fake Column">Fake column</field>
</form>

Read the XML file and parse it out into an Array:

< ! - - - p a r s e t h*e/ x
ml/ *f i l e - - - >
< cfset v a r i a b l e s . x m l = X M L P a r s e ( " t e s t . x m l " ) / >
< !*-/-
- /<* c f d u m p v a r = " # v a r i a b l e s . x m l # " l a b e l = " R a w x m l d o c u m e n t " > - - - >
*</
cfset/ *v a r i a bAluetsh.ofri e l d s = X:M LASuetahrocrhn(avmaer i a b l e s . x m l , " f o r m / f i e l d " ) >
< cfset v a r*ia/
b
les/.*t o t a l RDeactoe rwdrs i=t tAernr a y L:e nD(avtae r i a b l e s . f i e l d s ) >

Use something like this to dynamically generate the JQuery and table values:

Q "/d*at**a"**>*"*s*N*a*m*e*"*: *"*#*v*a*r*i*a*b*l*e*s*.*f*i*e*l*d*s*[*v*a*r*i*a*b*l*e*s*.*i*n*d*e*x*]*.*X*m*l*A*t*t*r*i*b*u*t*e*s*.*s*N*a*m*e*#*"*,***<**/*c*f*i*f/>

/ *          < c f i f s t r u cCtokmpeyaneyx iNsatmse( v a r i a b l e s . f i e l d     s    [    v    a        r    i*ab/l
es/.i*n**d*ex*]*.**X*ml*A*t**tr**ib**u*te*s*,* *'*s*T*i**tl**e*')**>*"*s*T*i*t*l*e*"*:* *"*#*v*a*r*i*a*bl*e*s**.*fi*e**l*ds*[**v*a*r*i*a*b*le*s*.*i*n*d*e*x*]**.*X*ml/A
ttr/i*b u t e s .PsrTocietldeur#"e N<ame/ c f:i fdb>o
. s s p_<stcofrief d_sptrrouccntkaemey e x i s t s ( v a r i a b l e s . f i e l d s [ v a*r/i
a
bl/e*s . i n d ePxa]r.aXmmeltAetrtsr i b u t e:s , ' s W i d t h ' ) > , " s W i d t h " : " # v a r i a b l e s . f i e l d s [ v a r*i/ab
le/s*. i n d e xR]e.tXumrlnA tCtordeisb u t e s: . s W i d t h # " < / c f i f >
} < c f i f v a r i a b l e s . i*nd/
e
x N/E*Q v a r i a b l e s . t o t a l R e c o r d s > , < / c f i f >
< / c f l o o p >
< / c f o u t p*u/t
>

/*< ! - - - Dteasbclrei pvtailoun e s -:- -De>sc
r
ipt<iocnf oouf twphuat>t
i t do<esc,f lpoaorpa misn edetcx = " v a r i a b l e s .*i/n
de/x"* f r o m = " 1 " t o = " # A r r a y L e n ( v a r i a b l e s . f i e l d s ) # " >
< t h a l i g*n/=
"
l/e*f t " > # v a r i a b l e s . f i e l d s [ v a r i a b l e s . i n d e x ] . X m l T e x t # < / t h >
* /

</*/ c f l o o p >
< / c f o u t p u t >

The JSON response is hard coded in this example, so the result will not filter or search. I'll handle that in article two.

There is a full example of this here.

Creating a pop up floating div with JQuery

This entry will deal with how to create a displayed / collapsible floating div, using JQuery. When I build a web platform I often like to include small sections of text alongside the functionality, just to provide the users with a little guidance on what is going on. Rather than having these inline, where they can often interfere with the content and display, I like to add them to a 'help' div that I float inside the framework. First we include the JQuery library from Google, and our link. It doesn't go anywhere, but we will attach a JQuery event to it.
<s/cript type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>

<a href="javascript:void(0);" id="help">Pop me up</a>
<div>stuff</div>
Next we create our JQuery function, attached to the 'help' div. This adds a div to the document with whatever content you have set in it. There is also a 'close' link in the floating div that calls the close function.
<s/cript>
$(function() {
$("#help").live('click', function(event) {
$(this).addClass("selected").parent().append('<div class="messagepop pop">Content<p><a class="close" href="/">Cancel</a></p></div>');
$(".pop").slideFadeToggle()
return false;
});

$(".close").live('click', function() {
$(".pop").slideFadeToggle();
$("#contact").removeClass("selected");
return false;
});
});

$.fn.slideFadeToggle = function(easing, callback) {
return this.animate({ opacity: 'toggle', height: 'toggle' }, "fast", easing, callback);
};
</script>
Lastly we add some styling and positioning to tie the whole lot together. This gives the pop up div its shape and style. I've positioned the floating div on top of the calling function text.
<style>
a.selected {
background-color:#1F75CC;
color:white;
z-index:100;
}

.messagepop {
background-color:#FFFFFF;
border:1px solid #999999;
cursor:default;
display:none;
margin-top: 15px;
position:absolute;
text-align:left;
width:394px;
z-index:50;
padding: 25px 25px 20px;
top: 0px;
left: 0px;
}
}

label {
display: block;
margin-bottom: 3px;
padding-left: 15px;
text-indent: -15px;
}

.messagepop p, .messagepop.div {
border-bottom: 1px solid #EFEFEF;
margin: 8px 0;
padding-bottom: 8px;
}
</style>
You can see an example functionality here.

More Entries

Site Credits
Aggregated by ColdfusionBloggers.org Powered by Coldfusion