<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Martini Lab Blog &#187; Apple</title>
	<atom:link href="http://www.martinilab.com/blog/tag/apple/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.martinilab.com/blog</link>
	<description>Web design, CSS, scripting, Adobe, tips and other scraps of things that come my way</description>
	<lastBuildDate>Fri, 20 Aug 2010 20:58:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Mobile Safari needs a little jQuery .live() love</title>
		<link>http://www.martinilab.com/blog/209/mobile-safari-needs-a-little-jquery-live-love/</link>
		<comments>http://www.martinilab.com/blog/209/mobile-safari-needs-a-little-jquery-live-love/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 22:53:08 +0000</pubDate>
		<dc:creator>Chris Williams</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[WebKit]]></category>

		<guid isPermaLink="false">http://www.martinilab.com/blog/?p=209</guid>
		<description><![CDATA[file under: the importance of device testing Just a quick note about how Mobile Safari gets along with .live(). As a matter of coding style, I usually assign my actions to links and buttons. Sometimes I don’t. &#60;li&#62;Title of Something &#8230; <a href="http://www.martinilab.com/blog/209/mobile-safari-needs-a-little-jquery-live-love/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em>file under: the importance of device testing</em></p>
<p>Just a quick note about how Mobile Safari gets along with <code>.live()</code>.  As a matter of coding style, I usually assign my actions to links and buttons.  Sometimes I don’t.</p>
<pre>
&lt;li&gt;Title of Something &lt;span class="more"&gt;&lt;/span&gt;&lt;/li&gt;
</pre>
<p>This code won’t get followed by a bot to show more info about the list item.</p>
<pre>
$('.more').click(function () {
    showMore();
});
</pre>
<p>Now I have an event assigned.  However, if this list item is added dynamically…</p>
<pre>
$(myListItem).appendTo('ul');

$('.more').live('click', function () {
    showMore();
});
</pre>
<p>Works great, except on Mobile Safari.  The workaround is <strong>really</strong> hacky though.  If this ‘more’ were a link (<code>&lt;a href="#" class="more"&gt;&lt;/a&gt;</code>), there wouldn’t be a problem, just like adding <code>onclick=""</code>.</p>
<pre>
&lt;li&gt;Title of Something &lt;span class="more" onclick=""&gt;&lt;/span&gt;&lt;/li&gt;
</pre>
<p>Problem Solved.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.martinilab.com/blog/209/mobile-safari-needs-a-little-jquery-live-love/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>YouTube’s H.264 turnaround time is the new dial up</title>
		<link>http://www.martinilab.com/blog/128/youtube-h264-turnaround-time/</link>
		<comments>http://www.martinilab.com/blog/128/youtube-h264-turnaround-time/#comments</comments>
		<pubDate>Thu, 21 May 2009 16:40:15 +0000</pubDate>
		<dc:creator>Chris Williams</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[content]]></category>
		<category><![CDATA[scalability]]></category>
		<category><![CDATA[usability]]></category>
		<category><![CDATA[YouTube]]></category>

		<guid isPermaLink="false">http://www.martinilab.com/blog/?p=128</guid>
		<description><![CDATA[Just how long does it take for a YouTube video to become available on the YouTube iPhone app? Seriously, if YouTube accepts .wmv, .avi, .mkv, .mov, .mpeg, .mp4, .flv, .ogg, 3gp and outputs to multiple .flv, mp4, 3gp… OMG, why &#8230; <a href="http://www.martinilab.com/blog/128/youtube-h264-turnaround-time/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Just how long does it take for a YouTube video to become available on the YouTube iPhone app?</p>
<p>Seriously, if YouTube accepts .wmv, .avi, .mkv, .mov, .mpeg, .mp4, .flv, .ogg, 3gp and outputs to multiple .flv, mp4, 3gp… OMG, why then is the link I just tapped not available?</p>
<p>I understand that once uploaded, videos take time to convert for display. Having uploaded some from my own iMovie library, waiting for YouTube to do its magic without a progress bar is torture.  But once it’s done and properly playing on the website, the video still has to become available for HD (if available), mobile, etc.</p>
<p>As we become more connected on more networks on new devices, our content experience should become more homogeneous. Websites should get closer to looking the same on our desktop computers as they do our mobile devices. Instead, because of mobile phones and netbooks (more specifically, their wireless connectivity) web designers, who once enjoyed building for higher display resolutions and bigger bandwidth, find themselves thrown back into building sites that are “dial-up” friendly.  It’s a whole new browser war sans Netscape Navigator.</p>
<p>Which brings me back to YouTube on the iPhone. Video codec H.264, briefly put, is designed for both high-def and small bandwidth playback.  Since YouTube offers multiple versions of the same video, it has to take the original video upload and convert it several times. And since the only way to view YouTube on Apple TV or the iPhone is with h.264, YouTube needs to make additional conversions/transcodings.</p>
<p>In the end, content for the web isn’t just for the browser.  It includes phones, game consoles, dvr (TiVo), and any future devices we don’t yet know we need.  And all of them need the same content in their own specific formats.</p>
<p>All of this means that the next time I see something along the lines of “@amboy00: too funny! http://tinyurl.com/pqhugm,” I’ll probably have to wait until I get back to my desk to see the funny.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.martinilab.com/blog/128/youtube-h264-turnaround-time/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tackling Safari’s slow gif “feature” with jQuery</title>
		<link>http://www.martinilab.com/blog/75/tackling-safaris-slow-gif-feature-with-jquery/</link>
		<comments>http://www.martinilab.com/blog/75/tackling-safaris-slow-gif-feature-with-jquery/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 23:19:36 +0000</pubDate>
		<dc:creator>Chris Williams</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[adobe]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Photoshop]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[usability]]></category>
		<category><![CDATA[WebKit]]></category>

		<guid isPermaLink="false">http://www.martinilab.com/blog/?p=75</guid>
		<description><![CDATA[Safari’s WebKit has a funny behavior of displaying animated gif files at a lower frame rate than Firefox. From what I can tell, WebKit (including Google Chrome) caps the animated gif frame rates at 10fps. While it may be faster &#8230; <a href="http://www.martinilab.com/blog/75/tackling-safaris-slow-gif-feature-with-jquery/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Safari’s WebKit has a funny behavior of displaying animated gif files at a lower frame rate than Firefox. From what I can tell, WebKit (including Google Chrome) caps the animated gif frame rates at 10fps. While it may be faster than some IE6 browsers, it’s not exactly helpful for those files with higher frame rates.</p>
<p>For example, the popular ajax loader file that hails from Apple’s own <a href="http://developer.apple.com/documentation/userexperience/Conceptual/AppleHIGuidelines/XHIGControls/XHIGControls.html">asynchronous progress indicator</a>, has 12 points and loops around once a second.  Well, for one thing, 12fps is really choppy, but it already plays slower on Apple’s nifty browser.</p>
<h2>jQuery to the rescue</h2>
<p>Did you know that jQuery can control css background positions? Are you thinking what I’m thinking?<br />
<span id="more-75"></span></p>
<h2>But first, back to drawing board</h2>
<p>So the first part was to break up the animated gif frames and spread them out across a very long canvas. Since Photoshop no longer opens animated gif files (unless you own ImageReady somewhere), Fireworks can open the file. Use Fireworks to export the frames to individual files and THEN Photoshop can import all the files as a stack.</p>
<p>File <code>&lt;Scripts&gt;</code> Load Files into Stack…</p>
<p>For our ajax loader, expand all the layers next to each other and then save it out to its own gif.  The file size won’t be that difference in fact.</p>
<h2>Now let’s get back to jQuery</h2>
<p>In our html, just set the div with a width and height to match your gif to prevent clipping and let the script do the rest.</p>
<pre lang="javascript" line="1">

$(document).ready(function(){
	var bgimage = 'url(images/ajax-loader-long.gif)';
	var frames = 24;
	var mpf = parseInt(1000/frames)  // how many miliseconds in each frame
	var currentFrame = 0;
	var offset = 0;

	$('.animate').css('background-image', bgimage);

	function animate() {
		offset = currentFrame * 64;
		$('.animate').css('background-position', '-' + offset + 'px 0px');
		currentFrame = (currentFrame == frames) ? 1 : currentFrame + 1;
	}

	setInterval(animate, mpf);
});
</pre>
<p>Now we have a script that will snap the position of the background over each “frame” at the correct frame rate. Actually, the frame rate is not divisible by 1000, but it’s close and it’s not like you could tell.</p>
<p>The only problem with this script is that it’s constantly running. If you look at the page in Firebug, your going to see the code whipping around with new values all the time. Annoying! Also, chances are your page isn’t going to need some animation playing constantly. Ajax loaders are intermittently called when a simple action is called as a… asynchronous progress indicator! Who knew.</p>
<p>So we’re going to put in a cancel command to this script: <strong>clearTimeout</strong>.</p>
<pre lang="javascript" line="1">

$(document).ready(function(){
	var bgimage = 'url(images/ajax-loader-long.gif)';
	var frames = 24;
	var mpf = parseInt(1000/frames)  // how many miliseconds in each frame
	var currentFrame = 0;
	var offset = 0;
	var runAnimate = 0;

	$('.animate').css('background-image', bgimage);

	function animate() {
		offset = currentFrame * 64;
		$('.animate').css('background-position', '-' + offset + 'px 0px');
		currentFrame = (currentFrame == frames) ? 1 : currentFrame + 1;
	}

	runAnimate = setInterval(animate, mpf);

	$('.animate').toggle(
		function () {
			clearTimeout(runAnimate);
		},
		function () {
			runAnimate = setInterval(animate, mpf);
		}
	);
});
</pre>
<p>Add in a toggle so show how to turn on and off the animation and were done.</p>
<p>It even works on ie6!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.martinilab.com/blog/75/tackling-safaris-slow-gif-feature-with-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery Triptych Slideshow</title>
		<link>http://www.martinilab.com/blog/54/jquery-triptych-slide-show/</link>
		<comments>http://www.martinilab.com/blog/54/jquery-triptych-slide-show/#comments</comments>
		<pubDate>Wed, 01 Apr 2009 23:58:04 +0000</pubDate>
		<dc:creator>Chris Williams</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.martinilab.com/blog/?p=54</guid>
		<description><![CDATA[My previous how-to showed a new way to look at the slider function featured at the Apple.com/mac site. This one goes to Apple once again and their bucket ads shown in the iTunes Music Store. The buckets are what I’m &#8230; <a href="http://www.martinilab.com/blog/54/jquery-triptych-slide-show/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>My previous how-to showed a new way to look at the slider function featured at the Apple.com/mac site. This one goes to Apple once again and their bucket ads shown in the iTunes Music Store. The buckets are what I’m calling them. They are the three spots at the top of the music store which rotate graphics like the slideshow functions of many galleries. The difference is that these three take turns.</p>
<p>I was able to replicate this function using Scriptaculous on our beloved <a href="http://www.zeuscomics.com">comic shop</a> website. But after a few years of constantly adding duct tape to the site, it was time to move everything to a single framework. And that mean making this triptych banner script run on jQuery.  Hopefully without a lot of html recoding.<br />
<span id="more-54"></span></p>
<h2>Make your list</h2>
<p>For the html, set your divs with a ‘slide’ class and a position class.  I guess you can do this in an unordered list, but whatever.</p>
<pre lang="html4strict" line="1">
&lt;div class="slide pos1"&gt;&lt;a href="link1"&gt;&lt;img src=""&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="slide pos2"&gt;&lt;a href="link2"&gt;&lt;img src=""&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="slide pos3"&gt;&lt;a href="link3"&gt;&lt;img src=""&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div class="slide pos1"&gt;&lt;a href="link4"&gt;&lt;img src=""&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="slide pos2"&gt;&lt;a href="link5"&gt;&lt;img src=""&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="slide pos3"&gt;&lt;a href="link6"&gt;&lt;img src=""&gt;&lt;/a&gt;&lt;/div&gt;
</pre>
<h2>Set your positions</h2>
<p>The easiest solution is to make the position classes absolute.</p>
<pre lang="css" line="1">

.pos1 {
    position: absolute;
    left: 0px;
    top: 0px;
}

.pos2 {
    position: absolute;
    left: 210px;
    top: 0px;
}

.pos3 {
    position: absolute;
    left: 420px;
    top: 0px;
}
</pre>
<h2>Good news, everyone! This script doesn’t need a plug-in.</h2>
<p>I always start my script codes with an apology, so why stop now.  I’m sorry.</p>
<p>The first part makes sure that the banners appear in the order that their written in html.  Because of the absolute positioning, however, they stack on top of each other and the last will be on top.</p>
<p>Also, I didn’t like how <code>i</code> in jQuery’s <code>each()</code> function started at 1 and not 0, but that’s just me.</p>
<pre lang="javascript" line="1">

$(document).ready(function(){
    var slideCount = $('.slide').size() - 1;
    $('.slide').each(function(i) {
        $(this).css('z-index', slideCount - i);
    });

    var currentSlide = slideCount;
    var zIndex = 0;

    function imgRotate() {
        $('.slide').each(function(i) {
            if($(this).css('z-index') == currentSlide)
            {
                $(this).fadeOut('slow', function() {
                    $(this).css('z-index', (0));
                    $(this).show();
                });
            }
            else
            {
                zIndex = $(this).css('z-index');
                zIndex = parseInt(zIndex) + parseInt(1);
                $(this).css('z-index', (zIndex));
            }
        });
    }

    setInterval(imgRotate, 4000);

});
</pre>
<p>This script should be able to make with any number of banners and any number of sets.  This example just used a set of three, but your can make it a set of two, or four, or ten!  Just make the list divisible by the set and fix your positions of course.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.martinilab.com/blog/54/jquery-triptych-slide-show/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A better jQuery slider</title>
		<link>http://www.martinilab.com/blog/25/a-better-jquery-slider/</link>
		<comments>http://www.martinilab.com/blog/25/a-better-jquery-slider/#comments</comments>
		<pubDate>Wed, 25 Mar 2009 22:09:51 +0000</pubDate>
		<dc:creator>Chris Williams</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.martinilab.com/blog/?p=25</guid>
		<description><![CDATA[If you haven’t seen Apple’s product slider in action, you must check it out. It’s a horizontal gallery of their products with horizontal slider controlled with javascript. I believe they are using the scriptaculous motion for this, but there should &#8230; <a href="http://www.martinilab.com/blog/25/a-better-jquery-slider/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>If you haven’t seen Apple’s product <a href="http://www.apple.com/mac/">slider</a> in action, you must check it out. It’s a horizontal gallery of their products with horizontal slider controlled with javascript.  I believe they are using the scriptaculous motion for this, but there should be a way to build this in jQuery.</p>
<p>Truth be told, I was a die-hard fanatic for scriptaculous/prototype, but after ExpressionEngine announce their adoption of jQuery for EE 2.0, it was time to grow beyond the one framework pony.</p>
<p>Luckily, someone already set out to build the slider in jQuery. And major hat’s off to Remy Sharp for a great approach to this. If you looking for a way to build your own slider, start there first.<br />
<span id="more-25"></span></p>
<h2>The Problem</h2>
<p>Actually, there was no problem until I had a client to didn’t fit into the strict mold set out for this widget. As with most inventive solutions, they are begat from necessity.</p>
<p>The slider is built on an unordered list, but doesn’t support nested lists. For my needs, the slider had to be able to not only show multiple categories of products, but also visually differentiate.</p>
<p>Now, this can be resolved by manually setting css values. This approach would “hard code” the positions of the categories. That isn’t very code may be puled from a database.</p>
<p>Also, the slider needs to work without javascript. I know. Who doesn’t use javascript? The answer is, I don’t know, but someone always points out if something doesn’t degrade properly.</p>
<h2>The Solution</h2>
<p>I built this out backwards, but it works. So don’t question it. This demo shows the slider with wireframes to show off the block level div’s and li’s.</p>
<p>You can see by this code example that the lists are simple and even has a space for the category description if your site requires it.</p>
<h2>HTML</h2>
<p>This is a simple template shoing how to format your product groups and your categories for them.  There can be as many needed.  This example should be able to display them all successfully.</p>
<pre lang="html4strict" line="1">
&lt;div id="mlSlideWidget" class="slideWidget"&gt;
	&lt;div id="sliderWindow" class="sliderGallery"&gt;
		&lt;ul class="sliderList"&gt;
			&lt;!-- Each category --&gt;
			&lt;li class="group"&gt;
				&lt;div class="groupContent"&gt;
					&lt;!-- Description info for category --&gt;
					&lt;p&gt;Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum vitae diam vitae leo hendrerit aliquet. Donec dolor. Integer placerat rhoncus metus. Proin sagittis. Nullam sed lacus accumsan orci convallis interdum. Aenean aliquet, nisi et sollicitudin posuere, orci tortor fermentum.&lt;/p&gt;
					&lt;ul class="groupButtons"&gt;
						&lt;!-- Each product for this category --&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 1&lt;/a&gt;&lt;/li&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 2&lt;/a&gt;&lt;/li&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 3&lt;/a&gt;&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/div&gt;
			&lt;/li&gt;
			&lt;li class="group"&gt;
				&lt;div class="groupContent"&gt;
					&lt;p&gt;Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum vitae diam vitae leo hendrerit aliquet. Donec dolor. Integer placerat rhoncus metus. Proin sagittis. Nullam sed lacus accumsan orci convallis interdum. Aenean aliquet, nisi et sollicitudin posuere, orci tortor fermentum.&lt;/p&gt;
					&lt;ul class="groupButtons"&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 4&lt;/a&gt;&lt;/li&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 5&lt;/a&gt;&lt;/li&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 6&lt;/a&gt;&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/div&gt;
			&lt;/li&gt;
			&lt;li class="group"&gt;
				&lt;div class="groupContent"&gt;
					&lt;p&gt;Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum vitae diam vitae leo hendrerit aliquet. Donec dolor. Integer placerat rhoncus metus. Proin sagittis. Nullam sed lacus accumsan orci convallis interdum. Aenean aliquet, nisi et sollicitudin posuere, orci tortor fermentum.&lt;/p&gt;
					&lt;ul class="groupButtons"&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 7&lt;/a&gt;&lt;/li&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 8&lt;/a&gt;&lt;/li&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 9&lt;/a&gt;&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/div&gt;
			&lt;/li&gt;
			&lt;li class="group"&gt;
				&lt;div class="groupContent"&gt;
					&lt;p&gt;Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum vitae diam vitae leo hendrerit aliquet. Donec dolor. Integer placerat rhoncus metus. Proin sagittis. Nullam sed lacus accumsan orci convallis interdum. Aenean aliquet, nisi et sollicitudin posuere, orci tortor fermentum.&lt;/p&gt;
					&lt;ul class="groupButtons"&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 10&lt;/a&gt;&lt;/li&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 11&lt;/a&gt;&lt;/li&gt;
						&lt;li class="singleButton"&gt;&lt;a href="#"&gt;Product 12&lt;/a&gt;&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/div&gt;
			&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;

	&lt;div id="scroll" class="slider"&gt;
		&lt;!-- the handler to action the slide --&gt;
		&lt;div class="handle"&gt;&lt;/div&gt;
		&lt;!-- labels appear against the slider, as pointers to the user --&gt;
		&lt;ul&gt;
			&lt;!-- These are categories --&gt;
			&lt;li class="marker"&gt;Category 1&lt;/li&gt;
			&lt;li class="marker"&gt;Category 2&lt;/li&gt;
			&lt;li class="marker"&gt;Category 3&lt;/li&gt;
			&lt;li class="marker"&gt;Category 4&lt;/li&gt;
		&lt;/ul&gt;
		&lt;div class="fakeHandle"&gt;
			&lt;table width="100%" cellpadding="0" cellspacing="0" border="0"&gt;
				&lt;tr&gt;
					&lt;td width="15"&gt;&lt;img src="images/handle-left.png" width="15" height="115" alt="&lt;" /&gt;&lt;/td&gt;
					&lt;td background="images/handle-middle.png"&gt;&nbsp;&lt;/td&gt;
					&lt;td width="15"&gt;&lt;img src="images/handle-right.png" width="15" height="115" alt="&gt;" /&gt;&lt;/td&gt;
				&lt;/tr&gt;
			&lt;/table&gt;
		&lt;/div&gt;
	&lt;/div&gt;

&lt;/div&gt;
</pre>
<h2>CSS</h2>
<p>I threw in a dash of <a href="http://developer.yahoo.com/yui/">YUI</a>’s css reset. Most of the id and class names are generic.  I would recommend renaming these to something more specific to avoid conflict.</p>
<pre lang="css" line="1">
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, img {border-width: 0px;margin:0;padding:0;}
#mlSlideWidget {
	font:11px arial,helvetica,clean,sans-serif;
	*font-size:small;
	*font:x-small;
	position: relative;
	height: 361px;
	width: 659px;
	background: url(images/slider-background.jpg) left top no-repeat;
}

#sliderWindow {
	margin: 1px;
	height: 365px;
	position: relative;
	width: 655px;
}

.sliderGallery {
	overflow: auto;
}

.sliderGallery ul.sliderList {
	top: 0px;
	left: 0px;
	margin-top: 135px;
	padding-bottom: 0;
	position: absolute;
	list-style: none;
	height: 210px;
	overflow: auto;
	width: 2000px;
	white-space: nowrap;
}

#mlSlideWidget .sliderGallery ul li.group {
	margin-left: 7px;
	margin-right: 7px;
	display: inline;
	float: left;
}

#mlSlideWidget .sliderGallery ul li.group .groupContent {
	margin-right: 10px;
	padding-left: 10px;
	padding-top: 10px;
	padding-bottom: 10px;
}

ul.groupButtons {
	height: 120px;
}

li.group {
	background: url(images/group-backgroundcap.png) no-repeat right top;
}

li.group .groupContent{
	background: url(images/group-background.png) no-repeat left top;
}

li.group p {
	width: 430px;
	height: 70px;
	font-size: 10px;
	line-height: 12px;
	white-space: normal;
}

li.group ul.groupButtons {
	list-style: none;
	white-space: nowrap;
}

li.group ul.groupButtons li.singleButton {
	width: 140px;
	float: left;
	height: 118px;
	text-align: center;
}
#scroll {
	position: absolute;
	top: 0px;
	left: 0px;
	z-index: 100;
	width: 639px;
	margin-left: 10px;
	margin-right: 8px;
}

#scroll ul {
	height: 123px;
	list-style: none;
}

#scroll li.marker {
	margin-top: 4px;
	padding-top: 60px;
	text-align: center;
	z-index: 90;
	font-size: 10px;
	height: 30px;
	width: 55px;
	padding-left: 20px;
	padding-right: 20px;
	margin-left: 10px;
	margin-right: 10px;
	float: left;
}

