A Technique for Tracking Page Print Using CSS Background Images

Printing a web page is still one of the most popular ways that customers interact with a classifieds search engine. At AutoConX, we try to track that metric for our sellers, so they can see how frequently people print off their listings for safe keeping. Our legacy platform presents users a print-dedicated page to track such details. But what is a modern, responsive technique for tracking that kind of interaction? I wanted something that could target printing by any means possible: triggering a JavaScript print event, using browser keyboard shortcuts or menu items and even using the cloud printing capabilities on mobile devices. CSS’s print media seemed like the way to go.

First, how to handle the actual tracking. A common technique involves creating a “tracking pixel.” When an image tag is dropped into the page, it appears to load a small, transparent gif. What actually happens is that special code executes behind the scenes and just returns data in the form of a small, transparent pixel. I crafted a 1px by 1px transparent gif as the tracking pixel and created a handler event that would call a stored procedure that would track the print in the database. Then the handler would return the data from the transparent pixel to the browser to be rendered as any other image. The CFML code roughly looked like this:

Next, I needed to use that URL as the `src` for an image. I dropped an image tag into a section of code already setup to show only for print media. The section displays a QR code and canonical URL so people with the paper version can get back to the web version. It looked like this:

I opened Chrome Dev Tools, chose the Network panel and reloaded the page. A call to my tracking pixel was made even though the image was hidden from the screen. This is an age old situation that has made it necessary to create new tags like picture and attributes like srcset for displaying different images for different browser scenarios. It was worth a shot, but now I knew this wouldn’t be as easy as I’d hoped.

Let’s try the stylesheet instead. I created the selector `.detail--trackprint` and used my tracking pixel as a background image. It looked like this:

I reloaded the page and… oh, right. CSS URLs are relative to the CSS file. Another rookie mistake. What I needed is something that is relative to the executing page so that the CFML framework gets the appropriate listing information needed for tracking. I tried briefly to use data attributes to build my background image URL, but the `attr()` function is still only good for content. Inline styling would be my best bet. I modified my original view:

I reloaded the page and watched the Network. No call. I emulated print media and reloaded the page. CALL! Success! I deployed the code to our dev server and put some other team members on QA. They weren’t seeing tracking counts as high as they should be. I dug into it with my own testing and found that the browsers (I saw this behavior in several of them) were caching the print preview after the first print. It makes sense and saves the browser some work and data transfer. However, I need to get as close to accurate as possible. I added a cachebuster to the background image:

This proved to be the solution we needed. But it doesn’t track every print! I know. This technique is equivalent to what we have in our legacy system, so in that sense it is a responsive implementation of the same accuracy our sellers already have. I could add some long polling JavaScript to increment the cachebuster while the page is loaded. This would give us
stats on the same page without reloading, but that seems overkill for a secondary metric. That number still wouldn’t be entirely accurate, because users can print more than one copy at a time. In the end, this was just enough development to meet the needs of the sellers.

Building AVR, Part 2: CFML Architecture

Once AIM was built, we needed a product to display the inventory that had been managed. The AutoConX Vertical (Responsive), or AVR, is a white-label product that allows publishers (newspaper or magazine) list inventory from sellers in their area. It’s a digital classified system that offers a lot of customization and flexibility.

This project was trickier than AIM because AIM was a brand new product. AVR, however, had to be a modern and responsive site that met all the publishers’ expectations from the legacy product. Publishers wouldn’t switch unless they saw real value in the new system. We had to build a product that we would put our own products on.

This is the story of the CFML architecture for AVR.

Continue reading “Building AVR, Part 2: CFML Architecture”

Building AVR, Part 1: Project Architecture

Once AIM was built, we needed a product to display the inventory that had been managed. The AutoConX Vertical (Responsive), or AVR, is a white-label product that allows publishers (newspaper or magazine) list inventory from sellers in their area. It’s a digital classified system that offers a lot of customization and flexibility.

This project was trickier than AIM because AIM was a brand new product. AVR, however, had to be a modern and responsive site that met all the publishers’ expectations from the legacy product. Publishers wouldn’t switch unless they saw real value in the new system. We had to build a product that we would put our own products on.

This is the story of the project architecture for AVR.

Continue reading “Building AVR, Part 1: Project Architecture”

Building AIM, Part 2: CFML Architecture

We needed to build an inventory system, one that was free from the restrictions of our legacy system. We wanted to build a system that could describe any piece of inventory: from cars to carpets, from houses to job listings. We needed an interface for our sellers to actually manage that inventory. That interface is the AutoConX Inventory Manager, which we call AIM.

This is the story of the CFML architecture for AIM.

Continue reading “Building AIM, Part 2: CFML Architecture”

Building AIM, Part 1: Project Architecture

We needed to build an inventory system, one that was free from the restrictions of our legacy system which could only describe automotive, agricultural and recreational inventory for dealerships across the United States. We wanted to build a system that could describe any piece of inventory: from cars to carpets, from houses to job listings. The process started with our database structure and maintenance areas. Then came a REST API to give us a nice separation of concerns. Once that was in place, we needed an interface for our sellers to actually manage that inventory. That interface is the AutoConX Inventory Manager, which we call AIM.

This is the story of the project architecture for AIM.

Continue reading “Building AIM, Part 1: Project Architecture”

Shortcut Functions in CFML

TL;DR Create shortcuts to long-named functions: variables.__ = intermediateFunction;

For a recent project at work, I found that a function I was going to be calling a lot had a very long name. The function was a translation look-up. I pass in a string which represents a language key, and the function returns a value for the target language.

