Permalink
Browse files

added smooth-scrolling and fixed a bunch of history/back-button stuff.

  • Loading branch information...
kswedberg committed Sep 8, 2010
1 parent d225231 commit 7ac515585887ab1dfea232dca0fec72517107e02
Showing with 223 additions and 35 deletions.
  1. +2 −1 index.html
  2. +16 −1 lib/extras.js
  3. +154 −0 lib/jquery.smooth-scroll.js
  4. +51 −33 scripts/search.js
View
@@ -10,7 +10,7 @@
<![endif]-->
</head>
<body>
- <form action="" class="group">
+ <form id="jqas" action="" class="jqas group">
<div>
<a id="search-again" class="js-hide btn" href="#">&#x271A; Search Again</a>
<h3>jQuery API Search <span class="note">A demonstration</span></h3>
@@ -82,6 +82,7 @@ <h5>Include in Results</h5>
.script('lib/jquery-1.4.2.min.js')
.wait()
.script('lib/jquery.bbq.js')
+ .script('lib/jquery.smooth-scroll.js')
.wait()
.script('lib/extras.js')
.script('scripts/search.js');
View
@@ -4,4 +4,19 @@ $('#toggle-advanced').click(function() {
$span.html($span.html() == '' ? '' : '');
$('#advanced').slideToggle();
return false;
-});
+});
+
+$('ol.toc a').live('click', function(event) {
+ event.preventDefault();
+ var tgt = this.hash;
+ $.bbq.pushState({scrollTarget: tgt});
+});
+
+$(window).bind('hashchange', function(event) {
+ var st = $.bbq.getState('scrollTarget');
+ if (st) {
+ $.smoothScroll({scrollTarget: st});
+ }
+
+
+});
View
@@ -0,0 +1,154 @@
+/*
+ * jQuery Smooth Scroll plugin
+ * Version 1.2 (July 6, 2010)
+ * @requires jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses (just like jQuery):
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+
+(function($) {
+
+var version = '1.2';
+
+var locationPath = filterPath(location.pathname);
+
+$.fn.extend({
+ scrollable: function() {
+ var scrollable = [], scrolled = false;
+ this.each(function() {
+
+ if (this == document || this == window) { return; }
+ var el = $(this);
+ if ( el.scrollTop() > 0 ) {
+ scrollable = [this];
+ return false;
+ }
+
+ el.scrollTop(1);
+ scrolled = el.scrollTop() > 0;
+ el.scrollTop(0);
+ if ( scrolled ) {
+ scrollable = [this];
+ return false;
+ }
+
+ });
+
+ return this.pushStack(scrollable);
+ },
+
+ smoothScroll: function(options) {
+ var opts = $.extend({}, $.fn.smoothScroll.defaults, options);
+ this.die('click.smoothscroll').live('click.smoothscroll', function(event) {
+
+ var link = this, $link = $(this),
+ hostMatch = ((location.hostname === link.hostname) || !link.hostname),
+ pathMatch = opts.scrollTarget || (filterPath(link.pathname) || locationPath) === locationPath,
+ thisHash = link.hash,
+ include = true;
+
+
+ if (!opts.scrollTarget && (!hostMatch || !pathMatch || !thisHash) ) {
+ include = false;
+ } else {
+ var exclude = opts.exclude, elCounter = 0, el = exclude.length;
+ while (include && elCounter < el) {
+ if ($link.is(exclude[elCounter++])) {
+ include = false;
+ }
+ }
+
+ var excludeWithin = opts.excludeWithin, ewlCounter = 0, ewl = excludeWithin.length;
+ while (include && ewlCounter < ewl) {
+ if ($link.closest(excludeWithin[ewlCounter++]).length) {
+ include = false;
+ }
+ }
+ }
+
+ if (include) {
+ opts.scrollTarget = opts.scrollTarget || thisHash;
+ opts.link = link;
+ event.preventDefault();
+ $.smoothScroll(opts);
+ }
+ });
+
+ return this;
+
+ }
+
+});
+
+$.smoothScroll = function(options, px) {
+ var opts, scrollTargetOffset, offPos = 'offset';
+
+ if ( typeof options === 'number') {
+ opts = $.fn.smoothScroll.defaults;
+ scrollTargetOffset = options;
+ } else {
+ opts = $.extend({}, $.fn.smoothScroll.defaults, options || {});
+ if (opts.scrollElement) {
+ offPos = 'position';
+ if (opts.scrollElement.css('position') == 'static') {
+ opts.scrollElement.css('position', 'relative');
+ }
+ }
+
+console.dir($(opts.scrollTarget)[offPos]());
+ scrollTargetOffset = px ||
+ ( $(opts.scrollTarget)[offPos]() &&
+ $(opts.scrollTarget)[offPos]()[opts.direction] ) ||
+ 0;
+ }
+ opts = $.extend({link: null}, opts);
+
+ var $scroller = opts.scrollElement || $('html, body').scrollable(),
+ dirs = {top: 'Top', 'left': 'Left'},
+ aniprops = {};
+
+ aniprops['scroll' + dirs[opts.direction]] = scrollTargetOffset + opts.offset;
+ $scroller.animate(aniprops,
+ {
+ duration: opts.speed,
+ easing: opts.easing,
+ complete: function() {
+ if ( opts.afterScroll && $.isFunction(opts.afterScroll) ) {
+ opts.afterScroll.call(opts.link, opts);
+ }
+ }
+ });
+
+};
+
+$.smoothScroll.version = version;
+
+// default options
+$.fn.smoothScroll.defaults = {
+ exclude: [],
+ excludeWithin:[],
+ offset: 0,
+ direction: 'top', // one of 'top' or 'left'
+ scrollElement: null, // jQuery set of elements you wish to scroll.
+ //if null (default), $('html, body').scrollable() is used.
+ scrollTarget: null, // only use if you want to override default behavior
+ afterScroll: null, // function to be called after window is scrolled. "this" is the triggering element
+ easing: 'swing',
+ speed: 400
+};
+
+
+// private function
+function filterPath(string) {
+ return string
+ .replace(/^\//,'')
+ .replace(/(index|default).[a-zA-Z]{3,4}$/,'')
+ .replace(/\/$/,'');
+}
+
+
+})(jQuery);
View
@@ -4,7 +4,7 @@
*
* Copyright 2010, Karl Swedberg
* Dual licensed under the MIT or GPL Version 2 licenses.
- *
+ *
*
* Date: Thu Sep 2 16:15:54 2010 -0400
*/
@@ -13,10 +13,12 @@ var KS = {
includes: {},
params: $.param.fragment(),
cache: {},
- url: /\.dev/.test(location.hostname) ?
+ url: /\.dev$/.test(location.hostname) ?
'http://api.dev/jsonp/?callback=?' :
'http://api.jquery.com/jsonp/?callback=?'
};
+var $form = $('#jqas');
+
$('#title').focus();
$('#search-again').bind('click', function(event) {
@@ -25,50 +27,64 @@ $('#search-again').bind('click', function(event) {
$(this).closest('form').find('fieldset').slideToggle();
});
-$('form').bind('submit', function(event) {
- event.preventDefault();
-
- $('#search-again').trigger('click');
+$.fn.includeParams = function() {
+ KS.include = this.find('input:checkbox').serializeArray();
- KS.params = $(this).find('input:text, input:radio').serialize();
- KS.include = $(this).find('input:checkbox').serializeArray();
-
+ KS.includes = {};
for (var i=0; i < KS.include.length; i++) {
KS.includes[ KS.include[i].value ] = true;
}
+ return '&' + $.param(KS.include);
+};
+
+$form.bind('submit', function(event) {
+ event.preventDefault();
+
+ $('#search-again').trigger('click');
+
+ KS.params = $form.find('input:text, input:radio').serialize();
+ $form.includeParams();
$.bbq.pushState('#' + KS.params);
-
-});
+});
+$form.find('input:checkbox').bind('click', function(event) {
+ $form.includeParams();
+ outputResults( KS.cache[ $.param.fragment() ]);
+});
-$(window).bind('hashchange', function(event) {
+$(window).bind('hashchange', function(event, initial) {
var search = $.param.fragment();
-
+ if ( $.bbq.getState('scrollTarget') && !initial ) {
+ return;
+ }
if (!window.location.hash) {
$('#log').html('');
} else if (search in KS.cache) {
- $('#log').html( KS.cache[search] );
+ outputResults( KS.cache[search] );
} else {
$('#log').html('<blink style="color: #999;">loading ...</blink>');
- $.getJSON(KS.url, search, outputResults);
+ $.getJSON(KS.url, search, function(json) {
+ outputResults(json, true);
+ });
}
});
// trigger the hashchange on page load so we can return to the initial state
// and in case the user goes directly to a search
-$(window).trigger('hashchange');
+$('form').includeParams();
+$(window).trigger('hashchange', true);
var buildItem = {
// build all of the signatures (syntaxes) for a single method
// calls buildItem.params() and buildItem.version()
signatures: function(item) {
var sigs = item.signatures;
- if (!sigs.length || (!KS.includes['added'] && !KS.includes['params'])) {
+ if (!sigs || !sigs.length || (!KS.includes['added'] && !KS.includes['params'])) {
return this.title(item, {index: 0});
}
- var allSigs = '';
+ var allSigs = '';
for (var i = 0, sigCount = sigs.length; i < sigCount; i++) {
allSigs += (i == sigCount -1) ? '<div class="signature last">' : '<div class="signature">';
@@ -81,7 +97,7 @@ var buildItem = {
}
allSigs += '</div>';
}
-
+
return '<div class="signatures">' + allSigs + '</div>';
},
// build all of the params for a single signature (syntax)
@@ -106,8 +122,8 @@ var buildItem = {
// build the title for each method signature (syntax)
title: function(item, options) {
var opts = $.extend({
- index: 0,
- pre: '<strong>',
+ index: 0,
+ pre: '<strong>',
post: '</strong>'
}, options);
@@ -126,15 +142,15 @@ var buildItem = {
}
return opts.pre + item.newTitle + opts.post;
},
-
+
// build the short description for each entry
desc: function(item) {
if (KS.includes['desc']) {
return '<div class="desc">' + item.desc + '</div>';
}
return '';
},
-
+
// build the long description for each entry
longdesc: function(item) {
if (KS.includes['longdesc']) {
@@ -145,30 +161,33 @@ var buildItem = {
};
-function outputResults(json) {
+function outputResults(json, xhr) {
var toc = [],
list = [],
entryCount = json.length;
+ if (xhr) {
+ KS.cache[ KS.params ] = json;
+ }
for (var i=0; i < entryCount; i++) {
var it = json[i],
itemParts = [],
ipCount = 0,
entryid = 'entry-' + i;
-
+
toc[i] = buildItem.title(it, {
- pre: '<li><a href="#' + entryid + '">',
+ pre: '<li><a href="#' + entryid + '">',
post: '</a></li>'
});
-
-
- itemParts[ipCount++] = '<h4><a id="' + entryid + '" href="' + it.url + '">' + it.title + '</a></h4>';
+
+
+ itemParts[ipCount++] = '<h4><a href="' + it.url + '">' + it.title + '</a></h4>';
itemParts[ipCount++] = buildItem.signatures(it);
-
+
itemParts[ipCount++] = buildItem.desc(it);
itemParts[ipCount++] = buildItem.longdesc(it);
-
+
list[i] = '<li id="' + entryid + '">' + itemParts.join('') + '</li>';
}
@@ -184,14 +203,13 @@ function outputResults(json) {
} else {
$('#log').html('<p>Sorry, nothing found.</p>');
}
- KS.cache[ $.param.fragment() ] = $('#log').html();
}
function resultMsg(num) {
var txt = '<strong>' + num + '</strong> ';
txt += num == 1 ? 'result found' : 'results found';
return '<p>' + txt + '</p>';
-
+
}

0 comments on commit 7ac5155

Please sign in to comment.