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.



Using the New York Times API to Chart Occurrences in Headlines

This weekend while at a conference, I discovered that the New York Times has a pretty deep developer API. It covers both their newspaper data as well as government and regional information. I played around with it a bit and found it very easy to use via JavaScript (I don't think they document it, but they do use CORS so you can skip JSONP) and thought I'd try to build a little experiment. What if we could use the API to map the number of times a keyword appeared in headlines over time?

I began by looking at the API documentation for article searching and discovered that they let you narrow your search term to a specific part of the article. I began with a simple example that just searched the entire database for a term in the headline.

$.get("http://api.nytimes.com/svc/search/v2/articlesearch.json", {
		"api-key":API,
		sort:"oldest",
		fq:"headline:(\""+term+"\")",
		fl:"headline,snippet,multimedia,pub_date"}, function(res) {
		console.dir(res.response);
	}, "JSON");

Fairly simple. I also limited the result set back. I'm not currently displaying any actual result data, just aggregate data, but I focused on a few key items for the result that I thought I might add later. The important thing though is the response object. It contains a "meta" key with the total number of results.

Ok, that's half way there. The next step was to limit the results to one calendar year. Again, the API makes this pretty darn simple. I wrote a function that accepted a year and search term and handled performing the search.

function fetchForYear(year, term) {
	//YYYYMMDD
	var startYearStr = year + "0101";
	var endYearStr = year + "1231";
	console.log('doing year '+year);
	
	return $.get("http://api.nytimes.com/svc/search/v2/articlesearch.json", {
		"api-key":API,
		sort:"oldest",
		begin_date:startYearStr,
		end_date:endYearStr,
		fq:"headline:(\""+term+"\")",
		fl:"headline,snippet,multimedia,pub_date"}, function(res) {
			//Ok, currently assume a good response
			//todo - check the response
			//console.dir(res.response);
			totalDone++;
	}, "JSON");
	
}

Note that I'm returning the promise generated by the jQuery's Ajax handler. Why? Well I need to perform a large number of Ajax calls. To handle knowing when they are all done, I can combine them into an array and wait for them all to finish. Promises are seriously cool for stuff like this.

function search() {
	var term = $search.val();
	if(term === '') return;
	totalDone = 0;
	
	console.log("Searching for "+term);
	var currentYear = START_YEAR;

	var promises = [];
	
	//Gather up all the promises...
	for(var i=START_YEAR; i<=END_YEAR; i++) {
		promises.push(fetchForYear(i,term));	
	}
	
	//And when done, lets graph this!
	$.when.apply($, promises).done(function() {
		console.log('DONE');
		console.dir(arguments);
	});
	
}

The code above worked perfectly. I tested it on a bunch of calls and it correctly handled waiting for them all to finish and giving me easy access to all the results. Then I ran into a problem. I modified my data to go from 10 calls to 100 and I then hit the NYT's API rate limiter. For some silly reason (and honestly, this is really stupid) the NYT refuses to tell you what their rate limits are until you sign up and make an app. Now, it is free to sign up so it doesn't cost you anything, but there is no valid reason for this! If you provide an API, be up front and direct with what your limits are. Ok, rant done. So their limit is 10 per second. This threw me for a loop. I'm aware of code that will limit the number of calls per time period, but these methods kill (as far as I know) the "extra" calls. I wasn't able to find a library that said, "If I give you X in time period Y and the limit is some smaller number, just push the rest till after Y." A follower on Twitter recommended simply building a recursive function and adding a timeout, so that's the approach I took.

I built a function called processSets, which basically looks at my desired data as a set of ... well sets. Given I want 100+ years of data, and given that the NYT wants no more than 10 hits per second, I thought doing 10 hits at once and then recursively calling myself in a timeout may work. I got this working, although I had to use a few global variables and I feel like this is a bit dirty. I should really abstract this out in a module. For now though, it works. Here is my current solution.

/*
Given an array of data, I process X items async at a time.
When done, I see if I need to do more, and if so, I call it in
Y miliseconds. The idea being I do chunks of aysnc requests with
a 'pad' between them to slow down the requests.
*/
var globalData;
var searchTerm;
var currentYear = START_YEAR;
var PER_SET = 10;
function processSets() {
	var promises = [];
	for(var i=0;i<PER_SET;i++) {
		var yearToGet = currentYear + i;
		if(yearToGet <= END_YEAR) {
			promises.push(fetchForYear(yearToGet,searchTerm));
		}
	}
	$.when.apply($, promises).done(function() {
		console.log('DONE with Set '+promises.length);
		
		//update progress
		var percentage = Math.floor(totalDone/(END_YEAR-START_YEAR)*100);
		$progress.text("Working on data, "+percentage +"% done.");
		
		//massage into something simpler
		// handle cases where promises array is 1
		if(promises.length === 1) {
			var toAddRaw = arguments[0];
			globalData.push({
				year:currentYear,
				results:toAddRaw.response.meta.hits
			});			
		} else {
			for(var i=0,len=arguments.length;i<len;i++) {
				var toAddRaw = arguments[i][0];
				var year = currentYear+i;
				globalData.push({
					year:year,
					results:toAddRaw.response.meta.hits
				});
			}
		}
		currentYear += PER_SET;

		//Am I done yet?
		if(currentYear <= END_YEAR) {
			setTimeout(processSets, 900);
		} else {
			$progress.text("");
			render(globalData);	
		}
	});

}

function search() {
	var term = $search.val();
	if(term === '') return;
	totalDone = 0;
	
	console.log("Searching for "+term);

	globalData = [];
	searchTerm = term;
	$progress.text("Beginning work...");
	processSets();
}

Hopefully this makes some sense. Again, I'm sure some of my readers will tear me a new one for how I did this, but, this is version 0 so be nice. ;) The final part of the puzzle was rendering the result. I started off trying to use Chart.js, but I was unable to get it to render a bar/line chart X-Axis with a smaller number of ticks than my dataset. I then switched to Highcharts. I was able to find a demo pretty darn close to what I wanted, but it was a bit of a struggle to understand some of their documentation. In fact, it took me almost as long to get the chart right as it did to get past my "10 per second" issue. Highcharts is very complex, or I was very tired, but I was able to get it working. One very cool part of their docs is that they have links to JSFiddle. In fact, this is how I ended up finally solving my issue. I used one of their fiddles, modified it, and figured out what I needed to do. The final result is impressive I think. Remember that I'm no designer so this could be done better probably, but I really like the look.

First, an example of a search for Internet. Click for larger image.

And here is a search for War. Again, click for full size.

Forgive the typo in the header - apparently my spelling skills are only slightly worse than my ability to dress well. So - want to play with this? I've attached a zip of my code to this blog entry, minus my API key. I'm also going to link to a demo, but please note that I only have 10K API hits allowed per day. My average blog post gets about 1000 page views, and if you all try it, it will quickly expire. I certainly don't fault the NYT for that, but keep it in mind if you try it. I don't have good error reporting (i.e. "any") so check the console. Because I'm assuming I will hit the limit, here is a video of it in action.


(Mon, 15 Sep 2014 08:15:00 -0400)
[view article in new window]

Video: My top features of ColdFusion 11

Here is the other presentation I did at NCDevCon - a review of my top features of ColdFusion 11. I should totally be in marketing. Honest.

Ray's Top Features of ColdFusion 11


(Sun, 14 Sep 2014 17:15:00 -0400)
[view article in new window]

Video: Building Hybrid Applications with Ionic

How cool is NCDevCon? The presentation I finished 10 minutes ago is online. Now. There may be some audio issues in the middle (had some feedback) so you may want to switch to headphones (let me know), but overall, check it out and let me know. I've made no secret of my love for Ionic and I hope this helps people get acquainted with it.

Video Link

p.s. I didn't include my slide deck and example apps, but if folks would like them let me know and I'll post a copy.


(Sat, 13 Sep 2014 10:07:00 -0400)
[view article in new window]

Having issues sending a Cordova app to an iOS device? Seeing lldb?

Yesterday I ran into an odd issue with an Ionic demo. I was trying to run it on an iOS device and it kept hanging. After about 5 seconds of hanging, I'd see (lldb) and then nothing else would happen. I switched to using the Cordova CLI and confirmed the same thing happened there. After a bit of Googling, I found myself on the Ionic forums at this thread: Error when doing 'ionic run ios'. Long story short, there is a process, lldb, that is hanging around and blocking access to the device. Use the suggested pkill lldb command and you should be good to go.


(Thu, 11 Sep 2014 17:15:00 -0400)
[view article in new window]

CommandBox CLI and Package Manager for ColdFusion

I'm a few days late on this, but I wanted to be sure my readers knew about the release of CommandBox by Ortus Solutions, the same fine folks behind the ColdBox series of products. CommandBox provides probably the number one feature missing from ColdFusion - a command line and package manager.

The CLI tool lets you quickly run CFML from the command line and build extensions for the command line with ColdFusion. Along with just running CF at the command line, CommandBox can quickly generate code for ColdBox and other products - essentially acting as a scaffolding tool from the command line.

On top of being able to run CF from the CLI, CommandBox also provides package management. If you've done anything at all with Node then you realize how big of a deal this is. At a high level, it lets me develop code that requires other parts, let's say Alpha and Beta. Alpha can define what it needs. Beta can do the same. But from one command, I can simply ask for my code and the tool handles getting all the dependencies down the line. This makes installation of code a heck of a lot easier. You can browse the list of available packages at ForgeBox.

As an example, via CommandBox I could install ColdBox like so: forgebox install coldbox-platform. Nice and simple, and what I've grown accustomed to with Node.

All in all, a very cool product and something ColdFusion has needed for a very long time. You can watch Brad Wood demonstrate the product below.

CommandBox Demo from Luis Majano on Vimeo.


(Thu, 11 Sep 2014 05:59:00 -0400)
[view article in new window]

Ionic Framework and CLI updated

Just a quick note to let folks know that Ionic has been updated - both the framework (the UI and UX bits, basically what you see) as well as the CLI itself. This forum post details the changes in the Ionic framework itself: http://forum.ionicframework.com/t/v1-0-0-beta-12-krypton-koala-released/9435.

As for the CLI, I'm not aware of a document just for that, but the latest version is 1.2.4 and a cool new addition has landed. You can now seed an Ionic project with the contents of a directory. This joins the existing other options (one of the three main templates or a CodePen) and is a great addition. Personally I think the "blank" template is perfect (and wish the Cordova default project was as good), but I know I'm going to need to tweak it a bit and once I do, I'll create a copy and use it for future Ionic projects.

In honor of this release - here is a result from a Google image search for "krypton koala":


Image credit: Discovery News


(Wed, 10 Sep 2014 16:47:00 -0400)
[view article in new window]

What is the optimal environment for trying Ionic?

So earlier today before the OMG A WATCH IT BURNS event, David asked me a question about Ionic on Twitter:

I told him I'd need a bit more than 144 characters to respond so this is my attempt. As always, take what I say with a grain of salt. This is my opinion.

First and foremost - David said, "trying" - which to me is a bit different than "working with." If your goal is to see it as quick as possible and you don't really have anything else, then you should be able to get by with just doing what their Getting Started guide recommends: npm install -g cordova ionic. This will not be enough to test on a device if you don't have SDKs, but you will be able to test in a browser. You can see the UI. You can see the directives being used. I think this will give you a good idea of what you get out of the box to at least let you know if you will like working with their framework. (Spoiler - you will - but I'm biased.)

To be clear though, where the Getting Started guide suggests adding the iOS platform, you will not be able to do that if you truly have a virgin machine. Instead you want to use ionic serve which will fire the project up in the browser. Just remember you can't test any device features, but you can test pretty much everything else in Ionic.

So that's the quick way. For the optimal setup for someone planning to commit to Ionic, I'd go ahead and ensure you get your SDKs set up. That's covered over at Cordova's web site and is an "involved" process, but deal with it. You can skip that if you want to use Ionic Box, but I'd probably still recommend biting the bullet and doing the SDKs locally.

Finally - as much as I like Android, nothing is as fast as iOS. Get a Mac. Seriously. Being able to send to the iOS emulator in about 3 seconds if a huge benefit. You don't have to drink the Apple Koolaid completely but at the end of the day my Macbook Pro has probably been the best development machine I've ever owned. As I said - take this with a grain of salt - and feel free to argue with me in the comments. ;)

Ok, I lied. I'm not done. As long as I'm rambling on with other recommendations, here are a few more:

  • Brackets is the best editor for web projects. Get it.
  • Ionic supports viewing log messages in the console, which is probably good enough for half of your debugging. Outside of that, use GapDebug. It gives you remote inspection for iOS and Android all in one Chrome tab.
  • For Android development, do not use simulators. Use Genymotion.

(Tue, 09 Sep 2014 14:43:00 -0400)
[view article in new window]

Proof of Concept: Live HTML checking for a textarea

Most online forms don't allow HTML, or allow a very strict subset of HTML, but for years now my blog form (the one I'm using right now) has allowed for any and all HTML. I figure if I can't trust myself, who can I trust? Of course, from time to time I screw up and forget to close a tag or make some other mistake. For a while now I've wondered - is there an easy way to check for that and potentially catch those mistakes before I save the form?

