Newer
Older
$(document).ready(function () {
$("#save-and-continue").click(function () {
var form = $(this).parents("form");
var hidden_field = $("<input type='hidden' name='_continue' value='1' />");
form.append(hidden_field);
form.submit();
});
$("[data-hide]").on("click", function () {
$("." + $(this).attr("data-hide")).hide();
});
var formDataChanged = false;
$(":input", this).change(function () {
if (this.form !== undefined && this.form !== null) {
formDataChanged = true;
}
});
$('.main-sidebar a').click(function () {
if (formDataChanged) {
return confirm("Data changed. Are you sure you want to leave?");
} else {
return true;
}
//disable all dropdown HTML select elements that should be readonly but aren't
$("select[readonly] option:not(:selected)").attr('disabled', 'disabled');
});
$.ajaxSetup({
beforeSend: function (xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
function showErrorInfo(content) {
var errorDialogDiv = document.createElement("div");
document.body.appendChild(errorDialogDiv);
errorDialogDiv.innerHTML = '<div class="modal-dialog" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">ERROR' +
'<button type="button" class="close" data-dismiss="modal" aria-label="Close">' +
'<span aria-hidden="true">×</span></button>' +
'</div>' +
'<div name="error-content" class="modal-body">' + content + '</div>' +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-outline pull-right" data-dismiss="modal">Close</button>' +
'</div>' +
'</div>' +
'</div>';
$(errorDialogDiv).attr("role", "dialog");
$(errorDialogDiv).addClass("modal modal-danger fade");
$(errorDialogDiv).modal("show");
}
//------------------------------------------------------
// common code for dynamic Data Tables
//------------------------------------------------------
if (!String.prototype.startsWith) {
String.prototype.startsWith = function (searchString, position) {
position = position || 0;
return this.indexOf(searchString, position) === position;
};
}
function createColumn(dataType, name, filter, visible, sortable, renderFunction) {
if (renderFunction === undefined) {
renderFunction = function (data, type, row, meta) {
return row[dataType];
}
}
return {
"type": dataType,
"name": name,
"filter": filter,
"visible": visible,
"render": renderFunction,
"sortable": sortable
};
}
/*
We use an auxiliary function to create the function due to the lack of block scope in JS.
https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
*/
function createRenderFunction(columnRow){
return function(data, type, row, meta){
/*
Fancy highlighting for the column matches.
*/
if(columnRow.filter == 'string_filter'){
//obtain the input element by its placeholdername which matches the column name: e.g.: <input type="text" style="width:80px" placeholder="First name">
filter_value = $(`input[placeholder="${columnRow.name}"]`).val();
//if there is any filter, we highlight the matching part
if(filter_value != undefined && filter_value.length > 0){
//global and case insensitive replacement
return data.replace(RegExp(filter_value, 'gi'), `<span class="highlight_match">${filter_value}</span>`);
}
}
return data;
};
}
function getColumns(columns, getSubjectEditUrl) {
var result = [];
for (var i = 0; i < columns.length; i++) {
var columnRow = columns[i];
if (columnRow.type === "address"){
var renderFunction = (function () {
return function (data, type, row) {
return data;
};
})();
var columnDef = createColumn(columnRow.type, columnRow.name, columnRow.filter, columnRow.visible, columnRow.sortable, renderFunction);
columnDef.className = 'subject-address';
columnDef.width = '150px';
result.push(columnDef);
} else if (columnRow.type === "edit") {
result.push(createColumn("id", columnRow.name, columnRow.filter, columnRow.visible, columnRow.sortable, function (data, type, row) {
var url = getSubjectEditUrl(row.id.toString());
return '<a href="' + url + '" type="button" class="btn btn-block btn-default">Edit</a>';
}));
} else if (/^visit_[0-9]+$/.test(columnRow.type)) {
var renderFunction = (function () {
var x = columnRow.type.replace("visit_", "");
return function (data, type, row) {
return create_visit_row(row.visits[x - 1]);
};
})();
result.push(createColumn(columnRow.type, columnRow.name, columnRow.filter, columnRow.visible, columnRow.sortable, renderFunction));
} else {
result.push(createColumn(columnRow.type, columnRow.name, columnRow.filter, columnRow.visible, columnRow.sortable, createRenderFunction(columnRow)));
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
}
}
return result;
}
function createHeader(columnsDefinition) {
var header = document.createElement("thead");
var headerRow = document.createElement("tr");
header.appendChild(headerRow);
for (var i = 0; i < columnsDefinition.length; i++) {
var column = columnsDefinition[i];
var element = document.createElement("th");
element.innerHTML = column.name;
headerRow.appendChild(element);
}
return header;
}
function createFilter(columnsDefinition) {
var footer = document.createElement("tfoot");
footer.style.display = "table-header-group";
var footerRow = document.createElement("tr");
footer.appendChild(footerRow);
for (var i = 0; i < columnsDefinition.length; i++) {
var column = columnsDefinition[i];
var element = document.createElement("th");
if (column.filter !== null) {
element.innerHTML = "<div name='" + column.filter + "'>" + column.name + "</div>";
}
footerRow.appendChild(element);
}
return footer;
}
function create_visit_row(visit) {
var color = "white";
var text = "---";
if (visit !== undefined && visit !== null) {
if (visit.status === "DONE") {

Carlos Vega
committed
color = "#6bff5a";
text = `<span title="Visit is finished, all appointments done.">OK</span>`;
} else if (visit.status === "MISSED") {
color = "pink";
text = `<span title="Visit is finished, some appointments were not carried out.">MISSED</span>`;

Carlos Vega
committed
} else if (visit.status === "UPCOMING") {
color = "#00ffff";
text = `<span title="Visit has not started yet.">UPCOMING</span>`;

Carlos Vega
committed
} else if (visit.status === "EXCEEDED") {
color = "orange";

Carlos Vega
committed
text = `<span title="Visit is over and no appointments were set.">EXCEEDED</span>`;
} else if (visit.status === "SHOULD_BE_IN_PROGRESS") {
color = "orange";

Carlos Vega
committed
text = `<span title="Visit has started but no appointments have been set yet.">IN PROGRESS (NO APPOINTMENTS)</span>`;
} else if (visit.status === "IN_PROGRESS") {
color = "lightgreen";

Carlos Vega
committed
text = `<span title="Appointments are taking place.">IN PROGRESS</span>`;

Carlos Vega
committed
var start_date = moment(visit.datetime_start);
var end_date = moment(visit.datetime_end);

Carlos Vega
committed
<span data-html="true" title="From: ${start_date.format('ddd Do MMMM YYYY')} </br> To: ${end_date.format('ddd Do MMMM YYYY')}">
From: ${start_date.format('D MMM. YYYY')}

Carlos Vega
committed
</span>
<br/>
<span data-html="true" title="From: ${start_date.format('ddd Do MMMM YYYY')} </br> To: ${end_date.format('ddd Do MMMM YYYY')}">
To: ${end_date.format('D MMM. YYYY')}

Carlos Vega
committed
</span>`
text += `<br/><span data-html="true" title="Visit details<br/>Appointment Types:<br/><div class='appointment_type_list'>${visit.appointment_types.join('<br/>')}</div>">
<a href="${visit.edit_visit_url}"><i class="fa fa-list" aria-hidden="true"></i></a>
</span>`;
if(!visit.is_finished){
text += `<span title="Add new appointment to visit"><a href="${visit.add_appointment_url}"><i class="fa fa-plus-square-o" aria-hidden="true"></i></a></span>`;
}else{
text += `<span title="Visit is marked as finished" ><i class="fa fa-check-circle" aria-hidden="true"></i></span>`;
}

Carlos Vega
committed

Carlos Vega
committed
return "<div class='visit_row' style='background-color:" + color + "';width:100%;height:100%>" + text + "</div>";
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
}
function createVisibilityCheckboxes(checkboxesElement, columns) {
var row = null;
for (var i = 0; i < columns.length; i++) {
if (i % 10 === 0) {
row = document.createElement("div");
row.style.display = "table-row";
checkboxesElement.appendChild(row);
}
var column = columns[i];
var element = document.createElement("div");
element.style.display = "table-cell";
var checked = "";
if (column.visible) {
checked = "checked";
}
element.innerHTML = "<input type='checkbox' " + checked + " data-column='" + i + "' name='" + column.type + "'/>" + column.name;
row.appendChild(element);
}
}
function createTable(params) {
var tableElement = params.tableElement;
var worker_locations = params.worker_locations;
if (worker_locations === undefined) {
worker_locations = [];
}
var subject_types_url = params.subject_types_url;
var locations_url = params.locations_url;
var flying_teams_url = params.flying_teams_url;
var appointment_types_url = params.appointment_types_url;
var subjects_url = params.subjects_url;
var voucher_types_url = params.voucher_types_url;
var voucher_partner_url = params.voucher_partner_url;
var columnsDefinition = params.columns;
var dom_settings = params.dom_settings || 'lrtip' // show table without search box;
tableElement.appendChild(createHeader(columnsDefinition));
tableElement.appendChild(createFilter(columnsDefinition));
tableElement.appendChild(document.createElement("tbody"));
createVisibilityCheckboxes(params.checkboxesElement, columnsDefinition);
var table;
$(tableElement).find('tfoot div[name="string_filter"]').each(function () {
var title = $(this).text();
$(this).html('<input type="text" style="width:80px" placeholder="' + title + '" />');
});
$(tableElement).find('tfoot div[name="yes_no_filter"]').each(function () {
$(this).html('<select style="width:60px" ><option value selected="selected">---</option><option value="true">YES</option><option value="false">NO</option></select>');
});
$(tableElement).find('tfoot div[name="yes_no_null_filter"]').each(function () {
$(this).html('<select style="width:60px" ><option value selected="selected">---</option><option value="true">YES</option><option value="false">NO</option><option value="null">N/A</option></select>');
});
$(tableElement).find('tfoot div[name="yes_no_null_inconclusive_filter"]').each(function () {
$(this).html('<select style="width:100px" ><option value selected="selected">---</option><option value="true">Positive</option><option value="false">Negative</option><option value="null">N/A</option><option value="inconclusive">Inconclusive</option></select>');
});
$(tableElement).find('tfoot div[name="virus_test_date"]').each(function () {
$(this).css('width', '100px');
$(this).text('');
});
//replace the hyphen with non breaking space hyphen to ensure the column names are more readable
$(tableElement).find('th:contains("RT-PCR")').each(function(){
non_breaking_hyphen = $.parseHTML('‑');
var text = $(this).text().replace('-', $(non_breaking_hyphen).text());
$(this).text(text);
});
$(tableElement).find('tfoot div[name="integer_filter"]').each(function () {
var options = '<option value selected="selected">---</option>';
for (var i = 1; i <= 8; i++) {
options += '<option value="' + i + '">' + i + '</option>';
}
$(this).html('<select style="width:60px" >' + options + '</select>');
});
$(tableElement).find('tfoot div[name="from_zero_integer_filter"]').each(function () {
var options = '<option value selected="selected">---</option>';
for (var i = 0; i < 8; i++) {
options += '<option value="' + i + '">' + i + '</option>';
}
$(this).html('<select style="width:60px" >' + options + '</select>');
});
$(tableElement).find('tfoot div[name="voucher_status_filter"]').each(function () {
$(this).html('<select style="width:60px" ><option value selected="selected">---</option>' +
'<option value="NEW">NEW</option>' +
'<option value="IN_USE">IN USE</option>' +
'<option value="USED">USED</option>' +
'<option value="EXPIRED">EXPIRED</option>' +
'<option value="REMOVED">REMOVED</option>' +
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
$(tableElement).find('tfoot div[name="visit_filter"]').each(function () {
$(this).html('<select style="width:60px" >' +
'<option value selected="selected">---</option>' +
'<option value="MISSED">MISSED</option>' +
'<option value="DONE">DONE</option>' +
'<option value="EXCEED">EXCEED</option>' +
'<option value="IN_PROGRESS">IN PROGRESS</option>' +
'<option value="SHOULD_BE_IN_PROGRESS">SHOULD BE IN PROGRESS</option>' +
'<option value="UPCOMING">UPCOMING</option>' +
'</select>');
});
$(tableElement).find('tfoot div[name="location_filter"]').each(function () {
var obj = $(this);
obj.html('<select style="width:80px"><option value selected="selected">---</option></select>');
var select = $('select', obj);
$.get(locations_url, function (data) {
$.each(data.locations, function (index, location) {
select.append('<option value="' + location.id + '">' + location.name + '</option>');
});
if (worker_locations.length === 1) {
select.val(worker_locations[0].id);
}
});
});
$(tableElement).find('tfoot div[name="voucher_type_filter"]').each(function () {
var obj = $(this);
obj.html('<select style="width:80px"><option value selected="selected">---</option></select>');
var select = $('select', obj);
$.get(voucher_types_url, function (content) {
$.each(content.data, function (index, voucher_type) {
select.append('<option value="' + voucher_type.id + '">' + voucher_type.code + '</option>');
});
});
});
$(tableElement).find('tfoot div[name="voucher_partner_filter"]').each(function () {
var obj = $(this);
obj.html('<select style="width:80px"><option value selected="selected">---</option></select>');
var select = $('select', obj);
$.get(voucher_partner_url, function (content) {
$.each(content.data, function (index, voucher_partner) {
select.append('<option value="' + voucher_partner.id + '">' + voucher_partner.name + '</option>');
$(tableElement).find('tfoot div[name="flying_team_filter"]').each(function () {
var obj = $(this);
obj.html('<select style="width:80px"><option value selected="selected">---</option></select>');
var select = $('select', obj);
$.get(flying_teams_url, function (data) {
$.each(data.flying_teams, function (index, flying_team) {
select.append('<option value="' + flying_team.id + '">' + flying_team.name + '</option>');
});
if (worker_locations.length === 1) {
select.val(worker_locations[0].id);
}
});
});
$(tableElement).find('tfoot div[name="appointment_type_filter"]').each(function () {
var obj = $(this);
obj.html('<select style="width:80px"><option value selected="selected">---</option></select>');
var select = $('select', obj);
$.get(appointment_types_url, function (data) {
$.each(data.appointment_types, function (index, appointment_type) {
select.append('<option value="' + appointment_type.id + '">' + appointment_type.type + '</option>');
});
if (worker_locations.length === 1) {
select.val(worker_locations[0].id);
}
});
});
$(tableElement).find('tfoot div[name="type_filter"]').each(function () {
var obj = $(this);
obj.html('<select style="width:80px"><option value selected="selected">---</option></select>');
var select = $('select', obj);
$.get(subject_types_url, function (data) {
$.each(data.types, function (index, type) {
select.append('<option value="' + type.id + '">' + type.name + '</option>');
});
});
});
$(function () {
var columns = [];
var columnDefs = [];
for (var i = 0; i < columnsDefinition.length; i++) {
var column = columnsDefinition[i];
columns.push({"data": column.type});
columnDefs.push({
"targets": i,
"render": column.render,
visible: column.visible,
className: column.className,
width: column.width,
orderable: column.sortable
});
}
table = $('#table').DataTable({
pageLength: 25,
lengthMenu: [[25, 50, 100, -1], [25, 50, 100, "All"]],
serverSide: true,
processing: true,
responsive: true,
ajax: subjects_url,
columns: columns,
columnDefs: columnDefs,
buttons: [
{ extend: 'excel',
exportOptions: {
modifier: { page: 'all', search: 'applied', order: 'applied' }
},
text: `<span class='excel-export-button'><i class="fa fa-file-excel-o" aria-hidden="true"></i> Export selection to excel</span>`
}
],
dom: dom_settings, //see docs: https://datatables.net/reference/option/dom
initComplete: function(settings, json) {
$('.excel-export-button').parents('button').tooltip({container: 'body', title: `Show <b>All</b> entries to consider all rows instead of current page. Filters and sorting will prevail.`, html: true});
}
// Apply the search
table.columns().every(function () {
var that = this;
$('input', this.footer()).on('keyup change', function () {
if (that.search() !== this.value) {
that.search(this.value).draw();
}
});
$('select', this.footer()).on('keyup change', function () {
if (that.search() !== this.value) {
that.search(this.value).draw();
}
});
});
$('#table_filter').css("display", "null");
});
$(params.checkboxesElement).find('input').on('click', function (e) {
var visible = $(this).is(":checked");
// Get the column API object
var column = table.column($(this).attr('data-column'));
// Toggle the visibility
column.visible(visible);
}
//------------------------------------------------------
// END common code for dynamic Data Tables
//------------------------------------------------------