Archive for the ‘Geekery’ Category

Socially Conscious Geek: Makin’ Money While Doin’ Good

Lauren Bacon | Thursday, January 14th, 2010

sxswi2010Two years ago, Emira & I went to South by Southwest (AKA SXSW) for the first time, and presented a panel called “Boss Lady” that featured tips for online business owners from several of the savviest women entrepreneurs we know: Vickie Howell, Jenny Hart & Alex Beauchamp, all of whom appear in the pages of our book, The Boss of You. We had such a good time that we knew we wanted to go back as soon as humanly possible, though last year we were too busy getting our book out the door to attend the conference.

But this year we’re back, this time with a panel that we hope will prove helpful to geeks of both the design and techie varieties – both camps are in full force at SXSW’s Interactive conference, which is a pure, 24/7, all-out geekfest – who are looking to bring their values into their paid work, whether it’s by learning to work with clients in the nonprofit sector, creating apps that help mission-driven organizations work more effectively, or infusing some environmental or social-justice savvy into their workplaces. The panel’s called “Socially Conscious Geek: Makin’ Money While Doin’ Good”, and it takes place Saturday, March 13th.

The topic was inspired by a topic our friend Noah Scalin (of Skull-A-Day and Another Limited Rebellion fame) spoke about at the 2009 HOW Conference. His focus was more on graphic design, since that’s his area of expertise, but when I asked him about riffing on his ideas for an interactive design audience, he shared his materials with me with typical generosity. (This is a guy who lives and breathes a DIY, share-and-share-alike mentality that a lot of designers could learn from. But that’s a topic for another day.)

This time I’ll be attending the conference solo, while Emira spends some time with her new baby; my co-facilitator for the session is Leif Utne, a friend and colleague who works for Zanby, a software company that specializes in supporting online social communities for change. Leif’s background includes a stint as the publisher of Worldchanging.org, and lots of experience building online communities; he’s also a journalist, activist and social entrepreneur.  Zanby is used to support The UpTake, a web video community that among other things was heavily involved in documenting the RNC and DNC prior to the 2008 election, and was also engaged in citizen vote monitoring during the election. He brings both amazing facilitation skills as well as a solid understanding of how businesses and nonprofits can work together in mutually beneficial ways.

We’ll be conducting our session in a highly interactive, inclusive format called a Core Conversation: Leif and I will be kick-starting the discussion and planting some seeds, but the idea is that whoever shows up will have a chance to step forward and contribute questions and ideas – so I’m really excited to see how it develops.

We’re hoping to address questions like:

  • What is a socially conscious geek?
  • How can I specialize in socially conscious work and earn a living wage?
  • What are some of the unique opportunities and challenges of specializing in socially conscious work?
  • What is the difference between non-profit and no-profit clients?
  • How do I make the transition from corporate work to working with non-profit and/or mission-driven clients?
  • What is the “triple bottom line” approach to business?
  • What are some examples of alternative business models that are emerging among socially conscious geeks?
  • How is socially conscious work different than “green” work?
  • What are some examples of clients I might be able to work with as a socially conscious geek?
  • How should I market myself to values-driven clients? Is it different from marketing to corporate clients?

Ultimately, though, the decisions about what we cover will rest with whoever shows up. So please help us spread the word – and if you’ll be at SXSW, we’d love to see you there!

Job Posting closes soon

Lauren Bacon | Tuesday, January 5th, 2010

Vacation’s only just over, but we are hitting the ground running here at Raised Eyebrow, and there are just two days left to apply for our Front-End Developer posting. If you’re passionate about clean code and building fabulous websites, and you’re looking for a position where you can learn from some of the best code artisans in town and work for clients who are making the world a better place, look no further.

We offer a friendly and healthy workplace, a client list that includes national and local nonprofits, mission-driven businesses, and government agencies, and a very competitive salary & benefits package. If you (or someone you know) might be a fit, please check out our posting & send your resume & cover letter in by 5:00 PM on Thursday, January 7th.

Using Drupal to deliver video

Colin Calnan | Tuesday, December 22nd, 2009

