frontend/app/assets/javascripts/rde.js
//= require jquery.event.drag-1.4.min
//= require jquery.kiketable.colsizable-1.1
//= require jquery.columnmanager.min
//= require bootstrap-multiselect
//= require linker
$(function () {
$.fn.init_rapid_data_entry_form = function ($modal, uri) {
$(this).each(function () {
var $rde_form = $(this);
var $table = $('table#rdeTable', $rde_form);
if ($rde_form.hasClass('initialised')) {
return;
}
$('.linker:not(.initialised)').linker();
// Cookie Names
var COOKIE_NAME_VISIBLE_COLUMN =
'rde.' + $rde_form.data('cookie-prefix') + '.visible';
var COOKIE_NAME_STICKY_COLUMN =
'rde.' + $rde_form.data('cookie-prefix') + '.sticky';
var COOKIE_NAME_COLUMN_WIDTHS =
'rde.' + $rde_form.data('cookie-prefix') + '.widths';
var COOKIE_NAME_COLUMN_ORDER =
'rde.' + $rde_form.data('cookie-prefix') + '.order';
// Config from Cookies
var STICKY_COLUMN_IDS = AS.prefixed_cookie(COOKIE_NAME_STICKY_COLUMN)
? JSON.parse(AS.prefixed_cookie(COOKIE_NAME_STICKY_COLUMN))
: null;
var COLUMN_WIDTHS = AS.prefixed_cookie(COOKIE_NAME_COLUMN_WIDTHS)
? JSON.parse(AS.prefixed_cookie(COOKIE_NAME_COLUMN_WIDTHS))
: null;
var COLUMN_ORDER = AS.prefixed_cookie(COOKIE_NAME_COLUMN_ORDER)
? JSON.parse(AS.prefixed_cookie(COOKIE_NAME_COLUMN_ORDER))
: null;
var DEFAULT_VALUES = {};
// jquery.columnmanager gets wonky if the first pass through column
// order needs to unhide anything, so don't load visibility yet
var VISIBLE_COLUMN_IDS;
// store section data
var SECTION_DATA = {};
$('.sections th', $table).each(function () {
SECTION_DATA[$(this).data('id')] = $(this).text();
});
var validateSubmissionOnly = false;
$modal.off('click').on('click', '.remove-row', function (event) {
event.preventDefault();
event.stopPropagation();
var $btn = $(event.target).closest('button');
if ($btn.hasClass('btn-danger')) {
$btn.closest('tr').remove();
} else {
$btn.addClass('btn-danger');
$('span', $btn).addClass('icon-white');
setTimeout(function () {
$btn.removeClass('btn-danger');
$('span', $btn).removeClass('icon-white');
}, 10000);
}
});
$modal.on('click', '#rde_reset', function (event) {
event.preventDefault();
event.stopPropagation();
$(':input, .btn', $rde_form).attr('disabled', 'disabled');
// reset cookies
AS.prefixed_cookie(COOKIE_NAME_VISIBLE_COLUMN, null);
AS.prefixed_cookie(COOKIE_NAME_COLUMN_WIDTHS, null);
AS.prefixed_cookie(COOKIE_NAME_STICKY_COLUMN, null);
AS.prefixed_cookie(COOKIE_NAME_COLUMN_ORDER, null);
VISIBLE_COLUMN_IDS = null;
STICKY_COLUMN_IDS = null;
COLUMN_WIDTHS = null;
COLUMN_ORDER = null;
// reload the form
$(document).triggerHandler('rdeload.aspace', [uri, $modal]);
});
$modal.on('click', '.add-row', function (event) {
event.preventDefault();
event.stopPropagation();
var $row = addRow(event);
$(':input:visible:first', $row).focus();
$('.linker:not(.initialised)').linker();
validateRows($row);
});
var setRowIndex = function () {
current_row_index = Math.max($('tbody tr', $table).length - 1, 0);
$('tbody tr', $table).each(function (i, row) {
$(row).data('index', i);
});
};
var current_row_index = 0;
setRowIndex();
var addRow = function (event) {
var $currentRow = $(event.target).closest('tr');
if ($currentRow.length === 0) {
$currentRow = $('table tbody tr:last', $rde_form);
}
current_row_index = current_row_index + 1;
var $row = $(
AS.renderTemplate(
'template_rde_' + $rde_form.data('child-type') + '_row',
{
path:
$rde_form.data('jsonmodel-type') +
'[children][' +
current_row_index +
']',
id_path:
$rde_form.data('jsonmodel-type') +
'_children__' +
current_row_index +
'_',
index: current_row_index,
}
)
);
$row.data('index', current_row_index);
$('.fieldset-labels th', $rde_form).each(function (i, th) {
var $th = $(th);
var $target;
// Apply any sticky columns
if ($currentRow.length > 0) {
if ($th.hasClass('fieldset-label') && $th.hasClass('sticky')) {
// populate the input from the current or bottom row
var $source = $(':input:first', $('td', $currentRow).get(i));
$target = $(':input:first', $('td', $row).get(i));
if ($source.is(':checkbox')) {
if ($source.is(':checked')) {
$target.attr('checked', 'checked');
} else {
$target.removeAttr('checked');
}
} else if (
$source.is(':hidden') &&
$source.parents().closest('div').hasClass('linker-wrapper')
) {
// a linker!
$target.attr('data-selected', $source.val());
} else if ($source.is('.linker:text')) {
// $source is a yet to be initialized linker (when adding multiple rows)
$target.attr('data-selected', $source.attr('data-selected'));
} else {
$target.val($source.val());
}
} else if (DEFAULT_VALUES[$th.attr('id')]) {
$target = $(':input:first', $('td', $row).get(i));
$target.val(DEFAULT_VALUES[$th.attr('id')]);
}
}
// Apply hidden columns
if ($th.hasClass('fieldset-label') && !isVisible($th.attr('id'))) {
$($('td', $row).get(i)).hide();
}
// Apply column order
if (COLUMN_ORDER != null) {
$.each(COLUMN_ORDER, function (targetIndex, colId) {
var $td = $("td[data-col='" + colId + "']", $row);
var currentIndex = $td.index();
if (targetIndex !== currentIndex) {
$td.insertBefore($('td', $row).get(targetIndex));
}
});
}
});
$currentRow.after($row);
initOtherLevelHandler(current_row_index);
initRestrictionDatesHandler($row);
return $row;
};
$modal.off('keydown').on('keydown', function (event) {
if (event.keyCode === 27) {
//esc
event.preventDefault();
event.stopImmediatePropagation();
}
});
// TODO - use hotkeys for this?
$modal.on('keydown', ":input, input[type='text']", function (event) {
var $row = $(event.target).closest('tr');
var $cell = $(event.target).closest('td');
if (event.keyCode === 13) {
// return
event.preventDefault();
if (event.shiftKey) {
$('.add-row', $row).trigger('click');
$(
':input:visible:first',
$('td', $row.next())[$cell.index()]
).focus();
}
} else if (event.keyCode === 27) {
//esc
event.preventDefault();
event.stopImmediatePropagation();
return true;
} else if (event.keyCode === 37) {
// left
if (event.shiftKey) {
event.preventDefault();
$(':input:visible:first', prevActiveCell($cell)).focus();
}
} else if (event.keyCode === 40) {
// down
if (event.shiftKey) {
event.preventDefault();
if ($row.index() < $row.siblings().length) {
$(
':input:visible:first',
$('td', $row.next())[$cell.index()]
).focus();
}
}
} else if (event.keyCode === 38) {
// up
if (event.shiftKey) {
event.preventDefault();
if ($row.index() > 0) {
$(
':input:visible:first',
$('td', $row.prev())[$cell.index()]
).focus();
}
}
} else if (event.keyCode === 39) {
// right
if (event.shiftKey) {
event.preventDefault();
$(':input:visible:first', nextActiveCell($cell)).focus();
}
} else {
// we're cool.
}
});
$modal.on('click', 'th.fieldset-label', function (event) {
$(this).toggleClass('sticky');
var sticky = [];
$('table th.sticky', $rde_form).each(function () {
sticky.push($(this).attr('id'));
});
STICKY_COLUMN_IDS = sticky;
AS.prefixed_cookie(
COOKIE_NAME_STICKY_COLUMN,
JSON.stringify(STICKY_COLUMN_IDS)
);
});
$modal.on('click', '[data-dismiss]', function (event) {
$modal.modal('hide');
});
var renderInlineErrors = function ($rows, exception_data) {
$('.linker:not(.initialised)').linker();
$rows.each(function (i, row) {
var $row = $(row);
var row_result = exception_data[i];
var $errorSummary = $('.error-summary', $row);
var $errorSummaryList = $('.error-summary-list', $errorSummary);
$errorSummaryList.empty();
if (
Object.prototype.hasOwnProperty.call(row_result, 'errors') &&
!$.isEmptyObject(row_result.errors)
) {
$row.removeClass('valid').addClass('invalid');
$.each(row_result.errors, function (name, error) {
var $input = $(
"[id='" +
$rde_form.data('jsonmodel-type') +
'_children__' +
$row.data('index') +
'__' +
name.replace(/\//g, '__') +
"_']",
$row
);
var $header = $(
$('.fieldset-labels th', $table).get(
$input.first().closest('td').index()
)
);
$input.closest('.form-group').addClass('has-error');
var $error = $("<div class='error'>");
if ($input.length > 1 || $input.hasClass('defer-to-section')) {
$error.text(SECTION_DATA[$header.data('section')]);
} else {
$error.text(
$(
$('.fieldset-labels th', $table).get(
$input.closest('td').index()
)
).text()
);
}
$error.append(' - ').append(error);
$error.append("<span class='glyphicon glyphicon-chevron-right'>");
$errorSummaryList.append($error);
$error.data('target', $input.first().attr('id'));
});
// force a reposition of the error summary
$('.modal-body', $modal).trigger('scroll');
} else {
$row.removeClass('invalid').addClass('valid');
}
});
};
var initAjaxForm = function () {
$rde_form.ajaxForm({
target: $('.rde-wrapper', $modal),
success: function () {
$(window).trigger('resize');
$rde_form = $('form', '#rapidDataEntryModal');
$table = $('table', $rde_form);
setRowIndex();
if ($rde_form.length) {
renderInlineErrors(
$('tbody tr', $rde_form),
$rde_form.data('exceptions')
);
initAjaxForm();
} else {
// we're good to go!
setTimeout(function () {
location.reload(true);
}, 1000);
}
},
});
// add ability to resize columns
$table.kiketable_colsizable({
dragCells: 'tr.fieldset-labels th.fieldset-label',
dragMove: true,
});
$('th.fieldset-label .kiketable-colsizable-handler', $table).on(
'dragend',
persistColumnWidths
);
// add show/hide
$table.columnManager();
// give the columns an id
$('table thead .fieldset-labels th').each(function (i, col) {
if (!$(col).attr('id')) {
$(col).attr('id', 'rdecol' + i);
}
$($('table colgroup col').get(i)).data('id', $(col).attr('id'));
});
initAutoValidateFeature();
applyColumnOrder(function () {
VISIBLE_COLUMN_IDS = AS.prefixed_cookie(COOKIE_NAME_VISIBLE_COLUMN)
? JSON.parse(AS.prefixed_cookie(COOKIE_NAME_VISIBLE_COLUMN))
: null;
applyPersistentVisibleColumns();
});
initColumnReorderFeature();
initRdeTemplates();
applyPersistentStickyColumns();
initColumnShowHideWidget();
initFillFeature();
initShowInlineErrors();
initOtherLevelHandler();
initRestrictionDatesHandler();
};
var initShowInlineErrors = function () {
if ($('button.toggle-inline-errors').hasClass('active')) {
$table.addClass('show-inline-errors');
} else {
$table.removeClass('show-inline-errors');
}
};
var initOtherLevelHandler = function (index = 0) {
var $select = $("td[data-col='colLevel']:eq(" + index + ') select');
if ($select.val() === 'otherlevel') {
enableCell('colOtherLevel', index);
} else {
disableCell('colOtherLevel', index);
}
$select.change(function () {
if ($(this).val() === 'otherlevel') {
enableCell('colOtherLevel', index);
} else {
disableCell('colOtherLevel', index);
}
});
};
var initRestrictionDatesHandler = function (elt = null) {
if (!elt) {
elt = $('#rdeTable');
}
function handleUpdate() {
var $select = $(this);
var id_base = $select.attr('id').replace(/_type_$/, '');
var restrictionsEnabled =
$select.val() === 'accessrestrict' ||
$select.val() === 'userestrict';
// Find the corresponding restriction begin + end fields and set their states to match the dropdown.
for (var range_type of [
'begin',
'end',
'local_access_restriction_type[]',
]) {
var input = $(
'#' +
id_base +
'_rights_restriction__' +
range_type.replace(/[[\]]/g, '_') +
'_'
);
input.attr('disabled', restrictionsEnabled ? null : 'disabled');
if (restrictionsEnabled) {
if (input.is('select') && !input.val()) {
// Select the first option by default
input.val(input.find('option:first').val());
}
} else {
// Clear the input
input.val('');
}
}
}
var selects = elt.find("td[data-col^='colNType'] select");
selects.change(handleUpdate);
selects.trigger('change');
};
var initAutoValidateFeature = function () {
// Validate row upon input change
$table.on('change', ':input:visible', function () {
var $row = $(this).closest('tr');
validateRows($row);
});
$('.modal-body', $modal).on('scroll', function (event) {
$('.error-summary', $table).css('left', $(this)[0].scrollLeft + 5);
});
$table.on('focusin click', ':input', function () {
$(this)
.closest('tr')
.addClass('last-focused')
.siblings()
.removeClass('last-focused');
});
$table.on('click', '.error-summary .error', function () {
var $target = $('#' + $(this).data('target'));
// if column is hidden, then show the column first
if (!$target.is('visible')) {
var colId = COLUMN_ORDER[$target.closest('td').index()];
$('#rde_hidden_columns').multiselect('select', colId);
}
$target.closest('td').ScrollTo({
axis: 'x',
callback: function () {
$target.focus();
},
});
});
$table.on('click', 'td.status', function (event) {
event.preventDefault();
event.stopPropagation();
if ($(event.target).closest('.error-summary').length > 0) {
// don't propagate to the status cell
// if clicking on an error
return;
}
if ($(this).closest('tr').hasClass('last-focused')) {
$('button.toggle-inline-errors').trigger('click');
} else {
$(this)
.closest('tr')
.addClass('last-focused')
.siblings()
.removeClass('last-focused');
}
});
$table.on(
'click',
'.hide-error-summary, .show-error-summary',
function (event) {
event.preventDefault();
event.stopPropagation();
$('button.toggle-inline-errors').trigger('click');
}
);
};
var initFillFeature = function () {
var $fillFormsContainer = $('.fill-column-form', $modal);
var $btnFillFormToggle = $('button.fill-column', $modal);
var $sourceRow = $('table tbody tr:first', $rde_form);
// Setup global events
$btnFillFormToggle.click(function (event) {
event.preventDefault();
event.stopPropagation();
// toggle other panel if it is active
if (!$(this).hasClass('active')) {
$('.active', $(this).closest('.btn-group')).trigger('click');
}
$btnFillFormToggle.toggleClass('active');
$fillFormsContainer.slideToggle();
});
// Setup Basic Fill form
var setupBasicFillForm = function () {
var $form = $('#fill_basic', $fillFormsContainer);
var $inputTargetColumn = $('#basicFillTargetColumn', $form);
var $btnFill = $('button', $form);
// populate the column selectors
populateColumnSelector($inputTargetColumn);
$inputTargetColumn.change(function () {
$('.empty', this).remove();
var colIndex = parseInt($('#' + $(this).val()).index());
var $input = $(
':input:first',
$('td', $sourceRow).get(colIndex)
).clone();
$input.attr('name', '').attr('id', 'basicFillValue');
$('.fill-value-container', $form).html($input);
$btnFill.removeAttr('disabled').removeClass('disabled');
});
$btnFill.click(function (event) {
event.preventDefault();
event.stopPropagation();
var colIndex =
parseInt($('#' + $inputTargetColumn.val()).index()) + 1;
var $targetCells = $(
'table tbody tr td:nth-child(' + colIndex + ')',
$rde_form
);
var fillValue;
if ($('#basicFillValue', $form).is(':checkbox')) {
fillValue = $('#basicFillValue', $form).is(':checked');
if (fillValue) {
$(':input:first', $targetCells).attr('checked', 'checked');
} else {
$(':input:first', $targetCells).removeAttr('checked');
}
} else {
fillValue = $('#basicFillValue', $form).val();
$(':input:first', $targetCells).val(fillValue).trigger('change');
}
$btnFillFormToggle.toggleClass('active');
$fillFormsContainer.slideToggle();
validateAllRows();
});
};
// Setup Sequence Fill form
var setupSequenceFillForm = function () {
var $form = $('#fill_sequence', $fillFormsContainer);
var $inputTargetColumn = $('#sequenceFillTargetColumn', $form);
var $btnFill = $('button.btn-primary', $form);
var $sequencePreview = $('.sequence-preview', $form);
// populate the column selectors
populateColumnSelector(
$inputTargetColumn,
null,
function ($colHeader) {
var $td = $('td', $sourceRow).get($colHeader.index());
return $(':input:first', $td).is(':text');
}
);
$inputTargetColumn.change(function () {
$('.empty', this).remove();
$btnFill.removeAttr('disabled').removeClass('disabled');
});
$('button.preview-sequence', $form).click(function (event) {
event.preventDefault();
event.stopPropagation();
$.getJSON(
$form.data('sequence-generator-url'),
{
prefix: $('#sequenceFillPrefix', $form).val(),
from: $('#sequenceFillFrom', $form).val(),
to: $('#sequenceFillTo', $form).val(),
suffix: $('#sequenceFillSuffix', $form).val(),
limit: $('tbody tr', $table).length,
},
function (json) {
$sequencePreview.html('');
if (json.errors) {
$.each(json.errors, function (i, error) {
var $error = $('<div>').html(error).addClass('text-error');
$sequencePreview.append($error);
});
} else {
$sequencePreview.html(
$("<p class='values'>").html(json.values.join(', '))
);
$sequencePreview.prepend(
$("<p class='summary'>").html(json.summary)
);
}
}
);
});
var applySequenceFill = function (force) {
$('#sequenceTooSmallMsg', $form).hide();
$.getJSON(
$form.data('sequence-generator-url'),
{
prefix: $('#sequenceFillPrefix', $form).val(),
from: $('#sequenceFillFrom', $form).val(),
to: $('#sequenceFillTo', $form).val(),
suffix: $('#sequenceFillSuffix', $form).val(),
limit: $('tbody tr', $table).length,
},
function (json) {
$sequencePreview.html('');
if (json.errors) {
$.each(json.errors, function (i, error) {
var $error = $('<div>').html(error).addClass('text-error');
$sequencePreview.append($error);
});
return;
}
// check if less items in sequence than rows
if (
!force &&
json.values.length < $('tbody tr', $modal).length
) {
$('#sequenceTooSmallMsg', $form).show();
return;
}
// Good to go. Apply values.
var targetIndex = $('#' + $inputTargetColumn.val()).index();
var $targetCells = $(
'table tbody tr td:nth-child(' + (targetIndex + 1) + ')',
$rde_form
);
$.each(json.values, function (i, val) {
if (i > $targetCells.length) {
return;
}
$(':input:first', $targetCells[i]).val(val);
});
$btnFillFormToggle.toggleClass('active');
$fillFormsContainer.slideToggle();
validateAllRows();
}
);
};
$btnFill.click(function (event) {
event.preventDefault();
event.stopPropagation();
applySequenceFill(false);
});
$('.btn-continue-sequence-fill', $form).click(function (event) {
event.preventDefault();
event.stopPropagation();
applySequenceFill(true);
});
};
setupBasicFillForm();
setupSequenceFillForm();
};
var persistColumnOrder = function () {
var column_ids = [];
$('table .fieldset-labels th', $rde_form).each(function () {
column_ids.push($(this).attr('id'));
});
COLUMN_ORDER = column_ids;
AS.prefixed_cookie(
COOKIE_NAME_COLUMN_ORDER,
JSON.stringify(COLUMN_ORDER)
);
};
// Remove elements from `a` that appear in `b`.
var setSubtract = function (a, b) {
const bSet = {};
for (const elt of b) {
bSet[elt] = true;
}
const result = [];
for (const elt of a) {
if (!bSet[elt]) {
result.push(elt);
}
}
return result;
};
var applyColumnOrder = function (callback) {
if (COLUMN_ORDER === null) {
persistColumnOrder();
} else {
// apply order from cookie
var $row = $('tr.fieldset-labels', $table);
var $sectionRow = $('tr.sections', $table);
var $colgroup = $('colgroup', $table);
// If there are columns present that aren't in our order, RDE might
// have gained some new columns since we persisted our list.
//
// Keep everything working by inserting the missing columns at the end
// of the list, just before colActions.
var missing = setSubtract(
$('th', 'tr.fieldset-labels').map(function () {
return $(this).attr('id');
}),
COLUMN_ORDER
);
COLUMN_ORDER = COLUMN_ORDER.filter(elt => elt !== 'colActions');
for (const elt of missing) {
COLUMN_ORDER.push(elt);
}
COLUMN_ORDER.push('colActions');
$sectionRow.html('');
$.each(COLUMN_ORDER, function (targetIndex, colId) {
var $th = $('#' + colId, $row);
var currentIndex = $th.index();
var $col = $($('col', $colgroup).get(currentIndex));
// show hidden stuff so we get the section headers right
// we'll reapply visibility at the end
if (!isVisible(colId) && targetIndex > 0) {
showColumn(currentIndex);
}
if (targetIndex !== currentIndex) {
$th.insertBefore($('th', $row).get(targetIndex));
$col.insertBefore($('col', $colgroup).get(targetIndex));
$('tbody tr', $table).each(function (i, $tr) {
$($('td', $tr).get(currentIndex)).insertBefore(
$('td', $tr).get(targetIndex)
);
});
}
// build the section row cells
if (targetIndex === 0) {
$sectionRow.append(
$('<th>').data('id', 'empty').attr('colspan', '1')
);
} else if (
$('th', $sectionRow).last().data('id') === $th.data('section')
) {
var $lastTh = $('th', $sectionRow).last();
$lastTh.attr('colspan', parseInt($lastTh.attr('colspan')) + 1);
} else {
$sectionRow.append(
$('<th>')
.data('id', $th.data('section'))
.addClass('section-' + $th.data('section'))
.attr('colspan', '1')
.text(SECTION_DATA[$th.data('section')])
);
}
});
if (callback) {
callback();
}
}
};
var templateList = null;
var initRdeTemplates = function () {
initSaveTemplateFeature();
loadRdeTemplateList(function () {
initManageTemplatesFeature();
initSelectTemplateFeature();
});
};
var loadRdeTemplateList = function (cb) {
var recordType = $rde_form.data('child-type');
$.ajax({
url: $rde_form.data('list-templates-uri'),
type: 'GET',
dataType: 'json',
success: function (_templateList_) {
templateList = _templateList_.filter(function (t) {
return t.record_type === recordType;
});
cb();
},
error: function (xhr, status, err) {
console.log(err);
},
});
};
var initSaveTemplateFeature = function () {
var $saveContainer = $('#saveTemplateForm', $modal);
var $containerToggle = $('button.save-template', $modal);
var $input = $('#templateName', $saveContainer);
var $btnSave = $('.btn-primary', $saveContainer);
// Setup global events
$containerToggle.off('click').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
// toggle other panel if it is active
if (!$(this).hasClass('active')) {
$('.active', $(this).closest('.btn-group')).trigger('click');
}
$containerToggle.toggleClass('active');
$saveContainer.slideToggle();
});
$input.on('change keyup paste', function () {
if ($(this).val().length > 0) {
$btnSave.removeAttr('disabled').removeClass('disabled');
} else {
$btnSave.prop('disabled', true);
}
});
$btnSave.click(function (event) {
event.preventDefault();
event.stopPropagation();
var template = {
record_type: $rde_form.data('child-type'),
name: $input.val(),
order: [],
visible: [],
defaults: {},
};
var $firstRow = $('table tbody tr:first', $rde_form);
$('table .fieldset-labels th', $rde_form).each(function () {
var colId = $(this).attr('id');
template.order.push(colId);
if ($(this).is(':visible')) {
template.visible.push(colId);
}
var $cellOne = $("td[data-col='" + colId + "']", $firstRow);
if ($('input', $cellOne).length) {
template.defaults[colId] = $('input', $cellOne).val();
} else if ($('select', $cellOne).length) {
template.defaults[colId] = $('select', $cellOne).val();
}
});
template.defaults = Object.keys(template.defaults).reduce(function (
acc,
key
) {
if (template.defaults[key].length > 0) {
acc[key] = template.defaults[key];
}
return acc;
},
{});
$.ajax({
url: $rde_form.data('save-template-uri'),
type: 'POST',
data: { template: template },
dataType: 'json',
success: function (data) {
loadRdeTemplateList(function () {
initManageTemplatesFeature();
initSelectTemplateFeature();
});
$containerToggle.toggleClass('active');
$saveContainer.slideToggle();
},
error: function (xhr, status, err) {
console.log(err);
},
});
});
};
var initManageTemplatesFeature = function () {
var $manageContainer = $('#manageTemplatesForm', $modal);
var $containerToggle = $('button.manage-templates', $modal);
var $templatesTable = $('table tbody', $manageContainer);
$containerToggle.off('click').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
// toggle other panel if it is active
if (!$(this).hasClass('active')) {
$('.active', $(this).closest('.btn-group')).trigger('click');
}
$templatesTable.empty();
renderTable();
$containerToggle.toggleClass('active');
$manageContainer.slideToggle();
});
$('button.btn-cancel', $manageContainer)
.off('click')
.on('click', function (e) {
e.preventDefault();
e.stopPropagation();
$containerToggle.toggleClass('active');
$manageContainer.slideToggle();
});
$('button.btn-primary', $manageContainer)
.off('click')
.on('click', function (e) {
e.preventDefault();
e.stopPropagation();
var templatesToDelete = [];
$manageContainer.find(':checkbox:checked').each(function () {
templatesToDelete.push($(this).val());
});
$.ajax({
url: $rde_form.data('list-templates-uri') + '/batch_delete',
type: 'POST',
dataType: 'json',
data: { ids: templatesToDelete },
success: function (updatedTemplateList) {
templateList = updatedTemplateList;
initSelectTemplateFeature();
},
error: function (xhr, status, err) {
console.log(err);
},
});
$containerToggle.toggleClass('active');
$manageContainer.slideToggle();
});
var renderTable = function () {
if (templateList.length == 0) {
$('.no-templates-message', $manageContainer).show();
$('.btn-primary', $manageContainer).hide();
return;
} else {
$('.no-templates-message', $manageContainer).hide();
$('.btn-primary', $manageContainer).show();
}
templateList.forEach(function (item) {
$templatesTable.append(
AS.renderTemplate('rde_template_table_row', { item: item })
);
});
};
$.ajax({
url: $rde_form.data('list-templates-uri'),
type: 'GET',
dataType: 'json',
success: function (_templateList_) {
templateList = _templateList_;
},
});
};
var applyTemplate = function (template) {
// we are relying on template.order to always
// contain all colIds
COLUMN_ORDER = template.order;
DEFAULT_VALUES = template.defaults;
// sets the order, then
// calls applyPersistentVisibleColumns,
// which iterates over colums in DOM,
// and hides or shows
applyColumnOrder(function () {
VISIBLE_COLUMN_IDS = template.visible;
AS.prefixed_cookie(
COOKIE_NAME_VISIBLE_COLUMN,
JSON.stringify(VISIBLE_COLUMN_IDS)
);
applyPersistentVisibleColumns(function () {
var $firstRow = $('tbody tr:first', $rde_form);
$('td', $firstRow).each(function (index, td) {
var $td = $(td);
var colId = $td.data('col');
var $$input = $(':input:first', $td);
if (
DEFAULT_VALUES[colId] &&
($$input.data('value-from-template') ||
$$input.val().length < 1)
) {
$$input.val(DEFAULT_VALUES[colId]);
$$input.data('value-from-template', true);
}
});
// zap the multiselect widget
var $select = $('#rde_hidden_columns');
$select.data('multiselect').destroy();
$select.removeData('multiselect');
$select.empty();
initColumnShowHideWidget();
});
});
};
var initSelectTemplateFeature = function () {
var $select = $('#rde_select_template');
$select.change(function () {
var id = $('option:selected', $select).val();
$.ajax({
url: $rde_form.data('template-base-uri') + '/' + id,
type: 'GET',
dataType: 'json',
success: function (template) {
applyTemplate(template);
$select.attr('data-style', 'btn-success');
$select.selectpicker('refresh');
},
});
});
var renderOptions = function () {
$select.empty();
$select.append(
$('<option>', { disabled: 'disabled', selected: 'selected' }).text(
$select.data('prompt-text')
)
);
templateList.forEach(function (item) {
$select.append($('<option>', { value: item.id }).text(item.name));
});
$select.selectpicker('refresh');
};
renderOptions();
};
var initColumnReorderFeature = function () {
var $reorderContainer = $('#columnReorderForm', $modal);
var $btnReorderToggle = $('button.reorder-columns', $modal);
var $select = $('#columnOrder', $reorderContainer);
var $btnApplyOrder = $('.btn-primary', $reorderContainer);
// Setup global events
$btnReorderToggle.off('click').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
// toggle other panel if it is active
if (!$(this).hasClass('active')) {
$('.active', $(this).closest('.btn-group')).trigger('click');
}
$btnReorderToggle.toggleClass('active');
$reorderContainer.slideToggle();
});
populateColumnSelector($select);
$select.attr('size', $('option', $select).length / 2);
var handleMove = function (direction) {
var $options = $('option:selected', $select);
if ($options.length) {
if (direction === 'up') {
$options.first().prev().before($options);
} else {
$options.last().next().after($options);
}
}
$btnApplyOrder.removeAttr('disabled').removeClass('disabled');
};
var resetForm = function () {
$btnReorderToggle.toggleClass('active');
$reorderContainer.slideToggle(function () {
$btnApplyOrder.addClass('disabled').attr('disabled', 'disabled');
// reset the select
$select.html('');
populateColumnSelector($select);
});
};
$('#columnOrderUp', $reorderContainer).bind('click', function () {
handleMove('up');
});
$('#columnOrderDown', $reorderContainer).bind('click', function () {
handleMove('down');
});
$('.btn-cancel', $reorderContainer).click(function (event) {
event.preventDefault();
event.stopPropagation();
resetForm();
});
$btnApplyOrder.click(function (event) {
event.preventDefault();
event.stopPropagation();
COLUMN_ORDER = ['colStatus'];
$('option', $select).each(function () {
COLUMN_ORDER.push($(this).val());
});
COLUMN_ORDER.push('colActions');
applyColumnOrder();
resetForm();
persistColumnOrder();
});
};
var populateColumnSelector = function (
$select,
select_func,
filter_func
) {
filter_func =
filter_func ||
function () {
return true;
};
select_func =
select_func ||
function () {
return false;
};
$('.fieldset-labels th', $rde_form).each(function () {
var $colHeader = $(this);
if (
$colHeader.hasClass('fieldset-label') &&
filter_func($colHeader)
) {
var $option = $('<option>');
var option_text = '';
option_text += $(
'.section-' + $colHeader.data('section') + ':first'
).text();
option_text += ' - ';
option_text += $colHeader.text();
$option.val($colHeader.attr('id')).text(option_text);
if (select_func($colHeader)) {
$option.attr('selected', 'selected');
}
$select.append($option);
}
});
};
var initColumnShowHideWidget = function () {
var $select = $('#rde_hidden_columns');
populateColumnSelector($select, function ($colHeader) {
return isVisible($colHeader.attr('id'));
});
$select.multiselect({
buttonClass: 'btn btn-small btn-default',
buttonWidth: 'auto',
maxHeight: 300,
buttonContainer: '<div class="btn-group" id="multiselect_btn"/>',
buttonText: function (options) {
if (options.length == 0) {
return $select.data('i18n-none') + ' <b class="caret"></b>';
} else if (options.length > 5) {
return (
$select.data('i18n-prefix') +
' ' +
options.length +
' ' +
$select.data('i18n-suffix') +
' <b class="caret"></b>'
);
} else {
var selected = $select.data('i18n-prefix') + ' ';
options.each(function () {
selected += $(this).text() + ', ';
});
return (
selected.substr(0, selected.length - 2) +
' <b class="caret"></b>'
);
}
},
onChange: function ($option, checked) {
var widths = persistColumnWidths();
var colId = $option.val();
var index = $('#' + colId).index();
if (checked) {
$table.showColumns(index + 1);
var $col = $($('table colgroup col').get(index));
$col.show();
$table.width($table.width() + widths[index]);
} else {
hideColumn(index);
}
VISIBLE_COLUMN_IDS = $select.val();
AS.prefixed_cookie(
COOKIE_NAME_VISIBLE_COLUMN,
JSON.stringify(VISIBLE_COLUMN_IDS)
);
},
});
function disableRequiredColumns() {
// Don't allow omitting required fields in RDE templates
// by disabling the bootstratp-multiselect.js generated
// list items and checkboxes that represent required RDE columns
var $requiredColumns = $.makeArray(
$('.fieldset-labels th.required', $rde_form)
);
$requiredColumns.forEach(function (column) {
var id = column.id;
var checkboxSelector = "input[type='checkbox'][value=" + id + ']';
var $li = $('li').has(checkboxSelector);
var $input = $(checkboxSelector);
$li.addClass('disabled');
$input.prop({ disabled: true });
});
}
disableRequiredColumns();
};
var persistColumnWidths = function () {
var widths = {};
$('table colgroup col', $rde_form).each(function (i, col) {
if ($(col).prop('width') === null || $(col).prop('width') === '') {
$(col).prop('width', $(col).data('default-width'));
} else if ($(col).css('width')) {
var newWidth = parseInt($(col).css('width'));
$(col).prop('width', newWidth);
}
widths[$(col).data('id')] = parseInt($(col).prop('width'));
});
COLUMN_WIDTHS = widths;
AS.prefixed_cookie(
COOKIE_NAME_COLUMN_WIDTHS,
JSON.stringify(COLUMN_WIDTHS)
);
return COLUMN_WIDTHS;
};
var setColumnWidth = function (colId) {
var width = getColumnWidth(colId);
var index = $('#' + colId).index();
// set width of corresponding col element
$($('table colgroup col', $rde_form).get(index)).width(width);
return width;
};
var getColumnWidth = function (colId) {
if (COLUMN_WIDTHS) {
return COLUMN_WIDTHS[colId];
} else {
persistColumnWidths();
return getColumnWidth(colId);
}
};
var applyPersistentColumnWidths = function () {
var total_width = 0;
// force table layout to auto
$table.css('tableLayout', 'auto');
$('colgroup col', $table).each(function (i, el) {
var colW = getColumnWidth($(el).data('id'));
$(el).prop('width', colW);
total_width += colW;
});
$table.width(total_width);
// and then change table layout to fixed to force a redraw to
// ensure all colgroup widths are obeyed
$table.css('tableLayout', 'fixed');
};
var applyPersistentStickyColumns = function () {
if (STICKY_COLUMN_IDS) {
$('th.sticky', $rde_form).removeClass('sticky');
$.each(STICKY_COLUMN_IDS, function () {
$('#' + this).addClass('sticky');
});
}
};
var isVisible = function (colId) {
if (VISIBLE_COLUMN_IDS) {
return $.inArray(colId, VISIBLE_COLUMN_IDS) >= 0;
} else {
return true;
}
};
var applyPersistentVisibleColumns = function (callback) {
if (VISIBLE_COLUMN_IDS) {
var total_width = 0;
$.each($('.fieldset-labels th', $rde_form), function () {
var colId = $(this).attr('id');
var index = $(this).index();
if ($(this).hasClass('fieldset-label')) {
if (isVisible(colId)) {
total_width += setColumnWidth(colId);
} else {
hideColumn(index);
}
} else {
total_width += setColumnWidth(colId);
}
});
$table.width(total_width);
if (callback) {
callback();
}
} else {
applyPersistentColumnWidths();
}
};
var hideColumn = function (index) {
$table.hideColumns(index + 1);
var $col = $($('table colgroup col').get(index));
$table.width($table.width() - $col.width());
$col.hide();
};
var showColumn = function (index) {
$table.showColumns(index + 1);
var $col = $($('table colgroup col').get(index));
$table.width($table.width() + $col.width());
$col.show();
};
var enableCell = function (colId, rowIndex) {
var row = $('tbody tr')[rowIndex];
var cell = $("td[data-col='" + colId + "']", row);
cell.removeClass('disabled');
$('input', cell).removeAttr('disabled');
};
var disableCell = function (colId, rowIndex) {
var row = $('tbody tr')[rowIndex];
var cell = $("td[data-col='" + colId + "']", row);
cell.addClass('disabled');
$('input', cell).attr('disabled', 'disabled');
};
var prevActiveCell = function ($cell) {
var prev = $cell.prev();
if (prev.hasClass('disabled')) {
return prevActiveCell(prev);
} else {
return prev;
}
};
var nextActiveCell = function ($cell) {
var next = $cell.next();
if (next.hasClass('disabled')) {
return nextActiveCell(next);
} else {
return next;
}
};
var validateAllRows = function () {
validateRows($('tbody tr', $table));
};
var validateRows = function ($rows) {
var row_data = $rows.serializeObject();
row_data['validate_only'] = 'true';
$('.error', $rows).removeClass('error');
$.ajax({
url: $rde_form.data('validate-row-uri'),
type: 'POST',
data: row_data,
dataType: 'json',
success: function (data) {
renderInlineErrors($rows, data);
},
});
};
// Connect up the $modal form submit button
$($modal).on('click', '.modal-footer .btn-primary', function () {
$(this).attr('disabled', 'disabled');
$rde_form.submit();
});
// Connect up the $modal form validate button
$($modal).on('click', '#validateButton', function (event) {
event.preventDefault();
event.stopPropagation();
validateSubmissionOnly = true;
$(this).attr('disabled', 'disabled');
$rde_form.append(
"<input type='hidden' name='validate_only' value='true'>"
);
$rde_form.submit();
});
// enable form within the add row dropdown menu
$('.add-rows-form input', $modal).click(function (event) {
event.preventDefault();
event.stopPropagation();
});
$('.add-rows-form button', $modal).click(function (event) {
var rows = [];
try {
var numberOfRows = parseInt(
$('input', $(this).closest('.add-rows-form')).val(),
10
);
for (var i = 1; i <= numberOfRows; i++) {
rows.push(addRow(event));
}
} catch (e) {
// if the field cannot parse the form value to an integer.. just quietly judge the user
}
validateRows($(rows));
});
// Connect the Inline Errors toggle
$modal.on('click', 'button.toggle-inline-errors', function (event) {
event.preventDefault();
event.stopPropagation();
$(this).toggleClass('active');
$table.toggleClass('show-inline-errors');
});
$modal.on('keyup', 'button', function (event) {
// pass on Return key hits as a click
if (event.keyCode === 13) {
$(this).trigger('click');
}
});
$(document).triggerHandler('loadedrecordform.aspace', [$rde_form]);
initAjaxForm();
$(window).trigger('resize');
// auto-validate the first row
setTimeout(function () {
validateAllRows();
});
});
$('select.selectpicker', $modal).selectpicker();
};
$(document).bind('rdeload.aspace', function (event, uri, $modal) {
var path = uri.replace(/^\/repositories\/[0-9]+\//, '');
$.ajax({
url: AS.app_prefix(path + '/rde'),
success: function (data) {
$('.rde-wrapper', $modal).replaceWith("<div class='modal-body'></div>");
$('.modal-body', $modal).replaceWith(data);
$('form', '#rapidDataEntryModal').init_rapid_data_entry_form(
$modal,
uri
);
},
});
});
$(document).bind('rdeshow.aspace', function (event, $node, $button) {
var $modal = AS.openCustomModal(
'rapidDataEntryModal',
$button.text(),
AS.renderTemplate('modal_content_loading_template'),
'full',
{ backdrop: 'static', keyboard: false },
$button
);
$(document).triggerHandler('rdeload.aspace', [$node.data('uri'), $modal]);
});
});