/* Lame trick...I increment the filename when I release a new version of this file, because on runserver, Chrome caches it, so all oTree users developing on Chrome would need to Ctrl+F5. */ function populateTableBody(tbody, rows) { for (let i = 0; i < rows.length; i++) { tbody.appendChild(createTableRow(rows[i], i)); } } let groupIsFiltered = false; function filterGroup(rowIdx) { if (groupIsFiltered) { for (let table of tables) { let tbody = table.querySelector('tbody'); let trs = tbody.querySelectorAll('tr'); for (let tr of trs) { tr.style.display = ''; } } for (let th of document.getElementsByClassName(`id-in-session`)) { th.style.backgroundColor = 'white'; } groupIsFiltered = false; } else { for (let tid = 0; tid < tables.length; tid++) { let table = tables[tid]; let data = old_json[tid]; let tbody = table.querySelector('tbody'); let trs = tbody.querySelectorAll('tr'); let curGroup = data[rowIdx][0]; let rowsInSameGroup = []; for (let i = 0; i < data.length; i++) { if (data[i][0] === curGroup) rowsInSameGroup.push(i); } for (let i = 0; i < trs.length; i++) { if (!rowsInSameGroup.includes(i)) { trs[i].style.display = 'none'; } } } for (let th of document.getElementsByClassName(`row-idx-${rowIdx}`)) th.style.backgroundColor = 'yellow'; groupIsFiltered = true; } } function createTableRow(row, row_number) { let tr = document.createElement('tr'); tr.innerHTML = `P${row_number + 1}`; for (let i = 0; i < row.length; i++) { let value = row[i]; let td = document.createElement('td'); if (i === 0) { td.innerHTML = `${value}`; } else { td.innerHTML = makeCellDisplayValue(value); } tr.appendChild(td) } return tr; } function createTableRowMonitor(row) { let tr = document.createElement('tr'); for (let [field, value] of Object.entries(row)) { let td = document.createElement('td'); td.dataset.field = field; td.dataset.value = makeCellDatasetValue(value); td.innerHTML = makeCellDisplayValue(value, field); tr.appendChild(td) } return tr; } function truncateStringEllipsis(str, num) { if (str.length > num) { return str.slice(0, num) + "…"; } else { return str; } } function makeCellDatasetValue(value) { if (value === null) return ''; return value.toString(); } function makeCellDisplayValue(value, fieldName) { if (value === null) { return ''; } if (fieldName === '_last_page_timestamp') { let date = new Date(parseFloat(value) * 1000); let dateString = date.toISOString(); return ``; } return value.toString(); } function updateDraggable($table) { $table.toggleClass( 'draggable', ($table.get(0).scrollWidth > $table.parent().width()) || ($table.find('tbody').height() >= 450)); } function flashGreen($ele) { $ele.css('background-color', 'green'); $ele.animate({ backgroundColor: "white" }, 10000 ); } function updateDataTable($table, new_json, old_json, field_headers) { let changeDescriptions = []; let $tbody = $table.find('tbody'); // build table for the first time let numRows = new_json[0].length; for (let i = 0; i < new_json.length; i++) { let rowChanges = []; for (let j = 0; j < numRows; j++) { if (new_json[i][j] !== old_json[i][j]) { let rawValue = new_json[i][j]; let $cell = $tbody.find(`tr:eq(${i})`).find(`td:eq(${j})`); let new_value = makeCellDisplayValue(rawValue); $cell.text(new_value); flashGreen($cell); let fieldName = field_headers[j]; let newValueTrunc = truncateStringEllipsis(new_value, 7); rowChanges.push(`${fieldName}=${newValueTrunc}`); } } if (rowChanges.length > 0) { // @ makes it easier to scan visually changeDescriptions.push(`@P${i + 1}: ${rowChanges.join(', ')}`) } } return changeDescriptions; } function makeTableDraggable($table) { var mouseX, mouseY; $table.mousedown(function (e) { e.preventDefault(); $table.addClass('grabbing'); mouseX = e.pageX; mouseY = e.pageY; }).on('scroll', function () { $table.find('> thead, > tbody').width($table.width() + $table.scrollLeft()); }); $(document) .mousemove(function (e) { if (!$table.hasClass('grabbing')) { return; } e.preventDefault(); $table.scrollLeft($table.scrollLeft() - (e.pageX - mouseX)); var $tableBody = $table.find('tbody'); $tableBody.scrollTop($tableBody.scrollTop() - (e.pageY - mouseY)); mouseX = e.pageX; mouseY = e.pageY; }).mouseup(function (e) { if (!$table.hasClass('grabbing')) { return; } e.preventDefault(); $table.removeClass('grabbing'); }); }