There are many ways to skin the cat when it comes to putting video on a Drupal site. I’ve tried and tested quite a few methods since my first introduction to Drupal 2 years ago. I’ve used Embedded Media Field as well as Video Filter but finally settled on the combination of FileField with JWPlayer or Flowplayer and in some cases the Media Mover Module for moving files to Amazon S3 storage. I’m going to use our recent launch of the CCPA website as a case study for how we currently handle video delivery. So let’s dissect this a little.

Uploading files

The video files need to be uploaded before we display them. This is best achieved using the wonderful Filefield Module. This is quite a simple yet powerful module developed/maintained by Lullabot, Nate Haug (quicksketch), whom I’ve had the pleasure of being trained by at one of their excellent Drupal Theming workshops. Once you install and enable the module you then add a new CCK field, of type “filefield”. In our case we have a content type called “Multimedia”. We add the field to this content type. You then need to configure the following:

1. Permitted upload file extensions

In most cases this is relatively straightforward, it’s just one file type. If you’re using JWPlayer or Flowplayer it will be FLV. Both these players are built to play Flash Video files (FLV). If you have Quicktime MOV’s or AVI’s that you want to upload then you’ll need to consider different options for playing video. For the purpose of this case study we’re just uploading FLV files.

2. File size restrictions

It’s very important that you set these, otherwise you may end up with users trying to upload 200MB videos, not a very good idea. I set this low as a learning feature for clients. Any reasonably long FLV file that is over 40MB is probably not optimized as well as it should be.

3. Path Settings

I like to keep all files that admin/editor users upload in a folder called uploads so that it’s easy to manage them later if they need to be exported etc.

File Field

Multimedia File Field Settings

Create a placeholder image

Most video players require some sort of poster/placeholder image to display before the video plays. In this case I created another FileField for the placeholder image. We’ll use that later on in conjunction with the ImageCache module to achieve our desired results.

Moving Files to Amazon S3

We’ve been using Amazon S3 for storing video files on quite a number of sites recently. One reason is that we were looking for a location off the webserver that could deliver the video, without impacting the performance of the server, so that in the event of a traffic spike the webserver wouldn’t fall over. We could also have used Amazon EC2 or another CDN service for this, however as most of our clients have a very regional (BC) audience. Most CDN’s have nodes in various locations across the US and Europe and this would have served no real improvement as the nearest cached version will always be in the same place for everyone.

So if they’re uploading the files directly to the Drupal site, how to the files get delivered from Amazon S3. That’s where the Media Mover module comes in. This module has many purposes, but for our needs it simply harvests all the files uploaded via the “Multimedia” content type and moves those files to Amazon S3 so that we can deliver them from there.

Download, install and enable the Media Mover module. You’ll also need an S3 account and will need to set that up via the module setting page. You then need to add a Configuration via https://www.yoursite.ca/admin/build/media_mover/add.

Media Mover has 4 actions which it performs on your files:

  • Harvest – Define/collect the files you want to perform actions on
  • Process – Perform certain actions on the files
  • Storage – Where to store files once the actions have been carried out
  • Complete – Final actions to perform on the files

So in this case we just want to harvest all Multimedia files and store them on Amazon S3.

So for clarification here Media Mover does NOT MOVE the files to Amazon S3, it simply COPIES them over to S3 and the original files remain on your server.

Media Mover Settings

Media Mover Settings

Delivering the moved Video files

So this is where the Drupal theming trickery comes in. Flowplayer and JWPlayer are both Flash based FLV video players than can be called using Javascript and that’s exactly what I do on this site. In plain english this is what happens:

  1. Output the placeholder image to screen as a link.
  2. Use Javascript so that when the user clicks on the image the video plays.
  3. Deliver the video from the file on Amazon S3 rather than the file on the webserver (Drupal site).

We need to modify three files to achive the above:

  • template.php
  • multimedia.js (a newly created JS file)
  • node-multimedia.tpl.php (a custom template file for all multimedia types)

template.php file

Setting up all the variables we’re going to need to use as well as making the javascript available

