Polish category/row addition and deletion

This commit is contained in:
Zander Otavka 2016-07-28 13:47:21 -07:00
parent 93f9f93b5a
commit aa909a1366
3 changed files with 93 additions and 65 deletions

View file

@ -457,8 +457,9 @@
"caption": "Permissions for Users in Groups", "caption": "Permissions for Users in Groups",
"categorize_by_key": "permissions_id", "categorize_by_key": "permissions_id",
"can_add_new_categories": true, "can_add_new_categories": true,
"can_add_new_rows": false,
"new_category_placeholder": "Add Group", "new_category_placeholder": "Add Group",
"new_category_needs_reload": true, "new_category_message": "Reload to see ranks",
"groups": [ "groups": [
{ {
@ -548,8 +549,12 @@
{ {
"name": "group_forbiddens", "name": "group_forbiddens",
"type": "table", "type": "table",
"caption": "Permissions denied to Users in Groups", "caption": "Permissions Denied to Users in Groups",
"can_add_new_rows": true, "categorize_by_key": "permissions_id",
"can_add_new_categories": true,
"can_add_new_rows": false,
"new_category_placeholder": "Add Blacklist Group",
"new_category_message": "Reload to see ranks",
"groups": [ "groups": [
{ {

View file

@ -41,11 +41,16 @@ body {
font-weight: bold; font-weight: bold;
} }
.table .value-category .message { .table .value-category [message]::after {
content: attr(message);
font-style: italic; font-style: italic;
font-weight: normal; font-weight: normal;
} }
.table .value-category.inputs {
font-weight: normal;
}
.glyphicon-remove { .glyphicon-remove {
font-size: 24px; font-size: 24px;
} }

View file

@ -42,7 +42,7 @@ var viewHelpers = {
form_group = "<div class='form-group " + (isAdvanced ? Settings.ADVANCED_CLASS : "") + "' data-keypath='" + keypath + "'>"; form_group = "<div class='form-group " + (isAdvanced ? Settings.ADVANCED_CLASS : "") + "' data-keypath='" + keypath + "'>";
setting_value = _(values).valueForKeyPath(keypath); setting_value = _(values).valueForKeyPath(keypath);
if (typeof setting_value == 'undefined' || setting_value === null) { if (_.isUndefined(setting_value) || _.isNull(setting_value)) {
if (_.has(setting, 'default')) { if (_.has(setting, 'default')) {
setting_value = setting.default; setting_value = setting.default;
} else { } else {
@ -56,11 +56,11 @@ var viewHelpers = {
} }
function common_attrs(extra_classes) { function common_attrs(extra_classes) {
extra_classes = (typeof extra_classes !== 'undefined' ? extra_classes : ""); extra_classes = (!_.isUndefined(extra_classes) ? extra_classes : "");
return " class='" + (setting.type !== 'checkbox' ? 'form-control' : '') return " class='" + (setting.type !== 'checkbox' ? 'form-control' : '')
+ " " + Settings.TRIGGER_CHANGE_CLASS + " " + extra_classes + "' data-short-name='" + " " + Settings.TRIGGER_CHANGE_CLASS + " " + extra_classes + "' data-short-name='"
+ setting.name + "' name='" + keypath + "' " + setting.name + "' name='" + keypath + "' "
+ "id='" + (typeof setting.html_id !== 'undefined' ? setting.html_id : keypath) + "'"; + "id='" + (!_.isUndefined(setting.html_id) ? setting.html_id : keypath) + "'";
} }
if (setting.type === 'checkbox') { if (setting.type === 'checkbox') {
@ -937,6 +937,7 @@ $('body').on('click', '.save-button', function(e){
}); });
function makeTable(setting, keypath, setting_value, isLocked) { function makeTable(setting, keypath, setting_value, isLocked) {
// TODO: enforce category sorting
var isArray = !_.has(setting, 'key'); var isArray = !_.has(setting, 'key');
if (!isArray && setting.can_order) { if (!isArray && setting.can_order) {
@ -952,9 +953,10 @@ function makeTable(setting, keypath, setting_value, isLocked) {
var nonDeletableRowKey = setting["non-deletable-row-key"]; var nonDeletableRowKey = setting["non-deletable-row-key"];
var nonDeletableRowValues = setting["non-deletable-row-values"]; var nonDeletableRowValues = setting["non-deletable-row-values"];
html += "<table class='table table-bordered " + (isLocked ? "locked-table" : "") + "' data-short-name='" + setting.name html += "<table class='table table-bordered " + (isLocked ? "locked-table" : "") + "' " +
+ "' name='" + keypath + "' id='" + (typeof setting.html_id !== 'undefined' ? setting.html_id : keypath) "data-short-name='" + setting.name + "' name='" + keypath + "' " +
+ "' data-setting-type='" + (isArray ? 'array' : 'hash') + "'>"; "id='" + (!_.isUndefined(setting.html_id) ? setting.html_id : keypath) + "' " +
"data-setting-type='" + (isArray ? 'array' : 'hash') + "'>";
if (setting.caption) { if (setting.caption) {
html += "<caption>" + setting.caption + "</caption>" html += "<caption>" + setting.caption + "</caption>"
@ -1012,22 +1014,20 @@ function makeTable(setting, keypath, setting_value, isLocked) {
_.each(setting_value, function(row, rowIndexOrName) { _.each(setting_value, function(row, rowIndexOrName) {
var categoryKey = setting.categorize_by_key; var categoryKey = setting.categorize_by_key;
var isCategorized = !!categoryKey; var isCategorized = !!categoryKey && isArray;
var categoryData = ""; var categoryPair = {};
if (isCategorized && isArray) { var categoryValue = "";
var predicate = {}; if (isCategorized) {
var categoryValue = row[categoryKey];
predicate[categoryKey] = categoryValue;
categoryValue = rowIsObject ? row[categoryKey] : row; categoryValue = rowIsObject ? row[categoryKey] : row;
categoryData = "data-category='" + categoryValue + "'"; categoryPair[categoryKey] = categoryValue;
if (_.findIndex(setting_value, predicate) === rowIndexOrName) { if (_.findIndex(setting_value, categoryPair) === rowIndexOrName) {
html += makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns, setting.can_add_new_categories, false); html += makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns, setting.can_add_new_categories, "");
} }
} }
html += html += "<tr class='" + Settings.DATA_ROW_CLASS + "' " +
"<tr class='" + Settings.DATA_ROW_CLASS + "' " + categoryData + " " + (isCategorized ? ("data-category='" + categoryValue + "'") : "") + " " +
(isArray ? "" : "name='" + keypath + "." + rowIndexOrName + "'") + ">" (isArray ? "" : "name='" + keypath + "." + rowIndexOrName + "'") + ">";
if (setting.numbered === true) { if (setting.numbered === true) {
html += "<td class='numbered'>" + row_num + "</td>" html += "<td class='numbered'>" + row_num + "</td>"
@ -1037,7 +1037,7 @@ function makeTable(setting, keypath, setting_value, isLocked) {
html += "<td class='key'>" + rowIndexOrName + "</td>" html += "<td class='key'>" + rowIndexOrName + "</td>"
} }
var isNonDeletableRow = !setting.can_add_new_rows && !setting.can_add_new_categories || setting.new_category_needs_reload; var isNonDeletableRow = !setting.can_add_new_rows;
_.each(setting.columns, function(col) { _.each(setting.columns, function(col) {
@ -1075,7 +1075,7 @@ function makeTable(setting, keypath, setting_value, isLocked) {
"</td>"; "</td>";
} }
}) });
if (!isLocked && !setting.read_only) { if (!isLocked && !setting.read_only) {
if (setting.can_order) { if (setting.can_order) {
@ -1093,6 +1093,10 @@ function makeTable(setting, keypath, setting_value, isLocked) {
html += "</tr>" html += "</tr>"
if (isCategorized && setting.can_add_new_rows && _.findLastIndex(setting_value, categoryPair) === rowIndexOrName) {
html += makeTableInputs(setting, categoryPair, categoryValue);
}
row_num++ row_num++
}); });
} }
@ -1103,7 +1107,7 @@ function makeTable(setting, keypath, setting_value, isLocked) {
html += makeTableCategoryInput(setting, numVisibleColumns); html += makeTableCategoryInput(setting, numVisibleColumns);
} }
if (setting.can_add_new_rows || setting.can_add_new_categories) { if (setting.can_add_new_rows || setting.can_add_new_categories) {
html += makeTableInputs(setting); html += makeTableInputs(setting, {}, "");
} }
} }
html += "</table>" html += "</table>"
@ -1111,16 +1115,11 @@ function makeTable(setting, keypath, setting_value, isLocked) {
return html; return html;
} }
function makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns, canRemove, needsReload) { function makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns, canRemove, message) {
var html = var html =
"<tr class='" + Settings.DATA_CATEGORY_CLASS + "' data-key='" + categoryKey + "' data-category='" + categoryValue + "'>" + "<tr class='" + Settings.DATA_CATEGORY_CLASS + "' data-key='" + categoryKey + "' data-category='" + categoryValue + "'>" +
"<td colspan='" + (numVisibleColumns - 1) + "'>" + "<td colspan='" + (numVisibleColumns - 1) + "'>" +
"<span>" + categoryValue + "</span>" + "<span message='" + message + "'>" + categoryValue + "</span>" +
((needsReload) ? (
"<span class='message'> - Reload to see contents.</span>"
) : (
""
)) +
"</td>" + "</td>" +
((canRemove) ? ( ((canRemove) ? (
"<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES + "'>" + "<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES + "'>" +
@ -1133,9 +1132,10 @@ function makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns,
return html; return html;
} }
function makeTableInputs(setting) { function makeTableInputs(setting, initialValues, categoryValue) {
var html = "<tr class='inputs'" + (setting.can_add_new_categories ? " hidden" : "") + var html = "<tr class='inputs'" + (setting.can_add_new_categories && !categoryValue ? " hidden" : "") + " " +
(setting.categorize_by_key ? (" data-keep-field='" + setting.categorize_by_key + "'") : "") + ">"; (categoryValue ? ("data-category='" + categoryValue + "'") : "") + " " +
(setting.categorize_by_key ? ("data-keep-field='" + setting.categorize_by_key + "'") : "") + ">";
if (setting.numbered === true) { if (setting.numbered === true) {
html += "<td class='numbered'></td>"; html += "<td class='numbered'></td>";
@ -1148,15 +1148,21 @@ function makeTableInputs(setting) {
} }
_.each(setting.columns, function(col) { _.each(setting.columns, function(col) {
var defaultValue = _.has(initialValues, col.name) ? initialValues[col.name] : col.default;
if (col.type === "checkbox") { if (col.type === "checkbox") {
html += "<td class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>" html +=
+ "<input type='checkbox' class='form-control table-checkbox' " "<td class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>" +
+ "name='" + col.name + "'" + (col.default ? " checked" : "") + "/></td>"; "<input type='checkbox' class='form-control table-checkbox' " +
"name='" + col.name + "'" + (defaultValue ? " checked" : "") + "/>" +
"</td>";
} else { } else {
html += "<td " + (col.hidden ? "style='display: none;'" : "") + "class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>\ html +=
<input type='text' class='form-control' placeholder='" + (col.placeholder ? col.placeholder : "") + "'\ "<td " + (col.hidden ? "style='display: none;'" : "") + " class='" + Settings.DATA_COL_CLASS + "' " +
value='" + (col.default ? col.default : "") + "' data-default='" + (col.default ? col.default : "") + "'" + (col.readonly ? " readonly" : "") + ">\ "name='" + col.name + "'>" +
</td>" "<input type='text' class='form-control' placeholder='" + (col.placeholder ? col.placeholder : "") + "' " +
"value='" + (defaultValue || "") + "' data-default='" + (defaultValue || "") + "'" +
(col.readonly ? " readonly" : "") + ">" +
"</td>";
} }
}) })
@ -1171,12 +1177,14 @@ function makeTableInputs(setting) {
} }
function makeTableCategoryInput(setting, numVisibleColumns) { function makeTableCategoryInput(setting, numVisibleColumns) {
var needsReload = setting.new_category_needs_reload; var canAddRows = setting.can_add_new_rows;
var categoryKey = setting.categorize_by_key; var categoryKey = setting.categorize_by_key;
var placeholder = setting.new_category_placeholder ? setting.new_category_placeholder : ""; var placeholder = setting.new_category_placeholder || "";
var message = setting.new_category_message || "";
var html = var html =
"<tr class='category-input inputs' data-needs-reload='" + needsReload + "' data-key='" + categoryKey + "'>" + "<tr class='" + Settings.DATA_CATEGORY_CLASS + " inputs' data-can-add-rows='" + canAddRows + "' " +
"<td class='" + Settings.DATA_CATEGORY_CLASS + "' colspan='" + (numVisibleColumns - 1) + "'>" + "data-key='" + categoryKey + "' data-message='" + message + "'>" +
"<td colspan='" + (numVisibleColumns - 1) + "'>" +
"<input type='text' class='form-control' placeholder='" + placeholder + "'/>" + "<input type='text' class='form-control' placeholder='" + placeholder + "'/>" +
"</td>" + "</td>" +
"<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES + "'>" + "<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES + "'>" +
@ -1366,35 +1374,40 @@ function addTableRow(row) {
row.after(input_clone) row.after(input_clone)
} }
function deleteTableRow(row) { function deleteTableRow($row) {
var table = $(row).closest('table') var $table = $row.closest('table');
var isArray = table.data('setting-type') === 'array' var categoryName = $row.data("category");
var isArray = $table.data('setting-type') === 'array';
row.empty(); $row.empty();
if (!isArray) { if (!isArray) {
row.html("<input type='hidden' class='form-control' name='" $row.html("<input type='hidden' class='form-control' name='" + $row.attr('name') + "' data-changed='true' value=''>");
+ row.attr('name') + "' data-changed='true' value=''>");
} else { } else {
if (table.find('.' + Settings.DATA_ROW_CLASS).length > 1) { if ($table.find('.' + Settings.DATA_ROW_CLASS + "[data-category='" + categoryName + "']").length <= 1) {
updateDataChangedForSiblingRows(row) // This is the last row of the category, so delete the header
$table.find('.' + Settings.DATA_CATEGORY_CLASS + "[data-category='" + categoryName + "']").remove();
}
if ($table.find('.' + Settings.DATA_ROW_CLASS).length > 1) {
updateDataChangedForSiblingRows($row);
// this isn't the last row - we can just remove it // this isn't the last row - we can just remove it
row.remove() $row.remove();
} else { } else {
// this is the last row, we can't remove it completely since we need to post an empty array // this is the last row, we can't remove it completely since we need to post an empty array
row $row
.removeClass(Settings.DATA_ROW_CLASS) .removeClass(Settings.DATA_ROW_CLASS)
.removeClass(Settings.NEW_ROW_CLASS) .removeClass(Settings.NEW_ROW_CLASS)
.removeAttr("data-category") .removeAttr("data-category")
.addClass('empty-array-row') .addClass('empty-array-row')
.html("<input type='hidden' class='form-control' name='" + table.attr("name").replace('[]', '') + "' " + .html("<input type='hidden' class='form-control' name='" + $table.attr("name").replace('[]', '') + "' " +
"data-changed='true' value=''>"); "data-changed='true' value=''>");
} }
} }
// we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated // we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated
badgeSidebarForDifferences($(table)) badgeSidebarForDifferences($table);
} }
function addTableCategory($categoryInputRow) { function addTableCategory($categoryInputRow) {
@ -1404,7 +1417,8 @@ function addTableCategory($categoryInputRow) {
console.error("Error cloning inputs"); console.error("Error cloning inputs");
} }
var needsReload = $categoryInputRow.data("needs-reload"); var canAddRows = $categoryInputRow.data("can-add-rows");
var message = $categoryInputRow.data("message");
var categoryKey = $categoryInputRow.data("key"); var categoryKey = $categoryInputRow.data("key");
var categoryValue = $input.prop("value"); var categoryValue = $input.prop("value");
var width = 0; var width = 0;
@ -1426,28 +1440,32 @@ function addTableCategory($categoryInputRow) {
// TODO: create inputs on initial template load // TODO: create inputs on initial template load
var $newCategoryRow = $(makeTableCategoryHeader(categoryKey, categoryValue, width, true, needsReload)); var $newCategoryRow = $(makeTableCategoryHeader(categoryKey, categoryValue, width, true, " - " + message));
$newCategoryRow.addClass(Settings.NEW_ROW_CLASS); $newCategoryRow.addClass(Settings.NEW_ROW_CLASS);
$categoryInputRow $categoryInputRow
.before($newCategoryRow) .before($newCategoryRow)
.before($rowInput); .before($rowInput);
if (!needsReload) { if (canAddRows) {
$rowInput.removeAttr("hidden"); $rowInput.removeAttr("hidden");
} else { } else {
addTableRow($rowInput); addTableRow($rowInput);
} }
} }
function deleteTableCategory(categoryHeaderRow) { function deleteTableCategory($categoryHeaderRow) {
var categoryName = categoryHeaderRow.data("category"); var categoryName = $categoryHeaderRow.data("category");
categoryHeaderRow $categoryHeaderRow
.closest("table") .closest("table")
.find("tr[data-category='" + categoryName + "']") .find("tr[data-category='" + categoryName + "']")
.each(function () { .each(function () {
if ($(this).hasClass(Settings.DATA_ROW_CLASS)) {
deleteTableRow($(this)); deleteTableRow($(this));
} else {
$(this).remove();
}
}); });
} }