Download Firefox -  a safer, easier to use web browser. Return to iribbit.net - Leap into the online experience! Return to iribbit.net - Leap into the online experience! iribbit.net - Leap into the online experience!

Project News :.

The latest project to launch was the site for Gorilla Offroad Company. Aside from their main site, a social media strategy was develop to launch the company into various industry specific automobile enthusist discussion board communities as well as popular social media fronts like Facebook, Pinterest, and Twitter.


Valid XHTML 1.0 Transitional

Valid CSS!

Section 508 Compliant

powered by: Macromedia ColdFusion MX

made with: Macromedia Dreamweaver MX

What is RSS

XML - often denotes RSS Feed information.

Macromedia - ColdFusion Programming
white horizontal rule

ColdFusion News :.

To bring a little life to my site, I've pulled a couple What is RSS Feeds into this page. You can currently choose between the technology related news stories from the following news sources:



You are currently viewing and RSS Feed from Raymond Camden's Blog.



HTML5 (or HTML in general) book recommendations?

A reader asked what I'd recommend in terms of a good book for learning HTML5 and after realizing I had no idea, I thought I'd post it here and let my smart readers (yes I'm buttering you up) have a say. To be clear, the reader is looking for books. In general I'd easily recommend the Mozilla Developer Network for this information online, but obviously you can't (shouldn't) print that out.

So, what do recommend?


(Mon, 01 Dec 2014 13:39:00 -0500)
[view article in new window]

Selecting a random record from an IndexedDB Object Store

A few days ago I ran across an interesting post on Stack Overflow, Is there any way to retrieve random row from indexeddb? The posted answer used the following process:

  • Open an index.
  • Iterate over every row.
  • On the first iteration, use the key value as an upper bound, and select a random number from 1 to that number.
  • Iterate until you hit that number.

