I'm currently fighting a fierce battle with an interface I'm trying to put together. I'm pretty decent at CSS & XHTML, but my jQuery/JavaScript skills are not too impressive. What I'm looking for is not so much a strict answer, but some hints on how to go about these kinds of tasks.
What I am trying to achieve is a layout with some boxes in the main-content area that can be expanded and collapsed when the user press either a link in the sidebar or on a header on the box itself.
Furthermore I want the browser to remember what box was expanded last by setting a cookie. If that wasn't enough I also want to be able to add a "limited"-class to each box and thereby disabling it, and it's corresponding sidebar-list-item.
Also I want the box to have a class based on it's state (expanded, collapsed, limited).
This is my markup:
<!-- S I D E B A R - L E F T -->
<div id="sidebar-left">
<ul class="sidebar-menu-1">
<li><strong>List headline</strong>
</li>
<li><a href="#">Open module 1</a>
</li>
<li><a href="#">Open module 2</a>
</li>
<li><a href="#">Open module 3</a>
</li>
</ul>
</div><!--/sidebar-left-->
<!-- M A I N - C O N T E N T -->
<div id="main-content">
<!-- dashboard-module -->
<div class="dashboard-module">
<div class="dashboard-module-content limited">
<h2>Headline 1</h2>
<p class="teaser">Teaser-text 1</p>
<div class="expand-collapse">
[some content]
´ </div>
</div>
</div><!--/dashboard-module-->
<!-- dashboard-module -->
<div class="dashboard-module">
<div class="dashboard-module-content limited">
<h2>Headline 2</h2>
<p class="teaser">Teaser-text 2</p>
<div class="expand-collapse">
[some content]
´ </div>
</div>
</div><!--/dashboard-module-->
<!-- dashboard-module -->
<div class="dashboard-module">
<div class="dashboard-module-content limited">
<h2>Headline 3</h2>
<p class="teaser">Teaser-text 3</p>
<div class="expand-collapse">
[some content]
´ </div>
</div>
</div><!--/dashboard-module-->
</div><!--/main-content-->
And this is my jQuery:
// If the dashboard-module is "limited" do this:
$('div[class*=limited]').each( function(index) {
var countFix = $('div.dashboard-module-content').index(this);
var countFixPlusTwo = countFix + 2;
$( 'ul.sidebar-menu-1 li:nth-child(' + countFixPlusTwo + ')' ).unbind('click').removeClass('selected').addClass('sidebar-menu-locked');
$(this).parent('.dashboard-module').find('h2').unbind('click');
$(this).find('.expand-collapse').remove();
$(this).find('.dashboard-module p:hidden').show();
$(this).addClass('limited-btn');
});
// Check for cookies and do stuff accordingly:
var cookieTest = $.cookie("cookie");
if(cookieTest == null){
$('.js-hidden').hide();
$('ul.sidebar-menu-1 li:not(.sidebar-menu-locked):eq(1)').addClass('selected');
$('.dashboard-module-content:not(.limited):eq(0)' ).toggleClass('hide-btn');
$('.dashboard-module-content:not(.limited):not(:eq(0))' ).removeClass('hide-btn');
$('.expand-collapse:eq(0)' ).show();
};
if(cookieTest != null){
var cookieTestPlusTwo = parseInt(cookieTest, 10) + 2;
$('.dashboard-module-content:eq(' + cookieTest + ')' ).toggleClass('hide-btn');
$('.dashboard-module-content:not(:eq(' + cookieTest + '))' ).removeClass('hide-btn');
$('ul.sidebar-menu-1 li:nth-child(' + cookieTestPlusTwo + '):not(.sidebar-menu-locked)').addClass('selected');
$('ul.sidebar-menu-1 li:not(:nth-child(' + cookieTestPlusTwo + '))').removeClass('selected');
$('.expand-collapse:eq(' + cookieTest + ')' ).show();
$('.expand-collapse:not(:eq(' + cookieTest + '))').hide();
};
// When clicking dashboard-module headers do stuff:
$('.dashboard-module h2:not(.limited h2):not(.tooltip h2)').click(function(index) {
var indexFoo = $('.dashboard-module h2:not(.tooltip h2)').index(this);
var indexPlusTwo = indexFoo + 2;
var indexCookie = indexFoo;
$.cookie("cookie", indexCookie, { expires: 7 });
$('.dashboard-module-content:eq(' + indexFoo + ')').toggleClass('hide-btn');
$('.dashboard-module-content:not(:eq(' + indexFoo + '))' ).removeClass('hide-btn');
$('ul.sidebar-menu-1 li:nth-child(' + indexPlusTwo + ')').addClass('selected');
$('ul.sidebar-menu-1 li:not(:nth-child(' + indexPlusTwo + '))').removeClass('selected');
$('.dashboard-module-content:eq(' + indexFoo + ') .expand-collapse').toggle('fast');
$('.dashboard-module-content:not(:eq(' + indexFoo + ')) .expand-collapse').hide('fast');
$('.dashboard-module-content:not(.limited)').each( function(){
if($(this).parent('.dashboard-module').find('.hide-btn').length == 0){
$(this).find('p.teaser').show();
}
else {
$(this).find('p.teaser').hide();
}
});
});
// When clicking sidebar list-items do stuff:
$('.sidebar-menu-1 li:not(.sidebar-menu-locked)').click(function(index) {
var indexFoo = ($('.sidebar-menu-1 li').index(this) - 1);
var indexPlusTwo = indexFoo + 2;
var indexCookie = indexFoo;
$.cookie("cookie", indexCookie, { expires: 7 });
$('.dashboard-module-content:eq(' + indexFoo + ')').toggleClass('hide-btn');
$('.dashboard-module-content:not(:eq(' + indexFoo + '))' ).removeClass('hide-btn');
$('ul.sidebar-menu-1 li:nth-child(' + indexPlusTwo + ')').addClass('selected');
$('ul.sidebar-menu-1 li:not(:nth-child(' + indexPlusTwo + '))').removeClass('selected');
$('.dashboard-module-content:eq(' + indexFoo + ') .expand-collapse').toggle('fast');
$('.dashboard-module-content:not(:eq(' + indexFoo + ')) .expand-collapse').hide('fast');
$('.dashboard-module-content:not(.limited)').each( function(){
if($(this).parent('.dashboard-module:not(.limited)').find('.hide-btn').length == 0){
$(this).find('p.teaser').show();
}
else {
$(this).find('p.teaser').hide();
}
});
});
As for now it all works in FF, but in IE7+8 it doesn't. But my question is not so much about how to make it work in IE, but more on how you would go about this kind of task? I suspect that my jQuery is not exactly DRY, but how do I condense it?
How would you write and organize your code? Sorry if this is a too broad and long-winded question, but I'm really interested in how experienced jQuery designers go about challenges like this one.
Update: Thanks to Tatu Ulmanen's help I've managed to put together this: http://timkjaerlange.com/foobar/jquery-test/index.html