if($variables['field_file'][0]['view']) { //If there is a file and there is something to display...
  if ($variables['field_aspect_ratio'][0]['value']) { //Aspect ratio handling
    $variables['aspect_ratio'] = $variables['field_aspect_ratio'][0]['value'];
  } else {
  $variables['aspect_ratio'] = 'normal';
  }
  $variables['multimedia_type'] = 'video'; //Set the type of multimedia - we also have audio and interactive...
  custom_theme_get_media_mover_files($variables['field_file'][0], $variables['media_mover'][3]); //Set the filepath to the media moved filepath...
  drupal_add_js(array('videoplayerpath' => path_to_theme() .'/scripts/plugins/flowplayer/flowplayer-3.1.1.swf'), 'setting'); //Set a JS variable to retrieve later...
  drupal_add_js(path_to_theme() .'/scripts/plugins/flowplayer/example/flowplayer-3.1.1.min.js', 'theme'); //Call the player...
  drupal_add_js(path_to_theme() .'/scripts/multimedia.js', 'theme');//Call the custom JQuery to handle creating the player...
}
 
/**
 * A function that takes a file object and a media_mover element array and set the file path to
 * its media moved path on Amazon S3 or wherever it moved to.
 *
 * It uses the unique file_id identifier to match file with media_mover file.
 *
 * $file = $variables['file_image'][0];
 * $media_mover = $variables['media_mover'][{id of media mover configuration}];
 *
 * @param 		&$file A Drupal file array (by reference)
 * @param 		$media_mover A media_mover file/element array
 */
function custom_theme_get_media_mover_files(&$file, $media_mover) {
  if(module_exists('media_mover_api') && $media_mover) { // If media mover is installed...
    foreach($media_mover as $media) { // Loop through each media_moved file...
      if($media['fid'] == $file['fid']) { // If they match (file id is a unique identifier...
        $file['filepath'] = $media['complete_file']; // Replace the attached file path with the media moved file path...
      }
    }
  }
} // custom_theme_get_media_mover_files()

Let me explain one thing in regards to line 9. I’ve created a custom function and I’m passing

$variables['media_mover'][3]

to my custom function. When you create a Media Mover configuration and map it to a CCK field, it creates an array in $variables to keep track of the Media Mover object. The array is called ‘media_mover’ and the number 3 in this case is the ID of the Media Mover configuration.

node-multimedia.tpl.php

Set up the template. Create a wrapper div with the placeholder image as the background image (this is run through imagecache) and display the play button as a link with the path set to the path of the Amazon S3 file. This link will also have an id attribute of ‘multimedia’. This is necessary as it allows us to attach the player, via Javascript, to this link.

<div id="containing-block">
<div id="video-wrapper" class="<?php print $aspect_ratio;?>">
<div>
     &lt; ?php print l('<img src="/'.path_to_theme().'/images/ccpa-button-play-large.png" alt="Play this video" />', $field_file[0]['filepath'], $options = array('html' => TRUE, 'attributes' => array('id' => 'multimedia', 'class' => $multimedia_type))); ?></div>
</div>
</div>

multimedia.js file

Hook the Flowplayer to the link, with id of ‘multimedia’, that we created in the template.

?View Code JAVASCRIPT
Drupal.behaviors.showMultimedia = function(context) {
  var interactive_path = $('#multimedia').attr('href'); /*Get the path to the video*/
  var interactive_image = $('#multimedia').css('background-image');	/*Get the path to the placeholder image*/
  interactive_image = interactive_image.slice(4,interactive_image.length-1);/*Tidying up the interactive image path*/
 
  if($('#multimedia').hasClass('video')) {/*If the link has a class of video*/
  $('#multimedia').flowplayer( /*Initialize the flowplayer and configure the controls*/
    Drupal.settings.basePath + Drupal.settings.videoplayerpath, /*Path to the player, gotten from temaplate.php*/
    {
      plugins: {
	controls: {
	  stop: true,
	  backgroundColor: '#efefef',
	  backgroundGradient: 'none',
	  borderRadius: '0px',
	  bufferColor: '#d2d6ab',
	  bufferGradient: 'none',
	  buttonColor: '#777777',
	  buttonOverColor: '#99a134',
	  durationColor: '#cccccc',
	  height: 25,
	  opacity: 1.0,
	  progressColor: '#99a134',
	  sliderColor: '#9999999',
	  sliderGradient: 'none',
	  timeBgColor: '#777777',
	  timeColor: '#ffffff',
	  tooltipColor: '#000000',
	  tooltipTextColor: '#ffffff',
	  volumeSliderColor: '#777777',
	  volumeSliderGradient: 'none'
	}
      }
    });
  }
};