I currently know of two services that let you check HTML. One is the W3C Validator. I've used this for one of my Brackets extensions (W3CValidation) and it works ok, but on simple tests it seemed to miss obvious things. For example, given input of: <b>moo it only notices the lack of a root docttype and declaration and basically throws up. Since my input will always be part of a full HTML page, the blog content, this didn't seem appropriate. Also, it would be asynchronous and I wanted something I could run entirely client-side.

I then decided to check out HTMLHint. HTMLHint provides rules-based reports on HTML input. It is pretty simple to use and - surprise surprise - I also have a Brackets extension for it (Brackets-HTMLHint). Since I could use it entirely client-side, I thought I'd check it out. I built a simple demo that did validation on keyup.

First, I created a simple HTML page and form.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="htmlhint.js"></script>
<script src="app.js"></script>
<style>
#blogContent {
	width: 500px;
	height: 300px;
}
#htmlIssues {
	font-weight: bold;
}
</style>
</head>
<body>

	<form>
	<textarea id="blogContent"></textarea>
	<div id="htmlIssues"></div>
	</form>
	
</body>
</html>

Nothing really special here. You can see the textarea as well as an empty div I plan on using for validation. Now let's look at the code.

$(document).ready(function() {
	$issueDiv = $("#htmlIssues");
	
	//From docs:
	var rules = {
		"tagname-lowercase": true,
		"attr-lowercase": true,
		"attr-value-double-quotes": true,
		"doctype-first": false,
		"tag-pair": true,
		"spec-char-escape": true,
		"id-unique": true,
		"src-not-empty": true,
		"attr-no-duplication": true
	}
	
	function htmlEscape(s) {
		s = s.replace(/\</g, "&lt;");
		s = s.replace(/\>/g, "&gt;");
		return s;
	}
	
	$("#blogContent").on("keyup", function() {
		var content = $(this).val();
		var issues = HTMLHint.verify(content, rules);
		
		if(issues.length === 0) {
			$issueDiv.html("");
			return;
		}
		console.dir(issues);
		var s = "Possible HTML issues found:<ul>";
		for(var i=0, len=issues.length; i<len; i++) {
			s += "<li>"+htmlEscape(issues[i].message)+"</li>";
		}
		s += "</ul>";
		$issueDiv.html(s);
		
	});
});

