CF Free Chat

July 25th, 2011 by Jessica Kennedy 5 comments »

After my friend at kisdigital wrote a simple chat app using jQuery and Coldfusion, I decided to extend the functionality for a recent project I had been working on. The result was a surprisingly stable chat application with the ability to PM, warn, and kick out users, plus a simple settings file to control these additional functionalities. I’ve set up a demo and download of Cf Free Chat here, so feel free to use as you’d like.

The chat application is coldfusion & jquery only, and should be highly customizable by simply changing the css.

Email Fixed!

July 25th, 2011 by Jessica Kennedy No comments »

I finally got the email function working on this blog. That should mean that I get notified when I get comments, instead of waiting 3 weeks to respond to people. Exciting!

NETWORK_ERR: XmlHttpRequest Exception 101 on Adroid Phones

July 1st, 2011 by Jessica Kennedy No comments »

So this little fella was the bane of my existance the past few days, and since my google-fu failed to yield the answer I was looking for, I figured I would post it so others would have better luck.

The scenario:
On the mobile version of a website I was working on, there was a form that was not submitting on some android phones. When the form was submitted, there was an AJAX call fired off to encrypt some data and inject the encrypted data into the form (this was for some PCI compliance rules). The AJAX call worked flawlessly in any browser (regular web or phone version) except some android phones, and we were not able to pinpoint what the difference was between phones that worked and those that did not. The AJAX call appeared to not be returning the expected data, and was instead returning the error “NETWORK_ERR: XmlHttpRequest Exception 101″. We had originally set the AJAX call to be a synchronous post. As soon as we changed the post to be asynchronous, the request went through without issue. Problem solved.

Getting Started with Web Programming

March 8th, 2011 by Jessica Kennedy No comments »

I was recently asked where to start if you were to want to learn web programming. Honestly, all you REALLY need is notepad and some great google-fu, but that’s the long difficult way of doing things, and programmers are all about making their lives easier, so here is my setup (well… mostly).

For HTML/CSS

If you can get your hands on Dreamweaver, I find it to be very helpful because it auto-completes tags. If not, there are plenty of free options that are excellent. jEdit is a good free option.

If you don’t have it already, download firefox. After installing firefox, install the Firebug plugin for Firefox. This will be your new bff.

For Coldfusion

I use cf for server-side scripting. It’s uber-expensive to buy, but luckily, you don’t have to buy it to develop with it and learn it. Plus, there are plenty of options for hosting that are reasonable with cf. Download and install Coldfusion 9 Developer’s Edition (Free). Adobe has made it tricky to find on the page… just scroll down about halfway to the Coldfusion Product Downloads section, and DL the developer’s edition.

Once you’ve downloaded coldfusion, you will have to install it. Do NOT click straight through the installation and select the suggested defaults, at least not for a couple of items. As you click through the install options, it will ask you what server you want to install CF on (i think the default is IIS). Unless you have a server running locally (and odds are very good you do not if you need this tutorial), you will want to select the “Enable Built-In Web Server” option. You will also encounter a window asking you about enabling RDS. The answer is “YES” you DO want to enable RDS. You should be able to keep the default options for everything else.

Once you’ve installed coldfusion, you will need to log in to the administrator and do a couple of things. I believe cf pulls up the administrator by default once install finishes, but if it doesn’t, just click on start> adobe> coldfusion> administrator and open it. you can log in with the password you set in your installation

After you log in, look on the sidebar for the Debugging/Logging link. You’re going to want to enable robust exception information.

Database

Download mySql, unzip the file, find the installer, and install it.

Now, download Navicat Lite (Free). Once it’s installed, open it on up and we will connect to mySql. Click on file> connection> new connection. use the following settings:

Connection name : localhost

Host : localhost

Username : root

Password : (empty) (may be “root”)

Port : 3306 (default)

now, with luck, if all goes according to plan, you should now see a connection called “localhost” in navicat. if you do, then give yourself a hug. you should hug yourself every day anyway.

Putting it together

ok, it is not going to be possible to put EVERYTHING together, but we can at least get a web page to display with our ridiculous amount of downloading that just happened.

  1. Fire up jEdit
  2. you will need to navigate to the following folder in jEdit… (in fact, you probably should just add a bookmark on your desktop here, because you will be here a LOT.) C> coldfusion9> wwwroot
  3. create a new folder in here… let’s call it “mySite”
  4. ok, inside of your new “mySite” folder, create a new file, called “index.cfm”
  5. open up your new file. clear everything out of it and just type in “hello world!”
  6. Save it.
  7. Ok, now you will need to open up firefox.
  8. go here: http://localhost:8500/mySite/index.cfm
  9. if you see “hello world” then give yourself another hug, you have just run a web page from a server on your local computer, no internet connectivity required! now you are finally ready to develop like the cool kids.

