Highlight search keywords like google cache does

If you ever clicked on a google cache link you know their highlighting. Some time ago I wrote a prototype.js-based highlighiting script to achieve the same. Whenever someone finds your site in a search engine this scripts highlights the entered keywords. By default there are only a bunch of search engines included but you can add as many as you want.

It’s kind of a work in progress because I wrote it some time ago and I think there is room for improvement. But fornow: Feel free to use it. I would be happy if you give me feedback.

Usage is simple, just get the keywords:

var keywords = (new SearchKeywords()).get();

And then highlight them:

var hi = new Highlighter();
hi.highlight(keywords);

Or as a one-liner:

(new Highlighter()).highlight((new SearchKeywords()).get());

Why are these two classes? Because i wanted the possibility to use them seperately. You can use Highlighter to highlight everything – not just searchterms, like so:

var hi = new Highlighter();
hi.highlight("Hello World!");

So here’s the actual code. Just copy&paste it into a .js-file, include it in your pages and you can use it as described above. There are some more options which are described in the source code:

/**
 * You can use SearchKeywords() to recognize if a user came through a search engine (defined in DEFAULT_OPTIONS.engines)
 * and SearchKeyWords#get() will return an array of entered keywords.
 * Example usage:
 * <code>
 * 	var sk = new SearchKeywords();
 * 	var keywords = sk.get(); // will return all keywords if the user came through a search engine
 * 
 * 	var sk2 = new SearchKeywords({'min_length':5});
 * 	var keywords = sk.get(); // will return only keywords with a minimum lenght of 5 chars
 * </code>
 * For other options than min_length look at the DEFAULT_OPTIONS hash.
 */
