March 12, 2010

Pages


Search Site


Subscribe

...to receive future posts via email.

Topics



Archives

Entries for month: January 2009

SweetTweetsCFC 1.3 — Now CF7 compatible

January 31 2009 by Adam

Over the last several days I've been working hard on not only changing SweetTweets to be ColdFusion 6 & 7 compatible, but also adding some serious improvements.

Here's a summary of what's changed:

  • Now working on ColdFusion 6 and 7 — Should also be Railo & OpenBD compatible, would love for someone to test it.
  • Bitly and Snurl url shortening services removed
  • If there are more tweets than the limit allows, a link is added to view all of them on Twitter Search. (Suggested by Rob Cawte)
  • Caching has been improved. Page load times will be much faster after tweetback data has been cached.
  • Caching is now optionally done in one of two places: Application scope or locally inside the CFC. (Suggested by Seb Duggan)

  • The getTweetbacksHTML function is a very simple web-service. It's always had access="remote", but now I include a couple of example files showing how to load tweetbacks via AJAX with both ColdFusion 8's CFDiv tag as well as jQuery.

Download

Of course, with a new version of SweetTweetsCFC comes a new version of my SweetTweets Mango plugin that makes it even easier for Mango users to add tweetbacks to their blogs, which means SweetTweets (the Mango Plugin) is now CF 6, 7, etc compatible and all of the other great stuff from this post.

Download the latest version of SweetTweetsCFC from RIAForge

Download the latest version of SweetTweets Mango Plugin from RIAForge

 

So, down to the nitty gritty. This post is going to be long enough as it is so I won't include code samples here. Not too much has changed, but check the example files for implementation guidelines.

ColdFusion 6, 7, OpenBD, and Railo Support — Please Test!

Unfortunately, I don't have all of these platforms at my fingertips to test with. I have tested against CF 7 and 8, but not CF 6, Railo, or OpenBD. If anyone out there wouldn't mind testing in one of these environments and leaving a comment to let me know how well it worked, that would be swell. The example files are ready to run; you just put them somewhere web-accessible and hit the URL of the template. I can't make it any easier than that.

I'll even buy you a beer at the next conference we both attend if you post a "trip report" for me. :)

Bye Bye Birdie Bitly (and Snurl)

I've come to find out that Bit.ly and Snurl.com (among other services) do not make any apparent attempt to shorten the same url into the same short url every time. In fact, some of them go out of their way to give unique short url's. (I'm still unclear what good that does them, but that's neither here nor there…) Because of that, they are more or less worthless to us, so we're not going to waste page load time, our bandwidth and cpu cycles and theirs accessing their API to get and search for short URLs. The end result would be that you would find your own tweets, and if it's important to you to see your tweets as tweetbacks, it's within your power to use one of the supported services. As of right now, supported services are TinyURL.com, Is.gd, Hex.io, and Cli.gs; with more to be added later. Feel free to suggest additional services.

Tweetback Limit Changes

I did account for limiting from the beginning, but I've improved it a bit in this version. The limit is still optional, and still defaults to 100. To specify unlimited, set a limit of 0. If the number of tweetbacks for the given post exceeds your limit, a link will be included to the Twitter Search results. One caveat here is that twitter search is case-INsensitive, so you'll get some false positives that the plugin is recognizing and stripping out. Does that bother people? If so, would you rather it had a facility to show all tweetbacks locally instead?

Caching Overhaul

First and foremost, I fixed a bug in cache expiration. Then I totally rewrote the cache system. The whole thing is much easier to use now and makes the rest of the code more readable, but more importantly, it's faster.