Now, what did you just do? well, if you care, here’s an explanation:

Your coldfusion server is located at the web address localhost:8500 (the :8500 is the port cf uses), coldfusion’s web root starts at the ‘wwwroot’ folder, so anything you stick in there you can get to by knowing it’s file path from the wwwroot folder and tacking it on the end. most of the time, you will organize your websites into folders in the wwwroot folder to keep them separated easier. So your awesomeLawnCare.com site would be in wwwroot/awesomeLawnCare, for example.

If you are wondering to yourself, and what about the mySql and navicat i just installed, how did that fit in? Well, it didn’t just yet. Later I’ll walk through using a database, that’s just a whole new level of craziness if you’ve not done anything with programming before.

Using Facebook Graph API to add an Event for a Page from a 3rd Party Site

December 27th, 2010 by Jessica Kennedy 6 comments »

I’m working on a project where a user wanted to be able to add events to their fan pages on Facebook as well as their personal web page. Since it was an uphill battle to get any useful information on doing this, I thought I’d share a step by step tutorial of how to accomplish this, starting from square one.

Square One: Setting up your App

  1. Log in to Facebook.
  2. Go to http://developers.facebook.com/setup/ to set up your app.
  3. You should now see your app’s information, but just for good measure, go to facebook.com/developers to get to more of your app’s information. You will have to allow the developers app permission. This will be where to go to configure your app’s information or look at stats for it at any later point in time.

Square Two: Create a web page

  1. Mine is called “addEvent.cfm”
  2. Add a pointer to your jQuery.js file, wherever that is. Your life will be easier if you embrace jQuery. Statement of fact.

Square Three: Start hooking Facebook in to your site

If you are developing in IE, STOP IT! Download Firefox and bask in its glory. If you don’t already have it installed, be sure to install Firebug extension for Firefox & activate it immediately. It will come in handy for debugging the AJAX you haven’t written yet, as well as any other problem you will ever have.

We’re going to add a login with Facebook button to the page. Luckily, if you can find it, Facebook has you covered. Just copy and paste in as they instruct (remember, you will need the app ID you just created at square 1), load up your page, and viola! you have a login button!

The beauty of the facebook single sign on is that it will go ahead and set a cookie for your site. You can do a dump of the cookie scope and you will see a lovely cookie with a bunch of jibberish, entitled fbs_(your app id).

<cfdump var="#cookie#"> 
<cfoutput>#cookie.fbs_(your appID)#</cfoutput>

Since this cookie really IS a bunch of gibberish (meaningful, but still gibberish), I decided to create a .cfm file that wrote more useful cookies if a user successfully signed on. Inside of the single sign-on code, we will place an AJAX request that fires to a separate coldfusion page that will write the cookies. There is probably a way to do this without using CF at all, but I didn’t look it up.

 FB.init({appId: 'your app id', status: true, cookie: true, xfbml: true});
 FB.Event.subscribe('auth.sessionChange', function(response){
  if(response.session){
   accessKey = response.session.access_token;
   fbUid = response.session.uid;
   $(document).fillPageOpts();//get the access key and fill in the pages we could post to
   $.ajax({//set cookies
    url: "setCookies.cfm",
    data: {
     accessKey: response.session.access_token,
     fbUid: response.session.uid,
    },
    type: "post",
    dataType: "json"
   });//end ajax
  }
  else{// The user has logged out, and the cookie has been cleared
   $('##error').show();
  }
 });

And here is our page that assigns the cookies:

<cfoutput>
<cfset frmLen = listLen(form.fieldnames)>
{<cfif structKeyExists(form, "accessKey")>
 <cfloop from="1" to="#frmLen#" index="i">
  <cfcookie name="#lcase(listGetAt(form.fieldnames, i))#" value="#form[listGetAt(form.fieldnames, i)]#" expires="never">
  #lcase(listGetAt(form.fieldnames, i))# : #form[listGetAt(form.fieldnames, i)]#
 </cfloop>
</cfif>}
</cfoutput>

You can see it’s very simple, and will return a JSON response.

Because the user could already be signed in, add this to the addEvent page in your script at the top to default to the cookie values:

  <cfif structKeyExists(cookie, "accessKey")><!---do we already have a cookie?  if so, set our vars accordingly--->
  accessKey = '#cookie.accessKey#';
  fbUid = '#cookie.fbUid#';
 </cfif>

Square Four: Create a form

