Animated <ul> modification
slide <li> to their new position, fade new elements in, removed elements out.
by rodneyrehm
HTML
<ul id="list">
<li id="L1">one</li>
<li id="L2">two</li>
<li id="L3">three</li>
<li id="L4">four</li>
<li id="L5">five</li>
<li id="L6">six</li>
</ul>
<div id="newlist" style="display:none"><!--
<ul>
<li id="L0">zero</li>
<li id="L1">one</li>
<li id="L3">three</li>
<li id="L4">four</li>
<li id="L7">alpha</li>
<li id="L8">bravo</li>
<li id="L5">five</li>
<li id="L9">charlie</li>
<li id="L6">six</li>
</ul>
--></div>
<button id="switch">modify</button>
CSS
#list {
position: relative;
font-size: 0;
}
#list > li {
font-size: 16px;
display: inline-block;
width: 150px;
height: 150px;
margin: 5px;
background: #EEE;
border: 1px solid #CCC;
}
#list.transitioning > li {
position: absolute;
}
JavaScript
function remove() {
$(this).remove();
}
$('#switch').on('click', function() {
var origin = {},
destination = {},
$list = $('#list'),
$first = $list.children().first(),
margin = {},
$oldChildren = $list.children(),
$newChildren = $($.trim(document.getElementById('newlist').firstChild.nodeValue)).children();
// identify margins (to correct absolute positioning)
$.each(["top", "left"], function(k, v) {
var key = "margin-" + v;
margin[v] = parseInt($first.css(key) || "0", 10);
if (isNaN(margin[v])) {
margin[v] = 0;
}
});
// capture origin position
$list.children().each(function() {
var $this = $(this);
origin[this.id] = $this.offset();
//origin[this.id].top += margin.top;
//origin[this.id].left += margin.left;
});
// switch in new elements
$oldChildren.detach();
$list.append($newChildren);
// force reflow
$list.css('top');
// capture destination position
$newChildren.each(function() {
var $this = $(this);
destination[this.id] = $this.offset();
//destination[this.id].top -= margin.top;
//destination[this.id].left -= margin.left;
});
// make stuff movable
$list.addClass('transitioning');
$newChildren.each(function(){
$(this).offset(destination[this.id]);
});
// find elements to remove
$oldChildren.each(function() {
if (!destination[this.id]) {
// insert element
var $this = $(this);
origin[this.id].top -= margin.top;
origin[this.id].left -= margin.left;
$this
.offset(origin[this.id])
.appendTo($list)
.fadeOut(100, remove);
}
});
// find elements to insert
$newChildren.each(function() {
var $this = $(this);
if (!origin[this.id]) {
...