I hope that was easy to follow. Now there’s one more thing to cover and that’s Aspect Ratio.

Aspect Ratio

The issue of aspect ratio is very important when figuring out how to display video. Not so recently YouTube switched all video display to the 16:9 ratio thus setting the stage for the proliferation of the widescreen aspect ratio across the web. So how do you allow the user to upload a video and choose it’s aspect ratio. I’m sure there are other ways to do this via Metadata etc, but for our needs on this site I used a CCK field. This is a simple CCK field set with three options:

  1. None (defaults to 4:3)
  2. Normal (4:3)
  3. Widescreen (16:9)
ccpa-aspect-ratio

Aspect Ratio Field Settings

We then check the value of this field in template.php above:

if ($variables['field_aspect_ratio'][0]['value']) { //Aspect ratio handling
    $variables['aspect_ratio'] = $variables['field_aspect_ratio'][0]['value'];
  } else {
  $variables['aspect_ratio'] = 'normal';
  }

and set a variable called ‘aspect_ratio” which we apply as a class to the div wrapping the video in the node-multimedia.tpl.php:

<div id="containing-block">
<div id="video-wrapper" class="<?php print $aspect_ratio;?>">
<div>
     < ?php print l('<img src="/'.path_to_theme().'/images/ccpa-button-play-large.png" alt="Play this video" />', $field_file[0]['filepath'], $options = array('html' => TRUE, 'attributes' => array('id' => 'multimedia', 'class' => $multimedia_type))); ?></div>
</div>
</div>

We have also created image cache presets for the placeholder images to account for both aspect ratios. These are named ‘multimedia_normal’ and ‘multimedia_widescreen’ and these have the appropriate dimensions associated with them:

ccpa-imagecache-presets

Image Cache Presets

So using the amazing article on A List Apart for creating intrinsic ratios for video we use CSS to resize the player based on the aspect ratio chosen by the user.

style.css file

/* -- Multimedia -- */
#containing-block {
  width: 100%;
}
 
#video-wrapper {
  position: relative;
  padding-top: 25px;
  height: 0;
}
 
  #video-wrapper div,
  #video-wrapper embed,
  #video-wrapper object {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
 
  #video-wrapper.normal {
    padding-bottom: 75%;
  }
 
  #video-wrapper.widescreen {
    padding-bottom: 56.25%;
  }
 
  * html #video-wrapper {
    margin-bottom: 45px;
    margin-bot\tom: 0;
  }
 
#video-wrapper #multimedia.audio {
  display:block;
  height:100%;
  margin:1em 0 0 0;
  text-align: center;
  width:100%;
}
 
#video-wrapper #multimedia {
  display:block;
}
 
  #video-wrapper.normal #multimedia img {
    /*margin:118.5px 0 0;*/
    margin:32% 42%;
  }
 
  #video-wrapper.widescreen #multimedia img {
    margin:22% 41%;
  }

And the end result looks something like this http://www.policyalternatives.ca/multimedia/matthew-poverty-and-looking-after-each-other-tough-times. They haven’t added any widescreen content yet, just testing content.

So what are the advantages of doing things this way?

  1. You can easily use any player to play your flash files (all you need to do  is change the path to your player and a few configuration params in multimedia.js)
  2. All your video content is hosted on and delivered from Amazon S3. But there is also a copy on your local server in the event of something going wrong on Amazon S3
  3. You don’t have to worry about your video looking skewed due to aspect ratio problems
  4. You can add many other apsect ratios pretty quickly
  5. The video file is still downloadable when javascript is not present or disabled

I’d love to get feedback on how other do this, please leave a comment or send me an email and let me know how you deliver Video content on your site.

We’re hiring…

Lauren Bacon | Tuesday, December 15th, 2009

We’re expanding our team here at Raised Eyebrow, and this time we’re looking for a Front-End Developer/Themer — someone who loves building websites, and is looking to extend their skills with Drupal and WordPress.

Beyond our roster of fantastic, progressive clients, we offer a positive & healthy work environment, beautifully remodeled heritage office space, and a team of web experts who love what we do and are keen to share knowledge and produce top-notch work.

Intrigued? Know someone who might be a fit? Check out the job description and get in touch.

Ubercart & Content Type machine names

