July 2010

Jul 30, 2010

This tutorial is sponsored by the Save Joseph campaign. Only 6 more days to save one man from a roomful of teeth. http://savejoseph.org.

I've recently been using the Evernote module to blog, which has made my life surprisingly more rich. After building the module, I started using it right away and found it was the missing piece in creating a workflow that would encourage quality, rapid posting - something I've always wanted to be able to do. Now that its set up, I feel like I can write with virtually no overhead, and using images - kind of tricky when using webforms and wysiwyg - is about as easy as it can get. Even adding annotations is super simple with Skitch (writeup for a workflow with Skitch is imminent).

The ease with which I can create content made me wonder if maybe I could run an entire Drupal site's content off of Evernote. So I gave it a shot when setting up http://josephcowman.com, and it worked like a charm!

What I've done is set up four separate feeds in the Evernote module, three of which correspond to different content types, and a third which imports unpublished blog nodes with instructions for using and administering the site:

The Gallery feed expects notes with a single image. This image is added to an imagefield and is displayed in a gallery fashion on pages like http://josephcowman.com/gallery and http://josephcowman.com/gallery/untitled. The author can put the image anywhere in the post and it will be stripped out using the HTML input filter.

The Blog and Pages feeds, on the other hand, pulls any number of images in and replaces them with local copies of the images, so they would end up looking something like this blog post.

The idea in setting up the site this way is to make management of the content extremely easy. Since Evernote has a desktop application, all the site admin has to do is create or edit a page in Evernote on their computer (even offline), and any changes get pulled into the site on a cron run. So, no log-ins, no working with web forms, it's just working directly with the content without having to deal with the middle man.

I'd love to see more people experimenting with this kind of integration. It makes for a pretty tight workflow. I even take this a little further with my blog (a more detailed article will be forthcoming) by automatically Tweeting and sending my post to Facebook through Evernote as well.

Jul 28, 2010

This tutorial is sponsored by the Save Joseph campaign, a grassroots effort to find a good friend, stellar artist and all around amazing person a satisfying, creative job in the next 8 days. I know the Drupal community could use this kind of talent. Learn more about the effort at savejoseph.org. If you have any ideas on how I can get the word out about this, let me know!

My use case was that I wanted to be able to use social media icons for menu items so that we could re-arrage, add or remove items directly from the menu management interface:. The result is what you see below:

To use images for menu items in Drupal, the first step is to create an override theme function for theme_menu_item_link() in your theme's template.php file. The idea is to first run your image handling bit to switch out text for images, and then hand it over to the parent theme to do the rest. In my case, I'm using the Zen theme.

/**
 * Implements theme_menu_item_link()
 */
function yourtheme_menu_item_link($link) {
  // Allows for images as menu items. Just supply the path to the image as the title
  if (strpos($link['title'], '.png') !== false || strpos($link['title'], '.jpg') !== false || strpos($link['title'], '.gif') !== false) {
    $link['title'] = '<img alt="'. $link['description'] .'" title="'. $link['description'] .'" src="'. url($link['title']) .'" />';
    $link['localized_options']['html'] = TRUE;
  }
  return zen_menu_item_link($link); // Let Zen take over from here.
}

Be sure to change the yourtheme in the function to the name of your theme. Also note that this only checks for .png files. If you want to use a jpeg or a gif, you will need to modify the code slightly.

Next, clear the theme registry (CTFC).

Now, you can use image paths instead of text for the image, as seen below:

Jul 26, 2010

This tutorial is sponsored by the Save Joseph campaign, a grassroots effort to find a good friend and stellar artist a satisfying, creative job in the next 10 days. I know someone in the Drupal community could use this kind of talent. Learn more about the effort at savejoseph.org.

I have 10 days to find my friend a job, and as part of this effort, I wanted to create an image people could use on their web sites that would dynamically change each day. My first thought was that imagecache would be great for this, but there are two issues that make dynamic text in imagecache tricky:

  1. Imagecahce images are... well... cached. Once they're made, they don't get re-made until you flush the cache.
  2. Browsers cache images too, so even if the image was refreshed on the server, the client-side image wouldn't change from one day to the next.

I was able to work around these using a couple of interesting techniques. The end result is something that looks like this:

Before you start, you'll need to download the Imagecache Actions module to add the ability to overlay text on an image.

The first step was to create the background image. I created the image in Photoshop with an empty space where the countdown was supposed to go:

Next, I created a new imagecache preset to overlay text. It's down there at the bottom:

I changed the following settings:

  • Font size: 9
  • X-offset: center
  • Y-offset: top+40
  • HEX: #FFFFFF

And for the text, I checked the Evaluate text as PHP code box, and used the following code:

$interval = strtotime('August 5, 2010') - time();
$interval = ucwords(format_interval($interval, 2) . ' left');
return $interval;

August 5th is my deadline, and what this code does is use the awesome format_interval function to create a string based on a time difference in seconds. I've set the granularity to 2 so that right now it will say 1 Week, 2 Days but in a few days it will say 6 days, 4 hours.

Next, I uploaded the background picture to the theme directory of my site. Then, I used the imagecache theme function to load up the image with the overlay:

theme('imagecache', 'save_joseph_box', path_to_theme() . '/images/save-joseph.png');

Then, I put this in a page preprocessing function in template.php and assigned it to a variable that I could use in my theme. This is really temporary code so that I can copy the output, so it could have gone anywhere.