From the top, I'm caching my results div so I can reuse it when doing validation. I modified HTMLHint's default rule set to turn off the doctype requirement. (Because, again, I'm validating a small part of a page, not the entire page.) And that's basically it. I run the library's verify method and just render out the results. Here is an example of it in action:

As you can see, it found the unmatched tag pair, but didn't notice that turd was an invalid tag. To be honest, I'm much more concerned about screwing up tag pairs so that makes me happy enough.

If you want to play with it yourself, I set up a demo below.


(Mon, 08 Sep 2014 14:13:00 -0400)
[view article in new window]

RSS Reader Cordova demo updated with Ionic

A few years back I wrote a series of blog entries (linked to at the bottom) that discussed building a simple RSS reader application with PhoneGap/Cordova. The application used two variables, a simple name and RSS url, to drive an application that would grab the RSS feed, make a list, and let you read individual entries in the app. The final version of the app made use of the (non-core at the time) ChildBrowser plugin to let you read the entry on the site itself. (This was especially useful for RSS feeds like mine that show partial content in RSS.) I decided to update this application to make use of Ionic. It isn't an incredibly complex app, but I thought folks would be interested in the update.

First, let's discuss some of the architecture changes at a high level.

  • The previous version of the application used jQuery Mobile. jQuery Mobile handed both the UI and the Single Page Architecture of the application. Now Ionic will handle that both. Ionic has its own UI and it uses Angular beneath the hood. Once again I'll remind folks - I'm an Angular noob.
  • The previous version of the application had no support for offline mode. It did have support for the RSS feed being done. It would check for a LocalStorage copy of the entries. For this version I decided to add "proper" offline checking but just ignore RSS errors. I was maybe being a bit lazy in that regards but I'm definitely happy with the offline check now. Currently it just gives you a nice error and - well - that's it. You can't say "Check Again" or some such. But it is definitely an improvement.
  • In terms of UI, I didn't get too complex. I think more could be done probably, but for now, I'm happy with it.
  • Yesterday I blogged about Ionic 1.2.0's new LiveReload feature. While it is very cool, it has an issue you should be aware of. Imagine your app, like mine, has an error state where it sends you to some path, like /error, and that's all you can do. When you test this under Ionic's LiveReload, as you edit your code the reload feature does a reload... on that URL. What I found was that I was "stuck" in /error and I couldn't get out. Now - for release - that's what I want. But I had expected LiveReload to reload the app as a whole, i.e. to go to /. To work around this, I added a few hacks to my code. I'll explain them when I get to the code. They are very short hacks so I won't bother removing them from the zip/GitHub repo, but you should be aware of why they are there. I filed a bug with Ionic on it: https://github.com/driftyco/ionic/issues/2144.

Ok, before we jump into the code, let's look at some screen shots!

On load, it uses an Ionic Loading widget while it checks for offline status and parses the RSS feed.

After everything is checked, the entries are then displayed using Ionic's List control.

Clicking an entry displays the RSS entry. Depending on the RSS URL, this may be a complete entry or a partial one. This - in particular - is where I think a bit more could be done to make it look nicer.

Finally, we use the now core plugin, InAppBrowser, to support reading the entry on the web site.

Ok, let's look at the code! (And yet another reminder - I'm new to Ionic and Angular.) First, the home page. Of special interest here is that I'm using ngCordova and Google's JavaScript API.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title>RSS Reader</title>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">
	  
    <script src="lib/ionic/js/ionic.bundle.js"></script>
	<script src="lib/ng-cordova.js"></script>
	  
    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>

	<script type="text/javascript" src="https://www.google.com/jsapi"></script>

    <script src="js/app.js"></script>
    <script src="js/controllers.js"></script>
  </head>
  <body ng-app="starter">
	  
  	<ion-nav-bar class="bar-positive">
		<ion-nav-buttons side="left">
			<button class="button" ng-click="goHome()" ng-show="notHome">
			Home
			</button>
		</ion-nav-buttons>
	</ion-nav-bar>

  	<ion-nav-view>
	</ion-nav-view>

  </body>