Colin Calnan | Wednesday, November 18th, 2009

If you use Ubercart on your Drupal website you may be familiar with product classes. Ubercart has, by default, a product content type, however say you have other content types on your site that you want to sell, you can create product classes from those – http://www.ubercart.org/docs/user/3341/understanding_product_classes.

This works nicely until that moment when you want to rename your content type machine name.. e.g from “contenttype” to “content_type”

I did that recently thinking everything would be hunky dory once I made the change, the results were not so nice. So to help prevent this from happening to anyone else, here’s a simple rule to follow before making changes to your content type machine name.

Make sure you remove your content type as a product class before changing it’s machine name.

It’s that easy, simply disassociate your content type from Ubercart. The page to do this can be a little scary (www.yoursite.com/admin/store/products/classes), but just click the delete link on the class you want to disassociate and you’ll get a “Are you sure you want to do this message”, go ahead, it won’t delete your nodes, it just removes a flag that tells Ubercart they’re products. Also, if you’re worried about losing your product data, like SKU, Price, Shipping info etc, in my case it retained all product info when I re-instated it. Please backup your data before doing this, I cannot be responsible for any problems this causes on your site. Now, go to your content type, change the machine name.

Oh, and don’t forget to double check all your views are still working, you may need to edit them to ensure they’ve picked up the new content type machine name. I guess this is a good lesson to remind you to give your content types a machine name that you will not want change later.

Generic caching function for Drupal 6

Chris | Wednesday, June 24th, 2009

One of the pieces of the Drupal performance puzzle is caching. After weeding out a couple of very demanding sql queries in a busy Drupal site, we decided to make more use of Drupal’s caching mechanisms to cut down some of the database load.

Back in 2007, Lullabot’s Jeff Eaton wrote a blog post about caching including a sample implementation for a caching function. This function was almost exactly what we wanted, but we wanted something more generic—a function that we could use in multiple places in the same module or template.php file without modification.

But in order to use one function to populate and retrieve different cache entries, we needed a way to call an arbitrary function from inside the caching function. Fortunately, PHP supports variable functions. This meant that we could pass the name and parameters of an arbitrary function to our caching function and, when necessary, populate the cache with the output from that function (alternatively, we could also have used the call_user_func() function or, like Drupal’s own theme() function, the func_get_args() function).

/**
 * This function returns the cached value for a given cache entry. If the entry does not exist, or if
 * the entry is empty, this function executes the passed function, caches the result and returns it.
 *
 * RENAME THIS FUNCTION FOR USE IN YOUR THEME OR MODULE'S NAMESPACE!
 *
 * @param string $cache_entry The full name of the cache entry--remember the namespace!
 * @param array $function An array with two keys:
 *			string $function['name'] The name of the function
 *			string $function['parameters'] A comma-separated list of parameters
 * @param string $table The name of the cache table to use (see cache_set())
 * @param CACHE_PERMANENT|CACHE_TEMPORARY|unix timestamp $expire Expiry period for this cache entry
 * @param boolean $reset If true, regenerate cache entry; if false, check first
 * @return string|array|object $cache_data The contents of the relevant row in the cache table
 * @see http://api.drupal.org/api/function/cache_set/6
 * @see http://api.drupal.org/api/function/cache_get/6
 */
function theme_name_theme_cache($cache_entry, $function, $table = 'cache', $expire = CACHE_PERMANENT, $reset = FALSE) {
  static $cache_data; // Establish the $cache_data variable for this page load...
  if(!isset($cache_data) || $reset) { // If the variable is not set, or if a cache reset has been requested...
  	if(!$reset &amp;&amp; ($cache = cache_get($cache_entry)) &amp;&amp; !empty($cache-&gt;data)) { // If $cache-&gt;data is set and reset not requested...
  		$cache_data = $cache-&gt;data; // Store the current value of $cache-&gt;data...
  	} else { // If we need to (re) generate the cache...
  		$function_name = $function['name']; // Get the function name to call..
  		$function_parameters = $function['parameters']; // Get the parameters for the function...
  		$cache_data = $function_name($function_parameters); // Set cache data to the return value of the function...
  		cache_set($cache_entry, $cache_data, $table, $expire); // Cache the resulting value...
  	}
  }
  return $cache_data; // Return the cached value...
} // theme_name_theme_cache()

