This is a pretty interesting idea. I was pretty mad at Sean for mailing this to me on Wednesday right when I had to fly! (In case folks are wondering why I was so silent recently, I flew up to CA on Wednesday and back home on Friday so I've been a bit remote.) As always, there are many ways we could attack this, but this is the route I chose.I have an existing application. Its for doctors and technologists who are applying for accreditation. There are a lot of terms that are used and the client wants the terms linked to a pop up that has a definition. Now, I can set up a CFC to grab the term's definition and return it to an ajax call from CF and link the term to it, that's no problem. The problem is, I don't want to go through each page, and then again when the content is changed and manually link any recognized words to the JS function that executes the remote call to the CFC. Do you know of a way, perhaps with jQuery or the built-in CF stuff, to, after each page loads, scan the text for any recognized words (this list can be retreived from another CFC call for all the words we "know of") and then link to it using the pop-up bubble?
- On load, use JavaScript to get all the text from one div. While Sean said he wanted to scan the 'page', I assume he really means the main page content, and not stuff like the header of footer.
- Convert that text into a unique list of words.
- Send that list to the server and figure out which words are 'hot', ie, terms that we have definitions for.
- When we get the list of terms back, update the content to create links to something that will display the definition.
2
3 <head>
4 </head>
5
6 <body>
7
8 <div id="content">
9 <p>
10 This is some <b>fun</b> text.
11 </p>
12 <p>
13 This is some <b>boring</b> text.
14 </p>
15 <blockquote>
16 <p>
17 For score and seven years ago...
18 </p>
19 </blockquote>
20 </div>
21
22 </body>
23 </html>
2 for(var i=0; i<words.length;i++) {
3 var word = words[i]
4 word = word.replace(/[\s\n]/g,'')
5 if(word != '' && uWords[word] == null) uWords[word] = ''
6 }
2 for(var w in uWords) aWords.push(w)
2
3 <!--- Hard coded list of terms we know. --->
4 <cfset variables.termList = ["boring","cool","hot","cold","nice","watch","score"]>
5
6 <cffunction name="filteredTermList" access="remote" returnType="array" output="false">
7 <cfargument name="termList" type="string" required="true" hint="List of words to search. Assumed to be unique.">
8 <cfset var term = "">
9 <cfset var result = []>
10
11 <cfloop index="term" list="#arguments.termList#">
12 <cfif arrayFind(variables.termList,term)>
13 <cfset arrayAppend(result, term)>
14 </cfif>
15 </cfloop>
16
17 <cfreturn result>
18 </cffunction>
19
20 <cffunction name="arrayFind" access="private" returnType="numeric" output="false" hint="Returns the position of an item in an array, or 0">
21 <cfargument name="arr" type="array" required="true">
22 <cfargument name="s" type="string" required="true">
23 <cfset var x = "">
24
25 <cfloop index="x" from="1" to="#arrayLen(arguments.arr)#">
26 <cfif arguments.arr[x] is arguments.s>
27 <cfreturn x>
28 </cfif>
29 </cfloop>
30
31 <cfreturn 0>
32 </cffunction>
33
34 </cfcomponent>
2 var currentContent = $("#content").html()
3
4 for(var x=0; x<data.length;x++) {
5 word = data[x]
6 //replace word with <a href="" click="return showTerm('term')">term</a>
7 var newstr = '<a href="" onclick="return showTerm(\''+word+'\')">'+word+'</a>'
8 //get current html
9 //replace word with the new html
10 var reg = new RegExp(word, "gi")
11 currentContent = currentContent.replace(reg,newstr)
12 }
13 //update it
14 $("#content").html(currentContent);
15 }
2 ColdFusion.Window.create('term','Definition of '+term,'term.cfc?method=definition&term='+escape(term)+'&returnformat=plain', {center:true,modal:true})
3 ColdFusion.Window.onHide('term',winClosed);
4 return false
5 }
6 function winClosed() {
7 ColdFusion.Window.destroy('term',true)
8 }
2 <cfargument name="term" type="string" required="true" hint="Word to look up.">
3
4 <cfreturn "The definition of " & arguments.term & " is, um, something.">
5 </cffunction>
- Why not simply load the known words on startup? I could have done that, especially with my short list of known words. But I figured that in a real production system your list of known words could be huge. That isn't something you probably want to add to each page load. I figured scanning for unique words and sending that to the server to get the known list back would mean less traffic. I don't know that of course, and this ties back to something I said at the NYCFUG earlier this month. Don't consider AJAX a magic bullet. Sending data back and forth with JavaScript isn't going to magically be 'better' just because it's JSON or XML or whatever.
- It would be cool to add tracing to which terms get looked up. If you notice that some words are almost always looked up, it may represent an opportunity for something you can educate yours users about. So for example, if you see a lot of traffic for terms related to throat diseases, maybe you could write additional content on that area of study. On the flip side, if no one ever looks up the definition of Foo, then you can probably remove Foo from the list of content to hot link.


