Smart Forms - Automate and Build Your Own Tools!

Written by Pete Corey on Sep 4, 2014.

I was recently tasked with building out hundreds of pages of pdf based forms into online accessible “smart-forms” complete with text-replacement, expanding content and usable inputs (text, datepickers, pre-populated fields, selects, etc…).

At first, I started to manually build out each of the forms as html/css partials with AngularJS interpolation to do the text replacement. I used Angular directives to accomplish any advanced functionality my inputs needed. Building out the forms manually turned out to be a huge undertaking. Simple pages would take ~45 minutes to build, and more extreme forms would take over 3 hours per page. There had to be some other way.

While talking with another developer about a similar system he’d build, he mentioned absolutely positioning the inputs over a screenshot of the form pdf. Perfect! Well, almost. Using a static image wasn’t an option since I needed to do things like text-replacement and text color changes. However, using svgs would be the perfect solution. An svg would allow me to use Angular interpolation for text replacement, change text color using ng-class and build expanding sections by injecting html in-between the svg objects.

The first thing I needed to do was convert all of the pdf pages into svgs. I also needed to remove any explicit width and height attributes on the svg elements and replace them with a viewBox attribute. Thanks to inkscape, I was able to whip up a quick shell script to convert every page file into a corresponding svg:

#!/usr/bin/zsh

for file in *.pdf; do
   inkscape $file --export-plain-svg=$file.svg
   sed -i 's/width=".*"//g' $file.svg
   sed -i 's/height=".*"/viewBox="0 0 765.75 990.75"/g' $file.svg
done
rename -v 's/pdf\.svg/svg/' *.pdf.svg

While this isn’t the prettiest script in the world, it saved me a huge chunk of time.


After creating all of my svgs, I needed to go through and find where my text replacement and logic-based coloring needed to happen. I probably could have done this with sed, but I ended up doing it by hand fairly quickly.

Below is an example of how I modified the svg generated by inkscape, and the corresponding css example:

<text transform="matrix(1,0,0,-1,195.09,397.14)" id="text278">
    <tspan
    x="0"
    y="0"
    id="tspan280"
    ng-class="{'invalid': form.name.$invalid}"
    style="font-size:11.00016022px;font-variant:normal;font-weight:normal; ... ">
        Your name is {{data.name}}, and this is an example!
    </tspan>
</text>
.submitted .invalid {
    fill: #C00000;
}

The one downside to this technique is that there is no word wrapping support. If your interpolated string is too long, the line will simple run off the document. I played with using the foreignObject element to inject html into my svg, but it was not supported in IE.


For each form I wrote an html partial to pull in each page and to hold all of the inputs. Sublime Text snippets helped speed up the process of creating all of these partials:

<div class="page">
    <div class="svg-wrapper">
        <!-- page 1 inputs go here -->
        <div ng-include="'forms/svg/formPage1.svg'" class="svg-include"></div>
    </div>
</div>
<div class="page">
    <div class="svg-wrapper">
        <!-- page 2 inputs go here -->
        <div ng-include="'forms/svg/formPage2.svg'" class="svg-include"></div>
    </div>
</div>

The svg-wrapper class has a display: relative, while each of the inputs have display: absolute.


The next step in the process was to manually position each of the inputs. It didn’t take long to realize that absolutely positioning each element by hand would take a considerable amount of time (although it was still faster than the original solution). I decided to build a tool to help me out.

I hacked together a very simple draggable Angular directive that let me click and drag to define input boxes. After a few iterations I had a tool that reduced the time to lay out a complex page from hours to just minutes. Honestly, the tool’s code is some of the worst I’ve written in years, but I think that’s what makes it amazing. Haphazardly built, poorly functioning code saved me from billing hundreds of hours of work to my client and produced a better result in the end. I’d call that a success!

Here’s a quick screencast of the tool working on an example W-9 form:

My Concurrent Jekyll Gruntfile

Written by Pete Corey on Aug 28, 2014.

I wanted to have a single default grunt command kick off my Jekyll server (jekyll serve --watch), and my grunt watch task. After sleuthing around StackOverflow, I found a solution using grunt-jekyll and grunt-concurrent. Concurrency is needed to prevent the jekyll server from blocking.

module.exports = function(grunt) {
    grunt.initConfig({
        jekyll: {
            serve: {
                options: {
                    serve: true,
                    watch: true
                }
            }
        },
        less: {
            development: {
                options: {
                    paths: ['./less'],
                    yuicompress: true
                },
                files: {
                    'css/main.css': 'less/main.less'
                }
            }
        },
        watch: {
            less: {
                files: ['less/**/*.less'],
                tasks: ['less']
            }
        },
        concurrent: {
            all: {
                tasks: ['jekyll:serve', 'watch'],
                options: {
                    logConcurrentOutput: true
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-jekyll');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-concurrent');

    grunt.registerTask('default', ['concurrent:all']);
};

Prism.js and Github Pages

Written by Pete Corey on Aug 27, 2014.

In a previous post I mentioned that I would be using Prism.js as my syntax highlighter. Originally, I tried adding prism.rb to my _plugins directory. That let me use the prism liquid tag locally:

{% prism javascript %}
    //javascript goes here...
{% endprism %}

BUT! After pushing those changes to Github, I recieved a build error email:

The page build failed with the following error:

The tag prism in _posts/2014-08-26-look-ma-no-wordpress.markdown is not a recognized Liquid tag. For more information, see https://help.github.com/articles/page-build-failed-unknown-tag-error.

The link leads to a page explaining how to use Jekyll plugins with Github Pages. Unfortunately, only a handfull of plugins are supported, and Prism isn’t one of them.


The workaround solution is to remove prism.rb from your _plugins directory, and use plain markdown to build your code blocks instead:

<pre><code class="language-javascript">
    //javascript goes here...
</pre></code>

Aside from a little more verbosity, the only real downside that I can find with this approach is that if your first line of code is not inline with your <pre><code> line, you will have an extra line break before your first line of code.