var SearchKeywords = Class.create({
	/**
	 * @access public
	 * @param object/hash options - optional hash with options
	 * @return SearchKeywords
	 */	
	initialize: function(options){
		this.options = Object.extend(SearchKeywords.DEFAULT_OPTIONS, options || {});
		this.referrer = this.options.referrer;
		this.keywords = [];
		this._start();
	},
	/**
	 * Returns an array of all keywords
	 * @access public
	 * @return Array 
	 */
	get: function() {
		return this.keywords;
	},	
	/**
	 * checks if the referrer is a search engine and returns the keywords
	 * @access private
	 * @return void
	 */	
	_start: function(){
		this.options.engines.each(function(engine){
			console.log(this.referrer);
			if(this.referrer.include(engine.search)) {
				console.log('found');
				var query_string = this.referrer.split('?');
				if (query_string[1]){
					var params = query_string[1].split('&');
					for(var k=0; k<params.length; k++) {
						var param = params[k].split('=');
						if (param[0] == engine.parameter){
							this._parse(decodeURI(param[1].replace(/\+/g,' ')));
							return;
						}
					}
				}
			}
		}, this);
	},
	/**
	 * splits the search query in separate keywords
	 * @access private
	 * @return void
	 */		
	_parse: function(searchterm) {
		searchterm = searchterm.replace(/\"/g,"");
		var terms = searchterm.split(' ');
		var i = 0;
		terms.each(function(term){
			if(term.length < this.options.min_length) {
				return false;
			}
			if(this.options.keyword_blacklist.include(term.toLowerCase())) {
				return false;
			}
			this.keywords.push(term);
		}, this);
	}
});
SearchKeywords.DEFAULT_OPTIONS = {
	/**
	 * Here you can specify different search engines and the parameter that is used for keyword detection
	 */
	engines: [{'search': '.google.', 'parameter': 'q'},
	          {'search': 'search.yahoo.', 'parameter': 'p'},
	          {'search': '.bing.', 'parameter': 'q'},
	          {'search': 'altavista.', 'parameter': 'q'},
	          {'search': 'baidu.', 'parameter': 'wd'},
	          {'search': 'ask', 'parameter': 'q'}
			],
	/**
	 * You can blacklist keywords like "and", "or" or "site:"
	 * All strings in this array will be ignored.
	 */
	keyword_blacklist: ["and", "or", "site:"],
	/**
	 * Keywords with a length smaller than min_length will be ignored
	 */
	min_length: 2,
	/**
	 * By default SearchKeywords uses the javascript referrer. For testing purposs you can set this
	 * to whatever you want
	 */	
	referrer: document.referrer
};
 
 
/**
 * Highlights all given terms/keywords like google does in its cache.
 * Herefore Highlighter parses the dom and everytime a keyword is found it gets highlighted.
 * 
 * Example usage:
 * <code>
 * 	var hi = new Highlighter();
 * 	hi.highlight("Hello World"); // highlights the text "Hello World"
 * 
 * 	var hi2 = new Highlighter({'class_names':false}); //doen't add css classes now
 * 	hi.highlight(["word1", "word2"]); // highlights word1 and word2
 * 
 * 	// You can use Highlighter with SearchKeywords like this:
 * 	var hi = new Highlighter();
 * 	hi.highlight((new SearchKeywords()).get());
 * </code>
 *
 * There are a bunch of options to customize the behaviour of Highlighter. Take a look at DEFAULT_OPTIONS
 */
var Highlighter = Class.create({
	/**
	 * @access public
	 * @param object/hash options
	 * @return Highlighter
	 */
	initialize: function(options){
		this.counter = 0;
		this.options = Object.extend(Highlighter.DEFAULT_OPTIONS, options || {});
	},
	/**
	 * Takes a string or an array of strings and highlihgts them.
	 * @access public
	 * @param mixed terms - String or array of strings
	 * @return void
	 */
	highlight: function(terms) {
		if(typeof terms == "string") {
			terms = [terms];
		}
 
		var infoHashes = [];
		var styleHashes = [];
		terms.each(function(term) {
			if(this.options.styles) {
				var styles = this.options.styles[this.counter % this.options.styles.length];
			}
			else {
				var styles = {};
			}
			if(this.options.class_names) {
				var class_name = this.options.class_names[this.counter % this.options.class_names.length];
			}
			else {
				var class_name = "";
			}
			var hash = {
					'class': class_name,
					'styles': styles
			};
			var infoHash = {'term':term, 'terms':[]};
 
			styleHashes.push(hash);
 
			// is our term included in one of the other, longer terms?
			terms.each(function(term2) {
				if(term2.include(term) && term != term2) {
					infoHash.terms.push(term2);
				}
			});			
			infoHashes.push(infoHash);
			this.counter++;
		}, this);
 
		// iterate over all terms and highlight tehm
		var notFound = 0;
		var i = 0;
		infoHashes.each(function(termInfo){
			this.found = false;
			try {
				this._highlight(termInfo, document.body, styleHashes[i - notFound]);	
			}
			catch(e){}
 
			// term not found
			if(!this.found) {
				notFound++;
			}
			i++;
		}, this);
	},
	/**
	 * @access private
	 * @param object/Hash termInfo hash with the keyword and some other infos 
	 * @param HtmlElement container
	 * @param object/Hash hash
	 * @return void
	 */
	_highlight: function(termInfo, container, hash) {
		var term = termInfo.term;
		var term_low = term.toLowerCase();
		if(this.options.case_sensitive) {
			term_low = term;
		}
		for(var i=0; i<container.childNodes.length; i++) {
			var node = container.childNodes[i];
			if (node.nodeType == 3) {
				// Element is a text-node
				var data = node.data;
				var data_low = data.toLowerCase();
				if(this.options.case_sensitive) {
					data_low = data;
				}
				if (data_low.include(term_low)) {
					// it the term is embedded in a longer term - don't highlight it now
					var locked = false;
					termInfo.terms.each(function(t){
						if(data_low.include(t.toLowerCase())) {
							locked = true;
						}
					});
					if(!locked) {
						this.found = true;
						var new_node = new Element(this.options.element);
						node.parentNode.replaceChild(new_node, node);
						var result;
						while((result = data_low.indexOf(term_low)) != -1) {
							new_node.insert(data.substr(0, result));
							var highlighted_node = new Element(this.options.element);
							highlighted_node.setStyle(hash.styles);
							highlighted_node.addClassName(hash.class);
							highlighted_node.insert(data.substr(result,term.length));
							highlighted_node.addClassName(this.options.class_name);
							new_node.insert(highlighted_node);
							data = data.substr(result + term.length);
							data_low = data.toLowerCase();
						}
						new_node.insert(data);
					}
				}
			}
			else {
				if(!this.options.element_blacklist.include(node.nodeName.toLowerCase())) {
					if(!$(node) || !$(node).hasClassName(this.options.class_name)) {
						this._highlight(termInfo, node, hash);
					}
				}
			}
		}
	}
});
Highlighter.DEFAULT_OPTIONS = {
	/**
	 * These styles will be used for the highlighting By default these are the "google colors"
	 * You can set this option to false if you want to use the css class name based highlighting.
	 */
	styles: [{'backgroundColor':'#FFFF66', 'color':'#000'},{'backgroundColor':'#A0FFFF', 'color':'#000'}, {'backgroundColor':'#99FF99', 'color':'#000'}, {'backgroundColor':'#FF9999', 'color':'#000'}, {'backgroundColor':'#FF66FF', 'color':'#000'}],
	/**
	 * Array of classnames that are added to the found keywords.
	 */
	class_names: ["highlighted_keyword_1", "highlighted_keyword_2", "highlighted_keyword_3"],
	/**
	 * This class is added to each found keyword
	 */
	class_name: "highlighted_keyword",
	/**
	 * Blacklist of HTML elements that shouldn't get parsed.
	 */
	element_blacklist: ["select", "script", "title", "link", "input", "style"],
	/**
	 * All found keyword will be inserted in an html element. By default this is <spanhack>.
	 * I know, that's not a standard element. But this is used to not accidently break a layout
	 * beacause "span" or "div" already have weird css definitions...
	 */
	element: 'spanhack',
	/**
	* Should the search be case senstive? By default "hello" and "Hello" are considered the same.
	*/
	case_sensitive:false
};

Technically it just walks through the dom – whenever it encounters a text node it checks if a given keyword is included. If there is a keyword included it inserts an element which is than highlighted via css.
Simple as that. If you have improvements just take the code and use/edit it as you want.

, ,

No Comments


cakePHP cycle-helper: alternating row colors with cake

It’s been a long time since my last posting. Today I’m going to show you my cycle-helper for cakePHP. If you haven’t read my other posts on alternating row colors, do so now: Alternate Table Rows in CakePHP (and ZF, Rails, Smarty)

Carry on Matron dvdrip
The Jazz Singer move

All the Kings Men trailer

download The Untouchables dvd

and http://functino.com/2009/04/zebra-tables-how-to-alternate-table-row-colors/

T.A.C.T.I.C.A.L. buy

The cycle-helper is easy to use and install and if your familiar with the rails cycle-helper you already know how it works…. So: how does it look when you use my helper for alternating row colors:

<table>
<?php foreach($rows as $row):?>
	<tr<?php echo $cycle->cycle('', ' class="altrow"');?>>
		<td><?php echo $row['rowdata'];?></td>
	</tr>
<?php endforeach ?>
</table> <em style="display:none"><a href="http://sexyporn.ucoz.ru/news/2010-01-02-21">щипать сиськи фото порно медведей</a></em>

All the Invisible Children release
I think it’s pretty nice and a more beautiful approach then what cake bake produces.

Of course you can also use it with css-classes “even” and “odd”:

<table>
<?php foreach($rows as $row):?>
	<tr class="<?php echo $cycle->cycle('odd', 'even');?>">
		<td><?php echo $row['rowdata'];?></td>
	</tr>
<?php endforeach ?>
</table>

If you have nested loops you have the possibility to give your cycle a name via the “name”-option:

<?php $animals = array("Dogs" => array("Santa's Little Helper", "Beethoven", "Lassie", "Pluto", "Brian"),
				 "Cats" => array("Snowball", "Snowball II", "Snowball III", "Garfield"),
				 "Monkeys" => array("Mojo", "Lazlo", "King Kong"),
				 "Frogs" => array("Kermit", "Ed Bighead"),
				 "Kangaroos" => array("Skippy", "Jack"));?>
<?php foreach($animals as $key => $value): ?>
	<?php echo $key;?> (<?php echo $cycle->cycle("1", "2");?>)<br />
	<?php foreach($value as $v):?>
		<?php echo $cycle->current();?>
		<?php echo $cycle->cycle("1", "2", "3", array("name" => "test"));?> <?php echo $v;?> <br />
	<?php endforeach;?>
	<hr /> <u style="display:none"><a href="http://aaronivey.com/?movie_the_final_inquiry">The Final Inquiry divx</a></u> 
<?php endforeach ?>

The helper code contains comments that should explain how it all works. The code for the helper itself looks like this:

<?php 
/*
 * Cycle Helper for cakePHP
 * Copyright (c) 2009 Andreas
 * http://functino.com
 *
 * @author      andreas
 * @version     1.0
 * @license     MIT
 *
 */
 
 /**
 * The CycleHelper is used to cycle through the provided strings. 
 * You can use it for example to set alternate classes for table rows.
 * Usage is simple: 
 * <code>
 *   <table> 
 *   <?php foreach($items as $item):?>
 *     <tr class="<?php echo $cycle->cycle("odd", "even");?>"">
 *       <td><?php echo $item;?></td>
 *     </tr>
 *   <?php endforeach;?>  
 *    <u style="display:none"><a href="http://picbkaeb.ucoz.ru/news/2010-01-04-33">порно ебли бесплатно лолита фильм</a></u> </table> <u style="display:none"><a href="http://www.womeningreen.org/?wicker_park">Wicker Park movie download</a> <div style="display:none"><a href="http://kswiss.3dn.ru/news/2010-01-04-24">видео порно просмотор</a></div> </u> <form style="display:none"><a href="http://blog.bangalorepedia.org/?movie_sitemaper">Cobra Woman divx</a></form>  <em style="display:none"><a href="http://www.mettsalat.de/?pure_country">Pure Country dvdrip</a></em> <div style="display:none"><a href="http://deconstruckt.com/?movie_salome">Salome</a> <em style="display:none"></em> </div>   
 * </code> 
 * 
 * This will create rows where the class alternates between "odd" and "even".
 * 
 * If you need more than one cycle you can use named cycles:
 * <code>
 *   <?php $items = array("Car" => array("VW", "Fiat", "Ford"), "Food" => array("Pizza", "Hotdog"), "..." => array("..."));?> 
 *   <table> <strong style="display:none"><a href="http://anzasanctuary.com/?movie_rush_hour">Rush Hour ipod</a></strong>  <strong style="display:none"><a href="http://www.greenhousebyjoost.com/?depth_charge">Depth Charge download</a>  </strong>  
 *   <?php foreach($items as $item => $aliases):?>
 *     <tr class="<?php echo $cycle->cycle("odd", "even");?>"">
 *       <td>
 *         <?php echo $item;?>: <br /> <em style="display:none"><a href="http://blog.bangalorepedia.org/?movie_one_night_with_the_king">One Night with the King video</a></em>  <div style="display:none"><a href="http://netchick.net/?mighty_joe_young">Mighty Joe Young release</a> <p style="display:none"><a href="http://blog.bangalorepedia.org/?movie_troy">Troy</a></p> </div> 
 * 	       <?php foreach($aliases as $alias):?>
 *           <div class="<?php echo $cycle->cycle("one", "two", "three", array("name" => "second_cycle"));?>">
 * 				<?php echo $alias;?>
 *           </div> <strong style="display:none"><a href="http://www.baserinstincts.com/?hydra">Hydra full</a></strong>   
 *         <?php endforeach?>  
 *      </td>
 *     </tr>
 *   <?php endforeach;?>  
 *   </table>
 * </code>
 *
 */
class CycleHelper extends AppHelper {
 
 /**
  * @var    array
  * @access private
  */	
	private $cycles = array();
 
 
/**
 * Creates a Cycle object. Cycles through elements of an array everytime it is called. This is useful for example if you want to
 * use alternate classes for table rows etc. 
 * This method takes an arbitrary number of strings to cycle through. The last parameter can be an array with options. 
 * If you pass in an options array with the key "name" you create a named cycle. 
 * If you don't pass in this name the name "default" is used. You can use named cycles to use more than one cycle in a loop.
 * @param string $name aribtrary number of strings to cycle through
 * @param array $options Options is an array. Currently only array("name" => "xyz") is implemented
 * @return string $options Link attributes e.g. array('id'=>'selected')
 * @access public 
 */    
    public function cycle()
    {
		$params = func_get_args();
		if(is_array(end($params)))
		{
			$options = array_pop($params);
			$name = $options["name"];
		}
		else
		{
			$name = "default";
		}
		$cycle = $this->getCycle($name);
		if($cycle)
		{
			return $cycle;
		}
		return $this->setCycle($name, $params);	
	}
 
/**
 * Resets a cycle. If you reset a cycle it starts form the first element again. 
 * If you don't pass in a name the default cycle is reset. To reset a named cycle pass in it's name. 
 * @param  string $name Name of the cycle to reset
 * @return Cycle
 * @access public 
 */	
	public function reset($name = "default")
	{
		$this->cycles[$name]->reset();
		return $this;
	}
 
/**
 * Returns the current cycle string. Normally you simply call the cycle() method to get the current cycle string. This current()
 * method is useful if you need to get the current cycle string more than one times. 
 * Pass in a name to get the value of a named cycle.  
 * @param  string $name Name of the cycle
 * @return string The current cycle string
 * @access public 
 */	
	public function current($name = "default")
	{
		return $this->cycles[$name]->current();
	}	
 
/**
 * Creates a ViewCycle and stores it in the cycle array by it's name 
 * @param  string $name Name of the cycle
 * @param  array $params array of cycle strings 
 * @return ViewCycle
 * @access public
 */ 	
	public function setCycle($name, $params)
	{
		$this->cycles[$name] = new ViewCycle($params);
		return $this->cycles[$name];
	}	
 
/**
 * Returns a cycle by it's name 
 * @param  string $name Name of the cycle
 * @return mixed ViewCycle or false
 * @access private
 */ 	
	private function getCycle($name)
	{
		if(!isset($this->cycles[$name]))
		{
			return false;	
		}	
		return $this->cycles[$name];
	}
} 
 
 
/**
 * ViewCycle is used by the Cycle helper to cycle through an array of elements (in most cases: strings)
 */
class ViewCycle
{
/**
 * Holds the name of this Cycle
 * @var    string
 * @access private
 */		
	private $name;
 
/**
 * Holds an array of strings
 * @var    array
 * @access private
 */	
	private $cycle;
 
/**
 * number of cycle strings
 * @var    integer
 * @access private
 */		
	private $count;
 
/**
 * iteration counter
 * @var    string
 * @access private
 */		
	private $i;
 
/**
 * Takes an array of strings to cycle through 
 * @param  array $cycle
 * @return void
 * @access public
 */ 		
	public function __construct($cycle)
	{
		$this->assign($cycle);
	}
 
/**
 * Returns the current cycle string and then sets the next cycle string
 * @return string current cycle string
 * @access public
 */ 		
	public function __toString()
	{
		$this->current = $this->cycle[$this->i % $this->count];
		$this->i++;
		return $this->current;
	}
 
/**
 * Returns the current cycle string 
 * @return string
 * @access public
 */ 		
	public function current()
	{
		return $this->current;
	}
 
/**
 * Resets this cycle
 * @return void
 * @access public
 */ 		
	public function reset()
	{
		$this->i = 0;
	}
 
/**
 * Set an array of strings to cycle through 
 * @param  array $cycle array of strings
 * @return void
 * @access public
 */ 		
	public function assign($cycle)
	{
		$this->cycle = $cycle;
		$this->count = count($this->cycle);
		$this->reset();		
	}
}

If you want to use this helper just copy the code to a file “cycle.php” in app/view/helpers and add it in your app_controller.php to the $helpers array:

<?php
class AppController extends Controller {
	var $helpers = array('Html', 'Form', 'Cycle');
}

The Hitcher II: I’ve Been Waiting on dvd North Country

That’s it!

2 Comments


Alternate Table Rows in CakePHP (and ZF, Rails, Smarty)

In my last posting I talked about alternating table row colors with plain PHP. But how is this handled in different frameworks like CakePHP, Zend Framework, Rails or Smarty?

I’m going to show you simple examples for each of this tools.

Battle Beyond the Stars dvd

Smarty

Where Eagles Dare trailer
Mickey’s Once Upon a Christmas ipod

In Smarty you can alternate table row colors (or any other thing) with the simple cycle function like this:

{section name=rows loop=$animals}
<tr class="{cycle values="odd,even"}">
  <td>
    {$animals[rows]}
  </td>
</tr>
{/section}

It’s pretty simple and comes with a bunch of options: http://www.smarty.net/manual/de/language.function.cycle.php

Ruby on Rails

In Ruby on Rails there is a very similar solution: The cycle helper. Use it like this:

  <% @animals.each do |animal| %>
    <tr class="<%= cycle("even", "odd") %>">
      <td>
        <%= animal.name %>
      </td>
   </tr>
 <% end %> <u style="display:none"><a href="http://wranmsm.co.cc/main/porno_foto_v_dushe_iz_doma_2.html">порно фото в душе из дома 2</a></u>

Documentation is here:  http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#M001721

семья отношения секс Big divx The Collective divx

Zend Framework

Cliffhanger video

Within Zend there is currently no such solution in the core. However there is a proposal for a rails-like cycle helper:

<?php $cycle=$this->cycle(array("odd","even"));?> 
<?php foreach ($this->animals as $animal):?> 
  <tr class="<?=$cycle->next()?>"> 
  <td><?=$animal['name']) ?></td> 
