Category Archives: Code

Mootools Gallery ZoomBox Plugin

I needed a simple lightweight Mootools Gallery Lightbox, and after a few googles, I found nothing that suited my needs with out all the extra ‘captions’ and grouping and bloat.

This is a simple zoom from start position type lightbox that uses only the Mootools Core version 1.2.4 at this time but should work with 1.3.x

I have used it on the Glass Effects web page which you can view for a demo.

You will notice on my class, I am adding a CSS class ‘shadow’ to the large image, this is used for basic styling and you can do any CSS you want to it. ( or none at all )

Here is how it is built up;

HTML:

< div id="photos">
	< ul>
		< li>< a href="http://www.glasseffects.co.nz/assets/volume1/2_large.jpg" class="zoomBox" title="Glass Effects - Painted toi toi image on glass splashback">< img src="http://www.glasseffects.co.nz/assets/volume1/2_small.jpg" alt="Glass Effects - Painted toi toi image on glass splashback" />< /a>< /li>
		< li>< a href="http://www.glasseffects.co.nz/assets/volume1/3_large.jpg" class="zoomBox" title="Glass Effects - Uniformed lines on Effects glass splashback">< img src="http://www.glasseffects.co.nz/assets/volume1/3_small.jpg" alt="Glass Effects - Uniformed lines on Effects glass splashback" />< /a>< /li>
		< li>< a href="http://www.glasseffects.co.nz/assets/volume1/5_large.jpg" class="zoomBox" title="Glass Effects - Textured Effect splashback using GlassArt colour #25 Iridium">< img src="http://www.glasseffects.co.nz/assets/volume1/5_small.jpg" alt="Glass Effects - Textured Effect splashback using GlassArt colour #25 Iridium" />< /a>< li>
		< li>< a href="http://www.glasseffects.co.nz/assets/volume1/6_large.jpg" class="zoomBox" title="Glass Effects - Stencilled Effect – toi toi. GJ Gardner Show Home, Tauranga">< img src="http://www.glasseffects.co.nz/assets/volume1/6_small.jpg" alt="Glass Effects - Stencilled Effect – toi toi. GJ Gardner Show Home, Tauranga" />< /a>< /li>
		< li>< a href="http://www.glasseffects.co.nz/assets/volume1/7_large.jpg" class="zoomBox" title="Glass Effects - Painted glass for bar. GlassArt colour #49 Red Red Red">< img src="http://www.glasseffects.co.nz/assets/volume1/7_small.jpg" alt="Glass Effects - Painted glass for bar. GlassArt colour #49 Red Red Red" />< /a>< /li>
	< /ul>
< /div>

JS ( In Page ):


window.addEvent('domready', function() {

	/* Any other JS needed for your page */
	
	var myZoomBox = new zoomBox();


	/* to set options */
	
	var myZoomBox = new zoomBox({
		zb_class:     '.mootools-ftw',
		zb_element:   'big_image',
		zb_loader:    './loading.gif'
	});

});

ZoomBox Class:

// Create the Mootools ZoomBox Class
var zoomBox = new Class({
	
	Implements : Options,
	// Editable Settings
    options: {
		zb_class:     '.zoomBox',                    // class of anchors/images to find on page.
		zb_element:   'zb_image',                    // id of zppmBox pop-up div
		zb_loader:    '/assets/images/loading.gif',  // path to loading image
		scale_image:  true,                          // scale large image if it is bigger than our screen size, bool true/false
		win_width:    1024,                          // basic window width, ignore
		win_height:   768                            // basic window height, ignore
    },

	initialize: function(options){
		// set options and internal settings
		this.setOptions(options);
		this.setWindowSize();
		this.currentIndex;
		this.images = new Array();
		this.positions = new Array();
		
		// create our loading image
		this.zb_loading = new Element('img', { 
			'id'    : 'zb_loading', 
			'src'   : this.options.zb_loader,
			'styles': { 
				'position': 'absolute',
				'display' : 'none',
				'left'    : 0,
				'top'     : 0
			}
		}).inject(document.body, 'bottom');

		// scan page for our class.
		this.thumbs = $$(this.options.zb_class);
		
		var self = this;
		
		// attach each image.
		this.thumbs.each(function(zb, index) {
			self.attach(zb, index);
		});
		
		// add event listener if the user resizes their window to scale max size of images.
		window.addEvent('resize', self.setWindowSize.bindWithEvent(this));
		
	},
	
	
	// attach out image and add event listeners.
	attach: function(zb, index) {
		var self     = this;
		// is we manually attach a new element this is needed.
		if(index == undefined) {
			index = (self.length + 1);
		}
		// set our basic width/heights.
		var zb_fx;
		var zb_src   = zb.get('href');
		var zb_org   = zb.getElements('img')[0];
		self.positions[index] = {};
		self.positions[index].zb_left = zb_org.getPosition().x;
		self.positions[index].zb_top  = zb_org.getPosition().y;
		// add out click event.
		zb.addEvent('click', function(clk) {
			new Event(clk).stop();
			// no point opening it, if its already open !
			if(!document.id(self.options.zb_element) || !document.id(self.options.zb_element).get('src').match(zb.get('href'))) {
				// add out loading gif to the image about to be opened.
				self.zb_loading.setStyles({
					'display' : '',
					'top'     : self.positions[index].zb_top,
					'left'    : self.positions[index].zb_left
				});
				// if we have one open, let it be gone
				if(document.id(self.options.zb_element)) {
					self.close(self.currentIndex);
				}
				// set current index.
				self.currentIndex = index;
				// create and place on top of the thumbnail. but keep it hidden.
				self.images[index] = new Element('img', { 
					'id'    : self.options.zb_element, 
					'src'   : zb_src,
					'styles': { 
						'position': 'absolute',
						'opacity' : 0,
						'left'    : self.positions[index].zb_left,
						'top'     : self.positions[index].zb_top
					}
				})
				.addClass('shadow') // we don't need this. but its basic styling for large image.
				.inject(document.body, 'bottom') // inject at teh bottom of our page.
				.addEvent('click', function(clk) {
					// bind out close even on clicking the new large image
					new Event(clk).stop();
					self.close(index);
				})
				// bind a load event so once the large image has loaded, we open it.
				.addEvent('load', function() {
					// get our large image size
					var zb_width  = self.images[index].getWidth();
					var zb_height = self.images[index].getHeight();
					// see if we need to scale it, so the image fits on screen.
					if(self.options.scale_image) {
						if(self.options.win_width < zb_width) {
							zb_width  = (self.options.win_width - 50);
							zb_height = (zb_width / zb_height) * zb_width;
						} 
						if(self.options.win_height < zb_height) {
							zb_height = Math.floor(self.options.win_height - 50);
							zb_width  = Math.floor((zb_height / zb_width) * zb_height);
						}
					}
					// set the imahe the size of the thumbnail
					self.images[index].setStyles({
						'width'   : zb_org.getWidth(),
						'height'  : zb_org.getHeight(),
						'cursor'  : 'pointer'
					});
					// hide teh loading gif/indicator 
					self.zb_loading.setStyle('display', 'none');
					// animate it BIG ! and center it on the screen
					var zb_fx = new Fx.Morph(self.images[index]).start({
						'top'     : ((self.options.win_height / 2) - (zb_height / 2)) + window.getScroll().y,
						'left'    : ((self.options.win_width / 2) - (zb_width / 2)),
						'width'   : zb_width,
						'height'  : zb_height,
						'opacity' : 1
					});
				});
			} else {
				// we have used it before, lets load it up.
				self.images[index].fireEvent('load');
			}
			// bind the 'escape' key to close the current image.
			window.addEvent('keyup', function(key) {
				if(key.code == 27) {
					self.close(index);
				} 
			});
		});
	},
	
	close: function(index) {
		var self = this;
		var zb_fx = new Fx.Morph(self.images[index], { 
			onComplete: function() {
				document.id(self.options.zb_element)
					.fade(0)
					.dispose();
			} 
		}).start({
			'top'     : self.positions[index].zb_top,
			'left'    : self.positions[index].zb_left,
			'width'   : 100,
			'height'  : 100,
			'opacity' : 0
		});
		window.removeEvents('keyup');
	},
	
	setWindowSize: function() {
		
		this.options.win_width = window.getWidth();
		this.options.win_height = window.getHeight();
		
	}
	
});

Download the Full Script:
[download id="11"]

Use PHP to find your mobile browser

I needed a quick way to include different files based on the if the visitor to a site is on a mobile device or a regular browser/computer.

Every browser has a user agent depending on the operating system, browser and system.

below are some common use agents, they can be found by echoing the server variable HTTP_USER_AGENT

< ?php echo $_SERVER['HTTP_USER_AGENT']; ?>

FireFox

Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7

Safari Mac

Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-en) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10 

Safari Windows

Mozilla/5.0 (Windows; U; Windows NT 6.0; en) AppleWebKit/522.13.1 (KHTML, like Gecko) Version/3.0.2 Safari/522.13.1 