function jc_preprocess_page(&$vars, $node) {
  $vars['save_joseph'] = theme('imagecache', 'save_joseph_box', path_to_theme() . '/images/save-joseph.png';
}

Then, I just added a print statement in my page.tpl.php page so I could see the image. Embedding this in the page template temporarily allowed me to play with the imagecache settings until I got the font size and positioning right while seeing a preview:

  <?php print $save_joseph; ?>

Okay, now we have a functioning text overlay that at least is current as of this moment. But, tomorrow, the image will be out of date. So, we need to flush this imagechange to get a re-rendering of the image whenever the text changes. Here's the strategy I used:

  1. Set up a hook_cron function
  2. In the function, use the same code above to create a textual output of the date.
  3. Load a variable that has the last textual output saved (the first time, this will be blank)
  4. Check if the new time and the previous time are different
  5. If so, clear the iimagecache
  6. Save the new text string to the variable we used before

And here's the code to do it:

function common_misc_cron() {
  $interval = strtotime('August 5, 2010') - time();
  $interval = ucwords(format_interval($interval, 2) . ' left');
  $last_time = variable_get('jc_save_time', 0);
  if ($interval != $last_time) {
    imagecache_preset_flush(array('presetid' => 'save_joseph_box'));
    variable_set('jc_save_time', $interval);
  }
}

Now we'll have an up-to-date image all the time. Except that browsers will cache images for a while, so we need a way to make the browser think it's a unique image every time to pull it fresh from the server. The way we do this is by adding a dynamic query string to the end of the image URL that will change randomly on every page load.

My goal was to make it really easy to put this image on a web page, so I needed a way to bundle this dynamic-ness with the image. So, using PHP to generate this string was out of the question. The way do to it was to use JavaScript to add the query string to the src of the image tag:

<script type="text/javascript">document.getElementById("save_joseph").src = 
document.getElementById("save_joseph").src + "?unique=" + new Date().valueOf();</script>

For folks that can't use JavaScript (in Facebook and MySpace, for example), I also provided an image that just had the end date on it, so it could be static. Not as cool, but at least functional:

Finally, I added the script with the HTML image output, copied it, and put in in a blog entry so that people could copy and paste the code to use on their sites.

Jul 26, 2010

Galleries and potential employers

You can contact Joseph directly through his contact form, or contact me through mine.

The story

In 10 days, an amazingly talented artist and friend, Joseph Cowman, will be forced to choose between a full time position building false teeth factory-style for the financial security it will bring has family OR possibly lose his current part-time position, straining his family but opening up the possibility of spending more time on creative work.

I think there's a third choice, but it will require a grassroots effort to make happen. I'm certain that there are positions available out there that will allow someone as skilled as Joseph to practice art and be creative but still earn a good livelihood. So, I'm tapping into my network and cashing in favors to see if I can find Joseph a job where he can really flex his skills.

If you want to learn a bit more about Joseph, keep reading. Or, you could jump straight to how you can help. This a grassroots effort, and there's something YOU can do!

Links

A few examples of Joseph Cowman's work

A referral

Joseph is probably the most capable person I know, and I think the only two reasons he hasn't landed a fulfilling position is that 1) he lives in a small town, which makes networking in the art world difficult and time-consuming and 2) between work, family, and practicing his art, doesn't have much time to get his work out there. For years I (and most people who know Joseph) have felt like there's this huge talent going to waste, like the world is just a little lamer because Joseph is building teeth instead of really pushing the boundaries of what he can do.

Anyone who has ever hired Joseph has loved working with him, and from knowing him on a personal level, I can understand why. In addition to being able to pick up anything, figure it out and then push it beyond what most people would, he's incredibly patient and empathetic, making him sensitive to other people and what they need. It's an interesting combination, one I don't run across very often.

The dream job

After talking with Joseph for a bit to figure out what kind of position he's looking for, he said anything that would be artistically challenging that has good variation. He said doing character work or design for games would be perfect, and he's also capable of working in a variety of styles. The bottom line is that he wants to leverage his work time to help hone his craft and improve his skills as an artist. Challenge and variety are key.

Joseph has been building false teeth for the last 7 years, and I anticipate him really exploding into whatever work that he takes on next. If it's artistic, he's going to do a fantastic job because he'll be so enthusiastic about it.

How YOU can help

Here's what you can do to help:

  1. Follow the campaign on Twitter
  2. If you know of any job opportunities along these lines, send them to me or directly to Joseph through his web site.
  3. Pass this story on to anyone you know who might be able to help with this effort. Anyone in any art-related industry, artists, empathetic people, sneezers, anyone. This is grassroots, and every root counts.
  4. Tweet about the campaign, and re-tweet!
  5. Give us any ideas you have on how we can improve the campaign, techniques we can use, tactics we can exploit
  6. Add the image countdown code to pull in the countdown box you see below to your web site, MySpace or Facebook page.
  7. Add comments to this post about interesting things that you know Joseph has done, any praise, whatever. If you take a look at his art and like it, mention it.
  8. Refer us to any artists you know who might have ideas on how to break into the biz
  9. Add a small amount to the Save Joseph Bounty that will be be awarded to the individual that provides the lead that lands Joseph a job

The Save Joseph countdown box 

To add the countdown image below to your web site, use the following code:

<a href="http://savejoseph.org"><img id="save_joseph" title="" alt="" src="http://josephcowman.impliedbydesign.com/sites/josephcowman.impliedbydesign.com/files/imagecache/save_joseph_box/sites/josephcowman.impliedbydesign.com/themes/jc/images/save-joseph.png"></a>

<script type="text/javascript">document.getElementById("save_joseph").src = document.getElementById("save_joseph").src + "?unique=" + new Date().valueOf();</script>

Note that even though the image will work in sites like Facebook and MySpace, the little script that's added to it which refreshes the image regularly to reflect the countdown change won't work. In those cases, you can use the static image which doesn't use a countdown:

<a href="http://savejoseph.org"><img id="save_joseph" title="" alt="" src="http://josephcowman.impliedbydesign.com/sites/josephcowman.impliedbydesign.com/themes/jc/images/save-joseph-static.png"></a>

Some of the interesting things Joseph has done outside of fine art.

Joseph has focused a lot on his artwork the last several years, but his creative prowess extends in a lot of other directions. He's the kind of guy I am always telling other people about because the interesting things he's done. I'd like to get these a lot more coverage, and I'll add pictures as I get them, but here are just a few of the ones that have impressed me the most:

  • When I met Joseph, he was 17. One of the first things he did was show me a fully functioning robotic arm he had built entirely out of scrap wood, hypodermic needles and IV tubing. No metal, no batteries, the whole thing ran off of the hydraulic pressure between two needs hooked up with the tubing. It was one of the coolest things I had ever seen.
  • The next thing he showed me was a robotic hand, complete with 3 fingers and an opposable thumb, that connected to a glove you could put on your own hand to move the robot hand. It used bike cables as tendons. It was made out of a box of old random parts that his family had laying around. Also one of the coolest things I've seen.
  • Then, he showed me a graphics program he had programmed on his computer in order to create graphics for a video game he wanted to make. It was more functional than any of the graphics-oritented programs I had on my computer.
  • He built a series of didgeridoos out of driftwood with awesome artwork around it. He had to use a drill to hollow out the entire thing, using old tools. They're the prettiest didges I've ever seen.
  • Back in the day when cool looking Oakley sunglasses were beyond his ability to purchase, he and a friend made their own pairs from thick aluminum sheet metal and cut their own lenses. At the time, they were really impressive.
  • Every Halloween Joseph puts together a stellar costume. Stuff that could win prizes. Last year he built a realistic ogre head out of cardboard and vinyl. The year before, he built a costume that made him look like he was riding a dinosaur. It was really effective.
  • Joseph and his wife completely renovated their entire home. When you walk through the house you can see the creative touch, and it looks beautiful.

Art inspired by the Save Joseph campaign

Save Joseph 

by TheFinalHikari

A man of great talent
Creativity abound
The kind heart of a father
The spirit of a dear friend
The mind and skill of an artist
Seeking new opportunity

Dreams and aspirations
Decorate every canvas of life

Skillful and trained hands
An eye for perfection

Please do not depart
Before you have seen it all
For every picture tells a story
A flowing rhapsody of inspiration
Communicating wordlessly
Feelings from you to me
Captured in the eternal beauty of art

Every single helping hand
Is welcomed to reach out

The choice is now yours
The request is simple
He needs your help, whatever you can do
Help him build a new future
To enrich the world with art

Within every masterful piece of art
There is a world to witness
They say a picture is worth one thousand words
But his art is clearly worth so much more

The choice is left to you
And until then,
Everyday
We shall pray
“Save Joseph…”

Jul 24, 2010

It's my 6th day outsourcing, and I've assigned a few tasks and gotten responses. Here's a summary of the results:

Task 1: "Spend 30 minutes to an hour brainstorming any other ideas for increasing the number of readers to my blog"

This task was a good one because it brings up a good question: Is it worth outsourcing question that you can find decent answers for with a quick Google search

After 2 days, I was sent a report that includes 26 ideas with headings and short paragraphs. No sources were sited, so I did a search on a few sentences from the report to see if I could find them. The result was a compilation of 2 articles that show up near the top of Google for a search for Ways to increase blog readership. I actually ended up liking the article at the top a little better, an article not referenced in the report.

To complete this same task myself took me a couple minutes, and I found results that were better suited to where I am.

Would it have been worth it to clarify the task, and give some background about who I am, about what I know already? What would I say? What bits of knowledge that would give someone else the ability to predict what kind of information I would have appreciated for this particular task? I'm not sure I know. My guess is that attempting to articulate it would have taken longer than completing the task myself.

Task 2: Trip ideas to Canada

My wife and I want to hone our Canadian accents but we don't really know Canada, and my wife's extensive searches online weren't turning up any compelling results. I decided that maybe having someone else narrow down some choices could help. So, I sent this to my VA:

I need to plan a trip with my wife in mid-August, leaving a Friday morning and returning a Monday evening. We would like to go somewhere in Canada, but have a limited budget. We'd like to find a few options of places that aren't too expensive to travel to, but that are nice, ideally on the coast. Can you come up with 4 or 5 ideas for places that meet this criteria with the least expensive cost of a plane trip from Boise, Idaho? When you send me details, please send links to the airfairs online as well as any information you gathered about the locations.

I got a report back 12 hours later (not bad) with a list of 7 different places in Canada, with screenshots of possible Orbitz flight itineraries for each one. Tickets were understandably a little high (up to $600 per person), but what got me was that several of the destinations were 400km from the nearest airport. How can this person be so disconnected from the task that they don't recognize that two 8 hour plane trips plus two 8 hour drives aren't practical for a 4 day vacation?

Was my fault that I was not specific enough? Or that I haven't established enough of a relationship yet with these folks to have them care enough about the tasks that they apply a certain level of reasoning to them?

Or, is an 8 year old kid in some VA sweatshop performing these tasks?

Now, this company got great reviews on Elance, with lots of feedback, so I know that they're capable of good stuff. It's just a matter of figuring out how to get that good stuff.

The state-side VA

I hired a state-side VA, but she is on a family vacation until Friday. It makes me realize that if I become dependent on a VA, I would need backup if I went with a single person.

Summary of emotional state

So far, this hasn't been a superb experience, but I also know that I'm still learning the ropes. I recognize that part of this might be that I just am not coming up with the right kind of task. But, they're tasks that were intended to build my confidence in the process so that I could leap in with more important stuff.

Another issue is that I wonder if my current life structure is possibly not suited for outsourcing. I've simplified what I do down to a handful of areas that are all things that I want to be doing. What I do for work I want to do myself. At home, the only things I would want to outsource are the dishes, laundry and mowing, all tricky tasks for a VA. Research seems like the only thing that comes to mind, and so far it looks like Google will give me better, more varied answers. I have a finely tuned set of tools for managing information and reminders, so I don't need someone to keep me abreast of what's coming down the pikes.

Now that I'm looking at it from this angle, my life is actually really simple. Almost anything that's on my list of things to do are things that I actually want to do because of the experience. That, or it's home repair and maintenance. If I was running a multi-person company, if I was doing extensive research on some subject, if I had a flood of e-mails to deal with, I could see the value of a VA. But what can I outsource right now and get a positive net gain?

One thought is that by knowing I have a VA waiting in the wings, maybe I will be more willing to take on things that would normally add complexity to my life, things that would be perfect for a VA.

I'm going to hang in there for a while and give myself time to really internalize the idea of relying on a VA. If the tasks are little banal, I think that's okay because I'm practicing and the hope is that eventually I would learn how to offload more significant tasks.

Jul 23, 2010

Up until a month ago, I hadn't had very good experiences managing commenting on Drupal blogs. Even with the hoops that commenters had to go through to write a post (i.e. long and frustratingly ambiguous captchas), tons of spam still got though, and the whole administration process was rather unwieldy. The e-mail notification modules available at the time were a little too in-depth, sending e-mails on new comments as well as new or updated nodes. Also, because of the spam, I'd set comments to only be published on approval, adding additional lag time to the discussion. It was a poor experience, and even I loathed posting comments on my own blog!

In setting up a blog for my Drupal training companyBlue How-To (currently a coming soon page), I decided to get things right. The installation was also going to be core to a multi-site that would include several other sites as well, so I'd be able to leverage the techniques across multiple sites. 

What I wanted in particular was:

I scanned through the Drupal modules matching the phrase comments and found a few gems, did the same in Google, and got started.

The modules you'll need

Spam
Comment Notify
Rules
Ajax Comments
Comments Bonus API (dependency for Ajax Comments)

Dealing with comment spam

The first step was figuring out how to deal with spam. I was using image captchas from the Captcha module. I had given Mollom a try on other sites, and while it will be my fall back if I end up needing captcah, I've gotten a lot of false positives in the mode where they show a captcha only if your content looks spammy (particularly on groups.drupal.org).

In my searching, I came a across a couple of easy-to-apply techniques using hook_form_alter(). The first is to add a text input that is hidden via CSS on forms so your users don't see it, but any bots will. Using a validation function, you check to see if the input is filled out, and if it is you throw an error and don't submit the form. I was familiar with this technique from way back and even used it in my first custom-made CMS, but it had slipped through the mental cracks.

Here's the code I use for this, which is slightly modified from the original. I was having issues on node forms, so I set it to not display there. I would also suggest changing the name of the input so as to not make this too predictable:

$form['#validate'][] = 'common_misc_honeytrap_check';    
if (strpos($form_id, 'node_form') === false) {
  $form['comment_body_two'] = array(
    '#type' => 'textfield',
    '#weight' => 0,
    '#required' => false,
    '#default_value' => '',
    '#attributes' => array('class' => 'honeypot'),
  );
}

We need to add a validation function to do the final check, and here it is:

function common_misc_honeytrap_check(&$form, &$form_state) {
  if (!empty($form_state['values']['comment_body_two'] ) ) {
    watchdog('notice', 'SPAM attempt at '
.$form['form_id']['#value'].' form', NULL, WATCHDOG_NOTICE);
    form_set_error('comment_body_2', 'Oops, you probably didn\'t mean to do that');
  }
}

So, if there's anything in this particular input, it will trigger the error.

The second thing we can do is set a timer on the form. Using this technique, we will add a hidden input with the current time to the form, and in a validation function make sure that it has taken the user more than a few seconds to fill out the form and throw an error if the submission un-humanly quick:

if ($form_id == 'comment_form') {
  $form['timegate'] = array(
    '#type' => 'value',
    '#title' => 'Timegate',
    '#weight' => 5,
    '#required' => false,
    '#default_value' => time(),
  );
}

I added the validation to the validation function above. Note I've set this to 10 seconds, but you can set it lower or higher.

if (time() < ($form_state['values']['timegate'] + 10 ) ) {
  form_set_error('comment_body_two', 'We KNOW you can\'t be THAT fast.');
}

Because I personally submit some forms faster than 10 seconds, I wrapped a check for an administrator role around both validations so that I wouldn't trigger the errors.

Setting up the spam module

These two techniques seem to work really well to stop automated spam. For spam that is produced by spam sweatshop laborers, I installed the Spam module. I enabled all of the included modules, but after a problem with one post triggering the Bayesian filter by beginning with the word "Thanks", I turned that one off. In the Custom filter, I added a regular expression so that I can add spammy words to as I discover them. Notice the <code>\b</code> around a word that could legitimately be part of some other word:

(bad_word|another_bad_word|\bword_that_could_be_in_some_other_word_but_is_still_bad\b)

So far, I've just had a couple of spam comments that could have been caught with the custom filter. It's a huge improvement, and there's no captcha to get in the way for real users.

Integrating simple notifications 

In a previous iteration of this blog, I used the watcher module, which had some nice features. I did some heavy CSS styling on it to match up the look, but I always kind of felt like there might be a better way.

I started by installing the Notifications module and attempting to chisel down it's many features to particular one I was looking for, which was customizable comment notifications. Ultimately I got the feeling that there had to be something more suited to this particular need. 

I finally landed on the Comment Notify module, which is what I'm using now to provide the nice "Notify me when comments are posted" feature:

The default e-mail that goes out for notifications is pretty heavy, so I trimmed the text a bit. You can find this setting at /admin/settings/comment_notify:

Hi !name,

!commname has commented on: "!node_title"

You can view the comment here: !comment_url

Below is the text of the comment:
!commtext

You can stop receiving emails when someone replies to this post,
by going to !link1

You can set up auto-following feature for all future posts
by creating your own user with a few clicks here !uri/user/register

Thanks!
Chris

So far, I've had a lot more repeat participation on my blog.

A special e-mail notice to administrators with some additional information 

Comment Notify is good, but it would require an administrator to manually sign up for each post. In addition, spam that got added but not published wouldn't send out any notification. As an administrator, I also wanted more information about the user that posted the comment, so I used the Rules module to set up an e-mail that got sent out whenever a comment was created.

In the first step, I set up my rule to be triggered when a new comment was saved:

Next, I set up a condition to check that the user doesn't have the administrator role, to make sure I don't get alerts for my own comments. Then, I added an action to send an e-mail to an arbitrary address:

Below is the text of the e-mail I'm sending out to myself:

Node title: <?php echo $node->title;?>


URL to comment: <?php echo url( 'node/'. $node->nid, array('fragment' => 'comment-'. 
   $comment->cid, 'absolute' => true));?>


User info: <?php echo $comment->name . '  '. $comment->mail . '  '. $comment->homepage;?>


<?php echo $comment->comment; ?>

Improving the usability of comments 

The main tool I found for really making the commenting process a more pleasant experience was the AJAX Comments module. With it, you get a ton of really nice ajax-y features:

  • When a user posts a comment, it loads it into the body via AJAX
  • You can administer comments via AJAX (to change the author, mark it as spam, etc)
  • Delete a comment via AJAX, with a key combination that will allow you to bypass the javascript approval dialog if you need to delete a bunch of comments.

It's really nice, and makes commenting and administering comments very fast. Working with comments is actually a pleasure now instead of a chore due chiefly to this module.

There's a couple of caveats, though:

  • AJAX Comments doesn't integrate well with Captcha or Mollum. The initial Captcha will show, but after that, no dice.
  • The comment Preview feature doesn't work
  • If the comment triggers the spam module, the user will get a not-so-helpful error dialog box instead of a useful inline error.
Jul 21, 2010

I finally got a chance to install the Managing News Drupal distribution the other day, and it's pretty slick. The idea behind it is to aggregate news feeds and allow multiple users to collaborate on organizing, commenting and sharing the items with others. After hearing what some people are doing with it, it made me really excited to use it on my own projects.

Below is a walkthrough of installing and working through the default features of Managing News, documented as I went through the process myself.

Installing Managing News

Download the distribution from http://managingnews.com/.

As with any Drupal installation, you'll need to:

  • Create a database
  • Have a domain or folder in a domain to work with
  • Copy the default.settings.php file in /sites/default to a new file called settings.php

Once you're ready to install, go to the folder and select "Managing News" installation profile and click "Save and Continue"

Fill out the database information, click next.

Fill out the user account information, click next.

You should now see the main Managing News screen:

Adding feeds

It sounds like the first think I need is a Feed, so I click on the Feeds button and type my blog's RSS feed into the Feed URL field and click "Preview." This is what I get:

Okay, looks like the preview features doesn't work, so I click Save.

Looks like it imported, here's what I see now:

Sharing

Now it's time to explore some of the features. I'm going to take a look at the Share feature.

Nice, I can share via Twitter, Facebook, MySpace or E-mail. My first thought is that there should be an Evernote link here, too, since I use that as a funnel to the other channels.

When I click the Twitter link, it takes me directly to Twitter, where I have to log in. After I'm logged in, I click the Twitter link again, and Managing News pre-populates my status box, including a shortened URL, nice!

When I click on the Facebook link, it gives me the option of posting a "share" on Facebook, with a couple other options, including connecting up a status update or sending the share as an e-mail. I'm not familiar with the Share feature, so I had to look up. Here's a bit about the Share feature for Facebook developers. Here's what the screen looks like:

When I click on the E-mail link, it populates an e-mail, complete with shortened url, like so:

Okay, this is nice and very straightforward.

When I click the Trash button, the item collapses in a nice, ajax-y fashion.

Editing tags for the posts is nice, too:

  • Click the edit button
  • Start typing tags, separated with commas
  • When you press Enter or click away from the tags, it will save the tags and make them clickable links, which will then direct you to a listing of all items that match that tag.

Getting a map error?

There was an error in the map rendering on the home page which made me want the mapping features even more:

So I added Development Seed's rss feed, figuring that if anyone had geolocation data in their feed it would be them. And sure enough, here's what the map looked like afterwards: 

That's sweet.

Viewing options

Up near the top of the page are some different viewing options, so I thought I should explore those:

When I click on the map, I get a larger rendering of the same map I saw above:

It took me a minute to figure out what the difference was between the News and List view (you can hover over the icons to see what they are), but I think it's just that the List view doesn't have snippets, only titles, so the output is a bit more concise.

Embedding Managing News Widgets

I got pretty excited when I saw the Embed link in the lower right hand corner of the page. When you click that, you get a preview of the widget plus embed code that you can then copy and paste into a web page. You can embed a preview map by going to the map view and clicking Embed, or a list view by going to News or List and clicking Embed. Here's what it looks like when you click on the Embed ink in the News view.

I tested it out by creating a dummy, pure HTML page and pasting the code in. It works! Here's what the Map preview looks like on an HTML page with nothing else on it:

So, this could be a very cool way to let other people share your aggregations.

Map layers

In the upper-right corner of the Map view, there's a cute little button that looks like a stack of papers. If you click that, you'll get some options on what layers you'd like to see on the map:

The OSM Maplink layer shows country names, and when you zoom in you can see roads and other borders as well:

In the lower right-hand corner, next to the embed options, is an account link. If you click that, you'll see some settings for your account:

Searching and saving searches

The Search view leverages Drupal's search infrastructure to search, so the first time you go to the search page, you probably won't be able to see much. Drupal's search compiles the index on cron runs, so eventually you'd want to set up cron to run on your site. However, you should be able to update the index manually by clicking the Update now link in the search index box:

I clicked the button twice and got the follow error, but that's because only one instance of cron can run at a time:

When I do a search for Great, I see a couple nice things. First, the instances of the text are highlighted, and second there is a Save this search button:

Clicking the button adds the search to the side Saved searches box:

Creating a channel

Okay, on to Channels. When I click the Channels link, here's what I get:

I click on the Example channel item, and it gives me some instructions:

I click edit, and add the test tag to the channel, which I've already added to a couple of articles. I run into a funny little visual error, where the submit buttons are hidden, but if I keep scrolling down they re-appear:

When I've submitted the form, I get a listing that renders pretty much the same as the Search or News listing, but contains matches for the tags I've set.

Between the Search and Channel features, I felt like there was some common ground. If you could do a search based on 1) keywords, 2) tags and 3) specific feeds, the channels would be the saved searches.

