ColdFusion and jQuery definition auto-linking (A DB driven implementation)
So, this post is inspired by Ray Camden's post on the same subject, Using jQuery and ColdFusion to create an auto-link for definition application, so all credit goes to Ray. I wanted to implement something similar, and also make it database driven as I beleive any implementation of this in an application would be DB driven anyway.
You can take a look at the demo here: http://coldfusion-ria.com/test/term.cfm
I recommend using Firefox, as I have encountered an issue where the jQuery click event stops working for the first word on IE7 after you click it once.
First things first, the DB structure, looks like this:

The TermName is the term that will be linked, the term HTML is what we will replace the term word with, the TermDef is the definition of the term, and track can be used to track URL clicks.
1 <div class="jqmWindow" id="dialog" style="display:none;">
2 <a href="#" class="jqmClose">Close</a>
3 <br/>
4 </div>
5
6 <div id="content" style="position:relative">
7 <p>
8 This is some fun text.
9 </p>
10 <p>
11 This is some boring text.
12 </p>
13 <p>
14 Ajax? Ajax is awesome.
15 </p>
16 <p>
17 No Definition exists on this like *sad panda*.
18 </p>
19 </div>
The rest of the page looks like:
2 <a href="#" class="jqmClose">Close</a>
3 <br/>
4 </div>
5
6 <div id="content" style="position:relative">
7 <p>
8 This is some fun text.
9 </p>
10 <p>
11 This is some boring text.
12 </p>
13 <p>
14 Ajax? Ajax is awesome.
15 </p>
16 <p>
17 No Definition exists on this like *sad panda*.
18 </p>
19 </div>
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html>
3 <cfajaxproxy cfc="term" jsclassname="term">
4 <head>
5 <link rel="stylesheet" type="text/css" media="screen" href="jqModal.css" />
6 <script src="jquery.js" type="text/javascript"></script>
7 <script src="jqModal.js" type="text/javascript"></script>
8
9 <script>
10 var objTerm = new term();
11 var termHTML = objTerm.getTermsHTML();
12 $(document).ready(function(){
13 $('#dialog').jqm();
14 var currentContent = $("#content").html();
15 for(var i in termHTML)
16 {
17 var word = new RegExp(i,"gi")
18 currentContent = currentContent.replace(word,termHTML[i]);
19 }
20
21 $("#content").html(currentContent);
22
23 $(".hint").bind("click",function(e)
24 {
25 var clickElement = e.target;
26 var clickText = $(clickElement).text();
27 $.post('term.cfc?method=getTermDef&returnFormat=json',{term:clickText},showHint,"json");
28 }
29 )
30
31 function showHint(data,textStatus)
32 {
33 var currentHink = $("#dialog").html()
34 var newContent = currentHink + data;
35 $('#dialog').html(newContent);
36 $('#dialog').jqmShow();
37
38 }
39
40 })
41 </script>
42 </head>
The first thing I do, is use cfajaxproxy, to get the Terms and their corresponding HTML replacements. Then in the document.ready function (to make sure everything has been loaded), we call the .jqm function to let jqModal know which div will be used for the dialog purpose.
Then we get all the current HTML content for the content div. Next, we iterate through the termsHTML object that was returned from our CFC, and replace the term words in the HTML with the termHTML. This then allows us to use jQuery's bind function to bind the "click" event to all elements with the class hint, $(".hint").bind("click",function(e). In this function, we get the text that was clicked on and pass it into the CFC, which returns the Term Definition. showHint function is the callback, which takes the definition, adds it to the dialog div, and then we use .jqmShow() function to show the dialog.
The CFC is a fairly simple one,
2 <html>
3 <cfajaxproxy cfc="term" jsclassname="term">
4 <head>
5 <link rel="stylesheet" type="text/css" media="screen" href="jqModal.css" />
6 <script src="jquery.js" type="text/javascript"></script>
7 <script src="jqModal.js" type="text/javascript"></script>
8
9 <script>
10 var objTerm = new term();
11 var termHTML = objTerm.getTermsHTML();
12 $(document).ready(function(){
13 $('#dialog').jqm();
14 var currentContent = $("#content").html();
15 for(var i in termHTML)
16 {
17 var word = new RegExp(i,"gi")
18 currentContent = currentContent.replace(word,termHTML[i]);
19 }
20
21 $("#content").html(currentContent);
22
23 $(".hint").bind("click",function(e)
24 {
25 var clickElement = e.target;
26 var clickText = $(clickElement).text();
27 $.post('term.cfc?method=getTermDef&returnFormat=json',{term:clickText},showHint,"json");
28 }
29 )
30
31 function showHint(data,textStatus)
32 {
33 var currentHink = $("#dialog").html()
34 var newContent = currentHink + data;
35 $('#dialog').html(newContent);
36 $('#dialog').jqmShow();
37
38 }
39
40 })
41 </script>
42 </head>
1 <cfcomponent>
2
3 <cffunction name="getTermDef" access="remote" returnFormat="json" output="false">
4 <cfargument name="term" type="string" required="true" hint="Gets Term Defition from DB">
5
6 <cfset result = "">
7
8 <cfset clickTracker(Arguments.term)>
9
10 <cfquery name="selTermDef" datasource="RIADemo">
11 SELECT
12 TermDef
13 FROM
14 Terms
15 WHERE
16 TermName = '#Arguments.term#'
17 </cfquery>
18
19 <cfif selTermDef.RecordCount GT 0>
20 <cfset result = selTermDef.TermDef>
21 </cfif>
22
23 <cfreturn result>
24
25 </cffunction>
26
27 <cffunction name="getTermsHTML" access="remote" returnFormat="json" output="false">
28
29 <cfset stcTerms = StructNew()>
30
31 <cfquery name="selTermHTML" datasource="RIADemo">
32 SELECT
33 TermName, TermHTML
34 FROM
35 Terms
36 </cfquery>
37
38
39
40 <cfloop query="selTermHTML">
41 <cfset stcTerms["#TermName#"] = "#TermHTML#">
42 </cfloop>
43
44 <cfreturn stcTerms>
45
46 </cffunction>
47
48 <cffunction name="clickTracker" access="private">
49 <cfargument name="term" type="string" required="true" hint="Term for which we will track the click">
50
51 <cfquery name="updTrack" datasource="RIADemo">
52 UPDATE
53 Terms
54 SET
55 track = track + 1
56 WHERE
57 TermName = '#Arguments.term#'
58 </cfquery>
59
60 </cffunction>
61
62 </cfcomponent>
I use some simple CSS, to highlight the term words (which are set to class hint).
2
3 <cffunction name="getTermDef" access="remote" returnFormat="json" output="false">
4 <cfargument name="term" type="string" required="true" hint="Gets Term Defition from DB">
5
6 <cfset result = "">
7
8 <cfset clickTracker(Arguments.term)>
9
10 <cfquery name="selTermDef" datasource="RIADemo">
11 SELECT
12 TermDef
13 FROM
14 Terms
15 WHERE
16 TermName = '#Arguments.term#'
17 </cfquery>
18
19 <cfif selTermDef.RecordCount GT 0>
20 <cfset result = selTermDef.TermDef>
21 </cfif>
22
23 <cfreturn result>
24
25 </cffunction>
26
27 <cffunction name="getTermsHTML" access="remote" returnFormat="json" output="false">
28
29 <cfset stcTerms = StructNew()>
30
31 <cfquery name="selTermHTML" datasource="RIADemo">
32 SELECT
33 TermName, TermHTML
34 FROM
35 Terms
36 </cfquery>
37
38
39
40 <cfloop query="selTermHTML">
41 <cfset stcTerms["#TermName#"] = "#TermHTML#">
42 </cfloop>
43
44 <cfreturn stcTerms>
45
46 </cffunction>
47
48 <cffunction name="clickTracker" access="private">
49 <cfargument name="term" type="string" required="true" hint="Term for which we will track the click">
50
51 <cfquery name="updTrack" datasource="RIADemo">
52 UPDATE
53 Terms
54 SET
55 track = track + 1
56 WHERE
57 TermName = '#Arguments.term#'
58 </cfquery>
59
60 </cffunction>
61
62 </cfcomponent>
1 .hint
2 {
3 border-bottom:1px dotted #333;
4 cursor:help;
5 }
The main thing here is for getTermsHTML function, I am not using the default ColdFusion JSON return for the query. Instead, I build a structure and return it in JSON (I found it easier to work with on the JS side).
The only issue right now is that on Internet Explorer, for the first word (in the demo that is fun), stops registering the click event after it has been clicked once. I have a message out on the jQuery google groups to try and see what could be wrong here.
So, there you have it, another take on the same problem, a DB driven implementation though.
Full Source Code: Here (CSS, JS or DB Files Not Included).
2 {
3 border-bottom:1px dotted #333;
4 cursor:help;
5 }
Glad you liked the blog post though Dan. I am still going through your RocketFM series.