A Quick Look at OmniFocus Versus Things

Tuesday, 26 August 2008

Via The Apple Blog:

There are dozens of productivity applications for your Mac, and a few for your iPhone. But there’s one application that’s available on both your Mac and your iPhone… OmniFocus.

Well, it’s definitely one application that’s available for both iPhone and Mac OS X, but it’s not the only one. As my voyage with Things continues, I figure I’d do a quick comparison of the OmniFocus features The Apple Blog listed with those from Things (which is still in beta). This is in no way a conclusive list, but I figure it’s a good comparison of the features most people care about.

Desktop Versions

  Inbox Quick Entry Shortcut Email Entries Backups
OmniFocus Yes Yes Yes Yes
Things Yes Yes No* Yes

* Does anyone really use this? Especially when there’s an iPhone pocket version?

Overall I’d say this is a pretty close match-up. The ability to email entries was a nice plus when all I had was the desktop version of OmniFocus. I could basically email myself a task that would later be automatically added to OmniFocus on my laptop. Unfortunately I never really used this since I pretty much always forgot the syntax. So, I’d end up emailing myself a note to manually add some task to OmniFocus. Something like “Don’t forget to write an article comparing OmniFocus to Things!” etc.

iPhone Versions

  Adding New Tasks Location Aware Syncing (with the desktop version)
OmniFocus Yes Yes Yes
Things Yes No Yes

The location aware functionality that OmniFocus for iPhone has sounds really interesting, but I’m curious as to whether or not it’s useful in practice. This is the one reason I’m really considering buying OmniFocus for iPhone, but I have a hard time believing I’d really use it. I’ve purchased OmniFocus, and Things for iPhone (the desktop version of Things isn’t on sale yet) but haven’t really had a compelling reason to try out the iPhone version of OmniFocus. Wouldn’t it be faster to just click the “grocery store” context rather than having to wait for Core Location to locate you and then tell you, “Hey! You’re at a grocery store! You could buy some eggs and milk!” This might be more useful if applications were allowed to run in the background. Then you could be notified, if say, you were driving by a grocery store and there was something on your list, but the fact that you have to have the app running makes me believe that it would be more of a novelty than anything.


Using Symfony Partials In DHTML and Ajax

Thursday, 21 August 2008

Often times when building dynamic applications with Ajax or DHTML you’ll come across the need to use a snippet of html code over and over. On the server side, this is typically accomplished with the use of reusable pieces of code that get stitched together to form a single web page. Wouldn’t it be nice to be able to use the same code fragments that are used to render the page on the server side, on client side?

Symfony, for example, allows for several different types of these code fragment components, the most basic being the “partial”. Partials are particularly useful when you need to add or update content to a page via Ajax.

For example, here’s a simple set of select boxes:

select lists

You can dynamically add a new select box by clicking the “Add another country” link or remove one using the “Remove” link. Pretty standard stuff. To generate one of these rows, we could include a partial from within our main template. Something like this:

<div id="country_lists">
    <?php include_partial('preferences/countrySelect', array('countries' => $countries, 'first' => true)); ?>
</div>

And here’s the partial’s contents:

<div class="country_list">
    <?php echo select_tag('countries[]', options_for_select($countries, null, array('include_custom' => '-- Select Country --')))?> &nbsp; 
    <?php echo link_to('Add another country', '#', 'class=add') ?>
    <?php if (!isset($first)): ?>&nbsp; | &nbsp; <?php echo link_to('Remove', '#', 'class=remove') ?><?php endif ?>
</div>

… as you can see, I’m doing a check to see if the partial we’re rendering is the first in the list and if it is, the link to remove the row is not included. Also, I’ve named the select_tag countries[] so that PHP automatically collects all of the results for these tags into one array on submission, regardless of how many the user added.

So far this is all really standard stuff. The interesting part comes when you need to dynamically add another row through javascript. For the javascript interactions I’ll be using jQuery and some simple event delegation. Here’s an example of how it might work:

<script type="text/javascript" charset="utf-8">
    // event delegation
    $('body').click(function(event) {
      var element = $(event.target);

      // "add" link clicked
      if (element.is('a.add')) {
        element.parent('div.country_list').after("<?php echo escape_javascript(get_partial('preferences/countrySelect', array('countries' => $countries))) ?>");
      }
      // "remove" link clicked
      else if (element.is('a.remove')) {
        element.parent('div.country_list').remove();
      }
    });
  });
</script>

Note that since we’re writing this jQuery code from within a symfony template, we have access to all of the Symfony goodness. For example, I’m echoing a partial from right within the jQuery after() call. Using simply include_partial directly would most likely result in a javascript parser error as the countrySelect partial contains line-breaks and both single and double quotes, so we’re using get_partial instead. The call to get_partial returns the partial as a string instead of echoing it directly. Then I’m wrapping it with a call to escape_javascript which is a standard symfony helper that will escape all of the potentially problematic characters so that the string can be used within a javascript call.