While this worked, it seemed like a bad idea to iterate over - possibly - a huge number of rows to get to the random row you wanted. I double checked the spec and discovered what seems to be a simpler solution. When you have opened a cursor (and for those who don't know IDB very well, think of it as simply a way to iterate over a table), you can either continue to the next row, continue to a specific key, or use the advance method to go forward a specific number of rows.

I figured advance would be a good way to handle this. I built a simple demo that demonstrates this. I won't bother showing the HTML as it is just two buttons (one to add some seed data and one to select the random value), but you can view source on the linked demo below if you want. Here is the JavaScript. Note - this code can definitely be rewritten to be a bit tighter.

/* global $,document,indexedDB,console */

/**
 * Returns a random integer between min and max
 * Using Math.round() will give you a non-uniform distribution!
 */
function getRandomInt (min, max) {
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

$(document).ready(function() {
	var db;

	var openRequest = indexedDB.open("randomidb",1);

	openRequest.onupgradeneeded = function(e) {
		var thisDB = e.target.result;

		console.log("running onupgradeneeded");

		if(!thisDB.objectStoreNames.contains("notes")) {
			thisDB.createObjectStore("notes", {autoIncrement:true});
		}
	};


	openRequest.onsuccess = function(e) {
		console.log("running onsuccess");

		db = e.target.result;

		$("#seedButton").on("click", function() {

			var store = db.transaction(["notes"],"readwrite").objectStore("notes");

			for(var i=0; i<10; i++) {
				var note = {
					title:"Just a random note: "+getRandomInt(1,99999),
					created:new Date()
				};

				var request = store.add(note);

				request.onerror = function(e) {
					console.log("Error",e.target.error.name);
					//some type of error handler
				};

				request.onsuccess = function(e) {
					console.log("Woot! Did it");
				};
			}

		});

		$("#randomButton").on("click", function() {

			//success handler, could be passed in
			var done = function(ob) {
				console.log("Random result",ob);	
			};

			//ok, first get the count
			var store = db.transaction(["notes"],"readonly").objectStore("notes");

			store.count().onsuccess = function(event) {
				var total = event.target.result;
				var needRandom = true;
				console.log("ok, total is "+total);
				store.openCursor().onsuccess = function(e) {
					var cursor = e.target.result;
					if(needRandom) {
						var advance = getRandomInt(0, total-1);
						console.log("going up "+advance);
						if(advance > 0) {
							needRandom = false;
							cursor.advance(advance);	
						} else {
							done(cursor);
						}
					} else {
						done(cursor);
					}

				};

			};

		});

	};

});

I assume we can skip the IDB setup and seed functions. I built the bare minimum so I could test the random aspect. The random selection code works by first doing a count on the object store. This returns - yes - the count. Once we have that, we open a cursor that would normally let us iterate over the entire store. On the first iteration it has the first row. We then ask for a random number. Our range starts at 0 because we want to support the first row being acceptable as well. Based on that number we advance X number of rows and return that result to the done function. If for some reason 0 was selected, we run done right away.

Not rocket science, but it seems to work well. At most you run two iterations, not N, so it seems like it should be much more performant than the original answer on Stack Overflow. As I said, this was my first version so the code could definitely be organized a bit better. You can view the demo here: http://www.raymondcamden.com/demos/2014/nov/30/test1.html.
(Sun, 30 Nov 2014 09:09:00 -0500)
[view article in new window]

Star Wars Teaser

I'm assuming most people who care have already watched this online, but I'm sharing it anyway. Today the teaser for the next Star Wars film launched and it is incredible. I know a lot of folks hated the prequels and will remind me that the first teaser for them was pretty exciting as well. I don't care. The prequels were not as cool as I had hoped, but frankly, I didn't mind. I enjoyed them. Not as much as the original series, which by the way, also had its groan-worthy moments, but I had a heck of a lot of fun just watching them. I'm thrilled by what I see here. The Stormtroopers, in particular, look to be bad ass. One of the best parts of the Prequels was seeing the Clone Troopers as an effective fighting force. I'd like to see them kicking butt again in this new series, especially if we get to see the Empire in the Rebellion's role from the classic series. Much smaller, much leaner, etc. Any way, enjoy.


(Fri, 28 Nov 2014 09:36:00 -0500)
[view article in new window]

Disqus update (and BlogCFC export script)

As folks know, I've been working on transitioning to Disqus over the past week. I ran into multiple problems, and I made multiple mistakes, but today the process completed and I'm ready to share details about my BlogCFC export script as well as some tips for others who may be considering making the jump.

I had two main issues when I did my import. The first was that some comments on my earliest blog entry didn't show up. This issue went away. I'm not sure why it did - but it was a minor issue compared to the second issue so I'm not concerned about it.

The second issue was the big one. When I did my import I discovered that my comments were not in the right order. This was because I screwed up my call to ColdFusion's timeFormat function. Yes - timeFormat. I've been using ColdFusion for about fifteen years and I made a rookie mistake there. (Actually I screwed it up twice which is even worse - but let's just pretend that I didn't.) This is where I ran into the problem with Disqus. When I reran my import, the changes were not reflected. I even went through the step of deleting all 6000+ of my previously imported comments, 25 at a time, to remove them and do my import. That didn't help either.

Turns out there is no way to do replacements in Disqus. Period. They recommend you test your imports on a dev forum, but even that wouldn't be helpful if you screwed up. You would need to make multiple testing forums which is probably not desirable. Luckily the fix was easy enough. Disqus looks at the <wp:comment_id> tag value in your imported XML to determine the uniqueness of a comment. I was using the UUID from my database table. To get around the issue, I literally just prefixed "m1_" in front of the ID. (Why m1? I assumed I was going to screw up again.) I should note that some folks on Twitter also suggested this but I held off trying it until I got confirmation from Disqus that this would work.

So... for the most part, that was the end of it. I ran my script about 4 times - generating "pages" of data over my BlogCFC entry list. Disqus recommends creating XML files less than 50 megs big. From what I could see I would have been a bit over that if I had done them all at once, but for folks who want to use my code you can probably generate a complete export if your comment count is less than mine. Another thing to watch out for is errors. I had about 20 comments in my database that were blank in regards to the actual text. I don't know why. Disqus considered these errors (rightly so), and reported the import as an error... but only while it was processing. Here is a screen shot of what I'm talking about:

Do you see how it says it only imported 900 or so? And see the error? This worried me but then I realized that it was still processing. The status seemed to imply a finished state but it was actually still digging through stuff. As I reloaded the number went higher and higher. (For folks curious, it took maybe 5 minutes to import 20K+ comments.)

If that UI in the screen shot doesn't match what you see in the Disqus import screen, that's because there is apparently two different places you can check imports. I was shown this url: http://import.disqus.com/group/FORUMNAME. This site seemed to provide slightly clearer reports so you may want to check it if you do a big import.

I want to give huge thanks to Matt Robenolt of Disqus. As I said, I had trouble with the "main" Disqus support. They were somewhat slow. I found Matt via contacts on Twitter and he dug deep into the issue. He agreed that there probably needs to be a way to force a reimport so hopefully that will come in the future.

For those of you on ColdFusion and running BlogCFC, I've attached my script. It was written for ColdFusion 11 but you can backport it easily enough to earlier versions. If you use it and it works for you, please let me know in the comments below.


(Wed, 26 Nov 2014 13:19:00 -0500)
[view article in new window]

Early Access to My Next Book - Apache Cordova in Action

Hey - guess what? I'm working on a book. This time the publisher is Manning, and one of the cool things they do is allow early access to a book. You basically pay for it while it is being developed and you can provide feedback to help improve the text. Obviously you get corrected/new chapters as they come out as well. If this is appealing to you, you can head over to the book page now.

"Apache Cordova in Action" will help readers learn how to use Apache Cordova. As you know, I'm an avid user of Cordova and PhoneGap. Sometimes the documentation can be a bit difficult to grasp. I think the docs are good, but there are a lot of different things developers need to synthesize in order to really get it. This book - I hope - will help tremendously in that area.

Currently three chapters are available, and you can read the first chapter (PDF) for free. The fourth should be released very soon with other chapters coming every two weeks or so.

For your perusal, here is the table of contents. This may change as the book is developed.

Part 1: GETTING READY
1 What is Cordova?
2 Installing Cordova and the Android SDK

Part 2: CORE CONCEPTS
3 Creating Cordova Projects
4 Working with Cordova Plugins
5 Mobile Design and User Experience
6 Considerations when Building Mobile Apps
7 Creating Custom Plugins
8 Debugging Mobile Apps
9 Packaging Options
10 Using PhoneGap Build

Part 3: WHAT'S NEXT?
11 Submitting to the App Stores


(Tue, 25 Nov 2014 07:58:00 -0500)
[view article in new window]

Status of Disqus updates, and a tool for URL migration

Well, I'm disappointed to say the least. I've had good luck with Disqus pretty much everywhere I've used it, but my attempts to migrate my 50K+ comments over have been met with a great amount of difficulty. I'm not giving up, but hopefully my notes here will help others.

I created a tool that read my database and exported comments in the XML format described by Disqus. I built it so it could do a "slice" of blog entries. My first test covered the first three blog entries ever posted and the second test covered the fourth entry plus a thousand more.

When I had these imported, and Disqus got them in pretty darn quickly (they warn you it can take 24 hours, but for me it was no more than 5 minutes), I ran into two issues.

The first thing I noticed was that comments on my very first blog post did not show up. I looked in the Disqus admin and they were there. Clicking to go to that thread from the admin worked. But they didn't actually load on the page.

The second thing I noticed was that my order was wrong on a particular thread. I discovered that my export script had screwed up the time output. Totally my fault. I fixed it and resubmitted the XML. I noticed though that it wasn't updating.

So Thursday night I submitted both issues as support problems via the Disqus site. I got a reply around noon on Friday. For the "missing comments" issue I sent them the URL. For the "replacing" issue, their email seemed to imply that you couldn't replace comments. I asked for clarification.

In both cases, I replied within minutes of getting their email. I've heard nothing back since then.

So I thought - screw it. I went into the admin and began deleting comments. You can sort by oldest so I knew I was safe to just mass delete the old ones. You can delete 25 at a time. I did this for 6000+ comments.

I resubmitted and... nothing. I seem to be unable to get these comments back in - even though they don't exist. I submitted another help request, but I guess they don't work the weekends.

Ok - so how about another issue? I found that some of my discussion threads had the wrong URL in them. This is because by default, Disqus uses window.location.href for the identifier. Their docs say you should not allow this default to happen, but if you don't know that, don't read carefully, etc, you miss that. I guess that's my fault too, but I really think Disqus should call this out. Heck, you only see this if you go into the JavaScript configuration variables page which is not the default. Disqus should really do a better job of pushing this on end users.

So luckily they have a URL migration tool. You can submit a CSV file of old URLs to new URLs so they can be migrated. Their docs suggest using their export tool to get the old URLs. That's fine and all but I've got almost 2000 old URLs in the system and guess what? The export can't be used for the import because it is only an old URL. You would have to copy and paste every URL so you have a valid CSV file.

Fine. So - I wrote a ColdFusion script to let me do this. You point it to an input file, tell it what to export, and modify a UDF that maps old URLs to new.

//change to the file disqus gave you
input = "raymondcamden-2014-11-23T15_12_05.133412-links.csv";
//change to the name you want to use for the new file
output = "new.csv";

//Will be passed the URL. Mod it as you see fit.
function map(s) {
	//fix 2015.raymondcamden etc
	s = replace(s, "2015.raymondcamden.com", "www.raymondcamden.com");
	s = replace(s, "dev2013.raymondcamden.com", "www.raymondcamden.com");
	//change mode=entry
	//this requires a db call
	if(findNoCase("mode=entry", s)) {
		var id = listLast(s, "=");
		var q = queryExecute("select posted from tblblogentries where id = :id", {id:id}, {datasource:"myblog"});
		//technically this doesn't take into account date offset, but screw it
		var newurl = "http://www.raymondcamden.com/#year(q.posted)#/#month(q.posted)#/#day(q.posted)#/#id#";
		return newurl;
	}
	//wordpress adds / at the very end
	if(right(s,1) == "/") s = mid(s, 1, len(s)-1);
	return s;
}

myData = fileOpen(expandPath("./#input#"),"read");
myOutput = fileOpen(expandPath("./#output#"),"write");

while(not fileisEOF(myData)) {
	line = fileReadLine(myData);
	newURL = map(line);
	newLine = line & "," & newURL;	
	fileWriteLine(myOutput, newLine);
}
fileClose(myData);
fileClose(myOutput);
writeoutput("Done processing.");

I've done this - and submitted the CSV - but while comment imports worked pretty quickly, this seems to be taking longer. Also, Disqus doesn't provide a status for this feature. (They do for importing.)

I know I'm a free user, but I'm really disappointed by the support from Disqus. At this point I'd pay to get technical support. I know once the import is done - and now that I've fixed the URL issue - I'll be good - but this delay is very frustrating.

Finally, and I don't think this is really impacting anyone, but I am sorry for regular readers of this blog who may be having issues now!


(Sun, 23 Nov 2014 09:34:00 -0500)
[view article in new window]

Check out FormKeep, another option for static sites

Over the past year or so I've been playing around with static site generators. After nearly fifteen years spent building dynamic web applications on the server-side, a simple solution involving a static site generator can be pretty darn appealing. Unfortunately, moving to static means you need to find alternatives for things that simply can't be static. Forms, forums, calendars, etc. I discussed options to handle this problem in my article for modernweb, Moving to Static and Keeping Your Toys. Today I'm going to introduce you to another option I discovered yesterday, FormKeep

FormKeep is a service that provides an end point for form submissions. They basically give you a place to point your forms, handle the processing, and then send your users to another page. It is incredibly simple but very useful. Let's look at a simple example. After signing up, you can quickly create your first form:

As you can see, you are given a form tag and one hidden form field. That's it. There are some suggestions for other fields, but at minimum, you just need those two. Now - to be clear - there is not a "form builder" here. After you copy and paste those two fields you will then need to build the rest of the form yourself. There is also no form checking built into the service. You would handle it client-side. If the end user disables that (and we all know end users can do that, right?) then FormKeep won't be able to prevent invalid submissions.

By default, form submissions will display a FormKeep page as a response:

But you can also easily input a return URL. Since their server simply outputs the URL to the browser to handle, you can use localhost as a test or a domain that resolves to 127.0.0.1 while you test. As an example, I used this: http://localhost/testingzone/trash/test2.html?done=1. That's the URL for my local server and the file I was using to test. Now let's look at the code I used.

<html>
	<head>
	<style>
		input, textarea { width: 250px; }
		label { width: 100px; display:inline-block; }
		input[type=submit] {
			width: 100px;
		}
		
		#status {
			font-weight: bold;	
		}
	</style>
	<script>
		document.addEventListener("DOMContentLoaded", function() {
			if(window.location.search.indexOf("done=1") >= 0) {
				document.querySelector("#status").innerHTML = "<p>Thank you for your comments. I care about them a lot.</p>";
			}
		});
	</script>
	</head>
	
	<body>
		
		<div id="status"></div>
	
		<form accept-charset="UTF-8" action="https://formkeep.com/f/439b8e051eac" method="POST">
			<input type="hidden" name="utf8" value="?">

			<label for="email">Email:</label> <input type="email" id="email" name="email" placeholder="Your Email"><br/>
			<label for="name">Name:</label> <input type="text" id="name" name="name" placeholder="Your Name"><br/>
			<label for="url">Homepage:</label> <input type="url" id="url" name="url" placeholder="Your Website"><br/>
			<label for="comments">Comments:</label> <textarea id="comments" name="comments"></textarea><br/>
			<input type="submit" value="Send Comments">
		</form>

	</body>

</html>

My example just mimics a basic contact form. But since FormKeep is returning with something in the query string, I used a bit of JavaScript to handle displaying a thank you message when it exists. FormKeep's FAQ also links to this cool example that does something similar but with CSS alone. As we know though CSS is the work of the devil so I had to use JavaScript instead.

By default form submissions are sent to you via email. This works as you imagine:

You also get a decent little online viewer as well:

To be clear - just sending an email is actually just the simplest thing you can do. You can use a webhook URL to send form data to - well - anything really. That includes things like Salesforce, Campaign Monitor, etc. Email is just the default. If you can find a service that lets you ping data to it via a URL, you can set up FormKeep to hit it with your form data.

Finally, there are two export options as well. You can dump everything out to CSV or to JSON via their "API." I put API in quotes there because right now the API is just "dump the whole thing to JSON", but I'm assuming we'll see more in the future. At minimum it will need to accept date filters.

Payment is kind of interesting. You basically pay what you want and get unlimited usage. Free usage will limit your dashboard view of data to the last ten entries, but that's certainly enough for testing. "Near Free" for personal users sounds like a pretty good deal to me.

So, check it out and let me know what you think in the comments below.


(Fri, 21 Nov 2014 13:54:00 -0500)
[view article in new window]

ColdFusion Startup Issue with Hostname

So - this is kind of crazy. Yesterday I fired up ColdFusion 11 to test something and discovered that every request for a CFM returned an error. The error was a Null Pointer Exception so not terribly helpful. (Or so I thought.) I checked the logs and saw this:

Could not determine local hostname.
java.lang.NullPointerException
    at coldfusion.runtime.RuntimeServiceImpl.getQueueLimit(RuntimeServiceImpl.java:2145)
    at coldfusion.runtime.RuntimeServiceImpl.load(RuntimeServiceImpl.java:487)

So I googled some more and came across this post on the forums: ColdFusion 10 install on RHEL 6.1. I looked closely at the exception reported by the user there and noticed it matched what I was seeing on my server, specifically this part: org.apache.catalina.authenticator.AuthenticatorBase.invoke.

If you read that post, you will see that Rupesh (part of the ColdFusion team) says this:

The license service makes use of InetAddress.getLocalHost() API and therefore your /etc/hosts file should have an entry for both localhost as well as for your host name.

Well, my hosts file definitely had an entry for localhost, but on a whim, I added my hostname. In terminal I typed hostname (total guess, I had no idea that was a valid function) and it reported Raymonds-MBP-8. I added that to my hosts file, restarted ColdFusion, and everything was gravy.

I have absolutely no idea why this happened yesterday, but hopefully it will help others if they run into the same problem. I am having issues with my router where DNS lookups and other things will fail from time to time. So maybe something on my machine got hosed network-wise enough to confuse ColdFusion. Of course, I don't even have a license for my local ColdFusion 11 server so why in the heck did it need to check a license server?


(Fri, 21 Nov 2014 08:01:00 -0500)
[view article in new window]

Blog Migration Update

Just a quick note. I've mentioned that I'm in the process of migrating the blog to a new platform (Wordpress). As part of that migration, I've went ahead and switched to Disqus. I'm still working on my export script (I'll share that when done) and since it will take up to 24 hours for the data to migrate (when I actually get the migration script even done!) I thought I'd take the plunge and enable it now.

However - that leaves me with having to display both the "old" comments (all 50,000+ of them) along with Disqus. I've done that now. Basically I just added the embed and removed the "Add Comment" form. I also put a little note so it was (hopefully) a bit obvious as to what in the heck was happening.

I know some folks aren't a fan of Disqus, but, going forward, this helps me make the blog a bit more migratable. (That's not a word and my editor is going to fuss at me. ;)


(Thu, 20 Nov 2014 17:16:00 -0500)
[view article in new window]

Determining installed plugins at runtime for Cordova and PhoneGap applications

Earlier today on Twitter a user asked an interesting question: How can I tell - via JavaScript - if a particular plugin is installed in a Cordova/PhoneGap application. I responded by asking how you wouldn't know since it is your own app, but then he mentioned that his code base was stand alone and would be used within other projects. (So basically - just JavaScript code that other Cordova/PhoneGap applications would use.)

There are a couple of different ways to handle this. The first, and simplest, is to look for the "hook" the plugin adds. For example, the barcode plugin adds methods to a cordova.plugins.barcodeScanner object. It would be trivial to see if that exists. Cool, problem solved, right?

Well in his case he was using InAppBrowser. This plugin simply modifies window.open so it isn't something you can really (as far as I can see) introspect. I did some more digging and found something interesting.

If you look at the platform build version of your www code, you will notice it includes a cordova_plugins.js file:

If you open it up, you will see a list of any plugins you have installed. I opened up cordova.js (honestly, I don't look at it often, but I should) and saw that cordova_plugins.js was being loaded in dynamically and parsed. My assumption is that this has to happen before deviceready fires so you can safely use any plugins you've got installed. On a whim then I tried the following code inside my deviceready:

var md = cordova.require("cordova/plugin_list").metadata;

The metadata part came from what I saw in cordova_plugins.js. While the rest of the file has random stuff based on the plugins installed, metadata appears to be just a list of your plugins. I confirmed that this worked well:

So - that's it. I should note that I spoke with Shazron and he mentioned that if you used browserify, it might mess with how the JS file is generated. I'd say use with caution and let me know (via the comments) how it works for you.


(Wed, 19 Nov 2014 13:27:00 -0500)
[view article in new window]

Using the autodivider feature in jQuery Mobile (take two)

Almost a year ago I blogged about using the autodivider feature in jQuery Mobile. This is a simple feature that enhances list views with dividers. It makes content a bit easier to parse when working with a large list.

One of my readers, Fher (who has a cool name - I kind of imagine her/him as a fire-breathing wolf), asked if there was a way to add a bubble count to the dividers. You can see an example of this on the docs for listview, but this is what the feature looks like:

So, the short answer is no, you can't do this with autodividers. Why? While the feature allows you to build a function to create dynamic dividers, it only lets you specify the text for the divider, not random HTML. However, if you are willing to give up having the "pretty bubble" effect, you can simply use it as part of the label. To make that work, I modified my code a bit from the previous demo (and again, you can read that here, I'd suggest checking it out just so you can see the context). Here is the complete JavaScript code. (The HTML didn't change.)

$(document).ready(function() {

	var dates = [
		"12/16/2013 12:00:00",
		"12/16/2013 14:00:00",		
		"12/17/2013 12:00:00",
		"12/18/2013 12:00:00",
		"12/19/2013 12:00:00",
		"12/19/2013 16:00:00"
	];

	var dateList = $("#dates");
	for(var i=0, len=dates.length; i<len; i++) {
		dateList.append("<li>"+dates[i]+"</li>");	
	}

	/*
	Create a generic func to return the label
	*/
	var getLabel = function(d) {
		return (d.getMonth()+1)+ "/" + d.getDate() + "/" + d.getFullYear();
	}
			
	/*
	Now that we have a func, use it to generate a label to count hash
	*/
	var dateCount = {};
	for(var i=0, len=dates.length; i<len; i++) {
		var l = getLabel(new Date(dates[i]));
		if(dateCount.hasOwnProperty(l)) {
			dateCount[l]++;
		} else {
			dateCount[l] = 1;
		}
	}
			
	dateList.listview({
		autodividers:true,
		autodividersSelector: function ( li ) {
			var d = new Date(li.text());
			var label = getLabel(d);
			
			return label + " (" +dateCount[label] +")";
		}
	}).listview("refresh");

});

The first change was to abstract out the code used to generate the divider - basically turning the date value into a label. Once I have that, I iterate over my data to figure out how many unique date labels I have. This is done with a simple object and a counter. Finally, my autodividersSelector function is modified to make use of this count. Here is the result.

There you go. Not exactly rocket science, but hopefully helpful. It is possible to create dividers with list bubbles, just not quite as simply as this entry demonstrates. I'll show that tomorrow.


(Tue, 18 Nov 2014 15:50:00 -0500)
[view article in new window]

Looking for Suggestions: Best Conferences for Mobile/Web Development

Earlier today my buddy Andy Trice posted a question about conferences:

I RTed it to help spread the word, but I thought I'd blog it here as well and see if folks could share their thoughts in the comments. This will hopefully reach a greater audience and let people have a bit more room to comment. If you manage a conference, I don't mind you sharing, just be sure to mention that in the comment.

As it stands, I was avoiding a lot of conferences over the past six months because of my adoptions, so I'm hoping to attend/present at more next year. You would be helping me as well.


(Tue, 18 Nov 2014 10:47:00 -0500)
[view article in new window]

Cordova's copy-from tip

Yesterday I was proof-reading a blog post about an update to the PhoneGap CLI (which you should read - PhoneGap CLI 3.6.3) and I discovered something interesting. For a while now the Cordova CLI has had the ability to create a new project based on another. This is great because the default Cordova/PhoneGap application annoys the heck out of me.

You can see this feature by typing cordova help create. Here is how the feature is documented:

--copy-from|src= ... use custom www assets instead of the stock Cordova hello-world.

Ok, nice and simple, right? So I built my own skeleton application with a minimal amount of code and just carried on my happy way. While reading that article about PhoneGap's update though I discovered this feature actually does two things.

If you point --copy-from at a folder that is not a Cordova application, it will copy the assets into the www folder of your new project.

If you point --copy-from at a folder that is a Cordova application, it will copy the www folder, the hooks folder, and the config.xml file. I had no idea that this was supported, and while I probably won't use the feature that often, it is good to know it exists. (And I'm going to file a bug report right now for the Cordova CLI to update the help text.)

p.s. As a reminder, definitely read that article about the PhoneGap CLI update. I primarily use the Cordova CLI but the PhoneGap one now has some features that Cordova does not. One of them I really like - if you try to run a platform that doesn't exist, it will simply add it for you. Nice.


(Fri, 14 Nov 2014 09:15:00 -0500)
[view article in new window]

Any WordPress users familiar with BlogCFC?

A long time ago a reader shared a BlogCFC to WordPress script. I'm assuming it is too far out of date to be useful. Has anyone converted a modern BlogCFC database to WordPress 4.0? I'm assuming I can figure it out myself, but if someone has a script handy, I'd appreciate it.


(Thu, 13 Nov 2014 14:00:00 -0500)
[view article in new window]

ColdFusion Example: Using jQuery UI Accordion with a ColdFusion query

A reader pinged me yesterday with a simple problem that I thought would be good to share on the blog. He had a query of events that he wanted to use with jQuery UI's Accordion control. The Accordion control simply takes content and splits into various "panes" with one visible at a time. For his data, he wanted to split his content into panes designated by a unique month and year. Here is a quick demo of that in action.

I began by creating a query to store my data. I created a query with a date and title property and then add up to three "events" over the next twelve months. I specifically wanted to support 0 to ensure my demo handled noticing months without any data.

<!---
Create some fake data with dates
--->
<cfscript>
q = queryNew("date,title");
for(i=1; i<12; i++) {
	//for each month, we add 0-3 events (some months may not have data)
	toAdd = randRange(0, 3);
	
	for(k=0; k<toAdd; k++) {
		newDate = dateAdd("m", i, now());
		queryAddRow(q, {date:newDate, title:"Item #i##k#"});	
	}
}
</cfscript>

To handle creating the accordion, I had to follow the rules jQuery UI set up for the control. Basically - wrap the entire set of data in a div, and separate each "pane" with an h3 and inner div. To handle this, I have to know when a new unique month/year "block" starts. I store this in a variable, lastDateStr, and just check it in every iteration over the query. I also need to ensure that on the last row I close the div.

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title>jQuery UI Accordion - Default functionality</title>
	<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
	<script src="//code.jquery.com/jquery-1.10.2.js"></script>
	<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
	<script>
	$(function() {
	$( "#accordion" ).accordion();
	});
	</script>
</head>
<body>
	<div id="accordion">

		<cfset lastDateStr = "">
		<cfloop query="q">
			<cfset thisDateStr = month(date) & "/" & year(date)>
			
			<!--- Is this datestr different? --->
			<cfif thisDateStr neq lastDateStr>
				<!--- We only 'close' a div if not on the first iteration --->
				<cfif currentRow neq 1>
					</div>
				</cfif>
				<cfoutput>
				<h3>#thisDateStr#</h3>
				</cfoutput>
				<div>
				<cfset lastDateStr = thisDateStr>
			</cfif>
			
			<cfoutput>
			#title#<br/>
			</cfoutput>
			
			<cfif currentRow is recordCount>
				</div>
			</cfif>
			
		</cfloop>
	</div>
</body>
</html>

And the end result:

So, not rocket science, but hopefully helpful to someone. Here is the entire template if you want to try it yourself.

<!---
Create some fake data with dates
--->
<cfscript>
q = queryNew("date,title");
for(i=1; i<12; i++) {
	//for each month, we add 0-3 events (some months may not have data)
	toAdd = randRange(0, 3);
	
	for(k=0; k<toAdd; k++) {
		newDate = dateAdd("m", i, now());
		queryAddRow(q, {date:newDate, title:"Item #i##k#"});	
	}
}
</cfscript>

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title>jQuery UI Accordion - Default functionality</title>
	<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
	<script src="//code.jquery.com/jquery-1.10.2.js"></script>
	<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
	<script>
	$(function() {
	$( "#accordion" ).accordion();
	});
	</script>
</head>
<body>
	<div id="accordion">

		<cfset lastDateStr = "">
		<cfloop query="q">
			<cfset thisDateStr = month(date) & "/" & year(date)>
			
			<!--- Is this datestr different? --->
			<cfif thisDateStr neq lastDateStr>
				<!--- We only 'close' a div if not on the first iteration --->
				<cfif currentRow neq 1>
					</div>
				</cfif>
				<cfoutput>
				<h3>#thisDateStr#</h3>
				</cfoutput>
				<div>
				<cfset lastDateStr = thisDateStr>
			</cfif>
			
			<cfoutput>
			#title#<br/>
			</cfoutput>
			
			<cfif currentRow is recordCount>
				</div>
			</cfif>
			
		</cfloop>
	</div>
</body>
</html>	

(Wed, 12 Nov 2014 08:21:00 -0500)
[view article in new window]


© The connection to the CAMDEN's RSS feed has timed out - please try again later. We are sorry for any inconvenience this may have caused.