Coldfusion Tutorials



Spry Tutorials

Air Tutorials


Quote of The Day

The objective of this tutorial is to create a rotating quote of the day. While the usefulness of this tutorial could be questionable you will be able to apply what you learn here to help you create a wide variety of more useful applications.

We will be using Coldfusion to read, manipulate, and cache, the quote of the day RSS feed from The Quotations Page. We will then use Spry to display a single quote and using the Spry Effects library fade to the next quote. We will continously loop through the available quotes switching every 6 seconds.

What You Need

You will need the following Spry library files XPath.js, SpryData.js, SpryEffects.js, SpryDomUtils.js. Additionally you will need to have Coldfusion Server 8 installed or provide the same functionality with another web programming language.

The Coldfusion Component Code

Copy the code below and save it as quotes.cfc.
<cfcomponent displayname="quotes">
<cffunction name="getQuotes" access="remote" output="yes" returntype="xml">
   <!--- get the absolute path to where we are going to store our xml starting at the webroot --->
   <cfset xmlFilePath=expandpath("/tutorials/spry/assets/xml/")>
   <!--- if the file doesn't exist or is older than one day then go grab the rss feed --->
   <cfif not fileExists("#xmlFilePath#qotd.xml") or (datecompare(getFileInfo("#xmlFilePath#qotd.xml").lastmodified,now(),"d") eq 1)>
   <!--- grab the rss feed --->
      <cffeed source = "http://feeds.feedburner.com/quotationspage/qotd"
         properties = "feedProperties"
         query = "qotd">

         <!--- the rss feed contains a lot of information we don't need so lets save to our file only what we really need --->
      <cfsavecontent variable="qotdFileXML">
         <quotes>
            <cfoutput query="qotd">
               <quote>
                  <text>
                   #mid(content,1,find('"',content,2))#
                  </text>
                  <author>
                     #title#
                  </author>
                  <id>
                     #id#
                  </id>
               </quote>
            </cfoutput>
         </quotes>
      </cfsavecontent>
      <!--- write the file out to the directory --->
      <cffile action="write" file="#xmlFilePath#qotd.xml" output="#qotdFilexml#">
   <cfelse>
      <!--- file exists or the same day so just return the xml document --->
      <cffile action="read" file="#xmlFilePath#qotd.xml" variable="qotdFileXml">

   </cfif>
   <!--- return the xml to the caller --->
   <cfreturn qotdFileXml>
</cffunction>
</cfcomponent>

The Javascript

The first thing we do in in the javascript is set up our XMLDataSet to point to the coldfusion component. Since we set the Coldfusion components access attribute to remote it automatically becomes a web-service this also enables us to access the component via a standard URL and specify the method or function we want to call within the component by using method=methodname if our method accepted arguments we could also provide those as url attribute pairs. We also set up a constant for our rotate interval of 6 seconds and define a variable that will hold the quotes elements

The next thing we do is define an observer that will be "watching" our Spry Region QOTDRegion. This observer will call the dateLoadedCallback function each time Spry fires a data event. The next thing we do is create our observer function. The argument that we are interested in here is the notificationType. We check the notification type for the onPostUpdate event, this tells us that Spry has finished with the region and all the data is loaded.

We then use the SpryDomUtilities library element selector to assign the quotes variable all the HTML elements with the class name of quote and at the same time set some style attributes, most importantly we set the opacity to 0 to make all the quotes invisible. Once we have all of the quotes we then can call our rotate function.

The rotate function should be pretty easy to follow it basically just provides a mechanism to continously loop through the quotes. The part that may be a bit confusion is the line of code "quotes.curIndex = (quotes.curIndex+1)%quotes.length" the percent sign here is the javascript modulus operator and is a nifty way to create an infinite loop. If we have 14 quotes in our list and we are at the end so currentIndex = 13 (we set the initial current index to length-1) then the currentIndex + 1 will be 14, when we mod 14 by 14 we get 0 and we are back at the beginning again. So with our curEle and our nextEle we then fade our the current element using the Spry effect library doFade effect and then right afterwards fade in the next element making sure to set up the timer for the next element to fire the rotate function again after the defined interval.

<script language="javascript">
   var dsQuotes = new Spry.Data.XMLDataSet("/spry/com/gg/qotd.cfc?method=getQuotes","/quotes/quote");
   var rotateInterval = 6000;
   var quotes;
   
//set up an observer to run on the databound region    Spry.Data.Region.addObserver("QOTDRegion",dateLoadedCallback);
   
   function dateLoadedCallback(notificationType, notifier, data)
   {
   //this observer function is called for every type of notification but we are only interested in the onPostUpdate       
if (notificationType =="onPostUpdate"){

      //we grab the number of quote div's (this is only available after the data is finished loading)          
quotes = Spry.$$(".quote").setStyle("position: absolute; top: 0px; left: 0px; opacity: 0; filter: alpha(opacity=0);");
      //call our rotate function          
rotateQOTD();
      }
   }

   function rotateQOTD(){
   //don't go any further is there aren't any quotes    
   if (!quotes|| quotes.length < 1)
      return;
   //create a variable that will point to the current quote element
   var curEle;
   
   /*we are add a current index property to our quotes only once since the next time
   the function is called it will exist*/

   
   if (typeof quotes.curIndex == "undefined")
      quotes.curIndex = quotes.length - 1;
   else
      curEle = quotes[quotes.curIndex];
   //here we increment the current index by one using mod
   quotes.curIndex = (quotes.curIndex+1)%quotes.length;
   var nextEle = quotes[quotes.curIndex];
   //run the fade effect on the current and next element and prepare the timer to run on the next element.
   if (curEle)
   Spry.Effect.DoFade(curEle, { from: 100, to: 0 });
   Spry.Effect.DoFade(nextEle, { to: 100, finish: function(){ setTimeout(function(){ rotateQOTD(); }, rotateInterval); } });
}

</script>

The HTML

The HTML for this example is really quite simple. Just put the styles in the head of your html document and you should be good to go.
<style>
.quote{
   opacity: 0;
   filter: alpha(opacity=0);
   padding:3px;
}
.quotebox{
position:relative;
   width:175px;
   font:italic 14px/18px Georgia, 'Times New Roman', Times, serif;
   color:#444;
   background-color: #F8F8F8;
   margin: 0 0 10px 10px;
   text-indent:-5px;
}
</style>
<div spry:region="dsQuotes" spry:repeatChildren="dsQuotes" id="QOTDRegion" class="quotebox">
   <div class="quote"><em>{text}</em><br>-<a href="{id}">{author}</a></div>
</div>

The Result

You should end up with something that looks similar to this
{text}
-{author}