</html>

Ok, now let's look at app.js. The big change here from core Ionic was to remove $ionicPlatform.ready from app.js. As I've blogged before, you have a race condition between Cordova's DeviceReady and your Angular app actually starting. So I decided to use my first controller as a way to bootstrap that particular issue.

(function() {
/* global angular,window,cordova,console */
	
	angular.module('starter', ['ionic','ngCordova','rssappControllers'])

	.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

		$stateProvider
			.state('Home', {
				url: '/',
				controller: 'HomeCtrl', 
				templateUrl: 'partials/home.html'
			})
			.state('Entries', {
				url: '/entries', 
				controller: 'EntriesCtrl', 
				templateUrl: 'partials/entries.html',
			})
			.state('Entry', {
				url: '/entry/:index',
				controller: 'EntryCtrl', 
				templateUrl: 'partials/entry.html',
			})
			.state('Offline', {
				url: '/offline', 
				templateUrl: 'partials/offline.html'
			});

		$urlRouterProvider.otherwise("/");

	}])

	.run(function($ionicPlatform, $rootScope, $location) {

		//EDIT THESE LINES
		//Title of the blog
		$rootScope.TITLE = "Raymond Camden's Blog";
		//RSS url
		$rootScope.RSS = "http://www.raymondcamden.com/rss.cfm";

		$rootScope.goHome = function() {
			$location.path('/entries');
		};
		
	});

}());