According to the Facebook Graph API Events Documentation, you will need to send the event’s title, start_time, end_time & access_token in to create a new event. Ok. So let’s make a form that has those in it. I have added a couple of optional parameters to my form as well. you will also notice I have added an “_fb” to the end of each form name. More on this momentarily.

 <form name="addEvent" id="addEvent" class="hide" action="##" method="post">
  <label for="name">Event Name:</label> <input type="text" name="name_fb" id="eventName" /><br />
  <label for="start_time">Start Time:</label> <input type="text" name="start_time_fb" /><br />
  <label for="end_time">End Time:</label> <input type="text" name="end_time_fb" /><br />
  <label for="location">Location:</label> <input type="text" name="location_fb" /><br />
  <label for="venue">Venue:</label> <input type="text" name="venue_fb" /><br />
  <label for="privacy">Privacy:</label>
  <select name="privacy_fb">
   <option value="OPEN">Open</option>
   <option value="CLOSED">Closed</option>
   <option value="SECRET">Secret</option>
  </select><br />
  <label for="access_token_fb">Page:</label> 
  <select name="access_token_fb" id="accessKey">
  </select><br />
  <input type="button" value="Create Event" id="sendEvent" />
 </form>

Excellent. However, all of this is completely useless as it is currently because we are missing a key ingredient: the access_token — and not the access_token for the USER, the access token for the PAGE. This brings us to…

Square Five: Obtaining the page access token & selecting which page to add an event for

This is a very important step, because without it, you will be posting events to YOUR profile, not your PAGE’s profile. First, you will need to have your app request permission to manage pages (not events, like you would think). Luckily, this is stupidly easy. Just add this attribute to your fb:login button, as depicted below:

 <fb:login-button perms="manage_pages"></fb:login-button>

Now, when a user logs in using your login button, they will have to allow permission to use your app. This will also give you the right to manage pages on their behalf. Let’s get into that now. First, we need to see what pages the user admins, so we will fire off this AJAX request (note: i made this into a jQuery plugin as it is needed at 2 places on my page):

 (function($){
  $.fn.fillPageOpts = function(){
   $.ajax({//what pages does the user admin?
    url: "https://graph.facebook.com/" + fbUid + "/accounts?access_token=" + accessKey,
    type: "get",
    dataType: "jsonp",
    success: function(d, t, x){//loop through each page and add it to the dropdown list
     $.each(d.data, function(id, val){
      $('##accessKey').append('<option value=\"' + val.access_token + '\">' + val.name + '(' + val.category + ')</option>');
     });
    }
   });//end ajax
   $('##addEvent').fadeIn(200);//show the form
  }
 })(jQuery);

This returns a list of all pages the user can admin, and will give you a list of all of the PAGE’s Access Tokens so you can add events on the page’s behalf, not the user’s. I’m looping through all of the items returned and feeding them in to the form created at Square Four.

Square Six: Adding a handler

At this point, you think you’re locked and loaded, just shoot the form over to FB via AJAX, and you’re set. False. AJAX didn’t remote over so well for me, so I had to create a cfhttp request do do the work for me. I stuck this in a .cfm, although it would probably be better suited for a function in a .cfc. Here is the code:

<cfoutput>
<cfset frmLen = listLen(form.fieldnames)>
<cfhttp method="Post" url="https://graph.facebook.com/events">
<cfloop from="1" to="#frmLen#" index="i">
 <cfhttpparam type="formfield" name="#lcase(left(listGetAt(form.fieldnames, i), len(listGetAt(form.fieldnames, i)) -3))#" value="#form[listGetAt(form.fieldnames, i)]#">
</cfloop>
</cfhttp>
#cfhttp.filecontent#
</cfoutput>

The nice thing here is that you will get back a JSON response from facebook that you can use to display a link or whatever to your newly created event. Here’s the jquery to fire this request & handle the return:

 $(document).ready(function(){
  $('##sendEvent').click(function(){//send the event to FB to get added.
   $('##error').hide();
   $.ajax({
    url: "postToFb.cfm",
    type: "post",
    dataType: "json",
    data: $('##addEvent').serializeArray(),
    success: function(d, t, x){
     $('##eventsAdded').prepend('<li><a href=\"http://www.facebook.com/event.php?eid=' + d.id +'\&index=1" target=\"_blank\">' + $('##eventName').val() + '</a></li>')
      .fadeIn(200);
    },
    error: function(x, t, e){
     $('##error').show();
    }
   });//end ajax
  });
 });

Square Seven: Finishing touches

Since we modularized the event sender, we need to go back and call it on page load if the user is already logged in, add to the code you already have:

 <cfif structKeyExists(cookie, "accessKey")><!---do we already have a cookie?  if so, set our vars accordingly--->
  accessKey = '#cookie.accessKey#';
  fbUid = '#cookie.fbUid#';
  $(document).fillPageOpts();//get the access key and fill in the pages we could post to
 </cfif>

Now, I like a little css to make things prettier and easier to use:

<style type="text/css">
.hide{
 display: none;
}
.error{
 color: #F00;
 font-weight: bold;
}
.right{
 float: right;
}
#addEventWrapper{
 width: 600px
}
#addEventWrapper{
 width: 600px
}
#addEvent label{
 display: inline-block;
 text-align: right;
 width: 125px;
}
</style>

And there you have it. Hopefully this will help someone out there!

Let’s look at the complete page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Add a Facebook Event</title>
<style type="text/css">
.hide{
 display: none;
}
.error{
 color: #F00;
 font-weight: bold;
}
.right{
 float: right;
}
#addEventWrapper{
 width: 600px
}
#addEventWrapper{
 width: 600px
}
#addEvent label{
 display: inline-block;
 text-align: right;
 width: 125px;
}
</style>
</head>
<script type="text/javascript" src="http://www.triadwebcrafters.com/lib/js/jQuery.js"></script></head>
<script src="http://connect.facebook.net/en_US/all.js"></script>
<body>
<cfoutput>
<div id="addEventWrapper">
 <ul id="eventsAdded" class="right hide"></ul>
 <div id="fb-root"></div>
 <fb:login-button perms="manage_pages"></fb:login-button>
 <div id="error" class="error hide">Error Occurred</div>
 <form name="addEvent" id="addEvent" class="hide" action="##" method="post">
  <label for="name">Event Name:</label> <input type="text" name="name_fb" id="eventName" /><br />
  <label for="start_time">Start Time:</label> <input type="text" name="start_time_fb" /><br />
  <label for="end_time">End Time:</label> <input type="text" name="end_time_fb" /><br />
  <label for="location">Location:</label> <input type="text" name="location_fb" /><br />
  <label for="venue">Venue:</label> <input type="text" name="venue_fb" /><br />
  <label for="privacy">Privacy:</label>
  <select name="privacy_fb">
   <option value="OPEN">Open</option>
   <option value="CLOSED">Closed</option>
   <option value="SECRET">Secret</option>
  </select><br />
  <label for="access_token_fb">Page:</label> 
  <select name="access_token_fb" id="accessKey">
  </select><br />
  <input type="button" value="Create Event" id="sendEvent" />
 </form>
</div>
<script>
 var accessKey = '', fbUid = '', pageAccessKey = '';
 (function($){
  $.fn.fillPageOpts = function(){
   $.ajax({//what pages does the user admin?
    url: "https://graph.facebook.com/" + fbUid + "/accounts?access_token=" + accessKey,
    type: "get",
    dataType: "jsonp",
    success: function(d, t, x){//loop through each page and add it to the dropdown list
     $.each(d.data, function(id, val){
      $('##accessKey').append('<option value=\"' + val.access_token + '\">' + val.name + '(' + val.category + ')</option>');
     });
    }
   });//end ajax
   $('##addEvent').fadeIn(200);//show the form
  }
 })(jQuery);
 <cfif structKeyExists(cookie, "accessKey")><!---do we already have a cookie?  if so, set our vars accordingly--->
  accessKey = '#cookie.accessKey#';
  fbUid = '#cookie.fbUid#';
  $(document).fillPageOpts();//get the access key and fill in the pages we could post to
 </cfif>
 FB.init({appId: '(your app id)', status: true, cookie: true, xfbml: true});
 FB.Event.subscribe('auth.sessionChange', function(response){
  if(response.session){
   accessKey = response.session.access_token;
   fbUid = response.session.uid;
   $(document).fillPageOpts();//get the access key and fill in the pages we could post to
   $.ajax({//set cookies
    url: "setCookies.cfm",
    data: {
     accessKey: response.session.access_token,
     fbUid: response.session.uid,
    },
    type: "post",
    dataType: "json"
   });//end ajax
  }
  else{// The user has logged out, and the cookie has been cleared
   $('##error').show();
  }
 });
 $(document).ready(function(){
  $('##sendEvent').click(function(){//send the event to FB to get added.
   $('##error').hide();
   $.ajax({
    url: "postToFb.cfm",
    type: "post",
    dataType: "json",
    data: $('##addEvent').serializeArray(),
    success: function(d, t, x){
     $('##eventsAdded').prepend('<li><a href=\"http://www.facebook.com/event.php?eid=' + d.id +'\&index=1" target=\"_blank\">' + $('##eventName').val() + '</a></li>')
      .fadeIn(200);
    },
    error: function(x, t, e){
     $('##error').show();
    }
   });//end ajax
  });
 });
</script>
</cfoutput>
</body>
</html>

View the Standalone

Download Source Code

A simple jQuery & Coldfusion Slider

December 21st, 2010 by Jessica Kennedy 3 comments »