Comment 1 written by Sean Coyne on 31 January 2009, at 1:06 PM
Comment 2 written by Raymond Camden on 31 January 2009, at 1:08 PM
Comment 3 written by Ron West on 31 January 2009, at 2:26 PM
I have a customer who is trying to this exact thing - he calls it his Glossary. We were considering just doing all of this on the ColdFusion side but maybe this technique will be more fun and visually appealing. I will point them to this script and see what they think.
Comment 4 written by Raymond Camden on 31 January 2009, at 2:28 PM
Comment 5 written by Gary Fenton on 31 January 2009, at 2:34 PM
Sean said it's for an accreditation website, so I took a look at one and found these multi-words that may benefit from a terminology tooltip:
accreditation standards, WTO TBT, company reputation, inspection bodies, independent evaluation.
Each word by themselves mean one thing, but when together with another word they take on a different meaning.
I think it will work better if you compare the 'database' of words and phrases against the text on the page rather than the other way around.
Comment 6 written by Edward Beckett on 31 January 2009, at 2:39 PM
Comment 7 written by Raymond Camden on 31 January 2009, at 2:47 PM
@GF - Good point there. However, I still think it would be bad to send the entire db of words to the client. Another option would be to maybe send the entire text to the server? Instead of unique words. Then you would be able to do what you want.
Comment 8 written by Edward Beckett on 31 January 2009, at 3:00 PM
Comment 9 written by anthony on 31 January 2009, at 3:03 PM
Comment 10 written by Raymond Camden on 31 January 2009, at 3:06 PM
@anthony - Sean specifically said this wasn't an option. Now, if the content you wanted to hot link was 100% db driven, then it probably would be simpler. But if it wasn't, then there wouldn't be an easy way to automatically add links when new terms are added. I don't agree that the first post will be huge since it is just unique words. The flip side to that though is that we all know what happens when you assume. If this were in production I'd add some logging to the cfc method. I could look later on to see, on average, how many unique words were being sent.
Comment 11 written by Edward Beckett on 31 January 2009, at 3:12 PM
Comment 12 written by denny on 31 January 2009, at 3:13 PM
I think that's the best way to do it.
You could do something like: send the text to the server, have the server wrap "hot" content with a span or href, and then use jQuery or whatnot to scan the returned text (adding a CSS class to the "hot" content makes this easy) and "widgit-ize" what needs to be.
FWIW: dojo has things that make all this pretty easy.
FWIW2: Seems sorta like this stuff could go in an a11y /i18ln deal...
Comment 13 written by Dan Sorensen on 31 January 2009, at 3:20 PM
I've been looking into something similar. However, in my variation I wanted to check all CAP WORDS against a list of known acronyms and if there is a match, replace it with an acronym tag with the definition in the title.
It seems like you can do most of this work on the server side.
Comment 14 written by Kumar on 31 January 2009, at 3:20 PM
For the pop-up, I recommend jqModal.
http://dev.iceburg.net/jquery/jqModal/
Example:
http://coldfusion-ria.com/test/test.cfm (FF works best).
Comment 15 written by Raymond Camden on 31 January 2009, at 3:23 PM
@denny - That could work as well. I know jQuery makes it easy to say, 'take items with class x and do y to them', so if the server added the links and used a class, that could also be an option. As I said - many ways to solve this. :)
Comment 16 written by todd sharp on 31 January 2009, at 3:57 PM
Comment 17 written by Raymond Camden on 31 January 2009, at 3:59 PM
Rey Bango pointed me to the jQuery UI groups so I'm going to give them a try sometime later today.
Maybe I can write something up and the jQuery folks could use it?
Comment 18 written by Jamie Krug on 1 February 2009, at 9:27 AM
Comment 19 written by Raymond Camden on 1 February 2009, at 9:34 AM
Comment 20 written by Kumar on 1 February 2009, at 5:16 PM
http://www.coldfusion-ria.com/Blog/index.cfm/2009/...
Comment 21 written by Raymond Camden on 2 February 2009, at 6:16 AM
Comment 22 written by Andy on 2 February 2009, at 3:27 PM
There is another table with just terms and their definitions. This is loaded into the server memory and the text block being submitted as part of the page text is compared word for word with the terms. When a word match is found, the word is rewritten with a style and some JS. Then the when all is done, the record is saved in the DB ready to be sent out to the browser. The JS function for the popup is in the header for the site. All I am doing is loading another CF Page passing the unique ID of the definition and querying for the definition. Not very hi-tech I know, but it works great. (see terms underlined in orange.)
Gary F. Has a good point and this is where the feature needs work. Context is important for a term and that is for version 2.0.
[Add Comment] [Subscribe to Comments]