/* 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 = [];
// 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);
}
}
// restore edit mode after navigating back
function restoreEditMode() {
if (!$('#editing').val())
return;
$('.module')
.each(function() {
slide_module($(this), 'hide', true);
});
$($('#editing').val().split(' '))
.each(function() {
slide_module($('#' + this), 'show', true);
});
$('#mode-btn').click();
$('.save-btn').prop('disabled', false);
$('#editing').val('');
}
// 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();
});
// url --> unsafe warning
$('.bug-url')
.click(function(event) {
var that = $(this);
event.stopPropagation();
if (!that.data('safe')) {
event.preventDefault();
if (confirm('This is considered an unsafe URL and could possibly be harmful. ' +
'The full URL is:\n\n' + that.attr('href') + '\n\nContinue?'))
{
try {
window.open(that.attr('href'));
} catch(ex) {
alert('Malformed URL');
}
}
}
});
// top btn
$('#top-btn')
.click(function(event) {
event.preventDefault();
$.scrollTo($('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
function clipboardSummary() {
return 'Bug ' + BUGZILLA.bug_id + ' - ' + $('#field-value-short_desc').text();
}
if ($('#copy-summary').length) {
// probe for document.execCommand("copy") support
var hasExecCopy = false;
try {
// on page load nothing will be selected, so we don't smash the
// clipboard doing this
document.execCommand("copy");
hasExecCopy = true;
} catch(ex) {
// ignore
}
if (hasExecCopy) {
$('#copy-summary')
.click(function() {
// execCommand("copy") only works on selected text
$('#clip-container').show();
$('#clip').val(clipboardSummary()).select();
document.execCommand("copy");
$('#clip-container').hide();
});
}
else {
// we don't know if flash is enabled without waiting for load to timeout
// remember the flash enabled state between pages
var hasFlash = true;
if (localStorage.getItem('hasFlash') === null) {
$('#copy-summary').hide();
}
else {
hasFlash = localStorage.getItem('hasFlash');
}
if (hasFlash) {
ZeroClipboard.config({ flashLoadTimeout: 5000 });
var zero = new ZeroClipboard($('#copy-summary'));
zero.on({
'ready': function(event) {
$('#copy-summary').show();
localStorage.setItem('hasFlash', true);
},
'error': function(event) {
console.log(event.message);
zero.destroy();
$('#global-zeroclipboard-html-bridge').remove();
$('#copy-summary').hide();
localStorage.removeItem('hasFlash');
},
'copy': function(event) {
var clipboard = event.clipboardData;
clipboard.setData('text/plain', clipboardSummary());
}
});
}
}
}
// 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();
}
});
// action button menu
$.contextMenu({
selector: '#action-menu-btn',
trigger: 'left',
items: $.contextMenu.fromMenu($('#action-menu'))
});
// reset
$('#action-reset')
.click(function(event) {
event.preventDefault();
var visible = $(this).data('modules');
$('.module-content').each(function() {
var content = $(this);
var moduleID = content.parent('.module').attr('id');
var isDefault = $.inArray(moduleID, visible) !== -1;
if (content.is(':visible') && !isDefault) {
slide_module($('#' + moduleID), 'hide');
}
else if (content.is(':hidden') && isDefault) {
slide_module($('#' + moduleID), 'show');
}
});
})
.data('modules', $('.module-content:visible').map(function() {
return $(this).parent('.module').attr('id');
}));
// expand all modules
$('#action-expand-all')
.click(function(event) {
event.preventDefault();
$('.module-content:hidden').each(function() {
slide_module($(this).parent('.module'));
});
});
// collapse all modules
$('#action-collapse-all')
.click(function(event) {
event.preventDefault();
$('.module-content:visible').each(function() {
slide_module($(this).parent('.module'));
});
});
// add comment menuitem, scroll the textarea into view
$('#action-add-comment')
.click(function(event) {
event.preventDefault();
// focus first to grow the textarea, so we scroll to the correct location
$('#comment').focus();
$.scrollTo($('#bottom-save-btn'));
});
// last comment menuitem
$('#action-last-comment')
.click(function(event) {
event.preventDefault();
var id = $('.comment:last')[0].parentNode.id;
$.scrollTo(id);
});
// use scrollTo for in-page activity links
$('.activity-ref')
.click(function(event) {
event.preventDefault();
$.scrollTo($(this).attr('href').substr(1));
});
if (BUGZILLA.user.id === 0) return;
//
// anything after this point is only executed for logged in users
//
// 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($('