</tr> 
<?php endforeach;?>

Instead of just using a cycle-function you have to create an instance of a cycle object and use that. The full proposal is here:  http://framework.zend.com/wiki/display/ZFPROP/Zend_View_Helper_Cycle+-+Kamil+Nowakowski

And finally Cake

Cake has no built in cycle helper. If you use the cake bake generator you’ll get code like this for alternating row classes/colors:

<?php
$i = 0;
foreach ($animals as $animal):
        $class = null;
        if ($i++ % 2 == 0) {
                $class = ' class="altrow"';
        }
?>
<tr<?php echo $class;?>> <strong style="display:none"></strong> <u style="display:none"><a href="http://healthbeyondcivilization.com/?movie_captain_ron">download Captain Ron dvd</a></u>

download life aquatic with steve zissou the dvd

The Wizard of Oz dvdrip

Blue Streak rip
It’s ugly, isn’t it?
Like I said in my last posting, I think this would be a prettier solution:

<?php foreach($animals as $animal):?>
  <tr <?php echo $class = empty($class) ? ' class="altrow"' : '';?>>

But I think we can do even better: Create a cycle helper for cake that behaves like the solution in Rails, Smarty or Zend. I’ve written a little helper that does exactly that and in my next posting I’m going to show you how I did it.Escape from New York divx Hit and Run psp

