Misplaced Hate on Flash Based Websites

By: SethCardoza - Published: 2010-02-19 15:26:53 in Category: Design

Flash receives a great deal of hate from the web development community, myself included. Common complaints include load times, performance, unnecessary animations/transitions, forcing users to watch (long) intro movies, inability to bookmark content or specific pages, inaccessibility (especially to mobile users), auto play audio, and that it is bad for SEO. The thing is, most of these same complaints can, and do arise from poor development using HTML, CSS, and Javascript.

I can easily include unnecessary animation and transition effects on my site with Javascript, especially with one of the many Javascript frameworks readily available now. I can load down the site with numerous images and other media, CSS and Javascript files, and bloated markup. I can make a website difficult to use for users, and especially mobile users. I can poorly use AJAX for everything making it difficult or impossible to link directly to anything but the home page.

Flash as a development tool does not require superfluous transition effects and animations (AFAIK). It doesn't force the developer to include an intro to the site, or to auto play some audio file. There are ways to make sites more accessible in Flash, allowing for bookmarking or directly linking to inner content. The website doesn't have to take an SEO hit just because it uses Flash. Flash would be less resource intense if there were fewer animations and transitional effects. A secondary, light weight version of the site can be made for mobile users, and others that either don't have Flash or don't want to use it.

In my experience, the blame for poor Flash sites often rests in the hands of the developer. It is a poor choice to load up a website with animations. It isn't user friendly to force users to watch an intro movie that you think is super awesome. The lack of bookmarking, direct linking, and the hit to SEO are all avoidable and to allow for otherwise is laziness. Remember, Flash is just another technology that is often used improperly through no fault of its own.

jQuery Form Focus Plugin

By: SethCardoza - Published: 2010-02-17 21:05:52 in Category: jQuery

This jQuery plugin will add a background color to text, password, and textarea input fields in forms when focused, and then revert to the original background color on blur. It is a one line call, with one (optional) parameter, the background color.

You can target all forms on the page with this simple line:

$('form').formFocus();

This will default the focused background color to: #f0f0c0

You can specify the background color as follows:

$('form').formFocus({backgroundcolor:'#ff0000});

which would make the focused background color a very bright red. You can also target forms specifically, whether you only want to use it on a single form, or if you want to specify different background colors for each.

$('#demo1').formFocus({backgroundcolor:'#ff0000});

$('#demo2').formFocus({backgroundcolor:'#0000ff});

Download jQuery Form Focus Plugin

Toolbars on the Bottom of the Page

By: SethCardoza - Published: 2010-02-16 11:20:45 in Category: Usability

Adding a toolbar pinned to the bottom of the view port is becoming more common for websites. The idea is to add a bit of functionality, making common links easily accessible at any time. The problem is that it can often give the site a false footer, as is the case with CNET.

CNET Toolbar gives website a false bottom.

As you can see with the image above, scrolling to this point of the article can give the reader the impression that this is the end of the article (as it did with me). But, viewing the image below will show you that there is a large amount of content below this point.

The rest of the page after the false bottom.

Because of the design of the rest of the site, mainly the appearance of the header, a reader can mistakenly assume that an article has ended, when they have yet to read the bulk of the content. When adding functionality such as a toolbar like this, make sure you aren't decreasing the usability of the site in the process.

CakePHP Image Helper

By: SethCardoza - Published: 2010-02-09 15:21:43 in Category: CakePHP

I've rewritten my image helper to extend off of CakePHP's built in HTML helper, rather than reinvent the wheel. The major benefit of using this helper is that it determines the image dimensions, if not specified, and applies them to the image tag, which is one of Google's rules to optimize browser rendering.

<?php
/**
 * This class builds an image tag. The main purpose of this is to get the image dimensions and
 * include the appropriate attributes if not specified. This will improve front end performance.
 *
 * @author Seth Cardoza <seth.cardoza@gmail.com>
 * @category image
 * @package helper
 */
class HtmlImageHelper extends AppHelper
{
    var $helpers = array('Html');

    /**
     * Builds html img tag determining width and height if not specified in the
     * attributes parameter.
     *
     * @param string $src relative path to image including the 'img' directory
     * @param array $attributes array of html attributes to apply to the image
     *
     * @access public
     *
     * @return no return value, outputs the img tag
     */
    public function image($src, $attributes = array()) {
        //get width/height via exif data
        //build image html
        if(file_exists(WWW_ROOT . $src)) {
            $image_size = getimagesize(WWW_ROOT . $src);
            if(!array_key_exists('width', $attributes) && array_key_exists('height', $attributes)) {
                $attributes['width'] = ($image_size[0] * $attributes['height']) / $image_size[1];
            } elseif(array_key_exists('width', $attributes) && !array_key_exists('height', $attributes)) {
                $attributes['height'] = ($image_size[1] * $attributes['width']) / $image_size[0];
            } else {
                $attributes['width'] = $image_size[0];
                $attributes['height'] = $image_size[1];
            }
        }

      
        return $this->Html->image($src, $attributes);
    }
}

Download CakePHP HTML Image Helper

Dissecting Yahoo's 10 Things Not to Buy in 2010

By: SethCardoza - Published: 2010-01-07 09:46:44 in Category: General

Yahoo has an article in finance listing 10 items that are pointless to buy in 2010. There are several items on the list that I will definitely still purchase in 2010 despite Yahoo's flawed logic. The first being DVDs. The article states:

On average, DVDs sell for at least $20 each. That's pricier than signing up for Netflix or renting movies from cable providers' on-demand channels.

I've never paid $20 or more for a DVD. Maybe if you are an idiot and go to a specialty shop to buy the DVD the week it comes out, you will end up paying this much for a DVD. I rarely pay more than $10 for DVDs because I don't mind waiting for them to drop in price after their initial release. It's similar for TV shows on DVD. I've never even paid $20 for a season of a TV show on DVD. While I do expect there to be a further decline in DVD purchase because of Blu-ray, Netflix, and Redbox, I see no reason not to buy a DVD if it's something you will enjoy over and over again.

External hard drives are another item listed, stating that online backup services are the way to go. First, never put all your eggs in one basket. You should have more than one backup, and never rely on someone else to do it for you. Secondly, the article even contradicts itself by stating these online backup services are more expensive than external hard drives. These online services have their benefits, but if you just need a backup of documents and pictures get a couple cheap external hard drives, or even better internal hard drives and an external enclosure.

Next up is compact digital cameras. It seems that in 2010 smaller is not better. Yahoo would have you believe that compact digital cameras are going the way of the pager because of bigger and better DSLR cameras. The problem is that DSLR cameras are much more expensive, and much much larger. While I would love to have a DSLR because I enjoy photography, no one is going to want to bring a these to the club, restaurant, party, etc. to take casual picturs with friends and family.

Update: Gareth makes a great point in the comments, while DSLR cameras probably won't replace compact point and shoot models, cell phone cameras are getting better with each generation. I expect them to be a much more likely replacement as it is a device almost everyone has on them at all times anyway.

Last up is CDs. This is the toughest one for me to argue for continuing buying, and is more of a personal preference. I still haven't paid for a digital download of any audio, but have purchased a few CDs as recently as a week ago. Just like DVDs, CDs can be found rather cheap if you don't mind looking around. I like the fact that I have a physical good for my money, for the same or even a lower price than its digital counterpart. It's easy for me to grab one disc and bring it wherever if that's all I want, but I will most likely rip it to my computer and put it on my mp3 player as well.

The average person will most likely be purchasing these items well through this year. While some are adopting newer and better technologies, not everyone needs to, or has the money to as newer technologies are often more expensive.

jQuery Selectors Last and Last-Child

By: SethCardoza - Published: 2009-12-17 22:57:28 in Category: jQuery

jQuery has a plethora of selectors, two of which being :last and :last-child. It should be very obvious that these do not achieve the same goal. Well, I spent the better part of an hour figuring that out. I went down the page of selectors knowing jQuery has a selector for :last-child, and saw :last first. I toyed around with it a bit to no avail. I finally did a couple searches on jQuery last selectors and found out that jQuery also has a :last-child selector, which is what I was really looking for.

The :last selector selects the last element on the page matching the entire selector. The :last-child selector selects all last children matching the entire selector.

$('div p:last') would select the paragraph highlighted in red:

<div>
    <p>Paragraph</p>
    <p>Paragraph</p>
    <p>Paragraph</p>
</div>
<div>
    <p>Paragraph</p>
    <p>Paragraph</p>
    <p>Paragraph</p>
</div>
<div>
    <p>Paragraph</p>
    <p>Paragraph</p>
    <p>Paragraph</p>
</div>

while $('div p:last-child') would select the paragraphs highlighted in red:
<div>
    <p>Paragraph</p>
    <p>Paragraph</p>
    <p>Paragraph</p>
</div>
<div>
    <p>Paragraph</p>
    <p>Paragraph</p>
    <p>Paragraph</p>
</div>
<div>
    <p>Paragraph</p>
    <p>Paragraph</p>
    <p>Paragraph</p>
</div>

eS Accel Shoes Are Painfully Uncomfortable

By: SethCardoza - Published: 2009-12-16 13:18:44 in Category: General

I've had these shoes for a little over 6 months now. I wear them everyday, but the most I will do with them is a lot of walking at the mall or theme park. Not long after I got them, my heels and the balls of my feet would hurt if I stood for more than a few minutes or walked for a long period of time. I contributed it to the fact that I've been getting lazier and lazier with age. I recently got some Dr. Scholl's insoles though, and in the midst of removing the ones that came with my shoes, I notice that they have become almost paper thin. These things have completely broken down with moderate wear. I threw in the Dr. Scholl's insoles and my feet are feeling great again. Don't buy these shoes, ever.

Rest Assured, Your Hand Job Is on Its Way

By: SethCardoza - Published: 2009-12-15 22:29:07 in Category: General

I got this letter from Hand Job customer support today, letting me know that they are working around the clock to deliver my Hand Job, hopefully by Christmas.

Dearest Handjob Consumers,

 

Thank you so much for your orders!

 

Due to many recent inquiries, we would like to take this opportunity to assure you that yes, this is a real product. And yes, you will be receiving your very own genuine Handjobs shortly.

 

We were taken by surprise at the overwhelming response and the number of orders we've received thus far, and we are working very hard to try to get all of your orders to you by Christmas time. Please note that we can make no guarantees, but we will be working around the clock between now and then in an effort to satisfy your wants and desires.

 

We take Handjobs very seriously, and we truly do appreciate each and every one of you for supporting us. And look forward to many new and exciting developments on the HJ front!

 

Thank you again, and we look forward to hearing about all the pleasure your heartwarming Handjobs provide this season! 

 

 

Cheers,

Lisa Q.

Handjob! Customer Service

Comcasts Buys NBC from GE: What Will It Mean for Hulu?

By: SethCardoza - Published: 2009-12-01 20:01:46 in Category: General

You can read the details over at Gizmodo

This is a big deal as Comcast already is a large telecommunications company, and fully or partly owns numerous networks already. The really interesting piece is how this will play out for Hulu. NBC owns a part of it along with Fox Entertainment Group and ABC Inc. It could play out any number of ways, but the two big scenarios I see are:

Comcast could take Hulu and run with it giving it a great head start on the competition. Streaming video content will happen whether the cable companies want it or not. Comcast could nurture the already flourishing product and make a ton of money while staying current with technology.

Comcast could do everything in its power to kill Hulu. This is a likely scenario as Comcast already sees it as competition to its traditional cable services, and rightly so. Comcast could hinder further development for Hulu in order to keep traditional cable afloat, thus setting back quality streaming video content in overall as Hulu is one of the largest providers. After all, why innovate when you can just buy the competition.

While I would prefer the former, as it would benefit everyone the most, given Comcast's track record, I expect the latter to be the more likely scenario.

Driving the Company Vehicle

By: SethCardoza - Published: 2009-11-26 00:16:04 in Category: General

The reputation of your business is very important, especially so when you are a small business. Business big and small have branding on their company vehicles, and many small business have advertising on their personal or family vehicles. If you are one of them, remember this next time are on the road. Make sure you are a responsible and courteous driver, and make sure your employees do the same while in a company vehicle. You might think nothing of cutting someone off, or speeding excessively, or not letting someone into your lane, but they might remember that the Joe's Plumbing truck is the one that cut them off, or nearly caused an accident.

Revenge of the Swine Flu

By: SethCardoza - Published: 2009-11-19 16:57:08 in Category: Comics

Revenge of the Swine Flu

Smashing Magazine and Twitter Ads

By: SethCardoza - Published: 2009-11-18 14:24:28 in Category: General

Yesterday, we saw our first ads via @smashingmag's Twitter feed. There was some outrage about it. People stating they were no longer following them because of it, which I find ridiculous. Smashing Magazine has provided valuable content, tutorials, and information at no charge to its readers. Smashing Magazine needs some way to pay the bills. There may be better ways than advertisements on its site and Twitter feed, but the amount of ads and their placement is by no means unreasonable. I didn't see any of the protesters state that they would gladly pay money for their content for it to be ad free. Smashing Mag quickly posted a poll following the backlash. Initially, it weighed heavily on "No way, I'll unfollow right away!", but the pool seems to have leveled out with the majority of people understanding that "Yes, you need to pay bills eventually." You can view the poll, and let your voice be heard too.

The tweet in question can be found here. As you can see, @smashingmag clearly states that this is an ad. They could have easily pushed this service as something they value without stating that it was a paid advertisement. I like the fact that they are up front about it. Think about how many tweets promote products and services, and now think about how many of them could have been paid for without your knowledge. Think about how many people you follow, and how many tweets come through your stream everyday. I currently follow a modest 59 people, and receive about 200 tweets per day. I don't have time to read every single one of them. Most of any twitter ads will get overlooked as many other tweets do. Twitter ads are not ideal, but depending on their frequency, they are a tolerable way for content providers to make money.

Mythbusters Beer and Liquor Analysis

By: SethCardoza - Published: 2009-11-03 22:34:59 in Category: General

The Mythbusters had a recent episode testing if drinking beer and liquor would make you more sick thann drinking just beer. They got the myth wrong in the first place. The real myth is that if you drink beer before liquor you will get sick, but not if you drink liquor before beer.

Their test had Tory and Grant drink the exact same amount of alcohol whether they were drinking beer or mixing beer and liquor. It should be pretty obvious that consuming the exact same amount of alcohol should yeild the same results.

The reason the real myth holds is because, generally, when someone starts drinking beer, and then switches to liquor, they usually have consumed several beers and have a buzz, and then consume a significant amount of liquor. Liquor usually goes down quicker because it is in more concentrated quantities. When someone drinks beer and then liquor, they generally have a stronger buzz, and aren't downing beers left and right. It doesn't matter if you mix beer and liquor, and in what order you mix them in, if you drink too much alcohol, you will pay the price.

CakePHP HasAndBelongsToMany (HABTM) Checkboxes Instead of Multiple Select

By: SethCardoza - Published: 2009-10-07 21:58:04 in Category: CakePHP

Changing CakePHP's default multiple select for HasAndBelongsToMany (HABTM) relationships to use multiple checkboxes used to be an arduous task. It is now a simple option as follows.

If you have a Post model that has a HABTM relationship with a Tag model, you would use the following line to display multiple checkboxes instead of the default multiple select:

<?php echo $form->input('Tag', array('multiple' => 'checkbox')); ?>

The magic is the array('multiple' => 'checkbox').

As you probably already know, and the reason you were searching for this solution, the multiple checkboxes are much more user friendly than the multiple select.

Akismet API Component for CakePHP 1.2

By: SethCardoza - Published: 2009-09-05 22:32:33 in Category: CakePHP

This is a component for CakePHP 1.2 and PHP 5+ that utilizes the Akismet API to fight comment SPAM. You will need an API key, which can be retrieved from wordpress.com.

<?php
/**
 * This is a component for CakePHP that utilizes the Akismet API
 *
 * See http://akismet.com/development/api/ for more information.
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @author Seth Cardoza <www.sethcardoza.com>
 * @category akismet
 * @package component
 **/

class AkismetComponent extends Object {

    /**
     * @var string
     */
    private $http;

    const API_KEY = '';
    const BASE_URL = 'rest.akismet.com';
    const API_VERSION = '1.1';
    const VERIFY_KEY_ACTION = 'verify-key';
    const COMMENT_CHECK_ACTION = 'comment-check';
    const SUBMIT_SPAM_ACTION = 'submit-spam';
    const SUBMIT_HAM_ACTION = 'submit-ham';

    const APP_USER_AGENT = 'CakePHP/1.2 | Akismet Model 1.0';

    public function __construct() {
        App::Import('Core', 'HttpSocket');
        $this->http =& new HttpSocket();
    }

    public function verifyKey($data) {
        $data = array();
       
        if (!isset($data['blog'])) {
            $data['blog'] = FULL_BASE_URL;
        }
       
        if (!isset($data['key'])) {
            $data['key'] = self::API_KEY;
        }
       
        $uri = 'http://' . self::BASE_URL . '/' . self::API_VERSION . '/' . self::VERIFY_KEY_ACTION;
       
        $request = array('header' => array('User-Agent: ' . self::APP_USER_AGENT));
       
        return $this->http->post($uri, $data, $request);
    }
   
    /**
     * This is just a wrapper function for Akismet::commentCheck(). the return result makes more sense calling this function.
     * The two functions can be used interchangeably
     * @param array $comment
     * @return string
     */
    public function isSpam($comment) {
        return $this->commentCheck($comment);
    }
   
    /**
     * returns true if comment is spam, false otherwise
     *
     * From API Documentation: If you are having trouble triggering you can send "viagra-test-123" as the author and it will trigger a true response, always.
     *
     * @param array $comment
     * @return string
     */
    public function commentCheck($comment) {
        return $this->__makeRequest($comment, self::COMMENT_CHECK_ACTION);
    }
   
    /**
     * @param array $comment
     * @return string
     */
    public function submitSpam($comment) {
        return $this->__makeRequest($comment, self::SUBMIT_SPAM_ACTION);
    }
   
    /**
     * @param array $comment
     * @return string
     */   
    public function submitHam($comment) {
        return $this->__makeRequest($comment, self::SUBMIT_HAM_ACTION);
    }
   
    /**
     * this is where the magic happens. this makes the call to get the default info if not set, and
     * makes the request, passing the necessary data
     */
    private function __makeRequest($comment, $action) {
        $comment = $this->__getDefaultData($comment);
       
        $request = array('header' => array('User-Agent: ' . self::APP_USER_AGENT));
       
        $uri = 'http://' . self::API_KEY . '.' . self::BASE_URL . '/' . self::API_VERSION . '/' . $action;
       
        $return = $this->http->post($uri, $comment, $request);
       
        return $return;
    }
   
    private function __getDefaultData($comment) {
        App::import('Component', 'RequestHandler');
        if (!isset($comment['blog'])) {
            $comment['blog'] = FULL_BASE_URL;
        }

        if (!isset($comment['user_ip'])) {
            $comment['user_ip'] = RequestHandlerComponent::getClientIP();
        }
       
        if (!isset($comment['referrer'])) {
            $comment['referrer'] = RequestHandlerComponent::getReferrer();
        }

        if (!isset($comment['user_agent'])) {
            $vars['user_agent'] = env('HTTP_USER_AGENT');
        }
       
        return $comment;
    }
}
?>

Download Akismet Component for CakePHP 1.2