scinote-web/app/assets/javascripts/protocols/index.js
2022-12-08 15:58:11 +01:00

715 lines
22 KiB
JavaScript

//= require protocols/import_export/import
/* global ProtocolRepositoryHeader PdfPreview */
// Global variables
var rowsSelected = [];
var protocolsTableEl = null;
var protocolsDatatable = null;
var repositoryType;
/**
* Initializes page
*/
function init() {
updateButtons();
initProtocolsTable();
initKeywordFiltering();
initProtocolPreviewModal();
initLinkedChildrenModal();
initModals();
initImport();
}
// Initialize protocols DataTable
function initProtocolsTable() {
protocolsTableEl = $("#protocols-table");
repositoryType = protocolsTableEl.data("type");
protocolsDatatable = protocolsTableEl.DataTable({
order: [[1, "asc"]],
dom: "RB<'main-actions'lf>t<'pagination-row'ip>",
stateSave: true,
sScrollX: '100%',
sScrollXInner: '100%',
buttons: [],
processing: true,
serverSide: true,
ajax: {
url: protocolsTableEl.data("source"),
type: "POST"
},
colReorder: {
fixedColumnsLeft: 1000000 // Disable reordering
},
columnDefs: [{
targets: 0,
searchable: false,
orderable: false,
sWidth: "1%",
render: function (data, type, full, meta) {
return `<div class="sci-checkbox-container">
<input type="checkbox" class="sci-checkbox">
<span class="sci-checkbox-label"></span>
</div>`;
}
}, {
targets: [ 1, 2, 3, 4, 5, 6 ],
searchable: true,
orderable: true
}],
columns: [
{ data: "0" },
{ data: "1" },
{ data: "2" },
{ data: "3" },
{
data: "4",
visible: repositoryType != "archive"
},
{ data: "5" },
{ data: "6" },
{ data: "7" }
],
oLanguage: {
sSearch: I18n.t('general.filter')
},
rowCallback: function(row, data, dataIndex) {
// Get row ID
var rowId = data["DT_RowId"];
$(row).attr("data-row-id", rowId);
if (data["DT_CanClone"]) {
$(row).attr("data-can-clone", "true");
$(row).attr("data-clone-url", data["DT_CloneUrl"]);
}
if (data["DT_CanMakePrivate"]) { $(row).attr("data-can-make-private", "true"); }
if (data["DT_CanPublish"]) { $(row).attr("data-can-publish", "true"); }
if (data["DT_CanArchive"]) { $(row).attr("data-can-archive", "true"); }
if (data["DT_CanRestore"]) { $(row).attr("data-can-restore", "true"); }
if (data["DT_CanExport"]) { $(row).attr("data-can-export", "true"); }
// If row ID is in the list of selected row IDs
if($.inArray(rowId, rowsSelected) !== -1){
$(row).find("input[type='checkbox']").prop("checked", true);
$(row).addClass("selected");
}
},
fnDrawCallback: function(settings, json) {
animateSpinner(this, false);
initRowSelection();
},
preDrawCallback: function(settings) {
animateSpinner(this);
},
stateSaveCallback: function (settings, data) {
// Set a cookie with the table state using the team id
localStorage.setItem(
"datatables_protocols_state/" +
protocolsTableEl.data("team-id") +
"/" + repositoryType,
JSON.stringify(data)
);
},
stateLoadCallback: function (settings) {
// Load the table state for the current team
var state = localStorage.getItem(
"datatables_protocols_state/" +
protocolsTableEl.data("team-id") +
"/" + repositoryType
);
if (state !== null) {
return JSON.parse(state);
}
return null;
}
});
}
function initRowSelection() {
let protocolsTableScrollHead = protocolsTableEl.closest('.dataTables_scroll').find('.dataTables_scrollHead');
// Handle click on table cells with checkboxes
protocolsTableEl.on("click", "tbody td, thead th:first-child", function(e) {
$(this).parent().find("input[type='checkbox']").trigger("click");
});
// Handle clicks on checkbox
protocolsTableEl.find("tbody").on("click", "input[type='checkbox']", function(e) {
// Get row ID
var row = $(this).closest("tr");
var data = protocolsDatatable.row(row).data();
var rowId = data["DT_RowId"];
// Determine whether row ID is in the list of selected row IDs
var index = $.inArray(rowId, rowsSelected);
// If checkbox is checked and row ID is not in list of selected row IDs
if (this.checked && index === -1) {
rowsSelected.push(rowId);
// Otherwise, if checkbox is not checked and row ID is in list of selected row IDs
} else if (!this.checked && index !== -1) {
rowsSelected.splice(index, 1);
}
if (this.checked) {
row.addClass("selected");
} else {
row.removeClass("selected");
}
updateDataTableSelectAllCheckbox();
e.stopPropagation();
updateButtons();
});
// Handle click on "Select all" control
protocolsTableScrollHead.find("thead input[name='select_all']").on('click', function(e) {
if (this.checked) {
protocolsTableEl.find("tbody input[type='checkbox']:not(:checked)").trigger('click');
} else {
protocolsTableEl.find("tbody input[type='checkbox']:checked").trigger('click');
}
// Prevent click event from propagating to parent
e.stopPropagation();
});
}
function initKeywordFiltering() {
protocolsTableEl.find("tbody").on("click", "a[data-action='filter']", function(e) {
var link = $(this);
var searchInput = $("#protocols-table_wrapper input[type='search']");
var query = link.attr("data-param");
// Re-search data
protocolsDatatable.search(query).draw();
// Don't propagate this further up
e.stopPropagation();
return false;
});
}
function initProtocolPreviewModal() {
// Only do this if the repository is public/private
if (repositoryType !== "archive") {
// If you are in protocol repository
var protocolsEl = protocolsTableEl;
// If you are in search results
if (document.getElementById("search-content")) {
protocolsEl = $("#search-content");
}
protocolsEl.on("click", "a[data-action='protocol-preview']", function(e) {
var link = $(this);
$.ajax({
url: link.attr("data-url"),
type: "GET",
dataType: "json",
success: function (data) {
var modal = $("#protocol-preview-modal");
var modalTitle = modal.find(".modal-title");
var modalBody = modal.find(".modal-body");
var modalFooter = modal.find(".modal-footer");
modalTitle.html(data.title);
modalBody.html(data.html);
modalFooter.html(data.footer);
initHandsOnTable(modalBody);
modal.modal("show");
ProtocolRepositoryHeader.init();
initHandsOnTable(modalBody);
PdfPreview.initCanvas();
},
error: function (error) {
// TODO
}
});
e.preventDefault();
return false;
});
}
}
function initLinkedChildrenModal() {
// Only do this if the repository is public/private
if (repositoryType !== "archive") {
protocolsTableEl.on("click", "a[data-action='load-linked-children']", function(e) {
var link = $(this);
$.ajax({
url: link.attr("data-url"),
type: "GET",
dataType: "json",
success: function (data) {
var modal = $("#linked-children-modal");
var modalTitle = modal.find(".modal-title");
var modalBody = modal.find(".modal-body");
modalTitle.html(data.title);
modalBody.html(data.html);
modal.modal("show");
childrenTableEl = modalBody.find("#linked-children-table");
if (childrenTableEl) {
// Only initialize table if it's present
var childrenDatatable = childrenTableEl.DataTable({
autoWidth: false,
dom: "RBltpi",
stateSave: false,
buttons: [],
processing: true,
serverSide: true,
ajax: {
url: childrenTableEl.data("source"),
type: "POST"
},
colReorder: {
fixedColumnsLeft: 1000000 // Disable reordering
},
columnDefs: [{
targets: 0,
searchable: false,
orderable: false
}],
columns: [
{ data: "1" }
],
fnDrawCallback: function(settings, json) {
animateSpinner(this, false);
},
preDrawCallback: function(settings) {
animateSpinner(this);
}
});
}
},
error: function (error) {
// TODO
}
});
e.preventDefault();
return false;
});
}
}
function initModals() {
function refresh(modal) {
modal.find(".modal-body").html("");
// Simply re-render table
protocolsDatatable.ajax.reload();
}
// Make private modal hidden action
$("#make-private-results-modal").on("hidden.bs.modal", function(e) {
refresh($(this));
updateDataTableSelectAllCheckbox();
updateButtons();
});
// Publish modal hidden action
$("#publish-results-modal").on("hidden.bs.modal", function(e) {
refresh($(this));
updateDataTableSelectAllCheckbox();
updateButtons();
});
// Confirm archive modal hidden action
$("#confirm-archive-modal").on("hidden.bs.modal", function(e) {
// Unbind from click event on the submit button
$(this).find(".modal-footer [data-action='submit']")
.off("click");
})
// Archive modal hidden action
$("#archive-results-modal").on("hidden.bs.modal", function(e) {
refresh($(this));
updateDataTableSelectAllCheckbox();
updateButtons();
});
// Restore modal hidden action
$("#restore-results-modal").on("hidden.bs.modal", function(e) {
refresh($(this));
updateDataTableSelectAllCheckbox();
updateButtons();
});
// Linked children modal close action
$("#linked-children-modal").on("hidden.bs.modal", function(e) {
$(this).find(".modal-title").html("");
// Destroy the embedded data table
$(this).find(".modal-body #linked-children-table").DataTable().destroy();
$(this).find(".modal-body").html("");
});
// Protocol preview modal close action
$("#protocol-preview-modal").on("hidden.bs.modal", function(e) {
$(this).find(".modal-title").html("");
$(this).find(".modal-body").html("");
$(this).find(".modal-footer").html("");
});
}
function updateDataTableSelectAllCheckbox() {
var table = protocolsDatatable.table().node();
var checkboxesAll = $("tbody input[type='checkbox']", protocolsTableEl);
var checkboxesChecked = $("tbody input[type='checkbox']:checked", protocolsTableEl);
var checkboxSelectAll = $("thead input[name='select_all']", table).get(0);
if (checkboxesChecked.length === 0) {
// If none of the checkboxes are checked
checkboxSelectAll.checked = false;
if("indeterminate" in checkboxSelectAll) {
checkboxSelectAll.indeterminate = false;
}
} else if (checkboxesChecked.length === checkboxesAll.length) {
// If all of the checkboxes are checked
checkboxSelectAll.checked = true;
if ("indeterminate" in checkboxSelectAll) {
checkboxSelectAll.indeterminate = false;
}
} else {
// If some of the checkboxes are checked
checkboxSelectAll.checked = true;
if ("indeterminate" in checkboxSelectAll) {
checkboxSelectAll.indeterminate = true;
}
}
}
function updateButtons() {
var cloneBtn = $("[data-action='clone']");
var makePrivateBtn = $("[data-action='make-private']");
var publishBtn = $("[data-action='publish']");
var archiveBtn = $("[data-action='archive']");
var restoreBtn = $("[data-action='restore']");
var exportBtn = $("[data-action='export']");
var row = $("tr[data-row-id='" + rowsSelected[0] + "']");
var rows = [];
if (rowsSelected.length === 1) {
// 1 ROW SELECTED
if (row.is('[data-can-clone]')) {
cloneBtn.removeClass('disabled hidden');
cloneBtn.off('click').on('click', function() { cloneSelectedProtocol(); });
} else {
cloneBtn.removeClass('hidden').addClass('disabled');
cloneBtn.off('click');
}
if (row.is('[data-can-make-private]')) {
makePrivateBtn.removeClass('disabled hidden');
makePrivateBtn.off('click').on('click', function() { processMoveButtonClick($(this)); });
} else {
makePrivateBtn.removeClass('hidden').addClass('disabled');
makePrivateBtn.off('click');
}
if (row.is('[data-can-publish]')) {
publishBtn.removeClass('disabled hidden');
publishBtn.off('click').on('click', function() { processMoveButtonClick($(this)); });
} else {
publishBtn.removeClass('hidden').addClass('disabled');
publishBtn.off('click');
}
if (row.is('[data-can-archive]')) {
archiveBtn.removeClass('disabled hidden');
archiveBtn.off('click').on('click', function() { processMoveButtonClick($(this)); });
} else {
archiveBtn.removeClass('hidden').addClass('disabled');
archiveBtn.off('click');
}
if (row.is('[data-can-restore]')) {
restoreBtn.removeClass('disabled hidden');
restoreBtn.off('click').on('click', function() { processMoveButtonClick($(this)); });
} else {
restoreBtn.removeClass('hidden').addClass('disabled');
restoreBtn.off('click');
}
if (row.is('[data-can-export]')) {
exportBtn.removeClass('disabled hidden');
exportBtn.off('click').on('click', function() { exportProtocols(rowsSelected); });
} else {
exportBtn.removeClass('hidden').addClass('disabled');
exportBtn.off('click');
}
} else if (rowsSelected.length === 0) {
// 0 ROWS SELECTED
cloneBtn.addClass('disabled hidden');
cloneBtn.off('click');
makePrivateBtn.addClass('disabled hidden');
makePrivateBtn.off('click');
publishBtn.addClass('disabled hidden');
publishBtn.off('click');
archiveBtn.addClass('disabled hidden');
archiveBtn.off('click');
restoreBtn.addClass('disabled hidden');
restoreBtn.off('click');
exportBtn.addClass('disabled hidden');
exportBtn.off('click');
} else {
// > 1 ROWS SELECTED
_.each(rowsSelected, function(rowId) {
rows.push($("tr[data-row-id='" + rowId + "']")[0]);
});
rows = $(rows);
// Only enable button if all selected rows can
// be published/archived/restored/exported
cloneBtn.removeClass('hidden').addClass('disabled');
cloneBtn.off('click');
if (!rows.is(':not([data-can-make-private])')) {
makePrivateBtn.removeClass('disabled hidden');
makePrivateBtn.off('click').on('click', function() { processMoveButtonClick($(this)); });
} else {
makePrivateBtn.removeClass('hidden').addClass('disabled');
makePrivateBtn.off('click');
}
if (!rows.is(':not([data-can-publish])')) {
publishBtn.removeClass('disabled hidden');
publishBtn.off('click').on('click', function() { processMoveButtonClick($(this)); });
} else {
publishBtn.removeClass('hidden').addClass('disabled');
publishBtn.off('click');
}
if (!rows.is(':not([data-can-archive])')) {
archiveBtn.removeClass('disabled hidden');
archiveBtn.off('click').on('click', function() { processMoveButtonClick($(this)); });
} else {
archiveBtn.removeClass('hidden').addClass('disabled');
archiveBtn.off('click');
}
if (!rows.is(':not([data-can-restore])')) {
restoreBtn.removeClass('disabled hidden');
restoreBtn.off('click').on('click', function() { processMoveButtonClick($(this)); });
} else {
restoreBtn.removeClass('hidden').addClass('disabled');
restoreBtn.off('click');
}
if (!rows.is(':not([data-can-export])')) {
exportBtn.removeClass('disabled hidden');
exportBtn.off('click').on('click', function() { exportProtocols(rowsSelected); });
} else {
exportBtn.removeClass('hidden').addClass('disabled');
exportBtn.off('click');
}
}
}
function exportProtocols(ids) {
if (ids.length > 0) {
var params = '?protocol_ids[]=' + ids[0];
for (var i = 1; i < ids.length; i++) {
params += '&protocol_ids[]=' + ids[i];
}
params = encodeURI(params);
window.location.href = $("[data-action='export']")
.data('export-url') + params;
}
}
function cloneSelectedProtocol() {
if (rowsSelected.length && rowsSelected.length == 1) {
var row = $("tr[data-row-id='" + rowsSelected[0] + "']");
animateSpinner();
$.ajax({
url: row.attr("data-clone-url"),
type: "POST",
dataType: "json",
success: function (data) {
animateSpinner(null, false);
// Reload page
location.reload();
},
error: function (error) {
animateSpinner(null, false);
// Reload page
location.reload();
}
});
}
}
function processMoveButtonClick(btn) {
var action = btn.attr("data-action");
var url = btn.attr("data-url");
if (action === "archive") {
confirmModal = $("#confirm-archive-modal");
confirmModal
.find(".modal-footer [data-action='submit']")
.on("click", function(e) {
confirmModal.modal("hide");
moveSelectedProtocols(action, url);
});
// Show the modal
confirmModal.modal("show");
} else {
moveSelectedProtocols(action, url);
}
}
function moveSelectedProtocols(action, url) {
animateSpinner();
$.ajax({
url: url,
type: "POST",
dataType: "json",
data: { protocol_ids: rowsSelected },
success: function (data) {
rowsSelected = [];
// Display the modal
var modal = $("#" + action + "-results-modal");
var modalBody = modal.find(".modal-body");
modalBody.html(data.html);
animateSpinner(null, false);
modal.modal("show");
},
error: function (error) {
animateSpinner(null, false);
if (error.status == 401) {
// Unauthorized
alert(I18n.t("protocols.index." + action.replace("-", "_") + "_unauthorized"));
} else {
// Generic error
alert(I18n.t("protocols.index." + action.replace("-", "_") + "_error"));
}
}
});
}
function initImport() {
// Some templating code duplication. I know, I hate myself
function newElement(name, values) {
var template = $("[data-template='" + name + "']").clone();
template.removeAttr("data-template");
template.show();
// Populate values in the template
if (values !== null) {
_.each(values, function(val, key) {
template.find("[data-val='" + key + "']").html(val);
});
}
return template;
}
function addChildToElement(parentEl, name, childEl) {
parentEl.find("[data-hold='" + name + "']").append(childEl);
}
var importResultsModal = $("#import-results-modal");
var fileInput = $("[data-role='import-file-input']");
// Make sure multiple selections of same file
// always prompt new modal
fileInput.find("input[type='file']").on("click", function() {
this.value = null;
});
// Hack to hide "No file chosen" tooltip
fileInput.attr("title", window.webkitURL ? " " : "");
fileInput.on("change", function(ev) {
var importUrl = fileInput.attr("data-import-url");
var teamId = fileInput.attr("data-team-id");
var type = fileInput.attr("data-type");
importProtocolFromFile(
ev.target.files[0],
importUrl,
{ team_id: teamId, type: type },
false,
function(datas) {
var nrSuccessful = 0;
var failed = [];
var unchanged = [];
var renamed = [];
_.each(datas, function(data) {
if (data.status === "ok") {
nrSuccessful++;
if (data.name === data.new_name) {
unchanged.push(data);
} else {
renamed.push(data);
}
} else {
failed.push(data);
}
});
// Display the results modal by cloning
// templates and populating them
var modalBody = importResultsModal.find(".modal-body");
if (failed.length > 0) {
var failedMessageEl = newElement(
"import-result-message-error",
{
message: I18n.t("protocols.index.import_results.message_failed", { nr: failed.length })
}
);
modalBody.append(failedMessageEl);
animateSpinner(null, false);
}
if (nrSuccessful > 0) {
var successMessageEl = newElement(
"import-result-message-success",
{
message: I18n.t("protocols.index.import_results.message_ok", { nr: nrSuccessful })
}
);
modalBody.append(successMessageEl);
}
var resultsListEl = newElement("import-result-list");
modalBody.append(resultsListEl);
if (unchanged.length > 0) {
_.each(unchanged, function(pr) {
var itemEl = newElement(
"import-result-unchanged-item",
{ message: pr.name }
);
addChildToElement(resultsListEl, "items", itemEl);
});
}
if (renamed.length > 0) {
_.each(renamed, function(pr) {
var itemEl = newElement(
"import-result-renamed-item",
{ message: I18n.t("protocols.index.row_renamed_html", { old_name: pr.name, new_name: pr.new_name }) }
);
addChildToElement(resultsListEl, "items", itemEl);
});
}
if (failed.length > 0) {
_.each(failed, function(pr) {
var itemEl = newElement(
"import-result-failed-item",
{
message: pr.name,
message2: (pr.status === "size_too_large" ? I18n.t("protocols.index.import_results.row_file_too_large") : "")
}
);
addChildToElement(resultsListEl, "items", itemEl);
});
}
importResultsModal.modal("show");
}
);
$(this).val("");
});
importResultsModal.on("hidden.bs.modal", function() {
importResultsModal.find(".modal-body").html("");
// Also reload table
protocolsDatatable.ajax.reload();
});
}
init();