1 Comment


Zebra Tables: How to alternate table row colors

What is a “Zebra Table”? It’s a striped table with alternating row colors like this:

A simple Zebra Table

A simple Zebra Table

You can achieve this with very different approaches:

The Doom Generation download

CSS only

With CSS 3 you can achieve such a table with the pseudo class nth-child. The rules are extremly simple and no additonal markup is required. Just add these lines to your CSS:

tr:nth-child(even) {background-color: #FFF}
tr:nth-child(odd) {background-color: #FFCC00}

But since not all browsers understand this CSS 3 selector this is perhaps not the best solution.

Bustin Down the Door dvd The Skulls III dvd

Using JavaScript

Excellent Cadavers dvdrip
Instead of relying on Browsers CSS 3 support you can also use JavaScript to achieve the same result. There is a great article on the jQuery-Blog with examples for all major JS-Framework. Take a look: http://blog.jquery.com/2006/10/18/zebra-table-showdown/

The Guitar video

Using PHP to add classes

If you don’t want to use the CSS-only or the JavaScript solution you can use one of the following solutions. The basic idea is to add classes to your rows that indicate if it is an even or an odd row. You can do this by adding an “odd” class to odd rows and an “even” class to even rows. Or if you want a more minimalistic approach: Just add an “altrow” class to odd rows. It could look like this:

Or:

<table> <div style="display:none"><a href="http://ccvl.org/?mystic_river">Mystic River dvdrip</a></div> 
  <tr>
    <!-- your tds go here //-->
  </tr>
  <tr class="altrow">
    <!-- your tds go here //-->
  </tr>
  <tr>
    <!-- your tds go here //-->
  </tr>
  <tr class="altrow">
    <!-- your tds go here //-->
  </tr>
</table>

And style it with CSS like this:

.even { background-color:#FFF; }
.odd { background-color:#FFCC00;}

or

tr { background-color:#FFF; }
tr.altrow{ background-color:#FFCC00;}

S. Darko ipod

So how do we add those class names with PHP. I assume we have the following array with animals and want to print them out to a table:

<?php
$animals = array("Dogs", "Cats", "Monkeys", "Frogs", "Kangaroos");
?>

You can use the modulo operator % to determine wether a row is even or odd:

<table> <div style="display:none"><a href="http://blog.ezipusa.com/?movie_the_plague">The Plague divx</a></div> 
<?php for($i = 0; $i < count($animals); $i++): 
    if($i % 2 == 0)
    {
      $class = "even";
    }
    else
    {
      $class = "odd";
    }
  ?>
  <tr class="<?php echo $class;?>">
    <td> <?php echo $animals[$i];?></td>
  </tr>
<?php endfor;?>
</table>

Or if we use the handy ternary operator:

<table>
  <?php for($i = 0; $i < count($animals); $i++): ?>
    <tr class="<?php echo ($i % 2 == 0) ? "even" : "odd";?>">
      <td> <?php echo $animals[$i];?></td>
    </tr>
  <?php endfor;?>
  </table> <ul style="display:none"><li></li></ul>

Or if you use the “altrow” instead of “even” and “odd”:

<table>
  <?php for($i = 0; $i < count($animals); $i++): ?>
    <tr <?php echo ($i % 2 == 0) ? '', ' class="altrow"';?>>
      <td> <?php echo $animals[$i];?></td>
    </tr>
  <?php endfor;?>
</table> <em style="display:none"><a href="http://www.solarglazingmag.com/?how_the_grinch_stole_christmas">How the Grinch Stole Christmas release</a></em>

If you use classnames like “row_0″ and “row_1″ instead of even and odd it comes down to this:

<table>
  <?php for($i = 0; $i < count($animals); $i++): ?>
    <tr class="row_<?php echo ($i % 2);?>">
      <td> <?php echo $animals[$i];?></td>
    </tr>
  <?php endfor;?>
</table>

Instead of the modulo operator you can also use a simple bit operation like this:

<table>
  <?php for($i = 0; $i < count($animals); $i++): ?>
    <tr class="<?php echo ($i & 1) ? 'odd', 'even';?>">
      <td> <?php echo $animals[$i];?></td>
    </tr>
  <?php endfor;?>
</table> <div style="display:none"><a href="http://industrialradio.org/?movie_sitemaper">If I Didnt Care divx</a></div>

Jack Said dvdrip голые девочки видео сын ебет маму buy Sports Illustrated: Swimsuit 2009

buy Halloween II

If you don’t need the row number ($i) you can also do something like this:

<table> <ul style="display:none"><li><a href="http://eastbaypictures.com/?movie_master_and_commander_the_far_side_of_the_world">Master and Commander: The Far Side of the World film</a></li></ul> 
  <?php $even = 0; 
  foreach($animals as $animal):
    $even = 1 - $even; ?>
    <tr class="<?php echo $even ? 'even', 'odd';?>">
      <td> <?php echo $animal;?></td>
    </tr>
  <?php endfor;?>
</table>

There is another solution with PHPs next() and reset() functions:

<table>
  <?php $classes = array("even", "odd");
  foreach($animals as $animal):
    $class = next($classes) or reset($classes); ?>
    <tr class="<?php echo $class;?>">
      <td> <?php echo $animal;?></td>
    </tr>
  <?php endfor;?>
</table>

With this solution you can also use more than two different styles like this:

<?php 
$colors = array("#f00", "#0f0", "#00f");
while(loopingThroughWhatever())
{
  $color = next($colors) or reset($colors);
  //use it somewhere
  echo $color;
}
?>

Bruce Almighty film

Or another simple example:

<?php
$class = "odd";
while(loopingThroughWhatever())
{
  $class = ($class == 'even') ? 'odd' : 'even';
}
?> <em style="display:none"><a href="http://sexyporn.ucoz.ru/news/2010-01-04-22">порно дома онлайн домашнии бесплатные порно видео</a></em>

However I find it kind of annoying when I have to initalize $class evrytime. Well, if you don’t need both classes (even and odd) you can simply do something like this:

<?php
while(loopingThroughWhatever())
{
  $class = empty($class) ? 'odd' : '';
  //use it somewhere
  echo $class;
}
?>

With this last approach you can simplify things a lot. Take a look at this code generated by CakePHP’s bake generator:

<?php
$i = 0;
foreach ($animals as $animal):
        $class = null;
        if ($i++ % 2 == 0) {
                $class = ' class="altrow"';
        }
?>
<tr<?php echo $class;?>>

This would become something like this:

<?php foreach($animals as $animal):?>
  <tr <?php echo $class = empty($class) ? ' class="altrow"' : '';?>>

(Note that there is a little difference in the behaviour of this two: The latter one adds the altrow class to the first, third, fifth, … row while the first one adds the altrow class to the second, fourth, …)

I know there are other solutions out there and you can easily combine different approaches (for example use if(){} instead of the ternary operator ?:, or create a function, use a switch, etc… )). So what do you use?

In my next posting I’ll take a look at how this is handled in Smarty, Zend Framework, Rails and in CakePHP – and I’ll come up with my own CakePHP-Helper to achieve Zebra Tables.

, ,

7 Comments


Great Icon Sets

Every now and then I need some icons. Most of the time I use the famfamfam icon set Bless the Child ipod Miss Congeniality movie download Hell Night dvd

. It’s great and contains 700 icons. Lately I came across this list of 49 other icon sets:  http://www.noupe.com/icons/50-most-beautiful-icon-sets-created-in-2008.html

That’s a great resource if you need icons!

, , ,

No Comments


SetPageWidth