Next - the controllers file. This is all pretty standard I think - nothing special. Again though I used a hack to detect when Ionic reloaded my app and I wasn't on the home page. Since the home page loads RSS entries, if they don't exist in the root scope, I just relocate back home. This worked for my app, it may not work for yours.

(function() {
'use strict';
/* global window,angular,console,cordova,google */

	angular.module('rssappControllers', [])

	.controller('HomeCtrl', ['$ionicPlatform', '$scope', '$rootScope', '$cordovaNetwork', '$ionicLoading', '$location', function($ionicPlatform, $scope, $rootScope, $cordovaNetwork, $ionicLoading, $location) {
		
		$ionicLoading.show({
      		template: 'Loading...'
		});
		
		function initialize() {
			console.log('googles init called');	
			var feed = new google.feeds.Feed($rootScope.RSS);
			
			feed.setNumEntries(10);
			feed.load(function(result) {
				$ionicLoading.hide();
				if(!result.error) {
					$rootScope.entries = result.feed.entries;
					console.log('move');
					$location.path('/entries');
				} else {
					console.log("Error - "+result.error.message);
					//write error
				}
			});

		}
		
		$ionicPlatform.ready(function() {

			console.log("Started up!!");

			if(window.cordova && window.cordova.plugins.Keyboard) {
				cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
			}
			if(window.StatusBar) {
				window.StatusBar.styleDefault();
			}

			if($cordovaNetwork.isOnline()) {
				google.load("feeds", "1",{callback:initialize});
			} else {
				console.log("offline, push to error");
				$ionicLoading.hide();
				$location.path('/offline');

			}

		});

	}])

	.controller('EntriesCtrl', ['$scope', '$rootScope', '$location', function($scope, $rootScope, $location) { 
		console.log('EntriesCtrl called');
		/*
		handle issue with Ionic CLI reloading
		*/
		if(!$rootScope.entries) $location.path('/');
		
		$rootScope.notHome = false;
		
		$scope.entries = $rootScope.entries;
		console.log(JSON.stringify($scope.entries[0]));

	}])
	
	.controller('EntryCtrl', ['$scope', '$rootScope', '$location', '$stateParams', function($scope, $rootScope, $location, $stateParams) { 
		console.log('EntryCtrl called');

		/*
		handle issue with Ionic CLI reloading
		*/
		if(!$rootScope.entries) $location.path('/');

		$rootScope.notHome = true;
		
		$scope.index = $stateParams.index;
		$scope.entry = $rootScope.entries[$scope.index];
		
		$scope.readEntry = function(e) {
			window.open(e.link, "_blank");
		};
		
	}]);

	
}());