Subscribing to RSS feeds

Managing News generates RSS feeds for any News, Tags, Search or Channels. Just navigate to the page you'd want to subscribe to and click the RSS Feed button:

Printing

Clicking the Print button above lets you print a nicely formatted list of feeds so you can read them later on:

This looks pretty slick, but would be more practical to me if could print out the entire body of the post.

Help

Clicking the ? icon in the upper right-hand corner of the screen will give you contextual help. If you click it on the home page, you'll get something like:

The is some basic help for all of the main tabs above, but none for saved searches or tags.

Additional notes

Nice input descriptions

I really like the conditional display of help text for inputs. It keeps the clutter way down. Here's an example:

The help text only shows when you are filling out or hovering over an input. Nice! I'd like to know if there's a module for that, or if it's theme based.

Modules used

To find the modules used by Managing News, you can go to /profiles/managingnews/. There are three folders there, and here are the contents of each:

contrib:

custom:

features:

Jul 20, 2010

Note: If you want to really bend this block to your will, you might need to learn some module building skills. Check out Build a Module.com for clean video tutorials on modifying the output of a page, theming and lots more.


Instructions

Download and install the Taxonomy Menu module.

Download and install the Menu Block module.

Optionally create a new parent menu where all the taxonomy-based menus will reside by going to /admin/build/menu/add. I named mine Taxonomy.

