eoredmine/javascripts/theme.js

401 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 dajout / 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();
});