Today I’m building an app for displaying products in a fairly small store. Rather than reload the page every time we want to see the next page of results, I’m going to load all of my results into one large div and slide it around to only show certain items at a time. The jQuery required for making this slick little app is pretty minimal, as most of the work is done with some simple css.

Here is the idea:

  1. create a div that is a specific pixel size, and be sure the overflow is set to hidden.
  2. create another div inside of the first with a set width of 9999em (we will be scrolling horizontally, not vertically) to make it easily large enough to hold any data we need to display.
  3. inside of this very long div, place a div for each page, floated left & set to the same pixel size as your very first div.
  4. put your content for each page in.
  5. use jquery to move a set pixel with in the specified direction.
  6. the end

Here is a working example of what I came up with:

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12

Item 13
Item 14
Item 15
Item 16
Item 17
Item 18
Item 19
Item 20
Item 21
Item 22
Item 23
Item 24

Item 25
Item 26
Item 27
Item 28
Item 29
Item 30
Item 31
Item 32
Item 33
Item 34
Item 35
Item 36

Item 37
Item 38
Item 39
Item 40
Item 41
Item 42
Item 43
Item 44
Item 45
Item 46
Item 47
Item 48

Item 49
Item 50

And here is the fully commented version of the code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>My Sweet Slider</title>
</head>
<script type="text/javascript" src="my_jQuery_file.js"></script></head>
<style type="text/css">
#sliderWrapper{
 width: 336px;
 overflow: hidden;
 position: relative;
 border: 1px solid #CCC;
}
#sliderContent{
 width: 9999em;
}
#sliderContent div.sliderPage{
 float: left;
 border:#CCC;
 width: 336px;
}
#sliderContent div.sliderPage div.sliderItem{
 float: left;
 background-color:#CCC;
 border: 1px solid #000;
 width: 100px;
 height: 125px;
 padding: 5px;
}
.hovery{
 cursor: pointer;
}
</style>
<body>
<cfoutput>
<cfset pageNum=ceiling(50/12)><!---how many pages do we have?--->
<div id="pageNav">
 <span id="reverse" class="hovery"><</span><!---back button--->
 <!---loop through and display all pages.--->
 <cfloop from="1" to="#pageNum#" index="i">
  <span class="pageNumber hovery">#i#</span>
 </cfloop>
 <span id="forward" class="hovery">></span><!---forward button--->
</div>
<div id="sliderWrapper">
 <div id="sliderContent">
  <div id="sliderPage0" class="sliderPage">
   <cfloop from="1" to="50" index="i"><!---loop through all of the items--->
    <div id="item#i#" class="sliderItem">Item #i#</div>
    <cfif not i mod 12><!---since we only want 12 items per page, have this next part execute every 12th loop--->
     </div><!---close the old div & start a new one--->
     <div id="sliderPage#i/12#" class="sliderPage">
    </cfif>
   </cfloop>
  </div>
 </div>
</div>
<script type="text/javascript">
 $(document).ready(function(){
  var currentPage = 1;//this holds what page we are currently on.
  $('##pageNav .pageNumber').click(function(){//jump to a particular page.
   var goToPage = $(this).html();//get the page number
   currentPage = goToPage;//set the current page
   $('##sliderContent').animate(
    {marginLeft: '-' + ((goToPage - 1) * 336) + 'px'},
    500);//make the page move.
    return false; //just to keep the anchor tags from doing anything.
  });
  $('##forward').click(function(){//go forward 1 page
   if(currentPage < #variables.pageNum#){//make sure we are not at the end of the pages
    $('##sliderContent').animate(
     {marginLeft: '-' + (currentPage * 336) + 'px'},
     500);//move page
    currentPage++;//add 1 to current page
   }
  });
  $('##reverse').click(function(){
   if(currentPage > 1){//make sure we are not on the first page
    $('##sliderContent').animate(
     {marginLeft: '-' + ((currentPage-2) * 336) + 'px'},
     500);//move page
    currentPage--;//subtract 1 from current page
   }
  });
 });
</script>
</cfoutput>
</body>
</html>

View the Standalone
Download the Slider Source Code

CSS Basics 101- Part 2

November 24th, 2010 by Jessica Kennedy No comments »

Rule of thumb: the closer to the element the style is, the more precedence it will take.
From furthest away to closest, here is how styles will be assigned:

1.Browser Defaults: These styles are set by the client and are what appears when no other style rules apply.

1. order external stylesheets are included on the page.

<link rel="stylesheet" href="style1.css" />
<link rel="stylesheet" href="style2.css" />

so for all styles in style1 that have a matching style in style2, the ones in style2 will take precedence.

2. order styles in external stylesheets are included on the stylesheet:

#this{
 color: #F00;
 background-color: #000;
}
#this{
 color: #CCC;
}