So now, after the page has been rendered, the partial’s code is injected right into the jQuery call. This is basic DHTML, but could be further extended with Ajax if we needed to insert a partial with dynamic content. New in Symfony 1.1 is the ability to render a partial directly from within an action so you don’t have to create a template that would just hold an include_partial call. This is perfect for Ajax. See the API docs for more information on renderPartial().


Things for iPhone 1.1 Update Released

Monday, 18 August 2008

Speaking of Things for iPhone, it looks like the 1.1 update (which introduces syncing with the desktop version) has finally propagated to Apple’s servers and is available in the iTunes store.

At first glance, it looks good. Syncing worked flawlessly and was really easy to set up. The iPhone app itself is lightweight and pretty well-done. It’ll be interesting to see how well my iPhone version stays synced with my desktop version as I work throughout the day.

Update: The Things blog has been updated with an announcement about the Things for iPhone 1.1 release.

Also, after using syncing for the last day or so I can say that it works very well and I’m actually really impressed with the seamlessness of it all.


Parsing jQuery's sortable("serialize") Method with PHP (and symfony)

Monday, 18 August 2008

It looks like as of jQuery version 1.2.6 there’s no built in way to serialize a sortable object into a javascript array for use in ajax calls.

This example uses symfony-specific code, but you should be able to use this method in any type of php scripting. Here’s some example HTML from the template where we’re going to make the ajax call:

<ul id="item_list">
<?php foreach ($items as $item): ?>
  <li id="item_order_<?php echo $item->getId() ?>"><?php echo $item->getName() ?></li>
<?php endforeach ?>
</ul>

And here’s our ajax call from within the template:

$('#save_btn').click(function(){
    $.post("<?php echo url_for('collection/reorder') ?>", { item_order_str: $('#item_list').sortable("serialize") });
});

Unfortunately, this simply sends a string of key/value pairs to the server under the variable name item_order_str. It would be nice if there was a serializeArray method for sortables in jQuery just like there is for inputs. That way php would automatically create an array of values for us but, luckily, PHP has a function for dealing with variables in this format: parse_str

Here’s the example symfony action for dealing with this string:

public function executeReorder()
{
  $item_order_str = $this->getRequestParameter('item_order_str');

  // this will generate $output['item_order'] from the string sent by the ajax call
  parse_str($item_order_str, $output);
  
  // do something with item_order... this is just an example:
  foreach ($collection->getItems() as $item)
  {
    $item->setSortOrder(array_search($item->getId(), $output['item_order']));
    $item->Save();
  }
  
  $this->renderText('Success!');
  return sfView::NONE;
}

The reason the name of the outputted variable from parse_str is item_order is because each of the li tags has an id prefixed with item_order_ and jQuery automatically parses that attribute and creates the key/value pairs accordingly which turns it into something like this:

item_order[]=10&item_order[]=9&item_order[]=4&item_order[]=2&item_order[]=13&item_order[]=3&item_order[]=16

A couple of notes: You can change the way this string is generated by jQuery. See the documentation for more info. Also, the array_search method is handy for returning the key of an associated item. I’m using it above to find out where in the sorted array my item is so that I can update its sort_order field.

Update: I edited the parse_str usage in the above example so that all of the variables expanded from the function are captured in $output.


OmniFocus, It's Not You, It's me... Really

Saturday, 16 August 2008

Via Subtraction:

Not long ago I downloaded a new productivity application that recently emerged from a prolonged beta period. Finally, the 1.0 version had arrived, and I was eager to get my hands on it, play around with its features and see what it had to offer. But, for the life of me, I couldn’t figure out how to use it.

To be fair, this application, which shall remain nameless, had clearly been designed with great attention to detail. Its interface is not unattractive and its fit and finish is commendable; you wouldn’t be remiss in regarding it as a completely professional product.

However. I kept staring at it, and kept clicking on interface widgets and pushing buttons, but the more I explored, the less likely it seemed that I would ever really master it. I’m sure that its workflow makes sense, that with some investment in time, a user could realize some significant benefits from it. I just had a hard time thinking that one of those users would be me.

I have a sneaking suspicion that Khoi Vinh may be writing about OmniFocus, but with the copious amount of Mac GTD apps out there, one can never be sure. Regardless, I’d have to say that this pretty much sums up my experience with OmniFocus. I desperately feel like I should love it and that it could make me more productive, but at the end of the day it feels like I’m doing more trying to keep my organizer organized than I am “Getting Things Done”.