So that's pretty much it. I have a few templates, but only the entry list is that interesting. Here it is.

<ion-view title="{{TITLE}}">

	<ion-content class="padding">

		<ion-list class="list list-inset">

			<ion-item ng-repeat="entry in entries" href="#/entry/{{$index}}">
				{{entry.title}}
			</ion-item>

		</ion-list>

	</ion-content>
	
</ion-view>

All in all - it was cool to rewrite this. I still wish there was an easier solution for the DeviceReady issue (I swear it seems like I'm the only person annoyed by this) and the reloading, but in general, I really like this version better. I've still got respect for jQuery Mobile (and, ahem, sell a good book on it ;), but Angular just feels much better for my Cordova apps, and Ionic's UI feels easier to use as well.

You can find the complete code under my main Cordova Examples repo, https://github.com/cfjedimaster/Cordova-Examples/tree/master/rssreader_ionic.


(Fri, 05 Sep 2014 08:32:00 -0400)
[view article in new window]

Bug with ColdFusion 11's Elvis Operator

Ok, snap quiz time, given the following code, and that url.name exists, will the UDF run?

function getfoo() {
	writeoutput("do you see me?");
	return "foo";	
}
	
u2 = encodeForHTML(url.name) ?: getfoo();

Ok, time's up. If you said it wouldn't run, because, of course, it doesn't need to, then you would be wrong. Even when url.name exists, getfoo() is executed. Now, in some ways, this is consistent with cfparam's behavior. But to me, that always made sense. When I see this: <cfparam name="url.name" default="#getfoo()#"> - I always figured the compiler had to run getfoo to get the value to cfparam so cfparam could then work. Maybe you don't agree - and that's cool - but it makes sense to me.

In the case of the Elvis operator though it does not make sense. As an FYI, both Railo and Groovy ignore the right hand side when they don't need it.

Bug: 3818770


(Thu, 04 Sep 2014 16:58:00 -0400)
[view article in new window]

Ionic 1.2.0 Released

Yesterday the Ionic folks released version 1.2.0. They've got a nice blog entry taking about the update, but I want to share the cool bits here as well. Definitely read their blog post for all the updates, but here are the ones that I think are really cool.

First and foremost is the new LiveReload feature. Previously Ionic supported automatic reloading in the browser via ionic serve. You type - you save - and the browser reloads. Cool. But now you can do this on an actual emulator - or device. That's right. You skip the whole part of rebuilding to the emulator. Admittedly that saves you just 30 seconds - but as soon as you start using this feature you really, really appreciate it. One caveat - it requires a device/os that supports web sockets so you can't test this with older Androids/iOS versions. Here is an incredibly short video showing this in action.

The other cool feature is support for console logs in terminal. Now - I typically use GapDebug for everything lately, but sometimes if I just need a quick view of logs, I like having the option to see it show up in the terminal as well. I blogged about using tail -f on the console log the Cordova CLI creates, and that's also an option, but again, this is even simpler. Just pass a flag to the Ionic CLI and it will show up directly in the Terminal:

Note that currently console.dir doesn't work. I mentioned this to one of the Ionic creators and he mentioned it would be added later. In the meantime, don't forget you can simply console.log(JSON.stringify(something)) as well.

Anyway, there's more to 1.2.0 (including CodePen support), so definitely upgrade. What's nice is that the CLI will actually tell you that an update is available so it is nice and obvious.


(Thu, 04 Sep 2014 09:07:00 -0400)
[view article in new window]

Speaking at NCDevCon 2014

I'm very happy to announce that I'll be speaking at NCDevCon 2014. I've spoken at this conference for a few years now but didn't submit a topic this year due to some personal issues. Those personal issues are currently in hibernation for a few months and when an opening popped up at the last minute, I leapt at it.

I'll be speaking on two topics this year. My first is a simple look at what I think are the top features of ColdFusion 11. This will be a very opinionated look at the features of ColdFusion 11 (and ColdFusion Builder 3) that I think are worth your attention.

The second topic will be a look at the Ionic framework. This is a presentation I was supposed to give a month or two ago but that event was cancelled. I'm a complete and utter Ionic fan boy so I can't wait to share the awesomeness of Ionic with others.

For folks who can't attend (shame on you - you should :) - all NCDevCon sessions are taped and will be available for free after the conference. But tickets are still for sale. It isn't too late. If you can make it, I highly recommend going!

p.s. Sorry for being quiet the last few days. I just got back from my brother's wedding and I'm somewhat swamped. I need a clone. Or three.


(Wed, 03 Sep 2014 12:04:00 -0400)
[view article in new window]

Datalist version of Country Dropdown

Earlier this morning I saw the following tweet:

I thought it made sense and figured - why not build a version using the <datalist> tag? I began by doing a quick Google search for a select drop down of countries. I came across this one: ISO Country List - HTML select/dropdown snippet. From that I simply copied and pasted the HTML. Here it is - with a few countries cut out. Like most of the world.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Select Country</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
</head>
<body>

<form>

<!-- credit: http://www.freeformatter.com/iso-country-list-html-select.html -->
<select>
	<option value="AF">Afghanistan</option>
	<option value="AX">Åland Islands</option>
	<option value="AL">Albania</option>
	<option value="YE">Yemen</option>
	<option value="ZM">Zambia</option>
	<option value="ZW">Zimbabwe</option>
</select>

</form>

</body>
</html>

And yeah - this works - but the UX is not terribly optimal. At minimum the US should really be on top if your audience is principally American. I mean, this is cool, right?

Ok, so how to convert this to a datalist? I just need to add a text input and convert the dropdowns. The current code uses both a value and a text field, but datalists support only one value. I went into my console and wrote this code:

s = $("select");
html = "";
for(var i=0;i<s.options.length; i++) { html+= "

This gave me a copy of the rendered string in my clipboard that I just then copied to a new file:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Select Country</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
</head>
<body>

<form>

<!-- credit: http://www.freeformatter.com/iso-country-list-html-select.html -->
<input name="country" list="countries">
<datalist id="countries">
<option value="Afghanistan">
<option value="Åland Islands">
<option value="Albania">
<option value="Algeria">
<option value="Zambia">
<option value="Zimbabwe">
</datalist>

</form>

</body>
</html>

The result is a bit nicer I think.

Of course, there are a few disadvantages to this approach. First, you lose the associated country code. But you could easily do that server side. If for some reason a user enters a made up country, or simply mispells, then you would need to either just accept it or make them enter it again. The other issue is what happens if the user is on a browser that doesn't support datalist. The cool thing is that - guess what - they can still type - so nothing is really lost. You could write a few lines of code to detect support for datalist and where it doesn't exist, dynamically replace the tag (you can still get it even if the browser doesn't support it) with a select tag.

On the off chance you want to try this, here is the giant dropdown version and here is the datalist version.


(Wed, 27 Aug 2014 16:03:00 -0400)
[view article in new window]

Chrome 37 has landed - but what exactly changed?

This is something of a pet peeve of mine, and something I tend to whine about from time to time, so I will more than understand if you take this opportunity to stop reading and do something more productive than to listen to me complain. Still here? Good. Yesterday Chrome 37 was released. Awesome. So what changed? Let's (try) to find out.

The first thing I'd expect in any application is an easy way to get to the release notes, probably from the menu: Some App / About Some App. For Chrome, the "Chrome / About Google Chrome", takes you to this page:

Nothing here seems to imply anything informative about the release. The Help link leads to documentation, but nothing specific about 37. (Well, I assume that if 37 added feature X, it is covered here, but as I don't know what X is, I can't confirm that.) At the bottom of the About page (not shown in the screen shot above) is a note about Chrome being based on Chromium. I would not expect that link to provide me anything. As Chrome is "based on" Chromium, I'd expect the release notes for Chrome to be different, much like how Adobe Edge Code is based on Brackets. Ok, complete dead end there. Let's try Google.

The first result for "chrome 37 release notes" takes me here: Stable Channel Update. Woot. Hopefully you know that "Stable Channel" is the same as the main release. That's obvious, right? There are three main bullet points on this article:

  • DirectWrite support on Windows for improved font rendering
  • A number of new apps/extension APIs
  • Lots of under the hood changes for stability and performance

So, I kind of expect to learn about two main areas of changes: End User changes and Developer changes. End User changes would be things like, "You can type cowbell in the URL bar to find Christopher Walken." It is the type thing that impacts everyone. As someone who uses Chrome every day - all day - I think I know it well but I'm sure there are things I may not know about. From what I can tell, only one big change landed here, and it only impacts Windows.

In terms of Developer changes, I'm thinking about things like - support for <dialog>, which according to HTML5Rocks, was in Chrome 37 beta. To me that's a pretty cool change, but I can see it not being important enough to be listed. So that web page links to all the changes as well. You can find this here: https://chromium.googlesource.com/chromium/src/+log/36.0.1985.0..37.0.2062.0?pretty=full.

This is a formatted list of SVN changes for the release. As an example, here is the first item.

Navigation transitions: Added "addStyleSheetByURL" function to insert stylesheet links. If transition-entering-stylesheet is defined in the response headers for the incoming document, they're parsed out, passed to the TransitionPageHelper in the embedder, and are applied to the page via addStyleSheetByUrl at the appropriate time in the transition. This is the chrome side of the CL, blink side here: https://codereview.chromium.org/285623003/ Design doc: https://docs.google.com/a/chromium.org/document/d/17jg1RRL3RI969cLwbKBIcoGDsPwqaEdBxafGNYGwiY4/edit# Implementation details: https://docs.google.com/a/chromium.org/document/d/1kREPtFJaeLoDKwrfmrYTD7DHCdxX1RzFBga2gNY8lyE/edit#heading=h.bng2kpmyvxq5 BUG=370696 Review URL: https://codereview.chromium.org/309143002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278856 0039d316-1c4b-4281-b951-d872f2087c98

Yep - no idea. I'm assuming this is an internal change of some sort. For fun, I did a "Save As PDF", and apparently there is 19 pages of this. I'll be honest - I stopped reading. I did, however, do a CTRL+F for dialog. As I said, it was in Chrome 37 Beta, so I bet it landed, right? Nope - no result for dialog.

And what about "A number of new apps/extension APIs"? Searching for API returns 14 results - the second one being for Android, which is nice and all but I'm trying to find out what changed for desktop Chrome.

But here is where things get weird. I went to the MDN page for Dialog, copied their sample code, and it worked perfectly in Chrome 37. So it did ship, right? But it isn't documented. Well, that's fair. Google could have decided that it wasn't quite ready for prime time yet. Many companies will do that.

But is that the case here? I honestly don't know. I expect HTML5Rocks may soon have an article about 37, but unless you know about the site, then how do you find out? How many of my readers know about HTML5Rocks? I'd also have to imagine Google has enough people on staff to get something written in time for release. (Hell, hire me and I'll do it. ;)

For comparison's sake - let's test Firefox.

Ok, useless. Let's try "Help, Firefox Help":

Boom. Ok, a bit small, and not terribly obvious, but there it is - "What's New". This takes you to this page: https://www.mozilla.org/en-US/firefox/31.0/releasenotes/.

This brings you to a wonderfully designed page with labels by each change:

This is perfect. I'd love to see Chrome start doing this. I hope they start doing this.

p.s. Have you noticed recently that textarea elements in Chrome will use a green/grey squiggle for grammar issue? This is different than the red squiggle for spelling issues.

I say green/grey because I swear this morning I saw a light green squiggle, but I can't reproduce it now.


(Wed, 27 Aug 2014 06:26:00 -0400)
[view article in new window]

Did you do this?

It isn't uncommon for Amazon to ship items from my wish list and leave off the name of the person who sent it to me (and if you ever sent me something and never got a thank you - that's why) - but this gift was sent to me and it wasn't even on my list. So... whoever you are... thank you! It has joined my collection. One day I'll share photos of my Star Wars collection. It hasn't quite hit Hoarders level yet, but I'm getting there.


(Mon, 25 Aug 2014 11:44:00 -0400)
[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.