/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This Source Code Form is "Incompatible With Secondary Licenses", as
* defined by the Mozilla Public License, v. 2.0. */
$(function() {
'use strict';
// update relative dates
window.setInterval(function() {
var now = Math.floor(new Date().getTime() / 1000);
$('.rel-time').each(function() {
$(this).text(timeAgo(now - $(this).data('time')));
});
$('.rel-time-title').each(function() {
$(this).attr('title', timeAgo(now - $(this).data('time')));
});
}, 60000);
// all keywords for autocompletion (lazy-loaded on edit)
var keywords = [];
// products with descriptions (also lazy-loaded)
var products = [];
// scroll to an element
function scroll_to(el, complete) {
var offset = el.offset();
$('html, body')
.animate({
scrollTop: offset.top - 20,
scrollLeft: offset.left = 20
},
200,
complete
);
}
// expand/collapse module
function slide_module(module, action, fast) {
if (!module.attr('id'))
return;
var latch = module.find('.module-latch');
var spinner = $(latch.children('.module-spinner')[0]);
var content = $(module.children('.module-content')[0]);
var duration = fast ? 0 : 200;
function slide_done() {
spinner.html(content.is(':visible') ? '▾' : '▸');
}
if (action == 'show') {
content.slideDown(duration, 'swing', slide_done);
}
else if (action == 'hide') {
content.slideUp(duration, 'swing', slide_done);
}
else {
content.slideToggle(duration, 'swing', slide_done);
}
}
// expand all modules
$('#expand-all-btn')
.click(function(event) {
event.preventDefault();
var btn = $(event.target);
var modules;
if (btn.data('expanded-modules')) {
modules = btn.data('expanded-modules');
btn.data('expanded-modules', false);
modules.each(function() {
slide_module($(this).parent('.module'));
});
btn.text('Expand All');
}
else {
modules = $('.module-content:hidden');
btn.data('expanded-modules', modules);
modules.each(function() {
slide_module($(this).parent('.module'));
});
btn.text('Collapse');
}
});
// expand/colapse module
$('.module-header')
.click(function(event) {
event.preventDefault();
slide_module($(this).parents('.module'));
});
// toggle obsolete attachments
$('#attachments-obsolete-btn')
.click(function(event) {
event.preventDefault();
$(event.target).text(($('#attachments tr:hidden').length ? 'Hide' : 'Show') + ' Obsolete Attachments');
$('#attachments tr.attach-obsolete').toggle();
});
// comment collapse/expand
$('.comment-spinner')
.click(function(event) {
event.preventDefault();
var spinner = $(event.target);
var id = spinner.attr('id').match(/\d+$/)[0];
// switch to full header for initially collapsed comments
if (spinner.attr('id').match(/^ccs-/)) {
$('#cc-' + id).hide();
$('#ch-' + id).show();
}
$('#ct-' + id).slideToggle('fast', function() {
$('#c' + id).find('.activity').toggle();
spinner.text($('#ct-' + id + ':visible').length ? '-' : '+');
});
});
// url --> unsafe warning
$('.unsafe-url')
.click(function(event) {
event.preventDefault();
if (confirm('This is considered an unsafe URL and could possibly be harmful. ' +
'The full URL is:\n\n' + $(event.target).attr('title') + '\n\nContinue?'))
{
try {
window.open($(event.target).attr('title'));
} catch(ex) {
alert('Malformed URL');
}
}
});
// last comment btn
$('#last-comment-btn')
.click(function(event) {
event.preventDefault();
var id = $('.comment:last')[0].parentNode.id;
scroll_to($('#' + id));
window.location.hash = id;
});
// top btn
$('#top-btn')
.click(function(event) {
event.preventDefault();
scroll_to($('body'));
});
// use non-native tooltips for relative times and bug summaries
$('.rel-time, .rel-time-title, .bz_bug_link, .tt').tooltip({
position: { my: "left top+8", at: "left bottom", collision: "flipfit" },
show: { effect: 'none' },
hide: { effect: 'none' }
});
// tooltips create a new ui-helper-hidden-accessible div each time a
// tooltip is shown. this is never removed leading to memory leak and
// bloated dom. http://bugs.jqueryui.com/ticket/10689
$('.ui-helper-hidden-accessible').remove();
// product/component info
$('.spin-toggle, #product-latch, #component-latch')
.click(function(event) {
event.preventDefault();
var latch = $($(event.target).data('latch'));
var el_for = $($(event.target).data('for'));
if (latch.data('expanded')) {
latch.data('expanded', false).html('▸');
el_for.hide();
}
else {
latch.data('expanded', true).html('▾');
el_for.show();
}
});
// cc list
$('#cc-latch, #cc-summary')
.click(function(event) {
event.preventDefault();
var latch = $('#cc-latch');
if (latch.data('expanded')) {
latch.data('expanded', false).html('▸');
$('#cc-list').hide();
}
else {
latch.data('expanded', true).html('▾');
$('#cc-list').show();
if (!latch.data('fetched')) {
$('#cc-list').html(
' Loading...'
);
bugzilla_ajax(
{
url: 'rest/bug_modal/cc/' + BUGZILLA.bug_id
},
function(data) {
$('#cc-list').html(data.html);
latch.data('fetched', true);
}
);
}
}
});
// copy summary to clipboard
if ($('#copy-summary').length) {
var zero = new ZeroClipboard($('#copy-summary'));
zero.on({
'error': function(event) {
console.log(event.message);
zero.destroy();
$('#copy-summary').hide();
},
'copy': function(event) {
var clipboard = event.clipboardData;
clipboard.setData('text/plain', 'Bug ' + BUGZILLA.bug_id + ' - ' + $('#field-value-short_desc').text());
}
});
}
// lightboxes
$('.lightbox, .comment-text .lightbox + span:first-of-type a:first-of-type')
.click(function(event) {
if (event.metaKey)
return;
event.preventDefault();
lb_show(this);
});
// when copying the bug id and summary, reformat to remove \n and alias
$(document).on(
'copy', function(event) {
var selection = document.getSelection().toString().trim();
var match = selection.match(/^(Bug \d+)\s*\n(.+)$/) ||
selection.match(/^(Bug \d+)\s+\([^\)]+\)\s*\n(.+)$/);
if (match) {
var content = match[1] + ' - ' + match[2].trim();
if (event.originalEvent.clipboardData) {
event.originalEvent.clipboardData.setData('text/plain', content);
}
else if (window.clipboardData) {
window.clipboardData.setData('Text', content);
}
else {
return;
}
event.preventDefault();
}
});
//
// anything after this point is only executed for logged in users
//
if (BUGZILLA.user.id === 0) return;
// dirty field tracking
$('#changeform select').each(function() {
var that = $(this);
var dirty = $('#' + that.attr('id') + '-dirty');
if (!dirty) return;
var isMultiple = that.attr('multiple');
// store the option that had the selected attribute when we
// initially loaded
var value = that.find('option[selected]').map(function() { return this.value; }).toArray();
if (value.length === 0 && !that.attr('multiple'))
value = that.find('option:first').map(function() { return this.value; }).toArray();
that.data('preselected', value);
// if the user hasn't touched a field, override the browser's choice
// with bugzilla's
if (!dirty.val())
that.val(value);
});
// edit/save mode button
$('#mode-btn')
.click(function(event) {
event.preventDefault();
// hide buttons, old error messages
$('#mode-btn-readonly').hide();
// toggle visibility
$('.edit-hide').hide();
$('.edit-show').show();
// expand specific modules during the initial edit
if (!$('#editing').val())
slide_module($('#module-details'), 'show');
// if there's no current user-story, it's a better experience if it's editable by default
if ($('#cf_user_story').val() === '') {
$('#user-story-edit-btn').click();
}
// "loading.." ui
$('#mode-btn-loading').show();
$('#cancel-btn').prop('disabled', true);
$('#mode-btn').prop('disabled', true);
// load the missing select data
bugzilla_ajax(
{
url: 'rest/bug_modal/edit/' + BUGZILLA.bug_id
},
function(data) {
$('#mode-btn').hide();
// populate select menus
$.each(data.options, function(key, value) {
var el = $('#' + key);
if (!el) return;
var selected = el.val();
el.empty();
$(value).each(function(i, v) {
el.append($('