diff options
author | Byron Jones <glob@mozilla.com> | 2015-05-26 17:59:57 +0200 |
---|---|---|
committer | Byron Jones <glob@mozilla.com> | 2015-05-26 17:59:57 +0200 |
commit | f8b984852ae27f14a5f44e651193f00977737ab1 (patch) | |
tree | 7b7d631f17fa9b82844f0db79b605f157fa48e2c /extensions/ProdCompSearch | |
parent | 95e71eea95c977eb7512156be813ede7eb161600 (diff) | |
download | bugzilla-f8b984852ae27f14a5f44e651193f00977737ab1.tar.gz bugzilla-f8b984852ae27f14a5f44e651193f00977737ab1.tar.xz |
Bug 1146782: backport bug 1159589 to bmo (migrate autocomplete from yui to jquery)
Diffstat (limited to 'extensions/ProdCompSearch')
3 files changed, 146 insertions, 107 deletions
diff --git a/extensions/ProdCompSearch/lib/WebService.pm b/extensions/ProdCompSearch/lib/WebService.pm index a28b5d059..521d1588f 100644 --- a/extensions/ProdCompSearch/lib/WebService.pm +++ b/extensions/ProdCompSearch/lib/WebService.pm @@ -113,7 +113,7 @@ sub prod_comp_search { unshift @order, "products.name != 'bugzilla.mozilla.org'"; } - my $products = $dbh->selectall_arrayref(" + my $components = $dbh->selectall_arrayref(" SELECT products.name AS product, components.name AS component FROM products @@ -124,6 +124,15 @@ sub prod_comp_search { ORDER BY " . join(", ", @order) . " $limit", { Slice => {} }); + my $products = []; + my $current_product; + foreach my $component (@$components) { + if (!$current_product || $component->{product} ne $current_product) { + $current_product = $component->{product}; + push @$products, { product => $current_product }; + } + push @$products, $component; + } return { products => $products }; } diff --git a/extensions/ProdCompSearch/template/en/default/prodcompsearch/form.html.tmpl b/extensions/ProdCompSearch/template/en/default/prodcompsearch/form.html.tmpl index 39919510c..c232f677d 100644 --- a/extensions/ProdCompSearch/template/en/default/prodcompsearch/form.html.tmpl +++ b/extensions/ProdCompSearch/template/en/default/prodcompsearch/form.html.tmpl @@ -35,10 +35,10 @@ <img id="[% id FILTER html %]-throbber" src="extensions/ProdCompSearch/web/images/throbber.gif" style="display:none" width="16" height="11"> - <span class="pcs-message" id="[% id FILTER html %]-no_components" style="display:none"> + <span class="pcs-message" id="[% id FILTER html %]-no_results" style="display:none"> No components found </span> - <span class="pcs-message" id="[% id FILTER html %]-too_many_components" style="display:none"> + <span class="pcs-message" id="[% id FILTER html %]-too_many_results" style="display:none"> Result limited to [% max_results FILTER html %] components </span> <span class="pcs-message" id="[% id FILTER html %]-error" style="display:none"> diff --git a/extensions/ProdCompSearch/web/js/prod_comp_search.js b/extensions/ProdCompSearch/web/js/prod_comp_search.js index 2c9516967..69cc7cc0b 100644 --- a/extensions/ProdCompSearch/web/js/prod_comp_search.js +++ b/extensions/ProdCompSearch/web/js/prod_comp_search.js @@ -9,112 +9,142 @@ $(function() { 'use strict'; - $('.prod_comp_search').autocomplete({ - minLength: 3, - delay: 500, - source: function(request, response) { - var el = this.element; - $(document).trigger('pcs:search', [ el ]); - var id = '#' + el.prop('id'); - var throbber = $('#' + $(el).data('throbber')); - throbber.show(); - $(id + '-no_components').hide(); - $(id + '-too_many_components').hide(); - $(id + '-error').hide(); - var url = 'rest/prod_comp_search/' + encodeURIComponent(request.term) + - '?limit=' + (el.data('max_results') + 1); - if (BUGZILLA.api_token) { - url += '&Bugzilla_api_token=' + encodeURIComponent(BUGZILLA.api_token); - } - $.ajax({ - url: url, - contentType: 'application/json' - }) - .done(function(data) { - throbber.hide(); - if (data.error) { - $(id + '-error').show(); - console.log(data.message); - return false; - } - if (data.products.length === 0) { - $(id + '-no_results').show(); - $(document).trigger('pcs:no_results', [ el ]); - } - else if (data.products.length > el.data('max_results')) { - $(id + '-too_many_results').show(); - $(document).trigger('pcs:too_many_results', [ el ]); - } - else { - $(document).trigger('pcs:results', [ el, data ]); - } - var current_product = ""; - var prod_comp_array = []; - var base_params = []; - if (el.data('format')) { - base_params.push('format=' + encodeURIComponent(el.data('format'))); - } - if (el.data('cloned_bug_id')) { - base_params.push('cloned_bug_id=' + encodeURIComponent(el.data('cloned_bug_id'))); - } - $.each(data.products, function() { - var params = base_params.slice(); - params.push('product=' + encodeURIComponent(this.product)); - if (this.product != current_product) { - prod_comp_array.push({ - label: this.product, - product: this.product, - url: el.data('script_name') + '?' + params.join('&') - }); - current_product = this.product; + + function hideNotifications(target) { + var id = '#' + $(target).prop('id'); + var that = $(id); + if (that.data('counter') === 0) + that.removeClass('autocomplete-running'); + $(id + '-no_results').hide(); + $(id + '-too_many_results').hide(); + $(id + '-error').hide(); + } + + function searchComplete(query, suggestions) { + var that = $(this); + var id = '#' + that.prop('id'); + + that.data('counter', that.data('counter') - 1); + hideNotifications(this); + if (document.activeElement != this) + that.devbridgeAutocomplete('hide'); + if (that.data('error')) { + searchError.call(that[0], null, null, null, that.data('error')); + that.data('error', ''); + } + + if (suggestions.length === 0) { + $(id + '-no_results').show(); + $(document).trigger('pcs:no_results', [ that ]); + } + else if (suggestions.length > that.data('max_results')) { + $(id + '-too_many_results').show(); + $(document).trigger('pcs:too_many_results', [ that ]); + } + else { + $(document).trigger('pcs:results', [ that, suggestions ]); + } + } + + function searchError(q, jqXHR, textStatus, errorThrown) { + var that = $(this); + that.data('counter', that.data('counter') - 1); + hideNotifications(this); + if (errorThrown !== 'abort') { + $('#' + that.attr('id') + '-error').show(); + console.log(errorThrown); + } + } + + $('.prod_comp_search') + .each(function() { + var that = $(this); + that.devbridgeAutocomplete({ + serviceUrl: function(query) { + return 'rest/prod_comp_search/' + encodeURIComponent(query); + }, + params: { + Bugzilla_api_token: (BUGZILLA.api_token ? BUGZILLA.api_token : ''), + limit: (that.data('max_results') + 1) + }, + deferRequestBy: 250, + minChars: 3, + maxHeight: 500, + tabDisabled: true, + autoSelectFirst: true, + triggerSelectOnValidInput: false, + width: '', + transformResult: function(response) { + response = $.parseJSON(response); + if (response.error) { + that.data('error', response.message); + return { suggestions: [] }; } - params.push('component=' + encodeURIComponent(this.component)); - var url = el.data('script_name') + '?' + params.join('&'); - if (el.data('anchor_component')) { - url += "#" + encodeURIComponent(this.component); + return { + suggestions: $.map(response.products, function(dataItem) { + if (dataItem.component) { + return { + value: dataItem.product + ' :: ' + dataItem.component, + data : dataItem + }; + } + else { + return { + value: dataItem.product, + data : dataItem + }; + } + }) + }; + }, + formatResult: function(suggestion, currentValue) { + var value = (suggestion.data.component ? suggestion.data.component : suggestion.data.product); + var escaped = value + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"'); + if (suggestion.data.component) { + return '- ' + escaped; } - prod_comp_array.push({ - label: this.product + ' :: ' + this.component, - product: this.product, - component: this.component, - url: url - }); - }); - response(prod_comp_array); - }) - .fail(function(xhr, error_text) { - if (xhr.responseJSON && xhr.responseJSON.error) { - error_text = xhr.responseJSON.message; + else { + return '<b>' + escaped + '</b>'; + } + return suggestion.data.component ? '- ' + escaped : escaped; + }, + beforeRender: function(container) { + container.css('min-width', that.outerWidth() - 2 + 'px'); + }, + onSearchStart: function(params) { + var that = $(this); + params.match = $.trim(params.match); + that.addClass('autocomplete-running'); + that.data('counter', that.data('counter') + 1); + that.data('error', ''); + hideNotifications(this); + }, + onSearchComplete: searchComplete, + onSearchError: searchError, + onSelect: function(suggestion) { + var that = $(this); + if (that.data('ignore-select')) + return; + + var params = []; + if (that.data('format')) + params.push('format=' + encodeURIComponent(that.data('format'))); + if (that.data('cloned_bug_id')) + params.push('cloned_bug_id=' + encodeURIComponent(that.data('cloned_bug_id'))); + params.push('product=' + encodeURIComponent(suggestion.data.product)); + if (suggestion.data.component) + params.push('component=' + encodeURIComponent(suggestion.data.component)); + + var url = that.data('script_name') + '?' + params.join('&'); + if (that.data('anchor_component') && suggestion.data.component) + url += "#" + encodeURIComponent(suggestion.data.component); + document.location.href = url; } - throbber.hide(); - $(id + '-comp_error').show(); - $(document).trigger('pcs:error', [ el, error_text ]); - console.log(error_text); }); - }, - focus: function(event, ui) { - event.preventDefault(); - }, - select: function(event, ui) { - event.preventDefault(); - var el = $(this); - el.val(ui.item.label); - if (el.data('ignore-select')) { - return; - } - if (el.data('new_tab')) { - window.open(ui.item.url, '_blank'); - } - else { - window.location.href = ui.item.url; - } - } - }) - .focus(function(event) { - var el = $(event.target); - if (el.val().length >= el.autocomplete('option', 'minLength')) { - el.autocomplete('search'); - } - }); - $('.prod_comp_search:focus').select(); + }) + .data('counter', 0); }); |