Task-based web browsing: Grunt and the grunt-open plugin

JavaScript , Miscellaneous 1 Comment »

Lately I've been playing around with Grunt, which is a JavaScript-based task runner similar to Ant and Gradle. Generally, these tools are used to automate software builds, but they can be utilized in other ways.

While browsing through the large collection of Grunt plugins, I came across one called grunt-open. The grunt-open plugin lets you create a task that opens a URL in your web browser. It looks like it was created with the idea of opening a web page at the end of a chain of Grunt tasks to check the result of a software build. But I thought it might be useful in automating everyday web browsing tasks.

I like to start off my work day with a bit of Internet humor and I have certains sites I visit for that. Dilbert has a new strip every day, while JoyOfTech and XKCD get published every Monday, Wednesday, and Friday, and the XKCD "What-If" article is published once a week, usually by Thursday. Rather than manually opening the appropriate bookmarks for the appropriate day of the week, I figured I'd program a task to take care of opening the appropriate sites.

I won't reinvent the wheel here trying to explain the basics of Grunt: the Grunt "Getting Started" guide does a good job of explaining how to install Grunt and generate the files needed (the package.json and the Gruntfile.js files). Here's what my Gruntfile looks like:

 
module.exports = function( grunt )
{
    grunt.initConfig({
        open: {
            joyoftech: {
                path: 'http://www.geekculture.com/joyoftech/',
                app: 'Chrome'
            },
            dilbert: {
                path: 'http://www.dilbert.com/',
                app: 'Chrome'
            },
            xkcd: {
                path: 'http://www.xkcd.com/',
                app: 'Chrome'
            },
            xkcdwhatif: {
                path: 'http://what-if.xkcd.com/',
                app: 'Chrome'
           }
        }
    });

    grunt.loadNpmTasks( 'grunt-open' );

    grunt.registerTask( 'webhumor', 'Load the funnies!', function() {
        var today = new Date();
        var dayOfWeek = today.getDay();

        switch( dayOfWeek ) {
            case 1: //Monday
            case 3:
            case 5:
                grunt.task.run( [ 'open:joyoftech', 'open:dilbert', 'open:xkcd' ] );
                break;
            case 0:
            case 6:
            case 2:
                grunt.task.run( [ 'open:dilbert' ] );
                break;
            case 4:
                grunt.task.run( [ 'open:dilbert', 'open:xkcdwhatif' ] );
                break;
        }
    })
};

So in the directory where this Gruntfile.js lives, I just have to type "grunt webhumor' in the command, and Grunt will open the appropriate sites. Not a huge timesaver, but kinda cool.

On Today's Experience Installing Ionic for Android Development (on Windows 8.1)

Miscellaneous No Comments »

This is one of those posts that's likely to become obsolete very quickly as the install process for Ionic changes, but if it helps someone else resolve the (minor) install issues I ran into today, then it's worth doing.

The installation instructions that start at http://ionicframework.com/docs/guide/installation.html are pretty good considering the number of technologies involved in getting up and running (npm, the Java JDK, the Android SDK, Cordova, etc.).  But as those technologies changes so does the install process, even if the change is slight.

The first issue I ran into occurred when I tried to run the "ionic start" command from the command line.  I got a two-part error message in the console.  The latter message, cast in red text, suggested that my version of Cordova was outdated:  not likely since I'd installed it 30 minutes ago.  The earlier message said "could not create work tree dir" and cited a nested folder under my user account folder called "plugman".  Fortunately, someone had posted the solution (the need to create the missing directory) in the Ionic forums:  http://forum.ionicframework.com/t/unable-to-add-plugins-perhaps-your-version-of-cordova-is-too-old/3807/10.

The next issue came up at the conclusion of the install process when I tried to run "ionic emulate android".  Again, the final error message wasn't that helpful; the earlier message stated that "abd" was not recognized as a command.  The reason that happened was because the instructions say to declare the ANDROID_HOME Path variable to point to the "tools" directory of the Android ADT bundle, but Google moved the adb executable from the "tools" directory to the "platform-tools" directory (they left a note in the tools directory about the move).  For Ionic to work you actually need pointers to both the "tools" and "platform-tools" directories in the path.

