preserve filters on ajax SERP (bug 695659)

This commit is contained in:
Chris Van 2011-10-21 20:42:30 -07:00
Родитель 21d3e6459e
Коммит 58a3e66e96
8 изменённых файлов: 165 добавлений и 21 удалений

Просмотреть файл

@ -40,7 +40,8 @@
<ul class="facet-group">
{% for link in links recursive %}
<li{% if link.selected %} class="selected"{% endif %}>
<a href="{{ request.get_full_path()|urlparams(page=None, **link.urlparams) }}">
<a href="{{ request.get_full_path()|urlparams(page=None, **link.urlparams) }}"
data-params="{{ link.urlparams|json }}">
{{ link.text }}</a>
{% if link.children %}
<ul>{{ loop(link.children) }}</ul>

Просмотреть файл

@ -20,16 +20,27 @@ $(function() {
if ($this.html() != newCount.html()) {
$this.replaceWith(newCount);
}
}).delegate('a[data-params]', 'rebuild', function(e) {
var $this = $(this),
url = rebuildLink($this.attr('href'), $this.attr('data-params'));
$this.attr('href', url);
});
if ($('body').hasClass('pjax') && $.support.pjax) {
initSearchPjax('#pjax-results');
if ($('body').hasClass('pjax') && $.support.pjax && z.capabilities.JSON) {
$('#pjax-results').initSearchPjax($('#search-facets'));
}
});
function initSearchPjax(container) {
var $container = $(container),
function rebuildLink(url, urlparams, qs) {
var params = JSON.parseNonNull(urlparams),
newVars = $.extend(z.getVars(qs), params);
return url.split('?')[0] + '?' + $.param(newVars);
}
$.fn.initSearchPjax = function($filters) {
var $container = $(this),
container = $container.selector,
timeouts = 0;
function pjaxOpen(url) {
@ -72,6 +83,8 @@ function initSearchPjax(container) {
// Insert the loading throbber.
$('<div>', {'class': cls, 'html': msg}).insertBefore($container);
$container.trigger('search.loading');
}
function finished() {
@ -84,14 +97,19 @@ function initSearchPjax(container) {
initListingCompat();
});
// Remove the loading indicator.
// Remove the loading throbber.
$wrapper.removeClass('loading').find('.updating').remove();
// Update the # of matching results on sidebar.
$('#search-facets .cnt').trigger('recount', [$wrapper.find('.cnt')]);
$filters.find('.cnt').trigger('recount', [$wrapper.find('.cnt')]);
// Scroll up.
// Update GET parameters of sidebar anchors.
$filters.find('a[data-params]').trigger('rebuild');
// Scroll up to top of page.
$('html, body').animate({scrollTop: 0}, 200);
$container.trigger('search.finished');
}
function turnPages(e) {
@ -113,4 +131,4 @@ function initSearchPjax(container) {
$('.pjax-trigger a').live('click', _pd(hijackLink));
$container.bind('start.pjax', loading).bind('end.pjax', finished);
$(document).keyup(_.throttle(turnPages, 300));
}
};

Просмотреть файл

@ -0,0 +1,27 @@
z.getVars = function(qs) {
if (typeof qs === 'undefined') {
qs = location.search;
}
var vars = {};
if (qs.length > 1) {
var items = qs.substr(1).split('&'),
item;
for (var i = 0; i < items.length; i++) {
item = items[i].split('=');
if (!!item[1]) {
vars[escape_(unescape(item[0]))] = escape_(unescape(item[1]));
}
}
}
return vars;
};
JSON.parseNonNull = function(text) {
return JSON.parse(text, function(key, value) {
if (typeof value === 'object' && value === null) {
return '';
}
return value;
});
};

Просмотреть файл

@ -0,0 +1,61 @@
module('Pjax Search', {
setup: function() {
this.container = $('#pjax-results', this.sandbox);
this.filters = $('#search-facets', this.sandbox);
this.container.initSearchPjax(this.filters);
}
});
test('Loading', function() {
var loaded = false;
this.container.bind('search.loading', function() {
loaded = true;
});
$.when(this.container.trigger('start.pjax')).done(function() {
ok(loaded);
})
});
test('Finished', function() {
var finished = false;
this.container.bind('search.finished', function() {
finished = true;
});
$.when(this.container.trigger('end.pjax')).done(function() {
ok(finished);
})
});
test('Rebuild links', function() {
function check(s, expected) {
// rebuildLink accepts the following parameters:
// 1) previous target URL,
// 2) fixed URL params,
// 3) new query string (i.e, location.search)
equal(rebuildLink(s[0], s[1], s[2]), expected);
}
// We're showing results for Macs, so the filter URLs should get updated
// to reflect that.
check(['/en-US/firefox/search/?q=adblock&amp;appver=10.0',
'{"appver": "10.0"}',
'?q=adblock&platform=mac'],
'/en-US/firefox/search/?q=adblock&platform=mac&appver=10.0');
// We're showing results filtered by cat 14, so the filter URL for cat 72
// should not change values.
check(['/en-US/firefox/search/?q=adblock&amp;appver=8.0&amp;cat=72&amp;atype=1',
'{"atype": 1, "cat": 72}',
'?q=adblock&cat=14&atype=1'],
'/en-US/firefox/search/?q=adblock&cat=72&atype=1');
// We're showing results filtered by cat 14, so the filter URL to show
// all categories/types should not contain cat=14.
check(['/en-US/firefox/search/?q=adblock',
'{"atype": null, "cat": null}',
'?q=adblock&cat=14'],
'/en-US/firefox/search/?q=adblock&cat=&atype=');
});

Просмотреть файл

@ -0,0 +1,39 @@
module('Serializers');
test('getVars', function() {
function check(s, expected) {
tests.equalObjects(z.getVars(s), expected);
}
check('', {});
check('?', {});
check('?a', {});
check('?==a', {});
check('?a=apple&a=apricot', {'a': 'apricot'});
check('?a=apple&b=banana&c=carrot',
{'a': 'apple', 'b': 'banana', 'c': 'carrot'});
check('?a?a=apple', {'a?a': 'apple'});
check('?a=apple&b?c=banana', {'a': 'apple', 'b?c': 'banana'});
check('?a=b=c&d=e', {'a': 'b', 'd': 'e'});
check('?<script>alert("xss")</script>="a"',
{'&lt;script&gt;alert(&#34;xss&#34;)&lt;/script&gt;': '&#34;a&#34;'});
check('?"a"=<script>alert("xss")</script>',
{'&#34;a&#34;': '&lt;script&gt;alert(&#34;xss&#34;)&lt;/script&gt;'});
});
test('JSON.parseNonNull', function() {
function check(s, expected) {
tests.equalObjects(JSON.parseNonNull(s), JSON.parse(expected));
}
check('[]', '[]');
check('{}', '{}');
check('{"x": "xxx", "y": "yyy"}',
'{"x": "xxx", "y": "yyy"}');
check('{"x": "null", "y": null}',
'{"x": "null", "y": ""}');
check('[{"x": "null", "y": null}, {"x": "null", "y": null}]',
'[{"x": "null", "y": ""}, {"x": "null", "y": ""}]');
check('[{"w": {"x": null, "y": {"z": null}}}]',
'[{"w": {"x": "", "y": {"z": ""}}}]');
});

Просмотреть файл

@ -3,21 +3,11 @@
"extra_media_urls": [
"js/lib/jstestnet.js",
"js/zamboni/tests.js",
"js/zamboni/buttons.js",
"js/impala/global.js",
"js/zamboni/devhub.js",
"js/zamboni/validator.js",
"js/zamboni/l10n.js",
"js/zamboni/truncation.js",
"js/zamboni/storage.js",
"js/zamboni/editors.js",
"js/zamboni/upload.js",
"js/zamboni/files.js",
"js/zamboni/contributions.js",
"js/zamboni/password-strength.js",
"js/impala/persona_creation.js",
"js/zamboni/browserid_support.js",
"js/impala/ajaxcache.js",
"js/impala/search.js"
"js/zamboni/browserid_support.js"
]
}

Просмотреть файл

@ -662,6 +662,7 @@ MINIFY_BUNDLES = {
'js/impala/users.js',
# Search
'js/impala/serializers.js',
'js/impala/search.js',
'js/impala/suggestions.js',

Просмотреть файл

@ -201,4 +201,11 @@
</form>
</div>
<div id="pjax-search">
<div id="search-facets">
<ul class="facets island pjax-trigger"></ul>
</div>
<div id="pjax-results"></div>
</div>
{% endblock %}