will yield a color of #CCC and a background of #000, as the first #this will have its color overwritten by the second #this.

3. on-page styles:
if a

tag is included on the page, styles inside of it will take precedence. Again, styles in the tag are order sensitive, ascending to descending.

4. inline styles:

<div style="color: #F00;"></div>

5. important! styles: styles located ANYWHERE that are followed by !important will be, as the name indicates, most important. If two !important tags are applied to teh same style element, the element that would normally take precedence with the !important tag will win.

Styles will also follow these rules:
- elements with no style will inherit some styles from parent, closest being most important, furthest being least
- for elements with both a class & an ID, ID will take precedence over class level styles.
- more specific IDs will take precedence. This can also be the case with id & class combinations:
Examples:

  #parentOfThis #this /*will be used over #this*/
  #parentOfThis .thisClass#this /*will be used over .thisClass or .thisClass or #this*/

CSS Basics 101

November 24th, 2010 by Jessica Kennedy No comments »

We will use this sample code as a reference:

<div id="sampleID" class="sampleClass1 sampleClass2">
 <div id="childID" class="sampleChild sampleClass2">
  <p class="sampleClass1">Test <span>Text.</span></p>
 </div>
</div>

css generally uses IDs, classes, and elements to assign a style to a particular element on an html page. Elements are the simplest to call. simply apply styles to the elemtn type. For example:

a{
 color: #CCC;
}

will apply a grey color to all anchor tags.

There are two major differences between IDs and classes:
1. IDs should only be used once per html page, whereas classes can be reused. Some browsers will have trouble rendering IDs if they appear on the page more than once.
2. Classes can be compounded, meaning you can assign as many classes as you would like to an element.

To reference a particular ID, use “#” followed by the id name.
#sampleID will reference the outer div.

to reference a particular class, use “.” followed by the class name.
.sampleClass1

One can also specify where to apply styles more specifically. compounding style ids and classes will allow this to happen

For example,
using the following style

.sampleClass2{
 border: 1px solid #CCC;
}

would yield both divs having a grey border. let’s say we only want to apply a grey border to the outer div:

#sampleID.sampleClass2{ /*look for an ID called "sampleID" that also has a class of "sampleClass2"*/
 border: 1px solid #CCC;
}

or

.sampleClass1.sampleClass2{/*look for any elements with the classes "sampleClass1 & sampleClass2"*/
 border: 1px solid #CCC;
}

will both yield a border only on the outer div.

Now let’s take that same example, but instead only apply the grey border to the inner div. there are several ways to accomplish this:

#sampleID .sampleClass2{ /*look for any classes called "sampleClass2" with a parent ID called "sampleID"*/
 border: 1px solid #CCC;
}

or

#childID.sampleClass2{ /*look for an ID called "childID" that also has a class of "sampleClass2"*/
 border: 1px solid #CCC;
}

or

.sampleChild.sampleClass2{ /*look for any elements with the classes "sampleChild & sampleClass2"*/
 border: 1px solid #CCC;
}

Notice the space in the first example denotes looking for any children inside of the element listed first. This will apply to ALL children of the element, not just direct children.
So, if we wanted all paragraphs inside our sampleID to be red, we could say:

#sampleID p{
 color: #F00;
}

even though the “p” element is not a direct child of sampleID, since p falls inside of sampleID, the style will apply to it.

using a nested tree structure with coldfusion to create a dynamic menu

October 21st, 2010 by Jessica Kennedy 7 comments »

Let’s say we have a tree structure like below:

  1. top level
    1. second level
  2. top level
    1. second level
      1. third level
      2. third level
        1. fourth level
      3. third level
    2. second level
  3. first level

There are basically two approaches to this problem: the classic parent/child relationship and the nested structure. Parent/child structure dictates that you need to know the parent of a node, and the children that node has. Armed with this information, you would do a recursive loop over the data to build a structure. The problem with this method is that it’s costly to process and can get sloppy fast. Enter nested tree structure. The idea is to assign each node in the tree a “first” number and a “last” number. So, for example, here would be the first & last numbers for our tree above:

  1. 1-top level-4
    1. 2-second level-3
  2. 5-top level-18
    1. 6-second level-15
      1. 7-third level-8
      2. 9-third level-12
        1. 10-fourth level-11
      3. 13-third level-14
    2. 16-second level-17
  3. 19-first level-20

Do you see the pattern? any nodes with a first number between the first and last numbers of the selected node will be children of that node. This simplifies our tree structure in 2 ways. first, we can easily run a query of the nodes we need for our dropdown menus and sort by the first num. second, this makes looping over our list to display in a useful manner much faster and easier. I have included below an example of how one could loop over the data to put items into nested lists. For simplicity, I have defined all variables in an array/structure. Obviously, to be useful this would better be implemented from a database.