In the above code sample, we pass an array ‘$function’ with two keys, ‘name’ and ‘parameters’ to the function. If the cache is not already populated, we determine the cacheable value with the following line:

$cache_data = $function_name($function_parameters);

We might use this function like this (for illustration purposes only!):

$cache_entry = 'theme_name:website_link';
$function = array(
	'name' => 'l',
	'parameters' => '"Drupal Website", "http://www.drupal.org/"'
);
$table = 'cache';
$expire = time() + (360*24*7);
$output = theme_name_theme_cache($cache_entry, $function, $table, $expire);

This would result in $output being set to the output of the call to Drupal’s l() function, and the cache entry ‘theme_name:website_link’ in the ‘cache’ table being set (or updated) to that value, with an expiry time one week in the future.

Of course the use of a function like this—like the use of the cache in general—should be limited to queries or calculations that are very resource intensive. The example above would actually add overhead compared to simply calling l() directly.

Strange permissions on Coda file uploads

Colin Calnan | Wednesday, June 24th, 2009

I’ve been working with Coda now for a few weeks and it’s been going pretty smoothly. There are a few bugs in the software, or they may even be feature requests :) When creating a file locally and subsequently uploading it to the server the file permissions are set to 700. This was causing all sorts of weirdness on a Drupal site that I’m currently theming. This is definitely a bug, however it’s pretty easy to overcome. In “Preferences -> Transfers” there is an option to “Set permissions on upload”. Set this to 644. This is the recommended permission for files in your theme folder in Drupal. You should now have no more problems when uploading files. If you’ve already uploaded files, it’s pretty easy to change via the command line using the chmod command:

chmod 644 filename.php

coda-pref-screen

coda-file-perms

Theming multiple value CCK fields in Views

Colin Calnan | Monday, June 22nd, 2009

I’m working on a site right now that has a Publications content type, which in turn has a multiple value CCK text field for Author. If more than one author was input I needed them to display as a comma separated list in a view. How do you go about modifying this? My first stop was the theming info link in Views, and that helped me narrow it down to a template file to use, views-view-field.tpl.php(). But that file didn’t allow me to modify the individual fields without getting a whole load of other HTML in the bargain.

< ?php
// $Id: views-view-field.tpl.php,v 1.1 2008/05/16 22:22:32 merlinofchaos Exp $
 /**
  * This template is used to print a single field in a view. It is not
  * actually used in default Views, as this is registered as a theme
  * function which has better performance. For single overrides, the
  * template is perfectly okay.
  *
  * Variables available:
  * - $view: The view object
  * - $field: The field handler object that can process the input
  * - $row: The raw SQL result that can be used
  * - $output: The processed output that will normally be used.
  *
  * When fetching output from the $row, this construct should be used:
  * $data = $row->{$field->field_alias}
  *
  * The above will guarantee that you'll always get the correct data,
  * regardless of any changes in the aliasing that might happen if
  * the view is modified.
  */
?>
< ?php print $output; ?>

