Walls Come Tumbling Down – Rethinking Workflow

Original Transcript

Worse still are the expectations that static visuals set in the minds of clients, particularly when designers use them as a method to get sign-off for a design. I often wonder, is the fact that so many web pages are fixed-width and centered, a direct result of clients signing off fixed-width design visuals?

I would even go so far and say that when you demonstrate a design as a static image, you are reinforcing a mistaken notion that a web page will be a facsimile of a frozen image. And when you demonstrate a design or ask for sign-off on a frozen image, you immediately leave yourself open to the problems that often come when you later implement that design.

We all know that it is impossible today for a design to render exactly the same in every browser or device.

You need only look at the different ways that Gecko and Webkit and Opera anti-alias text. The browser landscape is more diverse today than it ever has been before.

I know that many designers and developers understand that it’s neither practical, economical or desirable to attempt cross-browser pixel perfection, but what about the clients and managers that we work for? They still often subscribe to the outdated notion that you should strive for pixel perfection.

Using only Bootstrap 3’s grid system using LESS

Import the following files into your main LESS file, replacing “../components/” with the appropriate path to where Bootstrap is located:

@import "../components/bootstrap/less/scaffolding.less";
@import "../components/bootstrap/less/variables.less";

@import "variables.less"; // Put your custom variables in here

@import "../components/bootstrap/less/mixins.less";
@import "../components/bootstrap/less/forms.less";

// Delete next 2 lines if you don't want the navbar styles
@import "../components/bootstrap/less/navs.less";
@import "../components/bootstrap/less/navbar.less";

@import "../components/bootstrap/less/grid.less";
@import "../components/bootstrap/less/utilities.less";
@import "../components/bootstrap/less/responsive-utilities.less";

// Import Font Awesome
@import "../components/font-awesome/less/font-awesome.less";
// Font path to be printed in CSS
@fa-font-path: "../src/components/font-awesome/fonts";

//Put custom files here
@import 'custom.less';
@import 'header.less';

That’s all you really need to get up and running with the Bootstrap grid system. The benefits to doing this are that your compiled CSS file will be super light-weight because you’re only taking in the parts that you need.

Pattern Lab with Grunt and Live Reload

If you haven’t heard of Pattern Lab yet, go check it out. It’s a really cool tool that helps you build atomic design systems. There’s tons of reading over on the official site if you have no clue what any of that means. 🙂

I can be an efficiency freak, I like everything in my development and build process to be automated. I configured the php version of pattern lab into a node package (which might make some people raise an eyebrow) that allows for some pretty cool features, including:

  • CSS preprocessing (I personally use LESS, but SASS will work too if you make the appropriate adjustments)
  • Live reload

In this tutorial, I’ll walk through basic steps of setting up Pattern Lab with grunt and live reload. No web server needed for this (although you can certainly use one if you want)!

You’ll need:

  • An OS that knows what a proper terminal is 🙂
  • Git installed on the command line
  • Node.js/npm installed
  • Grunt-CLI installed
  • Slight familiarity with Pattern Lab

I haven’t tested this on a Windows machine, but it should work for Linux/Mac users.

Setting up

If you’ve already set up Pattern Lab, you can probably skip this step.

Open up a terminal window and head to wherever your primary workspace is and clone the patternlab-php repo.

git clone https://github.com/pattern-lab/patternlab-php.git

Now that patternlab-php has a place to live, lets build it for the first time. Your output might look slightly different, but as long as you have no errors, you’re good.

cd patternlab-php
php core/builder.php -g

At this point, you should be able to go to the path you installed patternlab-php in and then navigate to public/index.html and view it. In the case of my example the url would be: file:///Users/jfitzsim/projects/patternlab-php/public/index.html

Now you can edit files in the source/ folder, then rebuild Pattern Lab by running php core/builder.php -g, then refreshing the page to see your changes. If you keep following this article, you’ll eventually be able to edit files in source/ and have your browser automatically refresh with your changes. Before we get there, we’ve got a little work to do.

Nodifying Pattern Lab