Go to /admin/content/taxonomy and click the edit vocabulary link next to your tag vocabulary

Scroll down to the Taxonomy menu fieldset

Select your new menu for the Menu Location

I use the following options:

Most of the other options are there so that you can customize the paths to the taxonomy terms if you use Views, for example.

Click Save.

Go to the block administration page at /admin/build/block and click the Add menu block tab.

Start working your way down the form. Here's what I used for the Parent item settings:

I changed the custom visibility settings:

Then click the Save block button.

You'll see the menu in the disabled section of the page, and it will look something like this:

Set where you want the block to display, and then you've got your block! Here's what mine looks like:


If you want to really bend this block to your will, you might need to learn some module building skills. Check out Build a Module.com for clean video tutorials on modifying the output of a page, theming and lots more.

Jul 19, 2010

Today I assigned a couple of tasks to my new VA team in India, and heard back from the state-side VA. I'm kind of excited to see the results of this first assignment, a little apprehensive about what happens if the results feel like they're not worth it.

One thing I'm realizing is that passing a task onto a VA requires a tight coupling to feel effective. For one, before I assign the task, I need to be committed to it. Then, when it comes back I need to be committed to doing something with the results. If I let the distance between me and the task drive in a bit of apathy about the result and I lose enthusiasm for acting on it once the task is complete, then it will have been a waste of money and somebody's time.

An associate read my initial post on outsourcing, and had some interesting thoughts to share:

"My biggest hurdles in outsourcing is finding the right person to work with and defining the tasks that I would feel comfortable having someone else take care of.  Those tasks often reveal themselves through experience.  Like you, I'm a do-it-yourselfer and usually try things once.  I remodeled our bathroom and realized the savings in money wasn't worth the cost in time and happiness.  So when it came time to finish our basement, I outsourced it to a proper contractor and found it was well worth it.  Same goes with taxes and hiring a CPA.  On the reverse side, I enjoy sending emails to my wife far too much to delegate that to a PA in India.

One area I would love to outsource, would be the initial base installation of Drupal, hosting environment, repository setup and post-launch client support of sites.  Any thoughts on that?  Have you used any services or tools that would help with this?"

It sounds like we've had some of the same experiences. I also remodeled our bathroom and have had the sense that it's not something I want to do twice. I've also been very happy with hiring a CPA to outsource the particular method of emotional torture that is the most memorable result of filling out complex tax forms. I did like the idea of using a VA / PA for sending personal e-mail on occasion for the novelty factor, but it probably would be supplementary rather than a replacement.

In regards to outsourcing the base installation of Drupal, probably the best service I've seen for this is WebEnabled. At WE, you can spin up an instance of various versions and distributions of Drupal, and save your site at any point to use as your own personal distribution later. One issue with this is that you still need to keep modules and Drupal core updated. One additional plus is that WebEnabled has built-in SVN support, and when you spin up a new instance, it pulls it into a new repository automatically.

The other solution is to automate as much of the process as you can yourself, and come up with a good, repeatable workflow. One method is using a multi-site so it's much easier to maintain core and module updates across multiple sites. I know some folks have had success using Aegir to deploy new sites, but I haven't had the chance to play with that yet. Using a combination of install profiles and Features can reduce the amount of work in the initial setup as well.

As far as post-launch support goes, I don't have much experience with outsourcing this. Finding good, skilled service providers seems tricky, and often a matter of working through multiple providers until you find one that is a good fit. When I hear of people having good success with outsourcing skilled web development work, it's for simpler cookie-cutter sites. I personally didn't have a lot of success with it, but I also didn't try for very long.

Jul 19, 2010

My use case was that I had a super long blog entry that I didn't want to hog my blog's front page. So I needed to shorten it down to a certain pixel height, and add a link that would expand it completely.

First, we need a couple of jQuery bits:

  // Go through each item in the main blog page and shorten if bigger than 1500px
  $('.view-blog .views-row').each(function (i) {
    var div_height = $(this).height();
    if (div_height > 1500) {
      $(this).height(1500);
      $(this).append('<input type="hidden" class="item-height" value="' + div_height + '" />');
      var id = 'expando-num-' + i;
      $(this).attr('id', id);
      $(this).after('<a href="' + id + '" class="expando-div">This is a long blog post, click here to view the rest</a>');
    }
  });
  
  // Add the 'click to expand' behavior to the links
  $('.expando-div').click(function () {
    $(this).remove();
    var $div = $('#' + $(this).attr('href'));
    var div_height = $div.find('.item-height').val();
    $div.animate({height:div_height}, 1000);
    return false;
  });

I added this code inside of a function called Drupal.behaviors.custom_misc()Click here to read a bit more about Drupal behaviors.

Note that your selectors might be different. I'm using a Drupal view to display the blog, so I can rely on certain selectors.

Next, we need to add a couple of styles to our CSS (or LESS) file:

.view-blog .views-row {
  overflow:hidden;
}
.expando-div {
  display:block;
  margin-bottom:30px;
  background:#185686;
  color:white;
  text-decoration:none;
  padding:5px;
}

The only really necessary part there is the overflow:hidden, which makes it so the hidden content doesn't overlap on other stuff.

My result (with a little more CSS styling) looks like this:

Jul 19, 2010

Not too much happened today physically in moving towards outsourcing, but since it was on the mind, I had some small epiphanies and thoughts that may be worthy of sharing.

On the logistical front, I awarded my virtual assistant job on Elance to two providers, a company in India who can provide a team of folks for $5 / hr and an individual in the states fo r $8 / hr. The India-based team got back to me later in the day, but I haven't heard back from the state-side one yet.

I think taking physical steps towards trying something like this is probably the way to get into the right mindset. Just like I mentioned in Day 1, it seems like actually getting your hands dirty with a task is the way to pull your mind into it.

Here are some outsourcing thoughts I had today:

My original plan was to have the two virtual assistants complete the same tasks so I could measure them against each other. However, a lesson came to mind which I learned playing Mastermind one day with my father-in-law. My idea was to apply an algorithm to the challenge - doing all yellow pegs, then purple, then pink, and identifying without a doubt what colors were on the board. What my father-in-law suggested was that every move should be a possible solution based on what you know. So, if you try all yellows and you find out that one of pegs is yellow, all of your guesses from that point forward should have a yellow peg. The lesson being that every step you make should move you forward as much as possible. My guess is that I can move forward faster by having the two VAs do different things, even if I sacrifice the ability to isolate variables and have a more scientific experiment.

Often, what takes the longest amount of time when accomplishing a task is the exploration around the task, getting sidetracked and exploring other things. Sometimes this is good, but sometimes it distracts us from what's the most important to us. By outsourcing, we end up telling someone to take the shortest route to accomplishing the task, which might be way more efficient than the way we'd go about it.

One thing that makes outsourcing a hard concept for me is that I've tried to simply my life as much as possible. Part of this appeals to my sense of minimalism and portability. If the s**t hits the fan and we all have to fend for ourselves in some world of post-apocolyptic chaos, I want to know I can handle my life. I want my needs to be simple. But, what I might not realize is that the skills you develop in being able to guide people, in being creative enough to distribute meaningful tasks to others, might also prove a very useful skill in that kind of situation.

Sometimes the most important things you learn when doing your own research are not associated at all with what you're researching. You'll miss out on these things if you outsource them. I wonder you can find the right people that will also share stuff that they learned along the way.

Having a VA is like having a nanny of the mind. You can use them to augment your time in a good way, or take over responsibilities that you really shouldn't be delegating. I think that this is a bit of a fear for me, that I may end up outsourcing things that would actually help me grow into a more interesting person.

Jul 17, 2010

I received a comment on one of my posts which reminded me about one of the concepts in The 4 Hour Workweek that I didn't really internalize: the idea of outsourcing. Tim Ferris talks about this in Chapter 8, offering some anecdotes and suggestions on tasks that might be good candidates for outsourcing.

Overcoming fear

I've had a sense for a while that I land in the DIY camp more often than the Outsourcing one. The assumption that these two camps as mutually exclusive says a lot to me now that I'm re-evaluating my outlook. 

The feedback I get from the work I do is important. When I actually fulfill a task myself, I get a sense of how difficult the task was, get thoughts on how to improve my workflow, and with experience start to develop patterns that have the potential of making almost anything I do enjoyable. If I delegate a task to someone else, I have a sense that I'm robbing myself of this experience and the skills that come with it. What I'm learning instead is how to manage other people, and this doesn't interest me nearly as much as learning more about managing myself.

I also have a feeling that one of the most difficult and time-consuming parts of many tasks is identifying if the task is actually important enough to be done at all. So often I start building something and only after plugging in a sizable chunk time figure out that it's not necessary. But, the only way I come to that conclusion is by starting to work on it and setting my mind to the task. I wouldn't get in this mindset if the task was delegated, and because there wouldn't be as much on my plate, I wouldn't have the same pressure to find a way to remove the unnecessary from my life and automate as much as I can.

I've had a couple of experiences outsourcing my work - mostly design work - and the results have been less than stellar. So, the combination of the DIY attitude combines with a lack of success to form a fairly strong resistance to leaping in and experimenting with outsourcing.

But I want to change that. If I don't outsource I want to know it's not out of fear, and that these reasons I have to not do it are genuine and not an example of forming arguments to support an emotional reaction. So, I'm going to give it a shot.

What's likable about outsourcing?

Let me summarize briefly how the 4HWW articulates the benefits of outsourcing:

  • The ability to practice remote management skills without incurring the high cost of an employee in the states
  • Having a parter - someone who can take on stuff when you don't feel like it, give encouragement, and be there for you when you need them
  • The sense of power that comes from sitting in the boss' chair
  • The ability to focus on what you find most important or interesting and delegate the rest

There are examples of outsourcing all kinds of things, from very personal tasks like sending an e-mail to one's wife to full-on business proposals.

Step 1: What can I outsource?

After reading the chapter again, one take-away was that I might not know exactly how I could employ outsourcing until I start doing it. That it's like pretty much anything, the more you play with it, the more you realize what it's real purpose and potential is.

An idea that's iterated and re-iterated in the 4HWW is the idea that if a task is not well defined and important, no one should do it, and that delegation and automation multiplies any existing inefficiencies. So, it's important that the tasks you delegate are ones that you're committed do doing, and that you've at least taken the time to define what they actually are.