I was excited about the eminent release of OmniFocus for iPhone, but I just kept feeling like there was something very broken in the whole OmniFocus process to begin with. I enjoy the level of granularity that OmniFocus allows, but at some point it feels a bit trivial to have to specify things like, for example, whether or not I’m going to work on my “actions” in my “project” sequentially or in parallel–or maybe this project is simply a “single action list” that “contains loose, unrelated items instead of actions aimed toward the completion of a goal.” I mean, really, does this look like an “‘At-a-glance’ Quick Reference Chart” to you?

When I realized that I was getting in to the habit of writing To-Do items down on 3x5 cards so that I could first “organize” them before going through the mentally tedious act of officially putting them into OmmniFocus, I knew I had to try something else. OmniFocus’ GTD implementation is amazingly near-perfect. And that’s probably why it’s hard for me to use. You see, when it comes to really Getting Things Done, whatever system you’re using needs to completely disappear until you need it, and then it needs to disappear again after you’ve gotten what you need from it and you’ve gone back to work. With OmniFocus, there was just too much to get distracted by. Bells. Whistles. Context Mode. Planning mode. Perspectives. Grouping. Sorting. Filtering. The list goes on and on. I spent a lot of time deliberating what project should contain what and just setting everything up so that I could work that it took a long time to finally just get to work. On top of this, OmniFocus feels clunky and very un-Mac-Like for some reason. Well, mostly for these reasons actually.

I decided to try Cultured Code’s supposedly less sophisticated Things for a prolonged period of time. Being used to OmniFocus, I was almost immediately turned off by Things’ lack of… stuff. I mean, compared to OmniFocus:

OmniFocus Screenshot

… Things is positively devoid of stuff to do:

Things Screenshot

But maybe that’s just exactly what I needed? Over the last few weeks, I’ve found that I actually use Things and it’s almost transparent. There is a lot of power behind Things’ decision to use tagging instead of complex nested hierarchies like OmniFocus. The app seems to allow you to use it very simply as a To-Do list holder, or more powerfully as a more GTD-style user with nested tags for contexts. I find myself wishing there was a tad bit more structure in the way that Things offers projects, but I’ve always been able to replicate that bit of “more structure” with a good balance of Projects or Areas and nested tagging.

I’ve found that since I actually use Things, it’s much more reliable than OmniFocus for me. Not in any technical manner, but reliable in the sense that I actually use it to manage what I have to get done. If you’re a bit flustered with your current system, you might want to learn about Things and the The Morning Scrub.

I’m still a bit on the fence, but Things is steadily gaining ground. The deal-breaker may come down to OmniFocus for iPhone versus Things for iPhone (which has yet to offer sync with the desktop version).

Update: Things for iPhone has finally been updated and now syncs with the desktop version so I’ve put together a quick look at OmniFocus versus Things.


An Update to Dynamic Subdomains for Symfony 1.1

Friday, 08 August 2008

In a previous article, we saw how easy it was to enable dynamically loaded Symfony applications via subdomains. Well, the format for the controller files has changed slightly in Symfony 1.1 (most notably, the “SF_” constants have been banished) so here’s an updated version of the previous example index.php front controller:

<?php
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');

// get the domain parts as an array
list($tld, $domain, $subdomain, $subdomain2) = array_reverse(explode('.', $_SERVER['HTTP_HOST']));

// determine which subdomain we're looking at
$app = ($subdomain == 'staging') ? $subdomain2 : $subdomain;
$app = (empty($app) || $app == 'www' ) ? 'frontend' : $app;

// determine which app to load based on subdomain
if (!is_dir(realpath(dirname(__FILE__).'/..').'/apps/'.$app))
{
  $configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false);
}
else
{
  $configuration = ProjectConfiguration::getApplicationConfiguration($app, 'prod', false);
}

sfContext::createInstance($configuration)->dispatch();

For the full details of how this file works, be sure to read the previous article.


Giving Your Body Tag Some Kick

Wednesday, 06 August 2008

A while back, my friend Dave Dash shared a Symfony CSS tip with me that I still use in almost every project I work on. It’s incredibly simple, yet powerful.

This tip (for me at least) was born from the need for a simpler way to target classes that might have different appearances depending on what section of a site is being displayed. For example, I might have several modules in my Symfony project that use a class called “container” but which have a different border or background color depending on what module or page they’re being used in. It would be helpful then if it were possible to have a mechanism for defining (or overriding) a specific CSS class attribute depending on the page or module you’re in. It would be even better if it were automatic so that there was no need to add HTML markup to a page just so we could target that attribute differently that in other pages.

Enter the body Tag

If you’re working with CSS and HTML, chances are, you use already use the body tag to set up some defaults like font-family or color that are used throughout your site. Let’s extend this a bit. The basic concept is simple: give the body tag an id attribute corresponding to each Symfony module. Then we’ll be able to do something like this:

.container { color: blue } /* site-wide declaration */
#news .container { color: red } /* "news" module declaration */

This could very easily be accomplished by printing the module name as an id attribute of the body tag in your main Symfony layout.php file:

<body id="<?php echo $sf_context->getModuleName() ?>">

Which might render something like this:

<body id="news">

With this addition every module will now have a root-level id declaration that you can use in your style-sheet to override styles on a per-module basis. We can even take this a bit further with Symfony by adding a declaration based on the action as well:

<body id="<?php echo $sf_context->getModuleName() ?>" class="<?php echo $sf_context->getModuleName() . '_' . $sf_context->getActionName() ?>">

Now we can use even more specific targeting like so:

.container { color: blue } /* site-wide declaration */
#news .container { color: red } /* "news" module declaration */
#news.news_headlines .container { color: green } /* "news/headlines" module and action declaration */

This all looks great so far… but what if you need to change this for further granularity? For example, what if you had another dynamic attribute that you were passing as part of the URL that you wanted to have specific styles for? As it stands, you’re stuck, but this is where Symfony’s slot mechanism comes to the rescue.

Here’s the custom slot helper we’ll be using:

function text_slot($slot, $default = null)
{
    if (has_slot($slot))
    {
        include_slot($slot);
    }
    else
    {
        echo $default;
    }
}

You can drop this into your own custom helper file in the lib/helper folder. This is simply a wrapper for Symfony’s built-in slot functionality to make it a bit easier to use in this situation. Once that’s done, our body tag can be changed to something like the following:

<body id="<?php text_slot('body_id',$sf_context->getModuleName())?>" class="<?php text_slot('body_class',$sf_context->getModuleName() . '_' . $sf_context->getActionName()) ?>">

This is basically the same functionality as before, with one important difference. Now, by default, we’re putting the contents of our declarations into Symfony slots body_id and body_class respectively. This means that at any time in a module we can override the default body id or class attribute to something more relevant if we need to. For example, in our “news” module and our “headlines” action, we might be using another parameter to differentiate between types of headlines. Let’s call this the “type” parameter. In the “news/headlines” template we’ll redeclare the body_class slot like so:

<?php slot('body_class') ?><?php echo $sf_context->getModuleName() . '_' . $sf_context->getActionName() . '_' . $sf_params->get('type') ?><?php end_slot() ?>

… which would render something like this if our type parameter was set to “local”:

<body id="news" class="news_headlines_local">

As you can see, you can extend this little trick into many different use-cases. It’s especially useful for navigations where you need to know what section you’re in so you can change the navigation appropriately. With this trick you can let the CSS worry about doing the heavy lifting without having to add logic to your templates. It’s powerful, light-weight and automatic.


Symfony 1.1 Stable Released

Thursday, 03 July 2008

In cased you missed it, the latest incarnation of the Symfony Framework has been released:

http://www.symfony-project.org/blog/2008/06/30/the-wait-is-over-symfony-1-1-released


Washed Out Images When Using "Save for Web" in Photoshop

Tuesday, 10 June 2008

I’ve gotten stung by this before, but since I recently purchased a new MacBook Pro the problem has reared its ugly head once more: Images shift color and get washed-out while using “Save for Web” in Photoshop CS3.

The problem is that Photoshop is an application that manages color profiles whereas the web, generally speaking, is not a color-managed environment. Safari, for example, does honor color profiles in embedded images, but it is definitely the exception and not the rule.

Much has been written about this topic elsewhere, so instead of reinventing the wheel I’ll just point you to some existing resources:

There’s a good overview of the phenomenon here: http://www.gballard.net/psd/srgbforwww.html

And some tips for setting up Photoshop here: http://www.gballard.net/psd/saveforwebshift.html

Also, although more geared towards Aperture, this Apple Support article is a good read also: http://docs.info.apple.com/article.html?artnum=302827

Personally I tend to prefer the 1.8 Gamma that ships as the default on Apple hardware, but using a 2.2 Gamma setting with a D65 target white point really does help make my images look more consistent across browsers and platforms.


PHP Sucks, But It Doesn't Matter

Wednesday, 21 May 2008

Via Coding Horror:

I’ve written both VB and PHP code, and in my opinion the comparison is grossly unfair to Visual Basic. Does PHP suck? Of course it sucks. […] If you sit down to program in PHP and have even an ounce of programming talent in your entire body, there’s no possible way to draw any other conclusion. It’s inescapable.

An interesting read. I can’t argue with the inherent problems listed in the article against PHP. It’s no wonder that frameworks like Symfony have emerged to help give structure and elegance to PHP.