.handle {
	position: absolute;
	top: 8px;
	left: 0;
	z-index: 110;
	height: 115px;
}

.fakeHandle {
	position: absolute;
	top: 8px;
	left: 0;
	z-index: 80;
	height: 115px;
}
</pre>
<p>jQuery UI will need to be built with UI Core, Draggable, Slider, Effects Core, and Slide.  Some of the values of this rules in the example are built to my specs and can be modified to whatever specs fit your site.  Note the versions of jQuery at the time of this article.</p>
<p>This example doesn’t know how many objects exist in the slider.  If you use a set amount, this example can be greatly reduced.  However, if your categories are managed via a database or cms tool, the number of objects used can change.</p>
<h2>Javascript</h2>
<p>Try not to laugh at my n00b code.  I’m sure there are much better ways to write this.</p>
<pre lang="javascript" line="1">

//basic rules for controling the divs
$(document).ready(function(){

   //fix css rules
   //above css written for pages loaded without javascript
   $('.sliderGallery').css({'overflow-x': 'hidden', 'overflow-y': 'visible'});
   $('li.marker').css({'float': 'none', 'position': 'absolute', 'top': 0, 'left': 0});

	//set up some public variables and arrays
	var scrollBar = 639;
	var sliderListOffsetLeft = $('.sliderList').offset();
	var productWidth = 0;
	var groupWidth = 0;
	var sliderWidth = new Array();
	var sliderLeft = new Array();
	var groupRangeLeft = new Array();
	var marker = new Array();

	//measure the width of all the sub-categories
	//and the sub-sub-categories while we're at it
	$('li.group').each(function (i) {
		sliderLeft[i] = productWidth;
		$('li.singleButton', this).each(function (i) {
			groupWidth = groupWidth + $(this).width()
		});
		//hard coded minimum width for groups
		if (groupWidth < 450)
			groupWidth = 450;
		else
			groupWidth += 20;
		productWidth = productWidth + groupWidth + 16;
		//set width for each sub-caterogy
		sliderWidth[i] = groupWidth + 14;
		$(this).css({width: groupWidth});
		//reset the variable
		groupWidth = 0;
		//used in another function not used in demo
		groupOffsetleft = $(this).offset();
		groupRangeLeft[i] = groupOffsetleft.left - sliderListOffsetLeft.left - ((i > 0) ? 14 : 7 );
	});

	//Fix css to fit with slider content
	$('ul.sliderList').css({width: productWidth + 14});

	//Variables to make math easier
	var handle = (scrollBar / productWidth) * scrollBar;
	var markerLeft = 0;
	var scrollBarVisible = scrollBar - handle;

	$('li.marker').each(function (i) {
		markerLeft = (sliderLeft[i] / productWidth * scrollBar);
		markerWidth = (sliderWidth[i] / productWidth * scrollBar);
		$(this).css({left: markerLeft});
		marker[i] = (markerLeft / scrollBarVisible) * 100;
	});

	$('div.handle').css({width: handle});
	$('div.fakeHandle').css({width: handle});

	if (productWidth > scrollBar)
	{
		$('div.slideWidget').each(function () {
			var ul = $('ul.sliderList', this);
			var fake = $('.fakeHandle', this);

			var slider = $('.slider', this).slider({
				handle: '.handle',
				minValue: 0,
				maxValue: productWidth,
				slide: function (ev, ui) {
					ul.css('left', '-' + Math.round(ui.value / 100 * (productWidth - 657)) + 'px');
					fake.css('left', Math.round(ui.value / 100 * (scrollBar - handle)) + 'px');
				},
				stop: function (ev, ui) {
					move = ui.value / 100 * (productWidth - 657);
					ul.animate({ 'left' : '-' + Math.round(move) + 'px' }, 500);
					fake.animate({'left' : Math.round(ui.value / 100 * (scrollBar - handle)) + 'px'}, 500);
				}
			});
		})
	}

	else {
		$('.fakeHandle').css({width: 0});
		$('.handle').css({width: 0});
		$('.fakeHandle').css('visibility', 'hidden');
		$('.handle').css('visibility', 'hidden');
	}

});
</pre>
<p>Notice the versions of jQuery and UI.  1.7.1 has issues with this solution.  As of yet, I haven’t found a fix.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.martinilab.com/blog/25/a-better-jquery-slider/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