Coming up with ideas out of the blue that meet these criteria was a little tricky, but there are a few things that came up for me:

  • Transcribing the training videos on Build a Module.com for searchable textual content.
  • Finding out the relationship between the sale price and appraised value of homes in Boise, Idaho (we're considering buying a home there)
  • Where can I syndicate articles from my blog to improve readership and get posts like these to people who would be most interested in them?
  • Where can I get floss business cards for my company (I love those things, get some from my dentist at every cleaning)
  • Sending random encouraging e-mails to myself to see if it has any effect on bolstering enthusiasm.
  • Finding places in the Drupal.org handbook for some of my tutorial posts.

These are all things that are going to take a back seat for a while if I have to plug in the time to do them, but I know I want to do them at some point. So, they seem like good candidates for outsourcing.

Step 2: Finding a virtual assistant (VA)

The next step was to find a virtual assistant for me to start outsourcing tasks to. So, I posted a job on Elance.com, paid $15 for a premium listing, and in a couple hours I had four bids from $5 to $8 an hour, three of which seem like they have potential.

Over the next day or two I'll review any incoming bids and choose at least two to work with, one in the states and one outside of the states, then I'll give them a shot and start delegating. The idea here is that maybe it would be good to have a native English speaker for certain tasks, but it seems like you can get a better return overall by hiring out of the states.

Hopes and questions for the future

Now that I've committed to giving this a shot, I have some hopes that are bubbling to the surface. If this works out well, then I could expand my ability to get things done upwards of 50%. I can foresee that after a while, certain tasks will start to scream "outsource me!" and it could become a natural part of my workflow to delegate particular items. There's a whole slew of things I would never outsource because the experience seems to valuable to me, but I also know that I can learn a lot from other people doing something if they can tell me how they did it. Could having a virtual assistant be like having a personal trainer? Someone who can show you how they found something, where they looked, how they made certain decisions? And then you can take it from there, having a nice little boost towards your end goal? What would it feel like to have a partner on board who is on call, ready to plug into virtually anything you need help with?

But, I'm apprehensive as well. What should I expect from these folks? What happens if time after time I end up completing tasks I originally delegated because I'm not happy with the results? Will I be able to identify a task suitable for delegation from those that aren't? Will I be able to provide the right kind of encouragement to have my assistants appreciate doing the work? Can I be a boss without being a lame boss?

I guess I'm about to find out.

What happens next?

Read more about what happens in Day 2 of Outsourcing My Life, and Day 3 of Outsourcing My Life.

Jul 17, 2010

I decided to jump into Views Alpha 3 because I wanted to explore the Views Infinite Scroll module, and I have a friend using it on a large production site without any problems. Here are some notes from the upgrade experience.
No update.php run was required - nice.

I did get a WSOD on the /admin/build/views page, but I CTFC and all was good.

Here's the new interface, which looks a lot like the old one:

On one of my side blocks, a pager suddenly appeared, so I had to change the pagination settings here:

This is cool, the number of items and pagination settings have merged into a single setting.

I also started to notice that the configuration blocks are ordered a bit differently. There are basic and advanced settings panes now, and the new ordering does seem to make more sense, though it's hard to tell if it would make more sense to someone new to Views.

Ah, I've been wanting this feature, the ability to re-order the displays.

When setting pagination options, you can expose inputs for the number to show and the offset. Even though I think this is usually clutter, it's a common request from clients to have the ability to set the number displayed.

I installed the Views Infinite Scroll module (and the associated jQuery plugin, after some wheel spinning), and selected it as the pager option for my view. At that point, it said that it was incompatible with Ajax, which makes the search box above my view less responsive. So, I'll have to leave it to the default Views pager. I also kept getting this error, even after turning Ajax off on the view:

My friend also suggested that I upgrade Views Bulk Operations to the latest 6-3 dev release, which at the moment is here. No problems there, and it also didn't require an update via update.php.

Jul 16, 2010

If you don't use Navigate you could be missing out on some rather nice tools for rapidly setting up a site and helping clients and site users get comfortable in Drupal. Navigate is all about customizing the navigation experience to easily find menu items and content if you don't know where they are, and quickly build a set of personal menus to areas of a Drupal site that you use the most.

I use Navigate every day and it saves my bacon. 

The problem

The problem we're trying to solve here is that Drupal's navigation is deep and complex. Menus in menus in menus, and it takes a while to figure out how to find what you need. Navigate brings together a set of tools in an reasonably un-intrusive package that helps you get around. I'll take you through the features and how to set it up below.

Getting started

First, download the Navigate module and install the associated modules you see below:

Once installed, here's what you'll see in the top left corner of the screen:

Something's hiding there. Click it and it will expand to show you this:

This is Navigate. Navigate is a box that contains widgets. You can hide Navigate by clicking the steering wheel icon one more time. Above, you can see it has two widgets, one called Search and one called Favorites.

Let's play with these for a minute. Test out search by typing user in the search box and pressing enter. Navigate will search content and the menu to find any matches to your search and load them via AJAX. You'll see something like this:

One nice thing about Navigate is that it retains state. That means that if you click on a link, the same search results will display on the next page.

If you click the little cog wheel highlighted above, you'll see some settings for this widget:

TIP: I use the search widget to find menu items added by newly installed modules when I don't know where they are.

Here you can set the widget to search for content (the Full option uses Drupal's search engine), the menu and / or users. You can even set which types of content to search.

Why would you want to do this instead of searching everything? Well, Navigate lets you have as many widgets as you want, and you may want to keep one search result set open from page to page while using the other one to search around. You also might want to have a search widget for the menu, and another for content. Let me demonstrate.

Click the big cog wheel to display Navigate's settings:

This opens up some new options. I'll walk through this bit by bit. You should see something like this:

Here are the new areas that displayed, marked so we can reference them later

Our first goal here is to add a widget. To do so, all we need to do is click on an item in the "Add widgets" section. We want to add a new search widget, so we'll click the search item.

This will add a new search widget below the others, so you'll see something like this:

Now we have two search widgets we can set individually to search for particular things. One problem, though. They're both called Search. No biggie, we can change the title of each of them by double-clicking the title, typing the new title, and pressing enter:

Here's what they look like re-titled:

Now, it might make more sense to have the two search widgets next to each other, so grab the Search users title  to move the widget and drop it below the Search content widget.

Using the favorites widget

Now let's explore the Favorites widget. The idea of the favorites widget is to create bookmarks to commonly visited places. When you are on a page, you can add the page to your favorites by typing a name for the page and clicking the Add button.

Becomes...

Once you have a number of favorites, you can re-order them by dragging and dropping. You can delete items by clicking on the X that displays when hovering over an item. You can't see it because we're just using screenshots, but everything is done via AJAX and saved behind the scenes, so this is very quick process.

For complex shortcuts, I'll add a divider just by entering a series of dashes as a favorite:

Just like any other widget, you can have multiple favorite widgets and rename them as you'd like.

If you create a set of shortcuts that you'd like to use for another site, there's good news! Click the settings cog wheel for the widget, and you'll see an import / export form. Click the Export button to generate the data you can use to import into another site's widget:

Using the menu widget

Okay, let's explore another widget. The Menu widget provides a collapsible tree of any menu, and just like the search, it has a saved state so that you don't lose your place between pages. Let's see what that looks like.

Just like we did above, click the settings cog wheel to open up Navigate's settings, then click the menu item:

A new widget will appear below the others with a simple form to let you pick the menu to display:

Select the menu (I picked the Administer menu) and click the Load button. What displays will look something like this:

Every + sign denotes an expandable menu. Click it to expand or collapse a menu. Here's what happened when I clicked the one next to Reports:

Simple enough. I typically add a menu widget for the Create content menu when I start working on a site.

One of the big challenges of Drupal is teaching clients how to use it. There's just a lot to wrap your mind around. And often, there is more than one kind of person using the site, so the ability to have a customize set of navigation tools for each individual or role is useful.

With Navigate, you can set defaults for roles, or modify an individual user's widget set. Let me walk you through how to create a default set for a role.

Setting default widgets for a role

Let's take the widget set we've just created and set it for the default widget set for new administrative users. First, click the cog wheel to display the settings, then click the "Set" link next to the role you want to assign the widget set to:

Once you do this, when a user of that role logs in for the first time, if they don't have their own widget set already they'll get the default. Once you've set the defaults, some of the gray-ed out options become available:

Load - loads the widget set as your current widget set so you can modify it
Unset - Unsets the defaults for the role
Set all users - This will set the defaults for all users of that role, even if they have a widget set already.

Setting defaults for a single user

In the "Search name / UID" box, start typing a username or UID. Once you've typed something in, the gray-ed out options become available:

This works the same as the role. You can either set the user's widgets to be what you see on your current widget set, or you can load theirs to modify them.

One tricky thing here is that when we load a widget set, it replaces our current one. So, we need a way to export and import a widget set to save our settings while we work on the widget sets for other users.

Exporting and importing widget sets

In the settings pane, you'll see a couple of boxes like what you see below. When you click the "Export widget set" button, the textarea will be populated with the code you would need to paste into the "Import widget set" box in order to import.

You can use this tool to create a number of widget sets to use across multiple sites. In Navigate, everything is portable.

A few special features

Keyboard shortcuts

You can enable keyboard shortcuts to easily use Navigate. Click the "KEY" link at the bottom of the widget set to enable it (it will be white and non-italic when enabled):

CTL+SHIFT+N - Toggles Navigate visibility
CTL+SHIFT+S - Moves the cursor to the last search widget for rapid searching

Mini-mode

Double-click the Navigate title to hide all inputs and just show links (to free up some space):

Help!

Hovering over virtually anything in Navigate will give you some helpful information. For example, hovering over the Navigate title displays this:

Hovering over a link in a favorites widget displays this:

You can also click the HELP link at the bottom of Navigate to display the help page:

That's it, enjoy!

Jul 16, 2010

You can't get syntax highlighting in Evernote directly, but what you can do is use an online syntax highlighting service and copy the highlighted content straight from the page.

First, I went to http://tohtml.com/auto/ and pasted in some code:

<?php
  for ($i=0; $i<4; $i++) {
    echo 'This is a test of syntax highlighting in Evernote using Pastebin';
  }
?>

Then, I copied the resulting code from the output, which you see here, and paste it into an Evernote note. 

You could also use the Evernote Firefox plugin to create a note straight-up, but it's a pain trying to undo the CSS styling to get some plain text in before your code, so I would create a new note, add a couple of blank lines to the beginning, and paste in the code after that.

The result is what you see below. This works because Evernote stores HTML as HTML, and if there's embedded style tags, those will get copied over too. I first tried this experiment with Pastebin, but it didn't work because the styling is not inline.

<?php
  for ($i=0; $i<4; $i++) {
    echo 'This is a test of syntax highlighting in Evernote using Pastebin';
  }
?> 
Jul 16, 2010

Below is a list of things I own and like, curtesy of an Amazon aStore. There's stuff that I can't find on Amazon, so at some point I'll have to create a post with those.

Jul 15, 2010

Go to settings

Select Music...

Set "Shake to shuffle" to off

Did that work for you, Mom?

Jul 15, 2010

Similar to RTFM (Read The F****ing Manual), CTFC is a headslapper that solves at a good number of the "I did everything right, but it's still not working" issues that come up with Drupal. Drupal caches theme functions, menu items, sometimes forms and entire pages. If you look at the database for any tables prefixed with cache_, you'll get an idea of just how insiduous the caching component of Drupal is.

So if you're having issues, take two CTFC's and call me in the morning.

To clear your caches, you have a few options:

1) You can go to your /admin/settings/performance page and click the Clear cached data button way down there on the bottom.

2) You can install Administration menu and hover over the icon in the top left corner (mine looks like the Acquia logo) and click the Flush all caches link (or a particular submenu item thereof).

3) I'm pretty sure you can clear the cache by manually truncating all of your database tables that start with cache_ plus the cache table. I use a program called Sequel Pro (which kicks serious butt, btw), and when I filter my tables to match cache_, here's what I get:

Note that there's a couple matching tables that shouldn't get truncated (hint: they start with imagecache...).

4) If you're really fancy, you can clear the cache using drush cc.

Jul 14, 2010

