summaryrefslogtreecommitdiffstats
path: root/extensions/ProdCompSearch
diff options
context:
space:
mode:
authorByron Jones <glob@mozilla.com>2015-05-26 17:59:57 +0200
committerByron Jones <glob@mozilla.com>2015-05-26 17:59:57 +0200
commitf8b984852ae27f14a5f44e651193f00977737ab1 (patch)
tree7b7d631f17fa9b82844f0db79b605f157fa48e2c /extensions/ProdCompSearch
parent95e71eea95c977eb7512156be813ede7eb161600 (diff)
downloadbugzilla-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')
-rw-r--r--extensions/ProdCompSearch/lib/WebService.pm11
-rw-r--r--extensions/ProdCompSearch/template/en/default/prodcompsearch/form.html.tmpl4
-rw-r--r--extensions/ProdCompSearch/web/js/prod_comp_search.js238
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, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;');
+ if (suggestion.data.component) {
+ return '-&nbsp;' + 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 ? '-&nbsp;' + 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);
});