jQuery Scrolling Menu
When implementing the scrolling menu for Chrome and Firefox, I prototyped the menu using fiddlesalad’s LESS CSS editor. Then, I copied the compiled CSS and started coding with a straight forward procedural approach.
var selected = [$('#menu ul:first li.selected'), $('#menu ul:eq(1) li.selected')];
if (selected[0].length) $('#menu div:first').scrollTo(selected[0]);
if (selected[1].length) $('#menu div:eq(1)').scrollTo(selected[1]);
$('#menu ul:first').parallax({
takeoverFactor: .2,
mouseport: $('#menu ul:first').parent(),
xparallax: false
});
$('#menu ul:eq(1)').parallax({
takeoverFactor: .2,
mouseport: $('#menu ul:eq(1)').parent(),
xparallax: false
});
$('#menu ul:first li').click(function () {
window.location.assign(ajax_url + 'calendar/' + $(this).text() + '/');
});
$('#menu ul:eq(1) li').click(function () {
var course = $(this).text().split(' ');
window.location.assign(ajax_url + 'calendar/' + course[0] + '/' + course[1] + '/');
});
}
$('#menu ul:first li.last').livequery(displayMenu);
Later, I noticed that the performance can be improved by caching jQuery results. Also, many lines of code were repetitive. Before moving onto the more challenging part of the menu design, scrolling to the current location, I made it object oriented using plain JavaScript.
this.selector = selector; // #menu ul:first
this.$list = $(this.selector);
this.$container = this.$list.parent();
this.display = bindMethod(this, function () {
var selected = this.$list.find('.selected').prev(),
prevCount = 0;
var prev = selected.prev();
while (selected.length && prevCount++ < 3)
selected = selected.prev();
// only course pages have enough height, otherwise the courses at the top cannot be reached
if (selected.length && window.location.pathname.split('/').length == 5)
this.$container.scrollTo(selected);
this.$list.parallax({
takeoverFactor: .2,
mouseport: this.$container,
xparallax: false
});
});
this.$list.find('.last').livequery(this.display);
this.scrollTop = bindMethod(this, function () {
if (this.activated)
this.$container.scrollTo(this.$list.find('li:first'));
});
this.$container.mouseenter(bindMethod(this, function () {
this.activated = true;
}))
this.width = function () {
return this.$container.width();
}
}
Writing classes in JavaScript brings unexpected quirks, such as this being set to an HTML Element. However, using an additional helper, bindMethod, this problem is avoided. I used the scrollTop method to scroll to the top of the menu:
var $deptTop = $('#menu').prev().find('div:first'), $courseTop = $('#menu').prev().find('div:eq(1)');
$deptTop.width(deptMenu.width());
$courseTop.width(courseMenu.width());
$deptTop.hover(deptMenu.scrollTop);
$courseTop.hover(courseMenu.scrollTop);