Nexus One

Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD56C) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

Apple iPhone

Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3

Apple iPod Touch

Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A100a Safari/419.3 

Internet Explorer

Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.2; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)

PHP mobileAgent() Function

Here is my function, is it simple PHP function, is expects one paramerter, and array or expected user agents, but by leaving it blank, the function will use the default user agents.

Update: I have added more mobile user agents for older Android models, Blackberrry’s and the iPhone simulator. .

< ?php
	function mobileAgent($custom_agents = array()) {

		$agents = array_merge($custom_agents, array(
			'iphone',           // Apple iPhone
			'ipod',             // Apple iPod touch
			'aspen',            // iPhone simulator
			'nexus',            // Nexus One Android
			'dream',            // Pre 1.5 Android
			'android',          // 1.5+ Android
			'cupcake',          // 1.5+ Android
			'blackberry9500',   // Storm
			'blackberry9530',   // Storm
			'opera mini',       // Opera mobile
			'webos',            //  Nokia Browser
			'incognito',        // Other iPhone browser
			'webmate'           // Other iPhone browser
		));
		$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
		foreach($agents as $agent) if(strpos($user_agent, $agent)) return TRUE;
		return FALSE;

	}
?>

Usage

	< ?php if(mobileAgent()): ?>
	
	
	< ?php else: ?>
	
	< ?php endif; ?>

Javascript URI Address Segment Selection

I use the great CodeIgniter, PHP Framework a lot, Most site’s now days I create use it. One of the many good things is that way it handles pages request’s and PHP $_SERVER['REQUEST_URI'] to find which page we are on.

Here is how it works;

http://www.sheldon.lendrum.co.nz/posts/my-segment/my-page/15/2009/12

Now the way we do things, is break the site up, based on the ‘segments or the URI.
EG:
I am in the ‘posts ( segment 1 )’ part of the site. from ther directs to to the particular post I am on.

Here is some VERY simple javascript to find out any segment I am in.

var currentLocation = window.location.toString();  // find out what page we are on
var hostName = 'http://'+ window.location.hostname; // find our current domain name
var uriString = currentLocation.replace(hostName, '');  // get our segments minus our domain name
var uriSegment = uriString.split('/'); create our segment array

A simple example of usage would be, if you were using a GREAT MOOTOOLS accordion for your navigation, and having one open, based on the address of your page

// set out Accordion toggler elements
var togglers = $$('h3.toggler');

// set out menu var
var showMenu;

// loop our toggler elements, and see if our URI segment matches their name ( in my example. )
togglers.each(function(item, index){
        if(item.get('html').toLowerCase() == uriSegment[1]) showMenu = index;
});

// if our URI segment matched nothing, set a default ( closed in my example )
if(showMenu == undefined) showMenu = -1;

// create our Accordion
new Accordion(togglers , $$('ul.element'), {
        duration: 250,
        display: showMenu,
        initialDisplayFx: false,
        onActive: function(toggler, element) {
                toggler.set('class', 'active');
        },
        onBackground: function(toggler, element) {
              toggler.set('class', '');
        }
});

Use PHP and the GD Library to make CSS Sprites

I came across some neat free Icons a couple of day’s ago. I found 178 free icons by WooThemes.

They suited my needs for some navigation icons I was after, so after a quick download, I have them all. Great.

Now, when I code, I’m all about speed of page loads with our reducing quality of course. So more and more and with that I have been using CSS sprites for images, the Less requests, the faster a page loads. there are hundreds of articles explaining this sort of thing, like only use 1 CSS file, putting your Javascript at the bottom, I use them, I even have written a Mootools extensions for embedding Google Analytic in to my sites, that secretly embed the GA code after the page has loaded so its doesn’t slow down the rest of your site from loading, tracking external links and form submits, but any how that is for another post.

178 PNG icons

After extracting the ZIP, I found 178 separate icon files, and I wanted a gray-scale version of each for a hover state, that would mean up to 356 requests plus all of the rest of the images on that page.
Now of course I’m not going to use every Icon, but you never know !

Using PHP & the GD Library to make my Sprite

I must Credit Sandy for his awesomeness and contribution to this script.