<!---Add some styling to make it sexy--->
<style type="text/css">
 #dropdowns .secondary{
  display: none;
  position: absolute;
  left: 179px;
  top: -21px;
  margin: 0;
 }
 #dropdowns li:hover > .secondary{
  display: block;
 }
 #dropdowns li{
  position: relative;
  color: #009;
  width: 175px;
  line-height: 25px;
  height: 25px;
  border: 1px solid #CCC;
  background-color: #DDD;
  list-style: none outside none;
  margin: 0;
  cursor: pointer;
  padding: 2px;
 }
 #dropdowns li:hover{
  border: 1px solid #AAA;
  background-color: #BBB;
  color: #FFF;
 }
 ol#dropdowns, #dropdowns ol{
  list-style: none outside none;
  padding: 20px 20px 20px 0;
 }
 .more{
 float: right;
 }
</style>
<cfoutput>
<cfscript>
 mq = structNew();
 menuQry = arrayNew(1);
 menuQry[1] = structNew();
 menuQry[1]['controlName'] = "top level";
 menuQry[1]['first'] = 1;
 menuQry[1]['last'] = 4;
 menuQry[1]['level'] = 1;
 menuQry[2] = structNew();
 menuQry[2]['controlName'] = "second level";
 menuQry[2]['first'] = 2;
 menuQry[2]['last'] = 3;
 menuQry[2]['level'] = 2;
 menuQry[3] = structNew();
 menuQry[3]['controlName'] = "top level";
 menuQry[3]['first'] = 5;
 menuQry[3]['last'] = 18;
 menuQry[3]['level'] = 1;
 menuQry[4] = structNew();
 menuQry[4]['controlName'] = "second level";
 menuQry[4]['first'] = 6;
 menuQry[4]['last'] = 15;
 menuQry[4]['level'] = 2;
 menuQry[5] = structNew();
 menuQry[5]['controlName'] = "third level";
 menuQry[5]['first'] = 7;
 menuQry[5]['last'] = 8;
 menuQry[5]['level'] = 3;
 menuQry[6] = structNew();
 menuQry[6]['controlName'] = "third level";
 menuQry[6]['first'] = 9;
 menuQry[6]['last'] = 12;
 menuQry[6]['level'] = 3;
 menuQry[7] = structNew();
 menuQry[7]['controlName'] = "fourth level";
 menuQry[7]['first'] = 10;
 menuQry[7]['last'] = 11;
 menuQry[7]['level'] = 4;
 menuQry[8] = structNew();
 menuQry[8]['controlName'] = "third level";
 menuQry[8]['first'] = 13;
 menuQry[8]['last'] = 14;
 menuQry[8]['level'] = 3;
 menuQry[9] = structNew();
 menuQry[9]['controlName'] = "second level";
 menuQry[9]['first'] = 16;
 menuQry[9]['last'] = 17;
 menuQry[9]['level'] = 2;
 menuQry[10] = structNew();
 menuQry[10]['controlName'] = "first level";
 menuQry[10]['first'] = 19;
 menuQry[10]['last'] = 20;
 menuQry[10]['level'] = 1;
 mq.menuLen = arrayLen(menuQry);
 mq.childHide = 0;
 mq.onLevel = 1;
</cfscript>
<ol id="dropdowns">
 <li style="display: none"><!---first li will always be empty, so be sure it does not show.--->
 <cfloop from="1" to="#mq.menuLen#" index="i">
  <cfset mq.newLevel = menuQry[i].level - mq.onLevel>
  <cfset mq.onLevel = menuQry[i].level>
  <cfif mq.newLevel eq 1>
   <span class="more">>></span><ol class="secondary">
  <cfelseif mq.newLevel lt 0>
   <cfloop from="-1" to="#mq.newLevel#" index="j" step="-1">
    </li></ol></li>
   </cfloop>
  <cfelse>
   </li>
  </cfif>
  <li>#menuQry[i].controlName#
 </cfloop>
 </li>
</ol>
<!---close all open lists--->
<cfloop from="1" to="#mq.onLevel#" index="j">
 </li>
</ol>
</cfloop>
</cfoutput>

Here is the working version:

There are plenty of ways to use this to your advantage. I plan on using this method to implement menus for different types of users; the idea being I can filter my list items based on a user’s permissions and then dynamically build the list from the results.
The problem with using the code above and filtering based on a user role (or whatever) is how to handle nodes that are filtered out. Luckily, with a little extra code, we can still accomplish what we want:

<cfoutput>
<cfscript>
 mq = structNew();
 menuQry = arrayNew(1);//this would be replaced with a query outside of this exmaple.
 menuQry[1] = structNew();
 menuQry[1]['controlName'] = "top level";
 menuQry[1]['first'] = 1;
 menuQry[1]['last'] = 4;
 menuQry[1]['level'] = 1;
 menuQry[1]['showItem'] = 1;//Now we add a boolean to say whether or not to display the list item.
 menuQry[2] = structNew();
 menuQry[2]['controlName'] = "second level";
 menuQry[2]['first'] = 2;
 menuQry[2]['last'] = 3;
 menuQry[2]['level'] = 2;
 menuQry[2]['showItem'] = 1;
 menuQry[3] = structNew();
 menuQry[3]['controlName'] = "top level";
 menuQry[3]['first'] = 5;
 menuQry[3]['last'] = 18;
 menuQry[3]['level'] = 1;
 menuQry[3]['showItem'] = 1;
 menuQry[4] = structNew();
 menuQry[4]['controlName'] = "second level";
 menuQry[4]['first'] = 6;
 menuQry[4]['last'] = 15;
 menuQry[4]['level'] = 2;
 menuQry[4]['showItem'] = 0;
 menuQry[5] = structNew();
 menuQry[5]['controlName'] = "third level";
 menuQry[5]['first'] = 7;
 menuQry[5]['last'] = 8;
 menuQry[5]['level'] = 3;
 menuQry[5]['showItem'] = 1;
 menuQry[6] = structNew();
 menuQry[6]['controlName'] = "third level";
 menuQry[6]['first'] = 9;
 menuQry[6]['last'] = 12;
 menuQry[6]['level'] = 3;
 menuQry[6]['showItem'] = 1;
 menuQry[7] = structNew();
 menuQry[7]['controlName'] = "fourth level";
 menuQry[7]['first'] = 10;
 menuQry[7]['last'] = 11;
 menuQry[7]['level'] = 4;
 menuQry[7]['showItem'] = 0;
 menuQry[8] = structNew();
 menuQry[8]['controlName'] = "third level";
 menuQry[8]['first'] = 13;
 menuQry[8]['last'] = 14;
 menuQry[8]['level'] = 3;
 menuQry[8]['showItem'] = 1;
 menuQry[9] = structNew();
 menuQry[9]['controlName'] = "second level";
 menuQry[9]['first'] = 16;
 menuQry[9]['last'] = 17;
 menuQry[9]['level'] = 2;
 menuQry[9]['showItem'] = 1;
 menuQry[10] = structNew();
 menuQry[10]['controlName'] = "first level";
 menuQry[10]['first'] = 19;
 menuQry[10]['last'] = 20;
 menuQry[10]['level'] = 1;
 menuQry[10]['showItem'] = 0;
 mq.menuLen = arrayLen(menuQry);
 mq.childHide = 0;
 mq.onLevel = 1;
</cfscript>
<ol id="dropdowns">
 <li style="display: none"><!---first li will always be empty, so be sure it does not show.--->
 <cfloop from="1" to="#mq.menuLen#" index="i">
  <cfif mq.childHide eq 0 and menuQry[i].showItem eq 0><!---is this one supposed to hide, and is it the first child?--->
   <cfset mq.childHide = (menuQry[i].last - menuQry[i].first - 1)/2 + 1>
  </cfif>
  <cfif mq.childHide eq 0>
   <cfset mq.newLevel = menuQry[i].level - mq.onLevel>
   <cfset mq.onLevel = menuQry[i].level>
   <cfif mq.newLevel eq 1>
    <span class="more">>></span><ol class="secondary">
   <cfelseif mq.newLevel lt 0>
   <cfloop from="-1" to="#mq.newLevel#" index="j" step="-1">
    </li></ol></li>
   </cfloop>
   <cfelse>
    </li>
   </cfif>
   <li>#menuQry[i].controlName#
  <cfelse>
   <cfset mq.childHide = mq.childHide - 1><!---count down--->
  </cfif>
 </cfloop>
 </li>
</ol>
<!---close all open lists--->
<cfloop from="1" to="#mq.onLevel#" index="j">
 </li>
</ol>
</cfloop>
</cfoutput>

And the result of this code is below:

Lovely! This logic could also be implemented in a .cfc as a long string then stored in cache to keep from having to run this script on every page.

Implementing openID on an existing website

October 14th, 2010 by Jessica Kennedy No comments »

I’m beginning a project to add the option to sign in via openIDs like Facebook or Google to a website with an existing user database. The concept is pretty straightforward on the surface– let someone else authenticate my users. Of course, one then runs in to the issue of how to associate an openID with one of your existing user’s accounts to avoid duplicate accounts on your end. I did a little digging and found a very thorough outline here… openID Implementation.

I’ll try to post more on this as there isn’t tons of info on CF implementations of openID.