Because our project is heavily translated, it meant I’d be calling the method many times per page. It would going to be a lot of extra typing. The solution we found, to reduce that typing to a minimum, is something I’m calling “shortcut functions”.

Shortcut functions take three parts: the original function, an intermediate function, and the assignment of the shortcut function. With a shortcut function, you can go from writing application.translations.getTranslation( string ) to __( string ).

Don’t give me that look. That’s pretty cool.

  1. You should already have your original function. Chances are, it lives in another CFC somewhere, and that’s why you want to shortcut the name.
  2. Next you have to write your intermediate function. The goal of this function is to call your original function. We need this intermediate function to preserve the scoping of the original function. I like the pattern shortcutOriginalFunction. Your intermediate function can be an anonymous function, too, which might be less confusing for some people.
  3. Finally, you write your assignment. The assignment puts the intermediate function into the variables scope, so we can call it without an explicit scope. The assignment needs to go into the onRequest method of your Application.cfc and should not use parentheses. It should look something like this: variables.__ = intermediateFunction;

Let’s look at some code. Included is an index.cfm, a translation CFC (which contains our original function), and the Application.cfc that works our magic. This code has only been tested on Adobe ColdFusion 10.

cf.Subjective() 2012

I’ve heard cf.Objective() called “the [CFML] community’s conference.” Adobe’s MAX is all bombast and big budget, but cf.Objective() is where people go to learn, grow, and network. I can safely say, during my first experience at this conference, that reputation shone brightly through.

This year’s CF Objective (can I spell it this way, for now?) was held mid-May in Minneapolis, MN, but it connected CFML programmers and enthusiasts from across the globe. Speakers came from all sorts of backgrounds and organizations, including some from Google and a nice showing from Adobe. Some talked about technologies they use, some about technologies they’ve built, and some just shared their experiences in this crazy world of web development.

The conference kicked off with Adobe employees giving the keynote. Coincidentally (or was it?), ColdFusion 10 was newly released, and the focus of the keynote was to show off and expound on all the cool new features that were available. While it was a well executed plug for the brand new version of their product, it did introduce me to some features I wasn’t aware of; in particular, Adobe ColdFusion 10 has taken a strong stance in supporting HTML 5 technologies.

Nearly every session I attended felt worthwhile, interesting, and useful. One of my favorite speakers was Nathan Strutz, whose first presentation was technically disastrous but whose later presentation was awesome. LESS CSS, Meet ColdFusion fired me up about this popular CSS preprocessor. I had tried it several versions back, and his talk inspired me to play with it again. As much as I love pure CSS, I definitely began to see how using a pre-processor could increase my productivity. I even had a chance to talk to him in person, after the talk, and we discussed our equal frustration with the way Chrome handles loading localhost JavaScript files.

Pete Freitag is a guy who has ColdFusion security on his mind all the time. Maybe that’s overstating a little, but his company and web tools, like Hack My CF, are built around the mantra of “secure your stuff”. I knew he had a strong focus on CF security, but his talk really did outline how much he knows and thinks about this stuff. “Writing Secure CFML” was a great summary of security tips for all CFML writing and some of the new security features in ColdFusion 10.

New to CF Objective this year was a JavaScript development track. I’m unique in that I play pretty equally in the CFML arena and the HTML/CSS/JS arena, and I forgot that a lot of (most of?) the CFML world has no idea what’s on the other side of the fence. That said, the JavaScript talks I went to were far from elementary. Jason Kadrmas had a great talk on building HTML 5 games with PhoneGap, Steve Stroz also gave PhoneGap some love, and Elliott Sprehn discussed AngularJS. Elliott’s talk got me excited about AngularJS – and I immediately ran to go play with it – but the JavaScript talk I enjoyed the most was Simeon Bateman‘s “Node.js And You“. What I liked about it was that he gave the standard “build a web server” demo, and then told us, “But that sucks. Who wants to build their own web server?” I’ve played with Node.js and worked through the standard demos, but he built on all that and showed some of the really cool things you can do with it.

My favorite talk was also one of the longest; it was “Running CFML on Apache Tomcat: Deep Dive” by Matt Woodward. I first became aware of Matt’s expertise thanks to the podcast he used to do, ColdFusion Weekly. This session was one of the best at balancing the lecture and the lab. We got a lot of hands-on time, but we weren’t just thrown to the wolves. In the end, I learned a lot and had something to show for it.

Long story short, it was a great conference. There are fantastic speakers and sessions; there is a strong community showing; and (for me, at least) there is a convenient location. For any CFML developer wondering, I absolutely recommend cf.Objective().

Was It Saturday?

Have you ever had a date in your head, and wondered to yourself, “Did that happen on a Saturday?” Then, did you wish that there was a web app dedicated to just that, but not a calendar?

Oh, you didn’t? Not at all? Well, I did, and that’s what this project is.

About the Project

Let me give you some background. We were working on a project where the creative direction called for the very quick, specific knowledge of whether a date happened on a Saturday.

Obvious techniques would involve clicking over to a calendar, and browsing or searching for the date in particular. This works great for a small number of dates: one, two, a dozen, twenty-five. What if you have hundreds of dates to check? Then it might be nice to have a little app that gives you the skinny on the Saturday.

Demo

Demo the app at awayken.com/saturday.

Code

The app is written in CFML and uses a Google webfont. Otherwise, there’s nothing significant about it. Fork it at github.com/awayken/Was-It-Saturday.

Never wonder whether ’twas Saturday again.