Now to keep track of our project dependencies, lets initialize this as a node package. In patternlab-php’s root directory, make a file called package.json and put this in it.

{
  "name": "patternlab-php",
  "version": "0.0.0",
  "description": "- [Pattern Lab Website](http://patternlab.io/) - [About Pattern Lab](http://patternlab.io/about.html) - [Documentation](http://patternlab.io/docs/index.html) - [Demo](http://demo.patternlab.io/)",
  "author": "",
  "license": "MIT",
  "devDependencies": {
  }
}

What we’re currently most interested with is the devDependencies, which are currently blank. These devDependencies will make it easy for you to share your project with your developer colleagues. Once they pull your project down from git, they only need to type npm install and all the devDependencies will be downloaded.

Now it’s time to beef up our project with some grunt plugins. To do anything useful, you’ll want at least grunt-contrib-less (or sass), grunt-shell, and grunt-contrib-watch (I’ll explain later how to add CSS preprocessing). If you don’t put the --save-dev flag on the commands, your package.json file will not be updated with your devDependencies.

npm install grunt-contrib-less --save-dev
npm install grunt-shell --save-dev
npm install grunt-contrib-watch --save-dev

Quick explanation

grunt-shell will allow us to execute shell commands to automate the building of the patterns that is normally done via command line php.

grunt-contrib-watch will allow us to watch the project for changes then perform whatever task we want (like reload the page, or compile LESS/SASS).

grunt-contrib-less will compile our LESS into CSS. You could use SASS too, grunt is flexible. Do a google search for “grunt sass” and you should be able to find a suitable grunt plugin.

Make your Gruntfile

Now that we’ve installed these grunt plugins, lets put them to work by telling them what to do via our Gruntfile.js. In the patternlab-php root directory, make a new file called Gruntfile.js and put the following in it:

If this is confusing or scary, I highly recommend reading Chris Coyier’s article on grunt which demystifies what is happening here.
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Task configuration.
    shell: {
      patternlab: {
        command: "php core/builder.php -gp"
      }
    },
    less: {
      build: {
        files: {
          "public/css/style.css": "source/less/style.less"
        }
      }
    },
    watch: {
      html: {
        files: [
          'source/_patterns/**/*.mustache', 
          'source/_patterns/**/*.json', 
          'source/_data/*.json',
        ],
        tasks: [ 'shell:patternlab' ],
        options: {
          spawn: false,
          livereload: true
        }
      },
      styles: {
        files: [ 'source/less/style.less' ],
        tasks: [ 'less' ],
        options: {
          spawn: false,
          livereload: true
        }
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-contrib-less');

  grunt.registerTask('default', ['build']);
  grunt.registerTask('build', ['shell:patternlab', 'less']);

};

Now, using grunt-contrib-watch and grunt-shell we can remove one step of having to run that php command. Our watch task will listen for any changes in the directory we specified and when it notices one, it’ll run our build task, which as of right now is equal to running the shell:patternlab task followed by running the LESS task.

Hooking up LESS

The way you structure this is up to you, but here’s the setup I’m working with. This setup is will work with the Gruntfile I provided above.

Screen Shot 2014-04-16 at 2.48.45 PM

Now we’ve got it setup so when you run grunt watch and change your style.less file, it’ll automatically recompile a new CSS file and put it in the appropriate location within public/

Live Reload

Now, lets add in some Live Reload. Download the browser extension of your choice. I’m currently using the Chrome one.

Chrome users: Be sure to enable “Allow access to file URLs” checkbox in Tools > Extensions > LiveReload after installation. Otherwise it won’t work unless you’re running it from a web server.

Run the following command to start up the livereload server: grunt watch

Screen Shot 2014-04-14 at 4.07.16 PM

If it looks like that, it’s working.

Now go into Chrome and turn on your Live Reload client by clicking the icon: Screen Shot 2014-04-14 at 4.09.42 PM

The little circle in the center should fill in it should look like this:

Screen Shot 2014-04-14 at 4.09.02 PM

Now you can open up your style.less file and go to town. Every time you save your .less file, grunt will do the grunt work of building your CSS file.

patternlab-lr

This allows for super rapid development of styles because you can make the changes and then instantly see how it looks. We’ve completely removed the steps of having to re-build our site, go to the browser, and reload. Also, we’re able to live reload new patterns, which is super convenient.

patternlab-lr2

Party

You now have a bad ass (albeit basic) setup to rock out some design systems. The possibilities are very promising and this tutorial has just scratched the surface. For some additional reading:

Thoughts

I’d recommend using a server of some kind. Otherwise, when your Pattern Lab live reloads, you’ll be brought back to the “View All” page. If you’re running it on an apache server, it should save the page you’re on.

Hope this helps people get up and running with this awesome tool.

Adding a select box with categories into WordPress’ theme customizer

WP_themecusto

Note: for some awesome examples written by the WP team, check out their Github page with some great examples.

No more option pages

The WordPress theme customizer is the coolest thing since sliced bread. Maybe now, we as developers can all get on the same page when making WordPress themes. I’ve been playing with the theme customizer API and I think the days of theme options are numbered. I mean, do we really need pages and pages of theme options? I guess I can see it for overly complex WordPress as a giant CMS project. But the average blogger only needs a few powerful options.

If you’re starting a theme from scratch, I highly recommend working with Underscores, the starter theme from Automattic. This article assumes you’re using it. If you’re not, it still may work, you may just need to make some adjustments.

Keeping it modular

I wouldn’t recommend polluting your functions.php file with all this customizer code. If you’re using Underscores, they already scaffold out inc/customizer.php, then import it into function.php, which is super convenient.

If you didn’t know, there’s 3 parts to using WordPress’ theme customizer. You need a section, a control and a setting. I’ll explain more as we go.

Go into inc/customizer.php and lets make a section. Add this within the themename_customize_register( $wp_customize ) function

$wp_customize->add_section('mytheme_options', array(
  'title'    => __('Front Page Categories', 'themename'),
  'priority' => 120,
));

This creates a section for our control to live in. The control is literally the thing that you’ll be clicking on and selecting your category. So lets add the control to the section we just made:

$wp_customize->add_control( 'cat_1', array(
  'settings' => 'cat_1',
  'label'    => 'Left Box',
  'section'  => 'mytheme_options',
  'type'     => 'select',
  'choices'  => get_categories_select()
));

To do this correctly, in my opinion, we want 'choices' to take associative array in this form:

array (
  'slug' => 'Category Name'
)

If we do it like this we can use the ‘slug’ for the WP_Query (and to lookup anything else we want about the category) and ‘Category Name’ for what is displayed to the user. So here’s the function I referenced above called get_categories_select()

function get_categories_select() {
  $teh_cats = get_categories();
  $results;

  $count = count($teh_cats);
  for ($i=0; $i < $count; $i++) {
    if (isset($teh_cats[$i]))
      $results[$teh_cats[$i]->slug] = $teh_cats[$i]->name;
    else
      $count++;
  }
  return $results;
}

Awesome, now we need to create a place to store this setting. Thus, we should create the last part of the theme customizer’s holy trinity, the setting. This is what lets you retrieve the data you entered into the control.

$wp_customize->add_setting('cat_1', array(
  'default'        => 'uncategorized',
  'capability'     => 'edit_theme_options',
));

Using this method, after we save something within the theme customizer, we can access it using get_theme_mod('cat_1');. In my front-page.php, here’s how I’m grabbing these customizations that you see in my example.

<?php
  $args = array(
    'category_name' => get_theme_mod('cat_1'),
    'posts_per_page' => 5
  );

  // Displays the category's name
  echo "<h3>" . get_category_by_slug($args['category_name'])->name . </h3>;
  $the_query = new WP_Query( $args );

  // The Loop
  if ( $the_query->have_posts() ) :
    echo "<ul>";
    while ( $the_query->have_posts() ) : $the_query->the_post();
      $link = get_permalink();
      $title = get_the_title();
      echo '<li><a href="' . $link . '">'  . $title . '</a></li>';
    endwhile;
    echo "</ul>";
  endif;

  // Reset Post Data
  wp_reset_postdata();

?>

There you have it, that’s how I did it! For your reference, here’s my full customizer.php

<?php

function get_categories_select() {
 $teh_cats = get_categories();
    $results;
    $count = count($teh_cats);
    for ($i=0; $i < $count; $i++) {
      if (isset($teh_cats[$i]))
        $results[$teh_cats[$i]->slug] = $teh_cats[$i]->name;
      else
        $count++;
    }
  return $results;
}

/**
 * Add postMessage support for site title and description for the Theme Customizer.
 *
 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
 */
function basic_bootstrap_customize_register( $wp_customize ) {
  $wp_customize->get_setting( 'blogname' )->transport         = 'postMessage';
  $wp_customize->get_setting( 'blogdescription' )->transport  = 'postMessage';
  $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage';

  $wp_customize->add_section('mytheme_options', array(
    'title'    => __('Front Page Categories', 'basicbs'),
    'priority' => 120,
  ));

  $wp_customize->add_setting('cat_1', array(
    'default'        => 'uncategorized',
    'capability'     => 'edit_theme_options',
  ));
  $wp_customize->add_control( 'cat_1', array(
    'settings' => 'cat_1',
    'label'   => 'Left Box',
    'section' => 'mytheme_options',
    'type'    => 'select',
    'choices' => get_categories_select()
  ));

  $wp_customize->add_setting('cat_2', array(
    'default'        => 'uncategorized',
    'capability'     => 'edit_theme_options',
  ));
  $wp_customize->add_control( 'cat_2', array(
    'settings' => 'cat_2',
    'label'   => 'Center Box',
    'section' => 'mytheme_options',
    'type'    => 'select',
    'choices' => get_categories_select()
  ));

  $wp_customize->add_setting('cat_3', array(
    'default'        => 'uncategorized',
    'capability'     => 'edit_theme_options',
  ));
  $wp_customize->add_control( 'cat_3', array(
    'settings' => 'cat_3',
    'label'   => 'Right Box',
    'section' => 'mytheme_options',
    'type'    => 'select',
    'choices' => get_categories_select()
  ));

}
add_action( 'customize_register', 'basic_bootstrap_customize_register' );

/**
 * Binds JS handlers to make Theme Customizer preview reload changes asynchronously.
 */
function basic_bootstrap_customize_preview_js() {
  wp_enqueue_script( 'basic_bootstrap_customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), '20130508', true );
}
add_action( 'customize_preview_init', 'basic_bootstrap_customize_preview_js' );

My notes and overview on HighEdWeb Pittsburgh

Pittsburgh at sunset

 

hewebpittI wasn’t quite sure what to expect from my first conference. HighEd Web Pittsburgh by far exceeded my expectations and I’m glad it was my introduction to these types of events. What I found was a bunch of people who are in the same line of work as me, facing the same challenges, and offering advice in a warm atmosphere that fosters learning and growing. If you’re ever considering going to a HighEd Web conference, I’d highly recommend it.

Below I’m going to give a brief rundown of the talks that I attended.

I’m mostly going from memory here, so if I have something about a certain talk wrong, please don’t hesitate to clarify in the comments. It’d be greatly appreciated!

Without People, You’re Nothing – Georgy Cohen

This talk kicked off the conference making the point that no matter what we’re doing in higher ed, dealing with people is one of the biggest aspects of your job. Learning how to properly navigate those waters can lead to increased output from everyone involved and an overall better workplace. She touched on themes of empathy, listening, cooperation, and understanding.

Be kind, for everyone you meet is fighting a great battle

Everyone has ideas for how their organizations should be run, but something that Georgy emphasized was that for a lot of people, change is scary. Your ideas of how to do things affect people’s lives. Changing your group’s workflow can literally change someone’s life and take them out of their comfort zone, so it should be approached with empathy.

The path to change is paved with mutual respect.

Without everyone working together, your team is a broken machine. A broken machine can only produce sub-par work. The solution to a broken machine is to try to get everyone on the same page with a strategy. In the context of this conference, this meant coming up with a communications strategy: the “holy grail” of communication’s offices. However, this notion of strategy is far too abstract and should be solidified into a framework for everyone’s everyday work. This type of framework can empower teams and individuals to be working towards the same goal(s).

We all know how it is though in practice, once in a while we get together and come up with a kumbaya strategy that has lofty goals, then the next day everyone goes back to their broken ways. How do we combat this?

Be the change, it starts with us.

The only way out is to stop waiting for permission and to start leading.

Be your own advocate and just keep selling your ideas. Another powerful tip is to start building relationships with like-minded people. There’s strength in numbers and if you talk to some other people in your office, you may find they feel the same way as you do.

A part of the talk that stood out to me is when she showed a slide of a hedgehog as a symbol for that person that is difficult to work with (luckily I don’t think I’ve met that person where I work yet 😉 ). Even though we associate this person with being a large pain in our sides, they can often present an awesome opportunity. This person can have ideas you’ve never considered and are often coming from a place of more experience. If you go so far as to actually include them in future projects, they may end up being your biggest advocate.

The hardest people to work with may have the most useful things to bring to the table.

Getting back to “strategy”, Georgy went into some examples and gave us some tips for how we might come up with such strategies. She gave some links for some Universities that are “doing it right” so we could take a look. The only one I remembered to write down is Ball State University’s.

 

Reaching out to everyone who plays a part in your communication strategy is very important. Often times it’s administrative assistants who are in charge of updating the web content. They do the best they can, but often times have no communications training.

Training is not just about how to use the CMS. It’s about knowing how to use the right tools for the right purpose.

In other words, the CMS is a small part of what the training should be. Know how to compose quality content then use the CMS to convey that. Having online resources that people can reference is a great start. Creating “content affinity” groups can also be a huge help.

Other tips include having an example driven style guide. Don’t just tell people to write engaging content. Take it a step further and show them an example of what engaging content is. A good example of this is the University of Denver’s “Voice and Tone” guide. Have public written criteria for what is considered good content.

Creating Mobile-friendly Web Forms – Joe McGill

This was one of my favorite talks of the day, mainly because it dealt with an area that is very relevant to me: user experience. The overall theme of this talk, in my opinion, was “less is more”. A lot of marketing people look at a form as their one shot to get data from users, so they load it up with questions. This may actually be hurting the usability of the form and turning people off completely. Joe gave an analogy that really drives the point home.

Think of a movie theater transaction. When you go to the ticket booth, they attendant asks what movie you’d like to see, then asks for your payment, then gives you a ticket. It’s quick and to the point. Now imagine going to the window and after asking what movie you’d like, they’d hand you a clipboard with 20 questions like a first time visit to a doctor’s office. It’d be super annoying. And that’s the point. Don’t be annoying. Only ask for the information that you absolutely need. The importance of mobile-friendly forms becomes apparent when you look at the increase in mobile traffic. People want to do everything they can do on a desktop on their mobile phones.

Phones may not be the best kind of computer, but it’s the one I always have on me.

A good place to start is to audit your current forms on your site. Look at what you have and look for opportunities to improve.

Redesigning 101

  • Try limit inputs to 7 or less. There is actual data showing conversion/engagement dropping if there’s too many fields to fill out.
  • Ask: Can I postpone this question until later? Figure out the minimum amount of information you need to get.
  • Get important information first, then maybe have a screen saying “Succes! Thanks for registering, would you mind filling out more information?” This has actually worked on me before.
  • Again, reduce inputs.
  • Instead of asking for city, state, and zip, just ask for the zip code and use some back-end magic to figure out the city and state.
  • HTML5 placeholder attribute doesn’t substitute for label elements. Screen readers still look for labels.
  • Use checkboxes for yes/no or true/false answers instead of two radio buttons.
  • Use touch friendly targets (at least 44px x 44px as recommended by Apple)
  • Use feature detection to determine what to load/what is supported

Example of clever input field usage. This is a video showing an awesome expression of the notion of “reduce inputs”

Resources

Death to Governance… Embrace the Chaos – Tonya Oaks Smith & Ron Bronson (aka Ronya)

This was a high energy, fun talk that had a lot of informative information in it. There was a sense of duality in this talk because one speaker talked of governance and the other talked of chaos. Ronya started out with a resource to help one (wo)man departments at Universities who feel disconnected called HigherEd Solo.

When it comes to governance, there isn’t a silver bullet that will fix all the things. “If we only got this new CMS, it’d all be better.” We have governance ruling our departments that are separate from the content that is being produced. Producing quality content should fall under these governance models.

I’ll be honest, at this point I was hungry and found my mind wandering as the Pittsburgh Technical Institute staff was setting up our lunch. 🙂 Side note: During lunch I got a chance to briefly talk to Ron who told me he usually picks out a friendly face in the crowd at every talk he gives that he can look at from time to time and for this talk I was that friendly face. Thanks Ron! 😎

Tonya touched on chaos theory and pointed out that within the chaos of our team’s process, you can typically start to find patterns if you watch it long enough. This is very important because if you can find the patterns, you can find opportunities. Look for the repeat point in your team’s process. Once you find that you can use the butterfly effect to your advantage.

The Butterfly Effect: This effect grants the power to cause a hurricane in China to a butterfly flapping its wings in New Mexico. It may take a very long time, but the connection is real. If the butterfly had not flapped its wings at just the right point in space/time, the hurricane would not have happened. A more rigorous way to express this is that small changes in the initial conditions lead to drastic changes in the results.

At the start of your next project, try tweaking the initial conditions, it could lead to a drastically different outcome.

The Trouble With Tribbles: How LOL Cats ate Our Engagement – Jeff Stevens

Being a developer, I didn’t really know what to expect from this talk. What I did find was a whirlwind of information presented in a fun and engaging way.

  • Our University’s content is competing with all the other content on the web (Netflix, memes, YouTube)
  • We need to build better headlines and content, not better websites
  • Balance headlines between logic and emotion
  • Release good content that the community wants to see
  • Make sure users can socially share your content
  • Try using memes instead of news releases that no one will read (if upper administration would be okay with that)
  • Put the content where people are and in the way they expect to see it

If we build it better, they will come.

Although I’m not primarily a writer or communicator, I found this talk very engaging and informative. At the very least it gave me something to connect with my colleagues about.

Proactive vs. Reactive: A Cautionary Tale, or Use the Tool, Don’t BE the Tool – Shelley Keith & Curtiss Grymala

This talk was kind of a supplement to Georgy’s keynote, with a few useful additions.

Note: Hey that’s me sitting at the table on the left. 🙂

Talk problems, but also talk solutions.

This was a particularly good piece of advice for me. People are more likely to hear your complaints if you present a viable alternative. As Shelley said, “If you’re just complaining all the time people will think you’re like the guy in Times Square always yelling about how the end is nigh.” It’s important to bring up problems, but try not to exclusively bring up problems you don’t have any solutions for. Shelley and Curtiss talked a bit about the process they went through in redesigning their University’s website (which looks great, btw).

I particularly liked the part of the talk where they said they use data to back up decisions about what happens with the website. When they ran analytics on their mega menu, they found that they could gut a large majority of it because no one ever used it. They even admitted to having an option in the old design that let people change the background color of the mega menu which prompted an audible laugh from Brad Frost in the back of the room.

 

With their new data wielding power, they’ve found themselves much more in control when people come to them with “problems” about the website. They can say “We can change that, but we’re going to test it and see what the data says.” If it doesn’t perform any better, it gets moved back. Having data at your disposal can only help. Curtiss also said that sometimes that data can even prove you wrong, and that’s not a bad thing.

All in all very informative talk about navigating the waters of getting things done in higher ed.

Beyond Media Queries: The Principles of Adaptive Design – Brad Frost

Content parity is something that kind of goes hand in hand with his first principle. Whether users go to your website on a mobile device or desktop computer, they should get a similar experience. Unfortunately some people view the mobile web as “web light” because they think people won’t do X on a mobile device. When in reality, people will do everything on a mobile device that they can on a desktop device, if they’re given the proper means to do such actions. As far as flexibility, our sites are not just meant for desktop computers anymore. The web is a huge range of devices now. It’s kind of scary, but at the same time it’s our reality and we’ve got to deal with it. This is the web People who build their sites for specific pixel widths are bound to get burned eventually because there’s constantly new devices coming out. This will be the web? Performance was a large part of the talk. Brad showed some truly huge websites (65MB+ mobile sites) that would make anyone with a limited data plan cry. Unfortunately, performance is not a physical thing.

You can’t mockup performance in Photoshop. You can’t block out 3 days on your gantt chart for performance.

Performance is something that runs throughout the design/development process. It’s kind of like an under-current throughout, it’s always something you should be considering while weighing decisions about your site. Brad touched on the subject of progressive enhancement vs. graceful degradation. In his view, progressive enhancement is a much better avenue to take.

This ties into Luke Wroblewski’s idea of Mobile First. The general idea is, if you start with a mobile first design process, you are absolutely forced to decide what is important because the screen space is so limited. If you can figure out what goes on a mobile screen, scaling up your design will be much easier than if you did it desktop first. I think if you go from desktop to mobile, you run the risk of having a “web light” version for your mobile users.

A concept that may have been semi-controversial, but I think was very needed at a higher ed conference was his idea that users are growing increasingly tired of bullshit. I think at the top of his list of bullshit in higher ed websites are carousels.

Focus on the content, because that’s why people came to your site. Make it easy to find. Speaking of content, he went on to say we should be “orbiting around data”. Having portable data is a huge problem with websites and it’s something that vendors may not even be able to fix. Your site’s data should be like water: able to flow anywhere. The direction that we need to be moving is having an API for each site so that data can be extracted and used anywhere.

Conclusion

All in all it was a great event. I got the chance to meet some really cool people. Tyler from Waynesburg University, Joe McGill from Washington University, Nathan from Cornell University, Josh from Pittsburg Technical Institute (formerly), Steve from Brockport, and probably others that I can’t remember. I have lots of gratitude towards Dave Olsen and other helpers for all the work they did organizing this event. It was also great to have someone like Brad Frost speak at a higher ed conference, where his message is desperately needed. I got the chance to meet both Dave and Brad and they are great guys who have a passion for what they do, which is always inspiring.

Thoughts/resources for making a jQuery plugin

I thought I would share a couple resources for people looking to write a jQuery plugin but aren’t super confident in their JavaScript skills yet.

Writing a jQuery plugin was fairly simple. At first it seemed very difficult, but that was because I was looking at JavaScript wrong. I didn’t really know the language well and what it was capable of. This is mostly because I was used to just hacking around with vanilla JS and jQuery without knowing the “right” way to do things. I still might not be doing things the 100% “right” way but I’ve come a long way from what my code originally looked like.

First, get familiar with JavaScript. This might be terrible to say but honestly most of what I know about JavaScript is stuff I carried over from my Java knowledge in college. I knew enough to hack around and make things work. JavaScript and Java are so different and each language has its own set of strengths and places where it’d be useful. I’d highly recommend JavaScript: The Definitive Guide (6th edition) for learning the ins and outs of JS. You’ll probably be surprised at how much you didn’t know about JS.

If you can’t buy that book, check out Eloquent JavaScript. It’s a very good resource on JS. Do the examples, they’re very helpful.

Second, demystify jQuery and gain a deeper understanding of what’s going on with it by watching Paul Irish’s “10 Things I Learned From the jQuery Source”. Watching this really made a lot of things “click” in my head and gave me a better understanding of what is happening when you use jQuery.

Third, I’d recommend reading some stuff by Addy Osmani on design patterns. He gives some best practices on how to make a jQuery plugin. It seemed a little over my head at first, but I promise it’ll make sense if you stay with it and let all the new knowledge you took in gel together.

With these tools in your toolbox, you can’t fail. Go forth and make cool things for the web.

My first jQuery plugin – check it out!

Well, I finally got around to it. I’ve been talking about making a jQuery plugin for months now but I finally put my head down and did it. I took the scrolling progress meter that we used for the 2013 SUNY Oswego Annual Report, and made it a plugin.

Still have some work to do. There’s some functionality I’d like to add and I just noticed it doesn’t work properly in IE8 (big surprise), but I’ll get that ironed out soon.

Getting JSON data from Google spreadsheets and using it in Google maps

Map screen cap

The problem:

This is a screen shot of the map I am working with. Notice the 4 bench markers on the map. Each of these bench markers show an InfoWindow when clicked. The InfoWindow contains a picture of the view at the bench and maybe some caption text. The problem I needed to solve was to allow a non-technical to user to update these InfoWindows and add/remove markers as needed.

The solution:

The solution involved using Google spreadsheets to publish a spreadsheet to the web, then grabbing that data as JSON and feeding it into a function that creates Markers and InfoWindows. This post got me started, then I extended it to Google maps.

Here’s how the spreadsheet is laid out:

Spreadsheet Example

Google will truncate your latitude and longitude coordinates a bit. It didn’t even make a noticeable difference in the map I was working on but it’s worth noting if you’re looking for extreme precision.

First, publish your spread sheet

Publish the spread sheet

A dialog window will pop up and you’ll have some options to set. For the most part you can leave the defaults. The most important thing for this to work is getting the key from the link Google provides. Be sure to check “Automatically republish when changes are made” so if you make changes it’ll auto-update your app.

You should get a URL like this from that dialog: https://docs.google.com/spreadsheet/pub?key=<YOUR-KEY-HERE>&output=html

The part in bold is what we’re interested in.

Getting the JSON with jQuery

This is the piece of code that goes within your map’s initialize() function. The actual useful data we want is nested pretty deep within the JSON object that is returned from Google. Also, Google will take your row headings and make them lowercase and remove special characters.

For example: If the JSON object is named data, then you’d find the first cell of the “Bench ID” row at:
data.feed.entry[0].gsx$benchid.$t

Here’s how I looped through the results to extract the data:

$.getJSON('https://spreadsheets.google.com/feeds/list/<YOUR-KEY-HERE>/od6/public/values?alt=json', function(data) {

for (var i = 0; i < data.feed.entry.length; i++) {

  var id = data.feed.entry[i].gsx$benchid.$t;
  var photo = data.feed.entry[i].gsx$photourl.$t;
  var caption = data.feed.entry[i].gsx$captionoptional.$t;
  var string = '<img src="' + photo + '"><p>' + caption + '</p>';

  var lat = data.feed.entry[i].gsx$lat.$t;
  var long = data.feed.entry[i].gsx$long.$t;

  createMarker(lat, long);
  createInfoWindow(id, string);

}

};

Now, I just needed a simple function to make the markers and InfoWindows. I put this outside the scope of initialize();.

/* Initialize a blank array to store all the markers
 * that we're going to place on the map
 */
var markers = [];

/* Function takes in a latitude and longitude coordinate
 * and constructs a marker object, then pushes it on
 * the marker array we just created.
 */
function createMarker(lat, long) {

  var lol = new google.maps.LatLng(lat, long);

  var marker = new google.maps.Marker({
    position: lol,
    icon: "overlays/bench-icon.png",
    map: map,
    visible: true
  });

  markers.push(marker);

}

/* Function takes in the Bench ID and caption we constructed
 * in $.getJSON's callback function, then creates an InfoWindow
 * object and displays it on the map.
 */
function createInfoWindow(id, contentString) {

  var infowindow = new google.maps.InfoWindow({
    content: contentString
  });

  google.maps.event.addListener(markers[id], 'click', function() {
    infowindow.open(map,markers[id]);
  });  

}

The Result

The data has been pulled in and the InfoWindows have been populated. Time to party.

The Result