{"id":1022,"date":"2012-01-30T12:38:46","date_gmt":"2012-01-30T17:38:46","guid":{"rendered":"http:\/\/yuguangzhang.com\/blog\/?p=1022"},"modified":"2012-01-30T12:56:44","modified_gmt":"2012-01-30T17:56:44","slug":"jquery-scrolling-menu","status":"publish","type":"post","link":"http:\/\/yuguangzhang.com\/blog\/jquery-scrolling-menu\/","title":{"rendered":"jQuery Scrolling Menu"},"content":{"rendered":"<p>When implementing the <a href=\"http:\/\/uwcourseplanner.com\/calendar\/CS\/\">scrolling menu for Chrome and Firefox<\/a>, I prototyped the menu using <a href=\"http:\/\/fiddlesalad.com\/python\/animated-css-list-menu\/\">fiddlesalad&#8217;s LESS CSS editor<\/a>. Then, I copied the compiled CSS and started coding with a straight forward procedural approach.<br \/>\n[cc lang=&#8221;javascript&#8221;]<br \/>\nfunction displayMenu() {<br \/>\n    var selected = [$(&#8216;#menu ul:first li.selected&#8217;), $(&#8216;#menu ul:eq(1) li.selected&#8217;)];<br \/>\n    if (selected[0].length) $(&#8216;#menu div:first&#8217;).scrollTo(selected[0]);<br \/>\n    if (selected[1].length) $(&#8216;#menu div:eq(1)&#8217;).scrollTo(selected[1]);<br \/>\n    $(&#8216;#menu ul:first&#8217;).parallax({<br \/>\n        takeoverFactor: .2,<br \/>\n        mouseport: $(&#8216;#menu ul:first&#8217;).parent(),<br \/>\n        xparallax: false<br \/>\n    });<br \/>\n    $(&#8216;#menu ul:eq(1)&#8217;).parallax({<br \/>\n        takeoverFactor: .2,<br \/>\n        mouseport: $(&#8216;#menu ul:eq(1)&#8217;).parent(),<br \/>\n        xparallax: false<br \/>\n    });<br \/>\n    $(&#8216;#menu ul:first li&#8217;).click(function () {<br \/>\n        window.location.assign(ajax_url + &#8216;calendar\/&#8217; + $(this).text() + &#8216;\/&#8217;);<br \/>\n    });<br \/>\n    $(&#8216;#menu ul:eq(1) li&#8217;).click(function () {<br \/>\n        var course = $(this).text().split(&#8216; &#8216;);<br \/>\n        window.location.assign(ajax_url + &#8216;calendar\/&#8217; + course[0] + &#8216;\/&#8217; + course[1] + &#8216;\/&#8217;);<br \/>\n    });<br \/>\n}<\/p>\n<p>$(&#8216;#menu ul:first li.last&#8217;).livequery(displayMenu);<br \/>\n[\/cc]<br \/>\nLater, 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.<br \/>\n[cc lang=&#8221;javascript&#8221;]<br \/>\nfunction Menu(selector) {<br \/>\n\tthis.selector = selector; \/\/ #menu ul:first<br \/>\n\tthis.$list = $(this.selector);<br \/>\n\tthis.$container = this.$list.parent();<br \/>\n\tthis.display = bindMethod(this, function () {<br \/>\n\t\tvar selected = this.$list.find(&#8216;.selected&#8217;).prev(),<br \/>\n\t\t\tprevCount = 0;<br \/>\n\t\tvar prev = selected.prev();<br \/>\n\t\twhile (selected.length &#038;&#038; prevCount++ < 3)\n\t\t\tselected = selected.prev();\n\t\t\/\/ only course pages have enough height, otherwise the courses at the top cannot be reached\n\t\tif (selected.length &#038;&#038; window.location.pathname.split('\/').length == 5)\n\t\t\tthis.$container.scrollTo(selected);\n\t\tthis.$list.parallax({\n\t\t\ttakeoverFactor: .2,\n\t\t\tmouseport: this.$container,\n\t\t\txparallax: false\n\t\t});\n\t});\n\tthis.$list.find('.last').livequery(this.display);\n\tthis.scrollTop = bindMethod(this, function () {\n\t\tif (this.activated)\n\t\t\tthis.$container.scrollTo(this.$list.find('li:first'));\n\t});\n\tthis.$container.mouseenter(bindMethod(this, function () {\n\t\tthis.activated = true;\n\t}))\n\tthis.width = function () {\n\t\treturn this.$container.width();\n\t}\n}\n[\/cc]\nWriting classes in JavaScript brings unexpected quirks, such as <em>this<\/em> being set to an HTML Element. However, using an additional helper, <em>bindMethod<\/em>, this problem is avoided. I used the scrollTop method to scroll to the top of the menu:<\/p>\n<p>[cc lang=&#8221;javascript&#8221;]<\/p>\n<p>var deptMenu = new Menu(&#8216;#menu ul:first&#8217;), courseMenu = new Menu(&#8216;#menu ul:eq(1)&#8217;);<br \/>\nvar $deptTop = $(&#8216;#menu&#8217;).prev().find(&#8216;div:first&#8217;), $courseTop = $(&#8216;#menu&#8217;).prev().find(&#8216;div:eq(1)&#8217;);<br \/>\n$deptTop.width(deptMenu.width());<br \/>\n$courseTop.width(courseMenu.width());<br \/>\n$deptTop.hover(deptMenu.scrollTop);<br \/>\n$courseTop.hover(courseMenu.scrollTop);<\/p>\n<p>[\/cc]<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When implementing the scrolling menu for Chrome and Firefox, I prototyped the menu using fiddlesalad&#8217;s LESS CSS editor. Then, I copied the compiled CSS and started coding with a straight forward procedural approach. [cc lang=&#8221;javascript&#8221;] function displayMenu() { var selected = [$(&#8216;#menu ul:first li.selected&#8217;), $(&#8216;#menu ul:eq(1) li.selected&#8217;)]; if (selected[0].length) $(&#8216;#menu div:first&#8217;).scrollTo(selected[0]); if (selected[1].length) $(&#8216;#menu div:eq(1)&#8217;).scrollTo(selected[1]); [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[29],"tags":[152,133],"class_list":["post-1022","post","type-post","status-publish","format-standard","hentry","category-coursetree","tag-css3","tag-javascript"],"aioseo_notices":[],"_links":{"self":[{"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/posts\/1022","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/comments?post=1022"}],"version-history":[{"count":0,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/posts\/1022\/revisions"}],"wp:attachment":[{"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/media?parent=1022"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/categories?post=1022"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/tags?post=1022"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}