The last issue was particular to my machine.  I had a pre-existing Android Virtual Device (AVD) configuration from an earlier install of the Android Eclipse plugin, and when Ionic tried to use that AVD it complained that a kernel file was missing.  I ended up launching the AVD manager from the command line ("android avd") and using the "Repair" option to repair the AVD, and that apparently fixed the problem, and the emulator opened at its typical glacial pace.

 

Object Equivalency and Select Options in AngularJS ("Why Isn't the Correct Option Selected?")

AngularJS 1 Comment »

In my last blog post, I talked about the angular.equals() function in AngularJS and how it compares two JavaScript objects for equivalency based on the properties and property values of each object.  Angular provides that function because in JavaScript, object1 == object2 is only true if object1 and object2 are both pointers/references back to the same object in memory.

This default "equivalency by reference" can cause some counter-intuitive behavior at times.

Read more...

Determining if Data Has Changed in Your AngularJS-Powered Form

AngularJS 4 Comments »

So here's the scenario:  you've got a form enabled with AngularJS.  The form is populated with data from a data model object retrieved from a REST call.  You need to know at a certain point (perhaps at the end of every user action, or perhaps at the moment of submission) whether the form data is different from when it was originally retrieved.  How would you do that?

If you wrap your form elements within a set of HTML form tags and name the form, Angular automatically (via the ngFormController) monitors the overall state of the form and provides some status flags, one of which is the $dirty property.  Problem solved, right?  Well, not quite.

Read more...

Introducing validORM: A Development Tool for Creating ORM CFC And ValidateThis Files

AngularJS , CFML , ColdFusion 5 Comments »

In my previous post about relating different data constructs in AngularJS to each other via property names, I mentioned that I figured out that technique while working on an internal development tool.  This blog post is about that tool.

The AngularJS-powered validORM tool lets you design the ID and column properties of your ColdFusion/CFML ORM CFCs while at the same time creating a matching set of validation rules using the ValidateThis (VT) library (a great library for handling both client and server-side validation).

The first view of the tool is a menu view.  You can choose to generate an updated version of your CFC and VT rules file based on a previous session or create a new set of files from scratch.  Either choice takes you to the generator view.

The first two sections of the in the generator view are pretty obvious:  that's where you choose the name and database table for your ORM object and configue the ID property.

The third section, where you define your column properties and create your validation rules, is where AngularJS really comes into play.  The property drop-down selection, the form controls and the hover hints for each property attribute you add, and the validation rule options and parameters:  those are all AngularJS manifestations of JavaScript data constructs.  Using the "Add Attribute" button to add a property attibute simply adds a JavaScript object of that name to the dataset; the creation of the form elements on the page for that attribute is handled automatically by AngularJS based on the Angular directives in the HTML.  That's Angular's strength: driving page behavior purely through data manipulation. 

The data constructs created by your choice of property attributes and validation rules are separate from the JavaScript objects and arrays of objects that represent all of the attribute and rule options, but they reference each other via the attribute and rule key names.

The last two sections allow you to further define any ValidateThis conditions and contexts referenced in your column property rules.  When you're done, clicking the submission button will trigger the file generation process.  Your ORM and VT configuration data will be parsed by a CFC which will then generate three files in the output folder of the tool:

  • An ORM CFC written in script format.
  • A ValidateThis rules definition file matching that CFC written in JSON format.
  • A JSON-formatted snapshot of the configuration data, with a filename reflecting the name of the object and the timestamp when the file was generated.  Said file will then appear in the menu view of the tool.

Some caveats:  the tool only allows for one ID property, doesn't include absolutely every type of property attribute (just the majority of them), and it doesn't let you define ORM relationship properties.  And as my first foray with using AngularJS, I'm sure it violates one or two Angular best practices (if you're an Angular guru, feel free to chime in with any suggestions for improvement).

But it works and can provide a kickstart to creating any ORM files and ValidateThis rules for your projects.  It comes with an example "Employee" configuration set that you can play with and then delete once you start using the tool.

The tool is available for download (and modification) via GitHub:  https://github.com/bcswartz/validORM. I also created a short video of the tool in action and posted it on YouTube at: http://www.youtube.com/watch?v=-fnt_n65NWg