Admin improvements

This commit is contained in:
Godwin
2017-07-04 09:41:10 -07:00
parent d4b162426b
commit 9e55d27d33
24 changed files with 895 additions and 526 deletions
+11 -1
View File
@@ -40,7 +40,9 @@
dlg.removeAttribute('aria-hidden');
dlg.setAttribute('role', 'alertdialog');
dlg.setAttribute('tabindex', '0');
dlg.focus();
if (!dlg.getAttribute('data-nofocus')) {
dlg.focus();
}
setTimeout(function() { dlg.classList.add('open'); }, 100);
}
window.closeOverlay = function(dlg, primaryContent, body) {
@@ -114,6 +116,14 @@
return false;
});
});
var helpDlg = document.getElementById('help-dlg');
forEachElement('[data-help-text]', function(link) {
link.addEventListener('click', function(event) {
event.preventDefault();
openDlg(helpDlg, link);
return false;
});
});
var loginDlg = document.getElementById('login-dlg');
forEachElement('[data-sign-in]', function(link) {
link.addEventListener('click', function(event) {
+190 -158
View File
@@ -1,168 +1,200 @@
(function() {
var searchControl = document.getElementById('search');
var searchControl = document.getElementById('search');
function filterTable() {
forEach(document.getElementById('search-table').getElementsByTagName('TBODY')[0].getElementsByTagName('TR'), function(tr) {
if (tr.classList.contains('editable')) {
tr.classList.remove('hidden');
function filterTable() {
forEach(document.getElementById('search-table').getElementsByTagName('TBODY')[0].getElementsByTagName('TR'), function(tr) {
if (tr.classList.contains('editable')) {
tr.classList.remove('hidden');
var value = searchControl.value;
if (value) {
var words = value.split(/\s+/);
for (var i = 0; i < words.length; i++) {
var word = new RegExp(words[i].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), "i");
if (tr.innerHTML.search(word) == -1) {
tr.classList.add('hidden');
}
}
}
}
});
}
var value = searchControl.value;
if (value) {
var words = value.split(/\s+/);
for (var i = 0; i < words.length; i++) {
var word = new RegExp(words[i].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), "i");
if (tr.innerHTML.search(word) == -1) {
tr.classList.add('hidden');
}
}
}
}
});
}
// ref = https://davidwalsh.name/element-matches-selector
function selectorMatches(el, selector) {
var p = Element.prototype;
var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
};
return f.call(el, selector);
}
// ref = https://davidwalsh.name/element-matches-selector
function selectorMatches(el, selector) {
if (el instanceof Element) {
var p = Element.prototype;
var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
};
return f.call(el, selector);
}
return false;
}
function saveRow(row) {
if (row) {
row.classList.remove('editing');
var table = row.parentElement.parentElement;
var editRow = row.nextSibling;
var url = table.getAttribute('data-update-url');
var data = new FormData();
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4) {
row.classList.remove('requesting');
if (request.status == 200 && request.responseText) {
var tempTable = document.createElement('table');
tempTable.innerHTML = request.responseText;
var rows = tempTable.getElementsByTagName('tr');
row.innerHTML = rows[0].innerHTML;
editRow.innerHTML = rows[1].innerHTML;
}
}
}
request.open('POST', url, true);
cells = editRow.getElementsByClassName('cell-editor');
data.append('key', row.getAttribute('data-key'));
data.append('button', 'update');
var changed = false;
for (var i = 0; i < cells.length; i++) {
if (cells[i].value !== cells[i].getAttribute('data-value')) {
data.append(cells[i].getAttribute('name'), cells[i].value);
changed = true;
}
}
if (changed) {
row.classList.add('requesting');
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
request.send(data);
}
}
}
function saveRow(row) {
if (row) {
row.classList.remove('editing');
var table = row.parentElement.parentElement;
var editRow = row.nextSibling;
var url = table.getAttribute('data-update-url');
var data = new FormData();
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4) {
row.classList.remove('requesting');
if (request.status == 200 && request.responseText) {
var tempTable = document.createElement('table');
tempTable.innerHTML = request.responseText;
var rows = tempTable.getElementsByTagName('tr');
row.innerHTML = rows[0].innerHTML;
editRow.innerHTML = rows[1].innerHTML;
}
}
}
request.open('POST', url, true);
cells = editRow.getElementsByClassName('cell-editor');
data.append('key', row.getAttribute('data-key'));
data.append('button', 'update');
var changed = false;
for (var i = 0; i < cells.length; i++) {
if (cells[i].value !== cells[i].getAttribute('data-value')) {
data.append(cells[i].getAttribute('name'), cells[i].value);
changed = true;
}
}
if (changed) {
row.classList.add('requesting');
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
request.send(data);
}
}
}
function editTableCell(cell) {
if (cell && selectorMatches(cell, 'tr[data-key].editable td')) {
editTableRow(cell.parentElement, cell);
} else if (!cell || !selectorMatches(cell, 'tr[data-key].editable + tr, tr[data-key].editable + tr *')) {
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow) {
saveRow(currentRow);
}
}
}
function editTableRow(row, cell) {
if (selectorMatches(row, 'tr[data-key].editable')) {
var key = row.getAttribute('data-key');
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow && currentRow.getAttribute('data-key') !== key) {
saveRow(currentRow);
}
var editor = row.nextSibling;
if (!row.classList.contains('editing')) {
row.classList.add('editing');
var focusElement = null;
if (cell) {
focusElement = editor.querySelector('td[data-column-id="' + cell.getAttribute('data-column-id') + '"] .cell-editor');
}
focusElement = focusElement || editor.getElementsByClassName('cell-editor')[0];
focusElement.focus();
if (focusElement.tagName === 'TEXTAREA' || (focusElement.tagName === 'INPUT' && focusElement.type != 'number' && focusElement.type != 'email')) {
focusElement.setSelectionRange(0, focusElement.value.length);
}
}
}
}
document.addEventListener('click', function (event) { editTableCell(event.target); });
document.addEventListener('keyup', function (event) {
if (event.code === "Enter") {
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow) {
event.stopPropagation();
event.preventDefault();
var next = event.shiftKey ? 'previousSibling' : 'nextSibling';
var cell = document.activeElement.parentElement.getAttribute('data-column-id');
var row = currentRow[next] ? currentRow[next][next] : null;
if (!row) {
rows = currentRow.parentElement.children;
row = event.shiftKey ? rows[rows.length - 2] : rows[0];
}
editTableRow(row, row.querySelector('[data-column-id="' + cell + '"]'));
}
} else if (event.code === "Escape") {
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow) {
event.stopPropagation();
event.preventDefault();
saveRow(currentRow);
}
}
});
if (document.observe) {
document.observe("focusin", function (event) { editTableCell(event.target); });
} else {
document.addEventListener("focus", function (event) { editTableCell(event.target); }, true);
}
function sortBy(table, column, dir) {
if (!dir) {
dir = 'down';
} else if (dir == 'down') {
dir = 'up';
} else {
dir = 'down';
}
window.onbeforeunload = function() {
editTableCell();
};
var url = table.getAttribute('data-sort-url') + '?sort_column=' + column + '&sort_dir=' + dir;
var tableContainer = table.parentElement;
searchControl.addEventListener('keyup', filterTable);
searchControl.addEventListener('search', filterTable);
tableContainer.classList.add('requesting');
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4) {
tableContainer.classList.remove('requesting');
if (request.status == 200 && request.responseText) {
tableContainer.innerHTML = request.responseText;
}
}
}
request.open('GET', url, true);
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
request.send();
}
forEachElement('[data-expands]', function(button) {
button.addEventListener('click', function(event) {
var element = document.getElementById(event.target.getAttribute('data-expands'));
document.body.classList.add('expanded-element');
element.classList.add('expanded');
});
});
forEachElement('[data-contracts]', function(button) {
button.addEventListener('click', function(event) {
var element = document.getElementById(event.target.getAttribute('data-contracts'));
document.body.classList.remove('expanded-element');
element.classList.remove('expanded');
});
});
forEachElement('[data-opens-modal]', function(button) {
button.addEventListener('click', function(event) {
var element = document.getElementById(event.target.getAttribute('data-opens-modal'));
document.body.classList.add('modal-open');
element.classList.add('open');
});
});
forEachElement('[data-closes-modal]', function(element) {
element.addEventListener('click', function(event) {
document.getElementById(event.target.getAttribute('data-closes-modal')).classList.remove('open');
document.body.classList.remove('modal-open');
});
});
function editTableCell(cell) {
if (cell && selectorMatches(cell, 'tr[data-key].editable td')) {
editTableRow(cell.parentElement, cell);
} else if (cell && selectorMatches(cell, 'th[data-colname]')) {
sortBy(cell.parentElement.parentElement.parentElement, cell.getAttribute('data-colname'), cell.getAttribute('data-dir'));
} else if (!cell || !selectorMatches(cell, 'tr[data-key].editable + tr, tr[data-key].editable + tr *')) {
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow) {
saveRow(currentRow);
}
}
}
function editTableRow(row, cell) {
if (selectorMatches(row, 'tr[data-key].editable')) {
var key = row.getAttribute('data-key');
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow && currentRow.getAttribute('data-key') !== key) {
saveRow(currentRow);
}
var editor = row.nextSibling;
if (!row.classList.contains('editing')) {
row.classList.add('editing');
var focusElement = null;
if (cell) {
focusElement = editor.querySelector('td[data-column-id="' + cell.getAttribute('data-column-id') + '"] .cell-editor');
}
focusElement = focusElement || editor.getElementsByClassName('cell-editor')[0];
focusElement.focus();
if (focusElement.tagName === 'TEXTAREA' || (focusElement.tagName === 'INPUT' && focusElement.type != 'number' && focusElement.type != 'email')) {
focusElement.setSelectionRange(0, focusElement.value.length);
}
}
}
}
document.addEventListener('click', function (event) { editTableCell(event.target); });
document.addEventListener('keyup', function (event) {
if (event.code === "Enter") {
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow) {
event.stopPropagation();
event.preventDefault();
var next = event.shiftKey ? 'previousSibling' : 'nextSibling';
var cell = document.activeElement.parentElement.getAttribute('data-column-id');
var row = currentRow[next] ? currentRow[next][next] : null;
if (!row) {
rows = currentRow.parentElement.children;
row = event.shiftKey ? rows[rows.length - 2] : rows[0];
}
editTableRow(row, row.querySelector('[data-column-id="' + cell + '"]'));
}
} else if (event.code === "Escape") {
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow) {
event.stopPropagation();
event.preventDefault();
saveRow(currentRow);
}
}
});
if (document.observe) {
document.observe("focusin", function (event) { editTableCell(event.target); });
} else {
document.addEventListener("focus", function (event) { editTableCell(event.target); }, true);
}
window.onbeforeunload = function() {
editTableCell();
};
searchControl.addEventListener('keyup', filterTable);
searchControl.addEventListener('search', filterTable);
forEachElement('[data-expands]', function(button) {
button.addEventListener('click', function(event) {
var element = document.getElementById(event.target.getAttribute('data-expands'));
document.body.classList.add('expanded-element');
element.classList.add('expanded');
});
});
forEachElement('[data-contracts]', function(button) {
button.addEventListener('click', function(event) {
var element = document.getElementById(event.target.getAttribute('data-contracts'));
document.body.classList.remove('expanded-element');
element.classList.remove('expanded');
});
});
forEachElement('[data-opens-modal]', function(button) {
button.addEventListener('click', function(event) {
var element = document.getElementById(event.target.getAttribute('data-opens-modal'));
document.body.classList.add('modal-open');
element.classList.add('open');
});
});
forEachElement('[data-closes-modal]', function(element) {
element.addEventListener('click', function(event) {
document.getElementById(event.target.getAttribute('data-closes-modal')).classList.remove('open');
document.body.classList.remove('modal-open');
});
});
})();
+214 -75
View File
@@ -29,6 +29,61 @@ nav.sub-nav {
}
table, .table {
tr.spacer td {
border: 0;
height: 0.5em;
}
&[data-sort-url] {
[data-colname] {
position: relative;
cursor: pointer;
white-space: nowrap;
@include after {
content: '';
position: absolute;
bottom: -1em;
left: 50%;
font-size: 1.5em;
opacity: 0;
z-index: 2;
margin-left: -0.25em;
pointer-events: none;
@include _(transition, opacity 150ms ease-in-out);
}
&:hover {
@include after {
opacity: 1;
}
}
}
[data-dir] {
@include after {
opacity: 0.5;
}
&:hover {
@include after {
content: '';
}
}
}
[data-dir="up"] {
@include after {
content: '';
}
&:hover {
@include after {
content: '';
}
}
}
}
th, td, .table-th, .table-td {
&.center {
text-align: center;
@@ -51,45 +106,50 @@ table, .table {
width: 1.75em;
&.happy {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 87.8 73.2'><polygon fill='#{$colour-5}' points='34.3 73.2 0 32.6 18.7 16.8 35.4 36.5 70.1 0 87.8 16.8 '/></svg>");
@include after {
content: '\1F601';
opacity: 0.5;
}
}
&.unhappy {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path xmlns="http://www.w3.org/2000/svg" d="M50 5C25.1 5 5 25.1 5 50c0 24.9 20.1 45 45 45s45-20.1 45-45C95 25.1 74.9 5 50 5zM72.5 64.3l-8.2 8.2L50 58.2 35.7 72.5l-8.2-8.2L41.8 50 27.5 35.7l8.2-8.2L50 41.8l14.3-14.3 8.2 8.2L58.2 50 72.5 64.3z" fill="#{$colour-4}"/></svg>');
@include after {
content: '\1F621';
}
}
}
}
td, .table-td {
&.inner-table {
padding: 0;
padding: 0.5em;
table {
margin: 0;
width: 100%;
}
tr:first-child {
td, th {
border-top: 0;
}
}
// tr:first-child {
// td, th {
// border-top: 0;
// }
// }
tr:last-child {
td, th {
border-bottom: 0;
}
}
// tr:last-child {
// td, th {
// border-bottom: 0;
// }
// }
td, th {
&:first-child {
border-left: 0
}
// td, th {
// &:first-child {
// border-left: 0
// }
&:last-child {
border-right: 0
}
}
// &:last-child {
// border-right: 0
// }
// }
}
&.bold {
@@ -359,6 +419,7 @@ body.expanded-element {
z-index: 1002;
background-color: #F8F8F8;
flex: 1;
padding-bottom: 1em;
}
.actions {
@@ -636,6 +697,12 @@ nav.sub-menu {
}
}
#registrations-table {
.button {
margin-top: 0;
}
}
#main article #registration-admin-menu {
margin: 1em 0 0;
padding: 0;
@@ -745,6 +812,15 @@ nav.sub-menu {
}
}
@include keyframes(unhappy) {
from {
@include _(transform, rotate(15deg));
}
to {
@include _(transform, rotate(-15deg));
}
}
#admin-housing, #admin-schedule {
.guests-housed {
margin-bottom: 1em;
@@ -759,12 +835,33 @@ nav.sub-menu {
.data {
display: inline-block;
font-size: 1.125em;
@include after {
margin-left: 0.5em;
font-size: 1.5em;
}
&.happy {
@include after {
content: '\1F60D';
}
}
&.unhappy {
@include after {
content: '\1F61E';
}
}
}
}
#housing-table {
@include _(transition, opacity 1s ease-in-out);
table {
margin-left: 0;
}
&.loading {
@include _(opacity, 0.5);
pointer-events: none;
@@ -780,6 +877,10 @@ nav.sub-menu {
text-align: right;
@include font-family(primary);
}
.name {
min-width: 10em;
}
}
}
@@ -788,28 +889,17 @@ nav.sub-menu {
td {
background-color: lighten($colour-1, 40%);
&:hover {
background-color: $colour-1;
}
&.full {
background-color: $gray;
&:hover {
background-color: #CCC;
}
.button {
background-color: #888;
}
}
}
a {
display: block;
color: $white;
text-align: center;
@include font-family(secondary);
@include after {
display: none;
}
.button {
display: inline-block;
}
}
@@ -819,15 +909,31 @@ nav.sub-menu {
}
td {
vertical-align: top;
vertical-align: middle;
}
.state {
position: relative;
font-family: inherit;
padding: 0;
position: relative;
width: 2em;
height: 2em;
@include after {
position: absolute;
bottom: 0;
left: 0;
font-size: 1.5em;
}
&.unhappy {
cursor: pointer;
@include after {
@include _(transform-origin, bottom);
@include _(animation, unhappy ease-in-out 1s infinite alternate both);
}
}
ul {
@@ -837,7 +943,7 @@ nav.sub-menu {
top: 0;
background-color: $white;
border: 0.1em solid #CCC;
padding: 0.25em 0.75em 0.25em 1.5em;
padding: 0.25em 0.75em;
margin: 0;
list-style-type: square;
@include default-box-shadow(top, 2);
@@ -846,7 +952,12 @@ nav.sub-menu {
li {
white-space: nowrap;
margin: 0;
margin: 0 0 0 1em;
&:first-child:last-child {
list-style: none;
margin: 0;
}
}
&:hover {
@@ -893,25 +1004,71 @@ nav.sub-menu {
background-color: $white;
width: 80%;
margin: auto;
padding: 1em;
height: 80%;
cursor: default;
@include default-box-shadow(top, 2);
h3 {
text-align: center;
margin: 0 0 1em;
padding: 0.5em 0.6667em;
color: $white;
background-color: $green;
@include _(text-stroke, 1px rgba(0, 0, 0, 0.25));
}
}
}
}
.table-scroller.no-edit {
box-shadow: none;
background-color: transparent;
table {
margin-bottom: 0;
}
}
#table, #help-dlg {
.legend ul {
@include _-(display, flex);
list-style: none;
padding: 0;
li {
@include _(flex, 1);
text-align: center;
margin-bottom: 0.5em;
padding: 0.125em 0.5em;
margin: 0.1em;
border: 0.1em solid $light-gray;
background-color: #F8F8F8;
@include font-family(secondary);
&.other-host, &.other-space, &.bad-match {
opacity: 0.5;
}
&.selected-space, &.other-space {
background-color: $colour-5;
}
&.other-host {
background-color: $colour-1;
}
}
}
}
#table {
display: flex;
flex-direction: column;
position: relative;
overflow: auto;
height: 80%;
height: calc(100% - 4em);
height: calc(100% - 6.5em);
background-color: $white;
margin: 1em;
@include _(transition, background-color 250ms ease-in-out);
&.loading {
@@ -924,7 +1081,7 @@ nav.sub-menu {
}
table {
margin: 0 0 2em;
margin: 0 0 1em;
}
h4 {
@@ -992,45 +1149,27 @@ nav.sub-menu {
}
}
.legend ul {
@include _-(display, flex);
list-style: none;
padding: 0;
li {
@include _(flex, 1);
text-align: center;
margin-bottom: 0.5em;
padding: 0.125em 0.5em;
margin: 0.1em;
border: 0.1em solid $light-gray;
background-color: #F8F8F8;
@include font-family(secondary);
&.other-host, &.other-space, &.bad-match {
opacity: 0.5;
}
&.selected-space, &.other-space {
background-color: $colour-5;
}
&.other-host {
background-color: $colour-1;
}
}
}
.p {
max-height: 4em;
overflow: auto;
}
.guest-table {
flex: 1;
display: flex;
}
td, th {
white-space: nowrap;
&.break-ok {
white-space: normal;
min-width: 10em;
}
}
}
#admin-housing {
#table table {
min-width: 100em;
}
#hosts {
background-color: $white;
+58 -53
View File
@@ -141,21 +141,6 @@ table, .table {
background-color: transparent;
border: 0;
}
&.state {
background-size: 1.333em;
background-repeat: no-repeat;
background-position: center;
width: 1.75em;
&.happy {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 87.8 73.2'><polygon fill='#{$colour-5}' points='34.3 73.2 0 32.6 18.7 16.8 35.4 36.5 70.1 0 87.8 16.8 '/></svg>");
}
&.unhappy {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path xmlns="http://www.w3.org/2000/svg" d="M50 5C25.1 5 5 25.1 5 50c0 24.9 20.1 45 45 45s45-20.1 45-45C95 25.1 74.9 5 50 5zM72.5 64.3l-8.2 8.2L50 58.2 35.7 72.5l-8.2-8.2L41.8 50 27.5 35.7l8.2-8.2L50 41.8l14.3-14.3 8.2 8.2L58.2 50 72.5 64.3z" fill="#{$colour-4}"/></svg>');
}
}
}
th, .table-th {
@@ -167,42 +152,42 @@ table, .table {
}
}
td, .table-td {
&.inner-table {
padding: 0;
// td, .table-td {
// &.inner-table {
// padding: 0;
table {
margin: 0;
width: 100%;
}
// table {
// margin: 0;
// width: 100%;
// }
tr:first-child {
td, th {
border-top: 0;
}
}
// tr:first-child {
// td, th {
// border-top: 0;
// }
// }
tr:last-child {
td, th {
border-bottom: 0;
}
}
// tr:last-child {
// td, th {
// border-bottom: 0;
// }
// }
td, th {
&:first-child {
border-left: 0
}
// td, th {
// &:first-child {
// border-left: 0
// }
&:last-child {
border-right: 0
}
}
}
// &:last-child {
// border-right: 0
// }
// }
// }
&.bold {
@include font-family(secondary);
}
}
// &.bold {
// @include font-family(secondary);
// }
// }
tbody th {
width: 0.1rem;
@@ -2449,13 +2434,14 @@ a.logo {
.register-link {
font-size: 1.25em;
margin: 0.5em;
.button {
@include _(animation, radiate 2s linear infinite alternate);
}
}
}
.help-link {
float: right;
background-color: $red;
}
.conference-details {
.links {
text-align: center;
@@ -2906,6 +2892,29 @@ body {
text-align: left;
}
#help-dlg {
.dlg-content {
@include _-(display, flex);
@include _(flex-direction, column);
max-width: 60rem;
}
.dlg-inner {
overflow: auto;
}
.title {
background-color: $red;
font-size: 2em;
text-align: left;
}
.message {
text-align: left;
font-size: 1.125em;
}
}
#info-dlg .message {
text-align: left;
@@ -2956,10 +2965,6 @@ body {
to { background-position: 60px 30px; }
}
@include keyframes(radiate) {
to { background-color: $green; }
}
html :focus {
outline: 0;
}
@@ -10,7 +10,7 @@
"and_chr": ["59"],
"chrome": ["59"],
"edge": ["13"],
"firefox": ["50"],
"firefox": ["52"],
"ie": ["11"],
"ios_saf": ["8", "9"]
}