Depending on your implementation, you may want to store the cache inside the CFC instance itself (for example, in a Mango plugin, storing the cache in the CFC variables scope will enable you to clear its cache by de-activating and re-activating the plugin…). Note that if you choose to store the cache inside the CFC, you are responsible for persisting the CFC instance — otherwise the cache is worthless (worse yet, we're wasting time creating it, so it has a negative net impact!).

On the other hand, if you're lazy or otherwise inclined to, you can have the cache stored in the application scope. It will use Application.SweetTweetCache, which you can delete any time you like in order to clear the cache. As I mentioned previously, this is the behavior (currently there is no other option) when you access SweetTweets as a web service; since there is no other (practical) way to persist the data.

A Web Service, if you can call it that…

It's the crumbiest web service I've ever seen or written, but it still sort of almost counts. The getTweetbacksHTML method allows remote access, so you can hit it with AJAX to load your tweetbacks onto the page without affecting initial page loading time. The way I look at it is that by the time someone finishes reading your blog post, the tweetbacks will have loaded and they won't notice a difference — except that the server didn't need to churn longer before rendering the page for them. Seems like a good idea, right?

The zip now includes two additional examples that demonstrate loading tweetbacks via AJAX. One uses CF8's CFDiv tag, and the other uses jQuery; and just like the standard example, both are ready to use out of the box: just put them somewhere web-accessible (even on your localhost) and navigate to the page.

The reason I hesitate to call it a web service is that it still just returns HTML (and I don't want to insult the authors of real web services by putting this in the same category as their work). It's nothing overly fancy. One thing to note is that in the case of the jQuery example, if you're running on CF 6 or 7, (and you look at the request in firebug) you'll notice that the result is returned as a WDDX packet and I'm stripping it out of the packet and un-escaping some characters. I see this as one potential point of failure for Railo and OpenBD (and possibly CF 6) if the WDDX packet format is different. So please do let me know if there are any issues there, so that I can whip up a fix for you. :)

If there is enough interest in the idea, I might write a proper web service into it, and I'm thinking that might be neat because I could include pagination that way.

Fin

I think that's about enough information for one post, don't you?

Posted in ColdFusion | My projects | Mango | 4 comments

SweetTweets — A Plugin for Anything (Including Mango)

January 22 2009 by Adam

What a whirlwind evening. This afternoon, Rey Bango tweeted about something called "tweetbacks," and had previously written about how you can add them to your blog.

Tweetbacks are like "trackbacks" (which, if you're unfamiliar with those, is when you display a list of links — usually other blog posts — that link to the current post), except instead of being blog posts, they are tweets. See it in action just above the comment form on this very post!

I added them here on my blog; and while I was impressed with the idea and simplicity of adding it (a single line of JavaScript), it was un-acceptably slow. For starters, it was a dynamic JS file hosted on someone else's server (ugh), but it also took several seconds — sometimes as many as 10 — to do its thinking and let the page finish loading. Unacceptable!

So I set about writing my own version in CFML to run locally. What I came out with, several frantic hours later, is SweetTweets. (I still haven't eaten dinner. This is more fun.)

Well, really, I came out with SweetTweets — a Mango plugin — and SweetTweetsCFC, a drop-in CFML replacement for the JavaScript version from Dan Zarella.

It works by looking up the shortened URL for your blog entries from several of the shortening services (is.gd, tinyurl.com, hex.io, bit.ly, and snurl.com) and then using the Twitter Search API to find references to any of those URLs. The shortened versions of the URLs are cached semi-permanently (in Application scope), and the results from twitter searches are cached for 5 minutes, so that you don't overload them if you get lots of traffic or constant refreshing.

Bit.ly and Snurl.com require API keys to do url shortening, so you may want to register with those two sites (both optional) — I'll cover this in a little bit more depth in the instructions below.

I have to give a pair of hat tips to Nathan Mische and Andy Matthews, for their respective projects JSONUtil and shrinkURL, which saved me a lot of time in putting this together.

Due to some heavy use of implicit structure notation, both projects currently require ColdFusion 8. Not to fret, I've already set to work in converting them to work in CF7!

Implementing SweetTweets Mango Plugin

Download it from RIAForge

Unfortunately, there are no built-in events that I wanted to piggy-back on. I was almost satisfied with the placement when using the end-of-post-body event, but that would trigger it on the index and archives pages as well, several times a page, which I didn't want; and the placement wasn't exactly where I wanted it. So in the end, I decided to use a custom event name.

What this means for you is that installation is a 4-step process:

  1. Unzip plugin into place (/components/plugins/user/SweetTweets)
  2. Activate it in the admin console
  3. Configure its settings (either go to settings -> SweetTweets, or click the "configure it now" link after activating)
    1. This is where you'll enter your Bit.ly and Snurl.com API credentials, if you want to use those services.
    2. The other setting here is the tweet limit, which defaults to 100. This is the maximum number of tweets to display for a given post.
  4. Add a line of code (below) to your skin wherever you want the tweetbacks to be displayed. (Preferrably on the single-post/single-page template, but hey, that's your call.)

I'm happy to help you over IM, Twitter, or Email if you have any trouble with this.

Implementing SweetTweetsCFC on your Blog/etc

Download it from RIAForge

As I said above, you can implement SweetTweetsCFC in a single line of CFML. It does take a little chaining, and it's a little bit of a long line, but it's pretty simple, and technically it's a single line:

#createObject('component','path.to.SweetTweets').init('bitly_email','bitly_api_key','snurl_username','snurl_api_key').getTweetbacksHTML('current_url',limit)#

Note that all 4 arguments of the init function are optional, and if either of the first two is left blank Bit.ly will not be used, and if either of the last two are left blank… you guessed it… Snurl.com will not be used. If you're not using any of them, you can just do init(), you don't have to do init('','','','').

Lastly, you need to pass in the actual current URL of the blog post / page, and you can optionally set the tweet limit as the 2nd argument to the getTweetbacksHTML function. I hope you're capable of figuring out what your current URL is and plugging that in, but again, if you get stuck, I'm happy to help you over IM, Twitter, or Email.

Posted in My projects | Mango | 13 comments

Is ColdFusion Dead?

January 22 2009 by Adam

Here it is folks, we finally have a difinitive source.

http://www.IsColdFusionDead.com/

I guess that settles it, then. Be sure to point the haters and nay-sayers there from now on.

(via @ColdFusion)

Posted in ColdFusion | 3 comments

Log Viewer Plugin for Mango Blog

January 20 2009 by Adam

Did you know that Mango Blog traps and logs all sorts of errors (mostly from plugins)? And did you know that these logs are visible to the public?

They are!

http://your.blog.com/components/utilities/logs/warning.log.html
http://your.blog.com/components/utilities/logs/error.log.html

These two logs are extremely helpful when writing and debugging plugins, but they are kind of a pain to keep track of and manage… Not to mention you probably don't want to leave them there permanently for just any schmoe to see.

This plugin simply shows when you have error/warning logs, and lets you view and delete them from the comfort of your Mango admin.

See my project page for more information and screenshots. Download at RIAForge.

Posted in My projects | Mango | 2 comments

Relative Custom Tag Paths: Friend or Foe?

January 14 2009 by Adam

ColdFusion 8 added support for this.mappings and this.customTagPaths as per-application settings in Application.cfc, something many developers including yours truly will tell you was a god-send.

But did you know that they can be relative?

I stumbled on this — uh, feature? — and I'm still undecided on whether I like it or not.

I was doing some work for a client whose production environment is on shared hosting. When working on shared hosting, I never hard-code directory paths. Today the root directory of the site might be C:\sites\clientName\www\, but if a hard drive crashes or the server is upgraded, it could switch drive letters or folder locations in the blink of an eye with no warning, and all of a sudden your applications stop working, your websites go down, and your business isn't making money.

For that reason, I make judicious use of expandPath. Not only does this protect me from lack of control of the production environment, it allows differences between development, staging, and production environments without a giant switch-block that changes all sorts of settings based on environment.

So my Application.cfc code looked something like this:

this.name = "testHarness"; this.customTagPaths = ''; this.customTagPaths = listAppend(this.customTagPaths,expandPath('./customTags'));

Do you see what I did wrong there? I used a relative path starting with a dot, which indicates that the path is relative to the current directory. This is syntactically correct and doesn't cause any CF errors, itself. The only reason I was surprised at all was, because of a bad assumption.

The expandPath function just translates a string to the absolute path (at runtime), and my (bad) assumption was that it would run once on application load and live for the life of the application. If this were the case, the dot wouldn't matter because the path relative to the root would be set and used throughout the site. On the contrary, it runs on every page request, and is relative to the currently executing base (more on this later) template.

Where you'll run into problems with this syntax is when you try to use a custom tag from a page in a sub-folder. For example, take the following theoretical website:

Application.cfc
index.cfm
customTags/
    someTag.cfm
someFolder/
    somePage.cfm

Assume that Application.cfc sets this.customTagPaths in the form I specified above, and someFolder/somePage.cfm tries to use your "someTag" custom tag, you'll get an error similar to this:

ColdFusion attempted looking in the tree of installed custom tags but did not find a custom tag with this name. If you are using per-application custom tag mappings, ensure that per-application settings are enabled by the administrator.

What's happening is that ColdFusion is looking for someFolder/customTags/somePage.cfm, which doesn't exist.

I suppose you could use this to your advantage, if you had a need for it. For instance, you might have a layout custom tag that you wrap your pages with to make sure they all have the same header, navigation, and styling; but sub-pages in folders get slightly different navigation.

Having two custom tags in two different directories that are found relative to the current template is probably a bad idea as far as maintenance is concerned though. Joe the Programmer isn't likely to notice your "." in the custom tag path, and even if he does he's not likely to realize that it means all custom tag paths are relative; unless you make heavy use of the pattern and it becomes a standard in your organization.

But, it works. I tested it by creating two custom tags that indicate who they are:

/customTags/someTag.cfm:
I am the surface custom tag

/someFolder/customTags/someTag.cfm:
I am the deep custom tag

And to see the results, I used the same-named custom tag from each of our two pages. I also wanted to see what would happen if I included the deep page:

/index.cfm:

/someFolder/somePage.cfm:

The output of /index.cfm was as follows, indicating that the custom tag relative to the base template was used in both cases:

I am the surface custom tag
I am the surface custom tag

And the output of /someFolder/somePage.cfm was as follows, indicating that the custom tag from the sub-folder customTags was used:

I am the deep custom tag

This brings up yet another potential issue. If you have this relative custom tag path organization in use, and later decide you need to cfinclude a sub-page onto your home page to highlight it for the week, it won't use the same custom tag that it does in the sub folder. That's not to say it will fail, because if you're clever you can again use that to your advantage.

But again, being overly clever is often more of a problem than it is a good solution. In my opinion, you're better off with one custom tags folder and two different custom tag names.

Posted in ColdFusion 8 | 2 comments