/* 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. */ // 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() { var is_visible = content.is(':visible'); spinner.html(is_visible ? '▾' : '▸'); if (BUGZILLA.user.settings.remember_collapsed) localStorage.setItem(module.attr('id') + '.visibility', is_visible ? 'show' : 'hide'); } 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); } } function init_module_visibility() { if (!BUGZILLA.user.settings.remember_collapsed) return; $('.module').each(function() { var that = $(this); var id = that.attr('id'); if (!id) return; if (that.data('non-stick')) return; var stored = localStorage.getItem(id + '.visibility'); if (stored) { slide_module(that, stored, true); } }); } $(function() { 'use strict'; // update relative dates var relative_timer_duration = 60000; var relative_timer_id = window.setInterval(relativeTimer, relative_timer_duration); $(document).on('show.visibility', function() { relative_timer_id = window.setInterval(relativeTimer, relative_timer_duration); }); $(document).on('hide.visibility', function() { window.clearInterval(relative_timer_id); }); function relativeTimer() { 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'))); }); } // all keywords for autocompletion (lazy-loaded on edit) var keywords = []; // products with descriptions (also lazy-loaded) var products = []; // 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')); }); // bottom btn $('#bottom-btn') .click(function(event) { event.preventDefault(); $.scrollTo($('#bottom-actions')); }); // hide floating message when clicked $('#floating-message') .click(function(event) { event.preventDefault(); $(this).hide(); }); // use non-native tooltips for relative/absolute times and bug summaries $('.rel-time, .rel-time-title, .abs-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 function ccListLoading() { $('#cc-list').html( ' Loading...' ); } function ccListUpdate() { bugzilla_ajax( { url: 'rest/bug_modal/cc/' + BUGZILLA.bug_id }, function(data) { $('#cc-list').html(data.html); $('#cc-latch').data('fetched', true); $('#cc-list .cc-user').hover( function() { $('#ccr-' + $(this).data('n')).css('visibility', 'visible'); }, function() { $('#ccr-' + $(this).data('n')).css('visibility', 'hidden'); } ); $('#cc-list .cc-remove') .click(function(event) { event.preventDefault(); $('#top-save-btn').show(); var n = $(this).data('n'); var ccu = $('#ccu-' + n); if (ccu.hasClass('cc-removed')) { ccu.removeClass('cc-removed'); $('#cc-' + n).remove(); } else { $('#removecc').val('on'); ccu.addClass('cc-removed'); $('').attr({ type: 'hidden', id: 'cc-' + n, value: $('#ccr-' + n).data('login'), name: 'cc' }).appendTo('#changeform'); } }); } ); } if (BUGZILLA.user.id) { $('#cc-summary').addClass('cc-loadable'); $('#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')) { ccListLoading(); ccListUpdate(); } } }); } // copy summary to clipboard function clipboardSummary() { return 'Bug ' + BUGZILLA.bug_id + ' - ' + $('#field-value-short_desc').text(); } if ($('#copy-summary').length) { var hasExecCopy = false; try { hasExecCopy = document.queryCommandSupported("copy"); } 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 || event.ctrlKey || event.altKey || event.shiftKey) 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, #add-comment-btn') .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); }); // show bug history $('#action-history') .click(function(event) { event.preventDefault(); document.location.href = 'show_activity.cgi?id=' + BUGZILLA.bug_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($('