summaryrefslogtreecommitdiffstats
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/dropdown.js69
-rw-r--r--js/global.js41
2 files changed, 97 insertions, 13 deletions
diff --git a/js/dropdown.js b/js/dropdown.js
index fd71d0b6e..03345206b 100644
--- a/js/dropdown.js
+++ b/js/dropdown.js
@@ -16,7 +16,7 @@ $(function() {
// clicking dropdown button opens or closes the dropdown content
if (!$(e.target).hasClass('dropdown-button')) {
$('.dropdown-button').each(function() {
- toggleDropDown(e, $(this), $('#' + $(this).attr('aria-controls')), 1);
+ toggleDropDown(e, $(this), $('#' + $(this).attr('aria-controls')), false, true);
});
}
}).keydown(function(e) {
@@ -25,7 +25,7 @@ $(function() {
$('.dropdown-button').each(function() {
var $button = $(this);
if ($button.siblings('.dropdown-content').is(':visible')) {
- toggleDropDown(e, $button, $('#' + $button.attr('aria-controls')), 1);
+ toggleDropDown(e, $button, $('#' + $button.attr('aria-controls')), false, true);
$button.focus();
}
});
@@ -83,7 +83,7 @@ $(function() {
// navigate to an active link or click on it
// note that `trigger('click')` doesn't always work
if (e.keyCode == 13) {
- var $link = $('.dropdown-content:visible a.active');
+ var $link = $('.dropdown-content:visible .active');
if ($link.length) {
if ($link.attr('href')) {
location.href = $link.attr('href');
@@ -105,7 +105,7 @@ $(function() {
var $content = $div.find('.dropdown-content');
$button.click(function(e) {
// Do not handle non-primary click.
- if (e.button != 0) {
+ if (e.button != 0 || $content.hasClass('hover-display')) {
return;
}
toggleDropDown(e, $button, $content);
@@ -115,9 +115,13 @@ $(function() {
// prevent the form being submitted if the search bar is empty
e.preventDefault();
// navigate to an active link if any
- var $link = $content.find('a.active');
+ var $link = $content.find('.active');
if ($link.length) {
- location.href = $link.attr('href');
+ if ($link.attr('href')) {
+ location.href = $link.attr('href');
+ } else {
+ $link.trigger('click');
+ }
}
}
@@ -125,9 +129,49 @@ $(function() {
toggleDropDown(e, $button, $content);
}
});
+
+ if ($content.hasClass('hover-display')) {
+ const $_button = $button.get(0);
+ const $_content = $content.get(0);
+ let timer;
+
+ const button_handler = event => {
+ event.preventDefault();
+ event.stopPropagation();
+ window.clearTimeout(timer);
+
+ if (event.type === 'mouseleave' && $_content.matches('.hovered')) {
+ return;
+ }
+
+ timer = window.setTimeout(() => {
+ toggleDropDown(event, $button, $content, event.type === 'mouseenter', event.type === 'mouseleave');
+ }, 250);
+ };
+
+ const content_handler = event => {
+ event.preventDefault();
+ event.stopPropagation();
+ window.clearTimeout(timer);
+
+ $_content.classList.toggle('hovered', event.type === 'mouseenter');
+
+ if (event.type === 'mouseleave') {
+ timer = window.setTimeout(() => {
+ toggleDropDown(event, $button, $content, false, true);
+ }, 250);
+ }
+ };
+
+ // Use raw `addEventListener` as jQuery actually listens `mouseover` and `mouseout`
+ $_button.addEventListener('mouseenter', event => button_handler(event));
+ $_button.addEventListener('mouseleave', event => button_handler(event));
+ $_content.addEventListener('mouseenter', event => content_handler(event));
+ $_content.addEventListener('mouseleave', event => content_handler(event));
+ }
});
- function toggleDropDown(e, $button, $content, hide_only) {
+ function toggleDropDown(e, $button, $content, show_only, hide_only) {
// hide other expanded dropdown menu if any
var $expanded = $('.dropdown-button[aria-expanded="true"]');
if ($expanded.length && !$expanded.is($button)) {
@@ -148,13 +192,12 @@ $(function() {
$('[aria-controls="' + content_id + '"]').removeAttr('aria-activedescendant');
$content.find('#' + content_id + '-active-item').removeAttr('id');
}
- if ($content.is(':visible')) {
- $content.hide();
- $button.attr('aria-expanded', false);
- }
// if not using Escape or clicking outside the dropdown div, then we are hiding
- else if (!hide_only) {
- $content.show();
+ if ($content.is(':visible') || hide_only) {
+ $content.fadeOut('fast');
+ $button.attr('aria-expanded', false);
+ } else if (!$content.is(':visible') || show_only) {
+ $content.fadeIn('fast');
$button.attr('aria-expanded', true);
}
}
diff --git a/js/global.js b/js/global.js
index d0396d6a8..37567e3de 100644
--- a/js/global.js
+++ b/js/global.js
@@ -155,6 +155,47 @@ function display_value(field, value) {
return value;
}
+// ajax wrapper, to simplify error handling and auth
+// TODO: Rewrite this method using Promise (Bug 1380437)
+function bugzilla_ajax(request, done_fn, error_fn) {
+ $('#xhr-error').hide('');
+ $('#xhr-error').html('');
+ request.url += (request.url.match('\\?') ? '&' : '?') +
+ 'Bugzilla_api_token=' + encodeURIComponent(BUGZILLA.api_token);
+ if (request.type != 'GET') {
+ request.contentType = 'application/json';
+ request.processData = false;
+ if (request.data && request.data.constructor === Object) {
+ request.data = JSON.stringify(request.data);
+ }
+ }
+ return $.ajax(request)
+ .done(function(data) {
+ if (data.error) {
+ if (!request.hideError) {
+ $('#xhr-error').html(data.message);
+ $('#xhr-error').show('fast');
+ }
+ if (error_fn)
+ error_fn(data.message);
+ }
+ else if (done_fn) {
+ done_fn(data);
+ }
+ })
+ .fail(function(data) {
+ if (data.statusText === 'abort')
+ return;
+ var message = data.responseJSON ? data.responseJSON.message : 'Unexpected Error'; // all errors are unexpected :)
+ if (!request.hideError) {
+ $('#xhr-error').html(message);
+ $('#xhr-error').show('fast');
+ }
+ if (error_fn)
+ error_fn(message);
+ });
+}
+
// polyfill .trim
if (!String.prototype.trim) {
(function() {