401 lines
15 KiB
JavaScript
401 lines
15 KiB
JavaScript
function sort_table() {
|
||
var table = $(this).parents('tbody')[0];
|
||
|
||
/* get table column index */
|
||
var child = $(this)[0];
|
||
var col = 0;
|
||
while( (child = child.previousSibling) != null ) {
|
||
if (child.tagName == 'TD') col++;
|
||
}
|
||
|
||
/* save sorting preferences */
|
||
var asc = parseInt($(table).data('sort-asc') || 1);
|
||
var ccol = parseInt($(table).data('sort-col') || 0);
|
||
if (col == ccol) { asc = -asc; } else { asc = 1; }
|
||
$(table).data('sort-col', col);
|
||
$(table).data('sort-asc', asc);
|
||
|
||
/* fill the array with values from the table */
|
||
var rows = table.rows, rlen = rows.length, arr = new Array(), i, j, cells, clen;
|
||
for (i=0; i<rlen; i++){
|
||
cells = rows[i].cells;
|
||
clen = cells.length;
|
||
arr[i] = new Array();
|
||
for (j = 0; j < clen; j++){
|
||
var v = cells[j].innerHTML;
|
||
/* try to guess column type */
|
||
var date = v.match(/(\d\d?)\/(\d\d?)\/(\d\d\d\d)/i);
|
||
if (date) {
|
||
v = new Date();
|
||
v.setYear(date[3]);
|
||
v.setMonth(date[2]);
|
||
v.setDate(date[1]);
|
||
} else {
|
||
var date = v.match(/(\d\d?)\/(\d\d\d\d)/i);
|
||
if (date) {
|
||
v = new Date();
|
||
v.setYear(date[2]);
|
||
v.setMonth(date[1]);
|
||
v.setDate(1);
|
||
} else {
|
||
v = v.match(/\d+/i);
|
||
if (v) {
|
||
v = parseInt(v);
|
||
} else {
|
||
v = cells[j].innerHTML;
|
||
}
|
||
}
|
||
}
|
||
if (cells[j].innerText == '') {
|
||
v = null;
|
||
}
|
||
/* store both original html and typed value */
|
||
arr[i][j] = Array(cells[j].innerHTML, v);
|
||
}
|
||
}
|
||
|
||
var first_row = arr.shift(); /* skip first row (header) */
|
||
|
||
/* sort rows, empty cells last */
|
||
arr.sort(function(a, b){
|
||
a = a[col][1]; b = b[col][1];
|
||
if (a === null && b === null) return 0;
|
||
if (a === null) return 1;
|
||
if (b === null) return -1;
|
||
return (a == b) ? 0 : ((a > b) ? asc : -1*asc);
|
||
});
|
||
|
||
arr.unshift(first_row); /* pub back first row */
|
||
|
||
/* recreate content */
|
||
for (i = 0; i < rlen; i++){
|
||
arr[i] = "<td>"+arr[i].map(function(x) {return x[0];}).join("</td><td>")+"</td>";
|
||
}
|
||
table.innerHTML = "<tr>"+arr.join("</tr><tr>")+"</tr>";
|
||
|
||
/* set back callback */
|
||
$(table).find('tr:first-child td').on('click', sort_table).css('cursor', 'row-resize');
|
||
}
|
||
|
||
function alter_new_issue_page() {
|
||
// on global new issue page select "client" project by default
|
||
if ($('#issue_project_id option:contains("Interne")').length == 0) {
|
||
/* select last entry that is not a subproject */
|
||
$('#issue_project_id option:not(:contains("»"))').last().attr('selected', 'selected');
|
||
}
|
||
// limit exclamation marks
|
||
$('input#issue_subject').on('keypress', function(evt) {
|
||
/* initial code from
|
||
* https://stackoverflow.com/questions/3579219/show-different-keyboard-character-from-the-typed-one-in-google-chrome/3580352#3580352
|
||
*/
|
||
var val = this.value;
|
||
evt = evt || window.event;
|
||
|
||
// Ensure we only handle printable keys, excluding enter and space
|
||
var charCode = typeof evt.which == "number" ? evt.which : evt.keyCode;
|
||
if (charCode && charCode != 13 && charCode != 32) {
|
||
var keyChar = String.fromCharCode(charCode);
|
||
if (keyChar != '!') return true;
|
||
if (val.indexOf('!') == -1) return true; /* we still allow one */
|
||
|
||
var mappedChar = '❤';
|
||
|
||
var start, end;
|
||
if (typeof this.selectionStart == "number" && typeof this.selectionEnd == "number") {
|
||
// Non-IE browsers and IE 9
|
||
start = this.selectionStart;
|
||
end = this.selectionEnd;
|
||
this.value = val.slice(0, start) + mappedChar + val.slice(end);
|
||
|
||
// Move the caret
|
||
this.selectionStart = this.selectionEnd = start + 1;
|
||
}
|
||
return false;
|
||
}
|
||
});
|
||
$('input#issue_subject').on('change', function(evt) {
|
||
var val = $(this).val();
|
||
if (val.length < 5) {
|
||
return true;
|
||
}
|
||
var uppercases = (val.match(/[A-Z]/g) || "").length;
|
||
var all_letters = (val.match(/[^\s+]/g) || "").length;
|
||
var ratio = uppercases / all_letters;
|
||
if (ratio > 0.6) { // more than 60% of uppercase letters
|
||
// change to lower case
|
||
$(this).val(val.toLowerCase());
|
||
// and disable high priority values
|
||
$('#issue_priority_id option + option + option').attr('disabled', true);
|
||
}
|
||
return true;
|
||
});
|
||
}
|
||
|
||
function alter_issues_index_page() {
|
||
$('td.author a, td.assigned_to a').each(function(idx, elem) {
|
||
// remove suffixes used by people to indicate they're off.
|
||
$(elem).text($(elem).text().replace(/->.*/, '').replace(/→.*/, '').replace(/\(.*/, '').trim());
|
||
});
|
||
}
|
||
|
||
function alter_issue_show_page() {
|
||
if ($('.attachments_fields').length) {
|
||
var observer = new MutationObserver(function(mutations) {
|
||
mutations.forEach(function(mutation) {
|
||
$('input.filename.readonly').each(function(idx, elem) {
|
||
var filename = $(elem).val();
|
||
var extension = filename.substring(filename.lastIndexOf('.'));
|
||
if (extension == '.patch') {
|
||
$('#issue_custom_field_values_2').prop('checked', true);
|
||
if ($('#issue_status_id option[value=12]').length) {
|
||
$('#issue_status_id').val('12');
|
||
} else if ($('#issue_tracker_id option[value=1]').length) { // "bug" tracker
|
||
$('#issue_tracker_id').val('1');
|
||
$('<option value="12">Solution proposée</option>').appendTo($('#issue_status_id'));
|
||
$('#issue_status_id').val('12');
|
||
} else if ($('#issue_status_id option[value=2]').length) {
|
||
$('#issue_status_id').val('2');
|
||
}
|
||
}
|
||
});
|
||
});
|
||
});
|
||
var target = $('.attachments_fields')[0];
|
||
observer.observe(target, {attributes: false, childList: true, characterData: false});
|
||
}
|
||
$('textarea#issue_notes').on('keyup change', function() {
|
||
if ($(this).val().indexOf('<pre>\ncommit ') != -1) {
|
||
var issue_status = $('#issue_status_id').val();
|
||
if (issue_status == '1' || issue_status == '2' || issue_status == '12' || issue_status == '13') {
|
||
$('#issue_status_id').val('3');
|
||
}
|
||
}
|
||
});
|
||
/* hide context menu in linked issues */
|
||
$('#relations .hascontextmenu').removeClass('hascontextmenu');
|
||
|
||
if ($('#all_attributes').length) {
|
||
var author_id = $('p.author a.user').attr('href').split('/')[2];
|
||
var author_name = $('p.author a.user').text();
|
||
function adjust_assigned_to_list() {
|
||
var new_option = $('<option></option>', {value: author_id, text: '<< auteur·ice (' + author_name + ') >>'});
|
||
new_option.insertAfter($('#issue_assigned_to_id option')[1]);
|
||
}
|
||
adjust_assigned_to_list();
|
||
var attr_observer = new MutationObserver(function(mutations) {
|
||
// replay when attributes section is replaced by replaceIssueFormWith
|
||
// (on status changes, at least)
|
||
adjust_assigned_to_list();
|
||
});
|
||
attr_observer.observe($('#all_attributes')[0], {childList: true});
|
||
}
|
||
|
||
// global keyboard shortcuts
|
||
$(document).on('keypress', function(ev) {
|
||
var element = ev.target;
|
||
if (element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable) {
|
||
return true; // let it handle
|
||
}
|
||
if (ev.key == 'v') {
|
||
// v: validate patch and open modify/comment section
|
||
$('#issue_status_id').val('13');
|
||
$('.contextual .icon-edit').last().trigger('click');
|
||
}
|
||
if (ev.key == 'm') {
|
||
// m: open modify/comment section
|
||
$('.contextual .icon-edit').last().trigger('click');
|
||
}
|
||
return true;
|
||
});
|
||
$('textarea#issue_notes').on('keydown', function(e) {
|
||
// ctrl-enter in comment area -> focus on submit button
|
||
if ((e.ctrlKey || e.metaKey) && (e.keyCode == 13 || e.keyCode == 10)) {
|
||
$('input[name=commit]').last().focus()
|
||
return false;
|
||
}
|
||
return true;
|
||
});
|
||
|
||
function handle_jobs(jobs) {
|
||
$(jobs).each(function(idx, job) {
|
||
if (job.name.indexOf('wip%2F' + issue_no + '-') == 0) {
|
||
$.ajax({
|
||
url: job.url + 'lastBuild/api/json',
|
||
async: true,
|
||
dataType: 'json',
|
||
crossDomain: true,
|
||
success: function(data) {
|
||
var date = new Date(data.timestamp);
|
||
var $jenkins_link = $('<div class="jenkins jenkins-' + data.result + '"><a href="' +
|
||
data.url + '">Jenkins: ' + data.fullDisplayName + ': ' + data.result + '</a>' +
|
||
' (' + date.toLocaleString() + ') ' +
|
||
'+ <a href="https://git.entrouvert.org/entrouvert/' + project_name + '/commits/branch/' + job.name + '">Gitea</a>' +
|
||
'</div>');
|
||
$jenkins_link.appendTo($('#history'));
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
if ($('.controller-issues.action-show a.overview').length) {
|
||
var project_name = $('a.overview').attr('href').split('/')[2];
|
||
if (project_name == 'authentic2-auth-fc') { project_name = 'authentic'; }
|
||
if (project_name == 'au-quotidien') { project_name = 'auquotidien'; }
|
||
var issue_no = $('a.atom').attr('href').split('/')[2].split('.')[0];
|
||
var call1 = $.ajax({
|
||
url: 'https://jenkins.entrouvert.org/job/' + project_name + '-wip/api/json',
|
||
async: true,
|
||
dataType: 'json',
|
||
crossDomain: true,
|
||
});
|
||
call1.then(function (data) {
|
||
handle_jobs(data.jobs);
|
||
}, function () {
|
||
var call2 = $.ajax({
|
||
url: 'https://jenkins.entrouvert.org/job/gitea/job/' + project_name + '/api/json',
|
||
async: true,
|
||
dataType: 'json',
|
||
crossDomain: true,
|
||
});
|
||
call2.then(function (data) {
|
||
handle_jobs(data.jobs);
|
||
});
|
||
});
|
||
}
|
||
|
||
var $gitea_pr = $('.controller-issues.action-show .journal .wiki a[href*="https://git.entrouvert.org/"]').first();
|
||
if ($gitea_pr.length) {
|
||
var gitea_pr_number = $gitea_pr.attr('href').split('/').slice(-1)[0];
|
||
var $pr_div = $('<div><p><strong>Gitea</strong></p><p></p></div>');
|
||
var $pr_a = $('<a></a>', {href: $gitea_pr.attr('href'), text: "Demande d’ajout / Pull Request #" + gitea_pr_number});
|
||
var $pr_a2 = $('<a></a>', {href: $gitea_pr.attr('href') + '/files', text: "(modifications)"});
|
||
$pr_a.appendTo($pr_div.find('p').last());
|
||
$('<span> </span>').appendTo($pr_div.find('p').last());
|
||
$pr_a2.appendTo($pr_div.find('p').last());
|
||
$('<hr>').appendTo($('.issue.details'));
|
||
$pr_div.appendTo($('.issue.details'));
|
||
}
|
||
|
||
var user_href = $('#loggedas a').attr('href');
|
||
if (user_href) {
|
||
$('div.journal.has-notes').each(function(idx, entry) {
|
||
var user_entry_href = $(entry).find('a.user').attr('href');
|
||
if (user_entry_href && user_entry_href != user_href) {
|
||
$(entry).find('.icon-edit').hide();
|
||
}
|
||
});
|
||
}
|
||
|
||
if ($('div.issue.closed').length) { /* on a closed issue */
|
||
var last_activity_url = $('#history a[href*=activity]').last().attr('href');
|
||
if (typeof last_activity_url !== 'undefined') {
|
||
var date = new Date(last_activity_url.split('=')[1]);
|
||
var today = new Date();
|
||
if (today - date > (60 * 86400*1000)) { /* older than 60 days */
|
||
$('div#content > div.contextual .icon-edit').hide();
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($('.administration').length == 0) {
|
||
/* fake access control */
|
||
return;
|
||
}
|
||
|
||
/* always display edit link to admins */
|
||
$('div#content > div.contextual .icon-edit').show();
|
||
|
||
var issue_no = $('a.atom').attr('href').split('/')[2].split('.')[0];
|
||
$.ajax({
|
||
url: 'https://scrutiny.entrouvert.org/projects/api/issues/' + issue_no + '/',
|
||
async: true,
|
||
dataType: 'jsonp',
|
||
crossDomain: true,
|
||
success: function(data) {
|
||
if (data.platforms) {
|
||
$('<h3>Déploiements</h3><ul id="deployed"></ul>').appendTo('#sidebar');
|
||
var platforms = Object.keys(data.platforms);
|
||
platforms.sort();
|
||
platforms.forEach(function(val) {
|
||
var status = data.platforms[val];
|
||
$('<li class="' + status.status + '">' + val + ': ' + status.version + '</li>').appendTo($('#deployed'));
|
||
});
|
||
}
|
||
}
|
||
});
|
||
|
||
var marks = ($('#history').text().match(/wtf/i) || []).length;
|
||
if (marks && $('#history').html().match(/users\/(7|20)/)) {
|
||
var url = "https://perso.entrouvert.org/~fred/review/?";
|
||
for (i=0; i<marks; i++) {
|
||
url += Math.floor(Math.random() * 7) + 1;
|
||
}
|
||
var $main = $('#main');
|
||
$main.css('background-repeat', 'no-repeat');
|
||
$main.css('background-position', '99% 100%');
|
||
$main.css('background-size', '17%');
|
||
$main.css('background-attachment', 'fixed');
|
||
$main.css('background-image', 'url(' + url + ')');
|
||
}
|
||
}
|
||
|
||
$(function() {
|
||
// create #history if it does not exist, in order to show jenkins CI results
|
||
var historyExists = document.getElementById("history");
|
||
if (!historyExists) {
|
||
var history = document.createElement("div");
|
||
var content = document.getElementById("content");
|
||
history.id = 'history';
|
||
content.appendChild(history);
|
||
}
|
||
|
||
$('.wiki table tr:first-child td').on('click', sort_table).css('cursor', 'row-resize');
|
||
|
||
/* 440 is header image height (500px) - header height (60px) */
|
||
var timestamp = ((new Date().getTime() / 1000) % 86400 ) / (86400 / 440);
|
||
$('#top-menu').css('background-position', '0 -' + timestamp + 'px');
|
||
|
||
// don't allow assigning issues to Entr'ouvert group
|
||
$('body.controller-issues #issue_assigned_to_id option:contains("Entr\'ouvert")').hide();
|
||
// don't allow assigning issues to "support technique" group
|
||
$('body.controller-issues #issue_assigned_to_id option:contains("Support technique")').hide();
|
||
|
||
if ($('body.controller-issues.action-new').length == 1) {
|
||
alter_new_issue_page();
|
||
}
|
||
if ($('body.controller-issues.action-show').length == 1) {
|
||
alter_issue_show_page();
|
||
}
|
||
if ($('body.controller-issues.action-index').length == 1) {
|
||
alter_issues_index_page();
|
||
}
|
||
|
||
// don't allow linking blocking/blocked issues
|
||
$("#relation_relation_type option[value='blocks']").remove();
|
||
$("#relation_relation_type option[value='blocked']").remove();
|
||
|
||
// custom features, enabled on user request
|
||
|
||
function folded_custom_reports() { // fold "custom reports" in sidebar by default
|
||
var custom_reports_title = $('h3:contains("Rapports personnalisés")');
|
||
custom_reports_title.css('cursor', 'pointer').on('click', function() {
|
||
$('h3:contains("Rapports personnalisés") + ul').toggle();
|
||
}).trigger('click');
|
||
}
|
||
|
||
var current_user = $('#loggedas a.user').text();
|
||
if (["fpeters"].indexOf(current_user) != -1) {
|
||
folded_custom_reports();
|
||
}
|
||
|
||
// admin features, fake access control
|
||
if ($('.administration').length == 0) {
|
||
return;
|
||
}
|
||
|
||
// allow assigning issues to "support technique" group
|
||
$('body.controller-issues #issue_assigned_to_id option:contains("Support technique")').show();
|
||
|
||
});
|