Quick stats:

  • The treadmill is a Pro-Form 770 EKG. I bought it on Cragslist for $150 (my last treadmill was $50)
  • I walk from 1-2 MPH (no, I don't run, in spite of the picture you see below). 
  • I'm on the treadmill for 4-6 hours a day

People ask me if I run on this thing. I don't. Partially because it would make working impossible, and partially because I work upstairs in an older home and fear for its integrity.

The white part is kind of a 'floating' surface. It's not screwed down so that I can shift it from time to time - mostly depending on how big my lunch is.

Here's what I did to attach the desk surface to the handles:

  • First, I removed the rubber handles, exposing the metal bar you see above
  • Then, I took a drill and trilled two holes in each handle.
  • I took the two screws from other parts of the treadmill that didn't really need them (I hope) and screwed in the bookshelf braces. I got the braces as True Value for a couple bucks apiece.
  • Once these were stable, I laid a bit of spare plywood board on the braces and marked out where the screw holes were.
  • I created some pilot holes and screwed the braces to the plywood.

The bright red item you see to the right is a fly gun.

Jul 13, 2010

// $Id:$

Bible Field

Bible Field is sponsored by Calvary Chapel (http://www.ccboise.org/) and written by Chris Shattuck (http://drupal.org/user/166383). A live version of this README file can be found at 

Introduction

The idea behind the Bible Field module is to provide a CCK field that can reference a body of work by book, chapter and verse. Below are some features:

  • The ability to reference a range or single point
  • A special Views 'range filter' that allows for search within a ranged entry (like chapters 2 to 10)
  • A compound Views filter that allows you to specify the granularity of the filter to book, chapter or verse
  • Books are pulled from a CVS file, so you can reference arbitrary bodies of work (not just Bibles)
  • Chapter selectors are automatically adjusted to the number of chapters in the currently selected book

Installation

See http://drupal.org/getting-started/install-contrib for instructions on how to install or update Drupal modules.

Usage

The Bible Field module adds two features: a new CCK field type, and additional filters for views. For a guide with screenshots, see http://chrisshattuck.com/node/119.

To add the CCK field:

1. Click the "Manage Fields" link next to your content type in /admin/content/types and scroll down to the bottom. 
2. Select the "Bible reference" type and fill in the rest of the form.
3. Next, choose your settings. There are two settings specific to Bible Field, the Version and the alphabetical sorting. If set to sort alphabetically, any book fields will be sorted from 1-9 and A-Z, otherwise the sorting will follow the default, which is likely the real order.

Now, you can add references in that node type.

To add a chapter range filter:

  1. Click the plus button next to the Filters section of a view to add a new filter, and select the Content category. 
  2. Scroll down until you see the fields ending in "Ending chapter" or "Starting chapter"check the 'Ending chapter' or 'Starting chapter'.
  3. Click the Add button.
  4. Under the 'Operator' select field, select 'Within start and end range'.
  5. Optionally, expose the filter

This will add a select input with a chapter select input. Searching for a particular chapter will allow you to search for nodes that match a particular chapter range. For example, if I have a node that references Genesis chapter 5-12, and I filter for chapter 7, it will be a match.

If you add a filter for the book as well, the numbers in the chapter select input will be auto-loaded with each change to match the number of chapters in the book.

To add a granular filter (filter by book, by book and chapter or by book,chapter and verse)

  1. Click the plus button next to the Filters section of a view to add a new filter, and select the Content category. 
  2. Scroll down until you see the "Bible field composite" option.
  3. Select this and click the Add button.
  4. Select the granularity (book, chapter or verse)
  5. Expose the filter

This filter is like a ranged search for chapter and verse with the book filter as well.

To add other books or bibles

Bible Field doesn't work for just bibles - it can function to reference any body of work, and even co-releate references across multiple works. You can have multiple reference fields in the same content type that reference different bodies of work.

To add a new reference list, you can look in the module directory under /optional_csv/hitchhikers_guide_to_the_galaxy.txt. In this file, you can see the structure required to feed Bible Field the correct information. On each new line there is the name of the book, a comma, and the number of chapters in the book.

If you copy this file over to bible_csv, you will see a new option when you add a CCK field for referencing the Hitchhiker's Guide to the Galaxy. Using this as an example, you can add any body of work you'd like.

Jul 13, 2010

This is a quick guide to getting started with the Bible Field Drupal module.

Adding the field to your content type

Click the "Manage Fields" link next to your content type in /admin/content/types and scroll down to the bottom. Select the "Bible reference" type and fill in the rest of the form.

Next, choose your settings. There are two settings specific to Bible Field, the Version and the alphabetical sorting. If set to sort alphabetically, any book fields will be sorted from 1-9 and A-Z, otherwise the sorting will follow the default, which is likely the real order.

The version allows you to select from multiple Bible versions. As an example of using a different source file, I've added a file called hitchhikers_guide_to_the_galaxy.txt in the optional_csv folder to demonstrate how Bible Field can be used for any book reference. If you drag this file over to the bible_csv folder, you'll be able to choose from the default King James Bible or the Hitchhiker's Guide to the Galaxy.

Using the field

Now that you've added the field, you can add references in your nodes. Go to the node add page for the content type you added the field to, and you should see the following:

Here you can select as many references as you need to. When you select a book, the chapter input will automatically be populated with the number of chapters in that book. Choose a starting chapter will automatically set the ending chapter to the same number.

Setting up filters in Views

Once you have content with references, you can set up a View. You can use the book, starting chapter, ending chapter, starting verse and ending verse fields, but there are two special filters as well.

The first is a range selector, to allow searching through a range of chapters and verses.

First, click the plus button next to the Filters section of the view to add a new filter, and select the Content category. Scroll down until you see the following, check the 'Ending chapter' or 'Starting chapter' and click the Add button.

Now you'll see the settings form for the filter. The special one available here is called "Within start and end range, as you see below:

If you select that, and expose the filter, you'll see a select input with a list of chapters. To make this most useful, also add a filter for the book as well and expose it. The resulting form might look something like this when you preview it in Views:

If you do this, the chapter select input should auto-fill with the number of chapters in the selected book. So if someone is doing a search for Genesis, chapter 5, and a piece of content matches a range of Genesis chapters 3-10, it will match.

The second special filter is simple and granular. Add a new filter, select to show only Content filters, and select the "Bible field composite" item, as seen below:

This will open up an options form to allow you to select the granularity of the input. You can choose to display just the book, the book and chapter, or the book, chapter and verse inputs, as you see below:

This filter works only as an exposed filter, so make sure to expose it. When you do, it should look something like this if you selected 'verse' for the granularity:

That's it, enjoy!

Jul 13, 2010

I kept banging my head against this one because the PHP function array_merge() will act strangely if all of the keys in an associate array are integers. So doing the following DOES NOT WORK:

'#options' => array_merge(array('' => ''), drupal_map_assoc(range(1, 100))),

But, doing the following DOES:

'#options' => array('' => '') + drupal_map_assoc(range(1, 100)),

Another solution that works, but is not as concise:

'#options' => drupal_map_assoc(array_merge(array('' => ''), range(1, 100)));
Jul 12, 2010

Whenever it's time to add a module to the drupal.org contrib repository, I flounder a bit. Here's a little documentation on the steps I took when recently adding the Evernote module.

From the command line...

First, you need to login using your CVS account username (replace cvs_username below):

export CVSROOT=:pserver:cvs_username@cvs.drupal.org:/cvs/drupal-contrib

cvs login

Next, check out the drupal contrib repository. From the command line, do:

cvs checkout -l contributions/modules

Copy the module folder over to the modules/ directory and add it with the following commands:

cvs add example

cvs add example/*

Commit it with the following:

cvs commit -m "Super helpful commit message here"

Create a project on drupal.org: http://drupal.org/node/add/project-project. As Boris points out below, some people like to do this before adding the project to CVS. I prefer doing it this way so that when any 'new project' alerts go out on RSS, there's something for people to download and play with right away.

To create a development branch, cd to the module directory

cvscalvar tag -b DRUPAL-6--1

To create an official release, cd to the module directory

cvs tag DRUPAL-6--1-0-BETA1

To update your current checkout to use the development version:

cvs update -dP -r DRUPAL-6--1

Now, you need to add any releases to the module project page by clicking the "Add new release" link on the project page.

In order to get the development release showing on the project page, you need to click on the "Administer releases" link (see image above). Then, check the "Show snapshot release" checkbox (see below)

Useful links:

Jul 11, 2010

// $Id:$

CONTENTS OF THIS FILE

  • Introduction
  • Installation
  • Usage

INTRODUCTION

Creator: ChrisShattuck <http://drupal.org/user/166383>

The original idea behind the Evernote module was to integrate the pulling of content from Evernote for rapid blogging purposes. My hope is to further abstract out some of the tools used to do this so that the module can be used as an API for open-ended integration with Evernote.

This module will do the following:

  • Establish a connection with an Evernote account
  • Allow an administrator to set up a 'feed' that will perform a one-way sync from Evernote to Drupal based on multiple criteria. For example, you can set up a feed to pull content with a particular tag.
  • Allow 2-way syncing of 'tags' as taxonomy terms
  • Downloading images and other resources from Evernote notes into image or file fields
  • And a bunch more

INSTALLATION

See http://drupal.org/getting-started/install-contrib for instructions on how to install or update Drupal modules.

You will also need to add the Evernote API library to Drupal. Right now the API isn't quite set up for web applications like this, so you'll need to do some finagling. You can use the instructions below to build the library yourself, or you can go to this URL to read about how to download a ZIP file with this already done: http://chrisshattuck.com/blog/instructions-setting-evernote-library-evernote-drupal-module

  1. Download the Evernote API (labeled "Evernote API") - http://www.evernote.com/about/developer/api/
    2. Expand the zip
    3. Copy the folder /sample/php/EDAMWebTest/lib/HTTP to /lib/php
    4. Copy the folder /sample/php/EDAMWebTest/lib/OAuth to /lib/php
  2. Next we need a few PEAR libraries that might not be installed on your server, so...
  3. Download the HTTP_Request PEAR script and add to /lib/php/HTTP - http://pear.php.net/package/HTTP_Request/
  4. Download the Net_URL PEAR script and add to /lib/php/HTTP - http://pear.php.net/package/Net_URL/
  5. Download the Net_Socket PEAR script and add to /lib/php/HTTP -http://pear.php.net/package/Net_Socket/
  6. Rename the folder /lib/php to evernoteand move it to your /sites/all/libraries/folder

USAGE

  1. Go to /admin/build/module and click the 'create a new account' link
  2. If you don't mind saving your Evernote username and password on the server, fill in the username and password at the bottom of the form. To receive a temporary authentication from Evernote, fill in the widget.
  3. Once the account as been added, you can click on 'Add feed' next to the account to create a feed.
  4. Fill out the form to create the criteria for the feed. When cron runs, it will import any new matches and update any changed notes.
Jul 11, 2010

Below are instructions for putting together a PHP-based API library for Evernote, particularly for the Evernote Drupal module. I've attached a ZIP file to this post (see the bottom) which can be used temporarily until the brilliant Evernote folks have the time to compile a distribution.

If you use the ZIP file included below the following instructions (evernote-api.zip), just unzip it and add it to your /sites/all/libraries folder. To put it together yourself, use the following instructions.

  1. Download the file here (labeled "Evernote API) 
  2. Expand the zip
  3. Copy the folder /sample/php/EDAMWebTest/lib/HTTP to /lib/php
  4. Copy the folder /sample/php/EDAMWebTest/lib/OAuth to /lib/php
  5. Next we need a few PEAR libraries that might not be installed on your server, so...
  6. Download the HTTP_Request PEAR script and add to /lib/php/HTTP
  7. Download the Net_URL PEAR script and add to /lib/php/HTTP
  8. Download the Net_Socket PEAR script and add to /lib/php/HTTP
  9. Rename the folder /lib/php to evernote and move it to your /sites/all/libraries/folder
Jul 9, 2010

As mentioned here, today I've been evaluating some speech-to-text services. As a practical test of Google's transcription service, I called my Voice account and started playing one of my training videos from buildamodule.com. The idea being that it would be great to be able to search text in videos without doing an actual transcription, which would kill me.

The result was pretty poor and very funny. Here we go:

"Hi. This is Chris Shattuck google model, dot, com and in the studio. We're gonna be talking about working with function. Hoople. So what the video that came before this where we talked about a rate is. We're gearing this lesson more towards people. They don't have a backrest P H P Felt it, but they need to work with cooking, kuple for somebody. Hey, here's what we're gonna cover. First of all look at how to identify function. And then we'll talk about what the fuck's actually his, and while we were just want we'll go over some handy conventions for or preheating a function some. Technical, conventions as user scruples based in particular, hoarded using references, which is an important concept understand or is choosing Cox in. Kuple. Speaking folks will talk about how to identify hook function and you just want we won't go into a death in this lesson, but there is some other videos on the site they do. Thanks, we'll take a look at creating private function. Sir basically functions that we don't want other modules access. It's a look at using variables that are outside of the scooper function or they're basically to find somewhere else at triple. If I will look at storing of permanent dribble inside of function, so we can. We use it Let's go ahead and get started by looking at how to write that 5 Hi Chris, this to make it bigger we're creating a function We're gonna start off with the function. If you were followed by space next is the name of the function in this case it's demo underscore me following the our print this. He's an inside of those parentheses, or any parameters we wanna add to the function. So, the user is variable."

Some of my favorite parts:

  • Various transcriptions of Drupal: "Hoople", "kuple", 
  • "We're gearing this lesson more towards people" - as opposed to....
  • "First of all look at how to identify function. And then we'll talk about what the fuck's actually his"
  • "Speaking folks will talk about how to identify hook function"
  • "If I will look at storing of permanent dribble inside of function, so we can."
  • "So, the user is variable."

Okay, so using Google voice for legitimate transcription services is out. But, great for a party.

Jul 9, 2010

heard about Reqall.com here, and thought the idea was awesome - you send audio to a service via e-mail and it transcribes it for you and sends it back. I'd like to be able to take audio-based notes with Evernote and Reqall sounded perfect. After evaluating it for a bit, I think I'm going to have to wait on integrating it into my workflow. Here are my thoughts:

  • It touts Evernote integration, but it only integrates by pulling data from Evernote to match the internal notes. I would need it to send the transcription to Evernote
  • There is a 30 second limit - perfect for quick to-do items, but not for random journaling.
  • The test I did transcribed perfectly, which was really cool.

If I found out that I was able to work with the 30 second limit, I could have the transcription forwarded to my Evernote e-mail account, which would add it in - albeit without any tags.

I've checked out Google Voice for transcription services, but it's limited to 3 minutes. If it was worth it, you could just keep leaving 3 minute voice mails and see how well the audio transcribes.

Jul 8, 2010

The problem

Often I come to a crossroads where I can either experience a moment or capture it. This is a difficult decision. Do I take a picture, or do I watch with my own eyes? Do I think unrestrained, or do I write it down? Do the benefits of having the memento or reminder outweigh being a little more in the moment? 

That question is tough enough. But then the time spent out of the moment is compounded when sharing the moment with others. Downloading images from the camera, uploading them to Flickr, tweeting about it or updating your Facebook status. It takes time, and it's hard to measure the payoff. Are these artifacts that we're sacrificing a little slice of our lives for really worth it?

I'm pretty sure good to share, particularly with the right motive. If it took no time at all, the effort can only land on the side of good to convey interesting experiences or ideas to others. We can add to the global consciousness and do our part in the push towards greater things. But the reason I don't blog, and I don't tweet, and I don't FB these days is because the cost is too steep. I have specific work-oriented goals I'm shooting for, I have a son I'd love to spend a lot more time with, and another one on the way. I have a yard to mow and a body to keep from languishing. I feel like I'll have time to share someday, but usually it's not now. Or, when I share it can only be for very specific reasons that match up with other goals too.

I've been steadily working towards solving the first problem of capturing. A service called Evernote (you may have heard of it) plays a huge part. Of all the data-capturing applications I've worked with, Evernote streamlines the capturing process. It has a global hotkey (at least for Mac), so I can use it even if it's not open. All I need my mind to do is think that hotkey, and in a second (or a couple if the app has to open) I'm capturing. It syncs up with my iPod Touch so I can capture on the road.

In order to enrich my ability to capture other media, I recently purchased a mobile phone with audio and video capturing abilities. I can e-mail these to my Evernote account. This streamlines the capturing process so it feels like the cost is about as low as it can get without having embedded photo sensors in your forehead. No transferring of media, it just syncs up on its own.

This wasn't enough for me. I also wanted to tackle the problem of the lowering the overhead of sharing to the point where it felt like it was no longer a matter of if I had the time, but rather if the information was worthy of sharing.

One issue I have with sharing information is the multiplicity of channels. How can I expect that someone will monitor my Flickr, Twitter, Facebook, Blip, Digg and Delicious accounts, plus several of my own media channels. And even though there is some integration between these services, as far as I know there's not a single application that provides a centralized method of distributing media, so managing the distribution of the data I want to share requires hooking into multiple interfaces. Even if there was a unified interface, there's then two places to manage that data - your local copy and the copy on the channel, and I feel like it should be possible to reduce this to one. Change it locally, and it changes on the service as well.

The issue of centralizing the consumption of your media can be solved by pulling in all the data to a centralized feed - like a blog. It can aggregate your tweets, your videos, your blog posts, and anything else. But, there's still the problem of getting that data into the blog in the first place, and managing it once it's there.

The solution

So, I started putting a couple of pieces together. Evernote provides a method of embedding files of various types inside the notes, and it syncs them with a remote server. I remembered reading that Evernote also had an API, so I started looking into it to see if there might be a way to sync up a web site with Evernote. If so, then I could feasibly create a post locally and have it automatically appear in my blog. If I could centralize my media into Evernote and use it as a blog broadcasting tool, then I would have a solution to multiple problems: 1) Having only one interface for distributing multiple types of media, solving the multiple channels issue 2) Since I capture ideas and information in Evernote anyway, sharing it wouldn't add any overhead at all. 3) If I could broadcast out to multiple channels, I could get a lot of leverage for the data I capture, making it more likely that I would want to capture it in the first place - a useful feedback loop.

The idea really excited me, and as I started digging into the Evernote API, I realized it was totally possible. It's times like these that I'm really happy to be a developer.

I'll be posting more about the solution I came up with, but the idea is to use a Drupal site as a hub which polls Evernote for new notes that meet particular criteria (i.e. they have a particular tag) and adds them as nodes (pages) to the site. Any updates that are made in Evernote are automatically pushed to the site. I built a Drupal module (which will be available soon) that manages this process, and allows two types of tagging - the traditional type which organizes the nodes (i.e. family, recipes, etc) and the second which can be used as triggers for other activity. On this site, for example, I can add a tag called *tweetand Drupal will automatically tweet the node with a shortened URL. If I add a *fb tag, then the twitter post will be sent to Facebook as well.

So just to be clear, here's the workflow:

  1. I create a note in Evernote
  2. I give it the tags *tweet and *fb

That's all. The note is broadcasted to my blog, to Twitter and Facebook. You don't even have to save your note in Evernote, it saves it in the background. If there are any media files attached, it automatically saves them to the appropriate place in Drupal. If that media changes in Evernote, it will be updated in Drupal.

You'll have to excuse me, but I think this is pretty bad ass.

One other issue I wanted to solve was the issue of inter-linking between notes. Evernote is suspiciously wiki-ish, but there's no way to link between notes. What this Drupal module will do is post back a new note with a list of the pages that have been published through the module - with links - so you can copy and paste the links in other notes. Because Evernote has awesome search, it's easy to find the link if you know even a single word.

Oh, and one more piece of awesomeness? Evernote OCRs images on their server, and this module will capture the OCR-ed text and pull it back into Drupal to add to your pages in a variety of ways. Images become searchable! Damn!

The upshot is that I now have a tool that makes it amazingly natural to share information. Of the things that I think are worthy of capturing for my own benefit, there's a handful that I can see being useful to others. To share it, I only have to add a tag.

More to come about this, as well as a release of the Drupal Evernote module.