Using the brilliant “Theme developer” extension of the Devel module I was able to pin point the theme function – theme_content_view_multiple_field that would allow me to modify the actual value of the field without the wrapper div’s etc (I’m not getting into the views divitis argument.

Here’s a quick snippet of code to place in your template.php file of your theme to allow you to modify multiple value fields:

function custom_theme_content_view_multiple_field($items, $field, $values) {
  $output = '';
  switch($field['field_name']) {
    // If this is the author field then we need to comma separate the authors
    case 'field_author':
      $output .= '<div class="field-item">'. implode(', ', $items) .'</div>';
      break;
 
    default:
      foreach ($items as $item) {
        if (!empty($item) || $item == '0') {
	  $output .= '<div class="field-item">'. $item .'</div>';
	}
      }
      break;
  }
  return $output;
}

I used a switch statement because I have a lot of other multiple fields that need to be themed in different ways and it’s nicer than a whole load of if statements. Also switch provides a default state if a condition isn’t met.

Deaths Due to Reading Email while Crossing the Street are on the Rise

Anna | Friday, June 12th, 2009

I’m walking down the stairs, leaving our office at Tides Renewal Centre and I’m behind this other dude in a suit and we are both shuffling along because we are checking our Blackberries while walking downstairs. This strikes me as stupid, but forms the basis of a polite exchange of Crackberry jokes.

Spilling out onto sun drenched Hastings Street, I wonder what will become of us? Like lemmings, we march forward into the centre of a hornets’ nest–the downtown east side on a hot Thursday. How many obstacles will we encounter as we type and walk? I squint and strain to the read the tiny print on my Blackberry’s browser while walking under Woodward’s scaffolding, oblivious to cement being poured above. I stop and open a text message—poised in the middle of an active construction site–to read the message my sweetie has no doubt composed on his iPhone while driving 110 kilometres per hour on the highway.

I flip back to my browser window and type “ban reading email while crossing the street.”

If you want to cross a street in New York City or Buffalo, a New York state senator says, you should be fined $100 if you do so while in a state of “iPod oblivion.” (A Ban on iPods While Crossing)

I’m fascinated by regulations against Darwinian self-elimination.  Helmet laws, seatbelt laws, no talking on cell phone laws—all these regulations enacted to prevent us from doing something stupid.  Or hurting other people while doing stupid things.

Part of me wonders whether these laws are just the result of poor manners?  We’ve developed these technologies and adopted them like beloved children, adored with a sudden fierceness.  We haven’t had much time to establish etiquette for their use.  Our passion interferes with our judgement.  Wouldn’t it be polite if people put their toys away and walked smiling down the street, tipping their hats to each other and marveling about the lovely June weather instead?

An old colleague of mine once took me aside and pleaded,  “It’s imperative that you share your ideas about what is appropriate use of the Blackberry with your co-workers.  We can’t have people checking their emails absentmindedly while we are in meetings.”  Where is our iPhone Miss Manners?  Who will save us from being decapitated while walking down the street or giving all our friends the impression we aren’t interested in what they have to say because we are texting instead of listening?

Sent from my BlackBerry device on the Rogers Wireless Network

trcstairs

Duplicate results in Webform module Analysis display

Colin Calnan | Tuesday, June 9th, 2009

I came across a problem with the Webform module recently that seemed initially puzzling but on closer examination was actually quite simple.

The Problem

When viewing the webform results in the analysis page it appeared that there were duplicate values for some fields:

webform-analysis-duplicates

The Cause

TinyMCE. It seems that the webform and it’s components may have been created when TinyMCE was disabled and then edited at a later date when it was enabled. The visibility settings for TinyMCE were as follows:

node/*
user/*
comment/*
admin/build/block/*

This meant that TinyMCE was being attached to textareas in the webform component editing pages, usually at ‘node/xx/edit/components/x’.

“select” form components in webforms use a textarea to allow you to input the options for the select field. Each option value is input on a new line in the textarea. With TinyMCE enabled the options had a <br /> tag appended to them. Whenever the site editor edited the form component values, and had TinyMCE enabled, the value of the option changed from “College” to “College<br />”. So any further submissions to the form resulted in the submitted data being recorded as “College<br />”

When running analysis on this data, the results showed up as duplicates

College 34
College 215

due to the <br /> being rendered out in the HTML, it really should have read

College<br /> 34
College 215

The Solution

Turn off TinyMCE for all webform component editing pages. I did this via the Visibility setting in TinyMCE module:

node/add/*
node/*/edit
user/*
comment/*
admin/build/block/*

Now it only shows up on editing nodes and add nodes, not editing form components.

Now for the data. The first thing to do was to sort out the webform component. I tried to run a find and replace on the database in the ‘webform_components’ table, but this didn’t work, so I resorted to editing and re-saving each form component individually. Then I moved to cleaning up the submitted data. I ran a simple find and replace query on this to remove the unwanted <br /> tags:

UPDATE `webform_submitted_data` set `data` = replace(`data`,'&lt;br /&gt;','') WHERE `nid` = NODE_ID_HERE;

This says; Update my webform_submitted_data table by replacing all instances of <br /> in the data table, with nothing, and do this for all data submitted for the webform whose nid(Node ID) is the id of the webform with the funky data.

This worked a treat and the values reset themselves nicely:

webform-analysis-duplicates-2

 


t. 604.684.2498 | f. 604.721.4007 | e. turningheads [at] raisedeyebrow.com