< ?php
		function spriter($dir = '*.png', $dest = 'sprite.png', $spacing = 0) {

			// define icons sizes
			$icon_width = 32;
			$icon_height = 32;

			// start height of my sprite canvas
			$height = 0;

			// select all the icons and read theri height to build our canvas size.
			foreach (glob($dir) as $file) {
				list($w, $h) = getimagesize($file);
				// make sure out icon is a 32px sq icon
				if ($h == $icon_height)
					$height += ($h + $spacing);
			}

			// double our canvas height to allow for a gray-scale versions.
			$height = ($height * 2);

			// create our canvas
			$img = imagecreatetruecolor($icon_width, $height);
			$background = imagecolorallocatealpha($img, 255, 255, 255, 127);
			imagefill($img, 0, 0, $background);
			imagealphablending($img, false);
			imagesavealpha($img, true);

			// start placing our icons from the top down.
			$pos = 0;
			foreach (glob($dir) as $file) {
				$tmp = imagecreatefrompng($file);
				if (imagesy($tmp) == $icon_height) {
					imagecopy($img, $tmp, 0, $pos, 0, 0, $icon_width, $icon_height);
					$pos += ($icon_height + $spacing);
				}
				imagedestroy($tmp);
			}

			// place all of our icons on again, but this time convert them to gray-scale
			foreach (glob($dir) as $file) {
				$tmp = imagecreatefrompng($file);
				if (imagesy($tmp) == $icon_height) {
					imagefilter($tmp, IMG_FILTER_GRAYSCALE);
					imagecopy($img, $tmp, 0, $pos, 0, 0, $icon_width, $icon_height);
					$pos +=  ($icon_height + $spacing);
				}
				imagedestroy($tmp);
			}

			// create our final output image.
			imagepng($img, $dest);
		}

Sample Usage

< ?php
// IMPORTANT:  REMEMBER TO MAKE SURE THE WEBSERVER HAS WRITE ACCESS TO YOUR DESTINATION DIRECTORY.

spriter('icons/*.png', 'icons/sprite.png', 10);

Show our Sprite

icons/sprite.png

Basic REGEX for cleaning and prepping data

Over the last year or so, I have used a PHP Framework Code Igniter, Amongst many of its good features is its built in Form Validation Library.

Every now and then I either write a a small site out of Code Ignite, or help others to write or develop sections of their site, I constantly get MSN/IM messages asking for help which I am happy to help.

More recently I have started compiling a list of the little help functions I have written to generate my own ‘Form Validation’ Class, I hope to post it here soon.

Today though I have been doing a lot of Code Igniter validation, with some extra ‘callbacks’ using regex/preg_match & preg_replace combos,

Note: This is not are Regex tutorial, just some basic common examples.

Basic Examples

Strip non-numeric characters from a string.

< ?php

$string = 'sheldon is not james bond 007';
$numbers = preg_replace('/[^0-9]+/', '', $string);
// returns '007';
?>

Strip all none numeric and alpha characters from a string

$string = 'sheldon, Is james bond (007)';
$numbers = preg_replace('/^([a-z0-9])+$/i' '', $string); // the i means case insensitive.
// returns 'sheldon Is james bond 007';
?>

Create a safe URL string.

want to make url safe permalinks or strings?
lets strip out anything that’ll break our address.

// assume $_POST['name'] = "sheldon's wonderful *product* costs $19.95";
$name = str_replace(' ', '-', trim($_POST['name']));
$url = preg_replace('/^([a-z0-9-_])+$/i', '', $name);

header("Location: http://sheldon.lendrum.co.nz/". $url);
//  http://sheldon.lendrum.co.nz/sheldons-wonderful-product-costs-19.95
?>

preg_replace() & preg_match()

I have used preg_replace() to strip out the unwanted tags, but if you just want to validation against with out altering the users data, you can use preg_match().

Here is an example to make sure a user has only submitted a trough z and 0 trough 9 characters and spaces.

< ?php
// assume $_POST['name'] = "sheldon's wonderful *product* costs $19.95";
if(preg_match('/^([a-z0-9\ ])+$/i',  $_POST['name'])) {
	// valid data ( spaces are allowed. )
	// case insative
	echo('Validation Passed');
} else {
	// this was invalid data
	echo('Please enter a valid string.');
}
?>

In this example, our string would fail.

We allowed spaces in our test, to run the same match with out allowing spaces, re can remove the ‘\ ‘ form the Regex.

Here is an example to make sure a user has only submitted a trough z and 0 trough 0 characters .

< ?php
// assume $_POST['name'] = "sheldon";
if(preg_match('/^([a-z0-9])+$/i',  $_POST['name'])) {
	// valid data ( spaces are  NOT allowed. )
	// case insative
	echo('Validation Passed');
} else {
	// this was invalid data
	echo('Please enter a valid string.');
}
?>

In this example, our post data would pass the validation.