From 278c2c2a8237647e75fbe2706019b5b1b543b3e4 Mon Sep 17 00:00:00 2001 From: Felix Hamann Date: Wed, 20 Feb 2019 22:06:30 +0100 Subject: [PATCH 1/5] initial work on check-all-checkbox --- src/Foundation.hs | 1 + static/js/utils/asyncTable.js | 2 +- static/js/utils/checkAll.js | 70 +++++++++++++++++++++++++++++++++++ templates/table/layout.julius | 3 +- 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 static/js/utils/checkAll.js diff --git a/src/Foundation.hs b/src/Foundation.hs index 84766c47e..98bdd1c5a 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -1020,6 +1020,7 @@ siteLayout' headingOverride widget = do addScript $ StaticR js_utils_alerts_js addScript $ StaticR js_utils_asidenav_js addScript $ StaticR js_utils_asyncTable_js + addScript $ StaticR js_utils_checkAll_js addScript $ StaticR js_utils_form_js addScript $ StaticR js_utils_inputs_js addScript $ StaticR js_utils_setup_js diff --git a/static/js/utils/asyncTable.js b/static/js/utils/asyncTable.js index fe164d3b2..d11f6298e 100644 --- a/static/js/utils/asyncTable.js +++ b/static/js/utils/asyncTable.js @@ -18,7 +18,7 @@ var scrollTable; function init() { - var table = wrapper.querySelector('#' + tableIdent); + var table = wrapper.querySelector('#' + tableIdent); if (!table) { return; diff --git a/static/js/utils/checkAll.js b/static/js/utils/checkAll.js new file mode 100644 index 000000000..6b8d51e48 --- /dev/null +++ b/static/js/utils/checkAll.js @@ -0,0 +1,70 @@ +(function collonadeClosure() { + 'use strict'; + + window.utils = window.utils || {}; + + var JS_INITIALIZED_CLASS = 'js-initialized'; + var CHECKBOX_SELECTOR = '.checkbox'; + + window.utils.checkAll = function(wrapper, options) { + + if (!wrapper || wrapper.classList.contains(JS_INITIALIZED_CLASS)) { + return false; + } + options = options || {}; + + var columns = []; + + function init() { + + columns = gatherColumns(wrapper); + + var checkboxColumn = findCheckboxColumn(columns); + if (checkboxColumn) { + setup(checkboxColumn); + } + } + + function gatherColumns(table) { + var rows = Array.from(table.querySelectorAll('tr')); + var cols = []; + rows.forEach(function(tr) { + var cells = Array.from(tr.querySelectorAll('td')); + cells.forEach(function(cell, iCell) { + if (!cols[iCell]) { + cols[iCell] = []; + } + cols[iCell].push(cell); + }); + }); + return cols; + } + + function findCheckboxColumn(cols) { + var checkboxColumn = null; + cols.forEach(function(col, i) { + if (isCheckboxColumn(col)) { + checkboxColumn = i; + } + }); + return checkboxColumn; + } + + function isCheckboxColumn(col) { + var onlyCheckboxes = true; + col.forEach(function(cell) { + console.log('checking', cell); + if (onlyCheckboxes && !cell.querySelector(CHECKBOX_SELECTOR)) { + onlyCheckboxes = false; + } + }); + return onlyCheckboxes; + } + + function setup(column) { + console.log('setting up column', column); + } + + init(); + }; +})(); diff --git a/templates/table/layout.julius b/templates/table/layout.julius index 3bc39312d..d0f02a7d0 100644 --- a/templates/table/layout.julius +++ b/templates/table/layout.julius @@ -1,10 +1,11 @@ document.addEventListener('DOMContentLoaded', function() { var dbtIdent = #{String $ dbtIdent}; var headerDBTableShortcircuit = #{String (toPathPiece HeaderDBTableShortcircuit)}; - var selector = '#' + dbtIdent + '-table-wrapper:not(.js-initialized)'; + var selector = '#' + dbtIdent + '-table-wrapper'; var wrapper = document.querySelector(selector); if (wrapper) { window.utils.setup('asyncTable', wrapper, { headerDBTableShortcircuit, dbtIdent }); + window.utils.setup('checkAll', wrapper); } }); From d83fe11f4282c9cf8f33b652be02385c5600428c Mon Sep 17 00:00:00 2001 From: Felix Hamann Date: Wed, 20 Feb 2019 23:08:19 +0100 Subject: [PATCH 2/5] replace th of checkbox column with check-all-checkbox --- static/js/utils/checkAll.js | 69 ++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/static/js/utils/checkAll.js b/static/js/utils/checkAll.js index 6b8d51e48..f918e7d49 100644 --- a/static/js/utils/checkAll.js +++ b/static/js/utils/checkAll.js @@ -3,8 +3,12 @@ window.utils = window.utils || {}; - var JS_INITIALIZED_CLASS = 'js-initialized'; - var CHECKBOX_SELECTOR = '.checkbox'; + var JS_INITIALIZED_CLASS = 'js-check-all-initialized'; + var CHECKBOX_SELECTOR = '[type="checkbox"]'; + + function getCheckboxId() { + return 'check-all-checkbox-' + Math.floor(Math.random() * 100000); + } window.utils.checkAll = function(wrapper, options) { @@ -14,15 +18,21 @@ options = options || {}; var columns = []; + var checkboxColumn = []; + var checkAllCheckbox = null; + var lastInputWasCheckAllCheckbox = false; function init() { columns = gatherColumns(wrapper); - var checkboxColumn = findCheckboxColumn(columns); - if (checkboxColumn) { - setup(checkboxColumn); + var checkboxColumnId = findCheckboxColumn(columns); + if (checkboxColumn !== null) { + checkboxColumn = columns[checkboxColumnId]; + setupCheckAllCheckbox(checkboxColumnId); } + + wrapper.classList.add(JS_INITIALIZED_CLASS); } function gatherColumns(table) { @@ -53,7 +63,6 @@ function isCheckboxColumn(col) { var onlyCheckboxes = true; col.forEach(function(cell) { - console.log('checking', cell); if (onlyCheckboxes && !cell.querySelector(CHECKBOX_SELECTOR)) { onlyCheckboxes = false; } @@ -61,8 +70,52 @@ return onlyCheckboxes; } - function setup(column) { - console.log('setting up column', column); + function setupCheckAllCheckbox(columnId) { + var firstRow = wrapper.querySelector('tr'); + var th = Array.from(firstRow.querySelectorAll('th, td'))[columnId]; + th.innerHTML = 'test'; + checkAllCheckbox = document.createElement('input'); + checkAllCheckbox.setAttribute('type', 'checkbox'); + checkAllCheckbox.setAttribute('id', getCheckboxId()); + th.innerHTML = ''; + th.insertBefore(checkAllCheckbox, null); + window.utils.setup('checkboxRadio', checkAllCheckbox); + + // attach event listener to new checkbox + checkAllCheckbox.addEventListener('input', function(event) { + lastInputWasCheckAllCheckbox = true; + toggleAll(checkAllCheckbox.checked); + }); + + // attach event listeners to each checkbox in column + columns[columnId] + .reduce(function(acc, cell) { + acc.push(cell.querySelector(CHECKBOX_SELECTOR)); + return acc; + }, []) + .forEach(function(checkbox) { + checkbox.addEventListener('input', function(event) { + lastInputWasCheckAllCheckbox = false; + updateCheckboxState(); + }); + }); + } + + function updateCheckboxState() { + checkAllCheckbox.checked = checkboxColumn.reduce(function(acc, cell) { + return acc && cell.querySelector(CHECKBOX_SELECTOR).checked; + }, true); + } + + function toggleAll() { + // remember current state and maybe apply it later if no other checkbox got clicked inbetween + checkboxColumn.forEach(function(cell) { + cell.querySelector(CHECKBOX_SELECTOR).checked = checkAllCheckbox.checked; + }); + + if (lastInputWasCheckAllCheckbox) { + // restore previous state + } } init(); From 2ccff81cc81c5373c936cf164a86423ef99149af Mon Sep 17 00:00:00 2001 From: SJost Date: Thu, 21 Feb 2019 09:32:17 +0100 Subject: [PATCH 3/5] Touching this branch to fix build --- static/js/utils/checkAll.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/utils/checkAll.js b/static/js/utils/checkAll.js index f918e7d49..21d96fc4d 100644 --- a/static/js/utils/checkAll.js +++ b/static/js/utils/checkAll.js @@ -4,7 +4,7 @@ window.utils = window.utils || {}; var JS_INITIALIZED_CLASS = 'js-check-all-initialized'; - var CHECKBOX_SELECTOR = '[type="checkbox"]'; + var CHECKBOX_SELECTOR = '[type="checkbox"]'; function getCheckboxId() { return 'check-all-checkbox-' + Math.floor(Math.random() * 100000); From 4fd23e94971418d1cc048fcb22bb5d0d420cca2f Mon Sep 17 00:00:00 2001 From: Felix Hamann Date: Thu, 21 Feb 2019 18:46:16 +0100 Subject: [PATCH 4/5] fix check-all-checkbox column id --- static/js/utils/checkAll.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/utils/checkAll.js b/static/js/utils/checkAll.js index 21d96fc4d..6e2048ce8 100644 --- a/static/js/utils/checkAll.js +++ b/static/js/utils/checkAll.js @@ -27,7 +27,7 @@ columns = gatherColumns(wrapper); var checkboxColumnId = findCheckboxColumn(columns); - if (checkboxColumn !== null) { + if (checkboxColumnId !== null) { checkboxColumn = columns[checkboxColumnId]; setupCheckAllCheckbox(checkboxColumnId); } From 05733ec85ba963c2561fa4c627281ffc5adaf041 Mon Sep 17 00:00:00 2001 From: Felix Hamann Date: Fri, 22 Feb 2019 21:58:21 +0100 Subject: [PATCH 5/5] check-all-checkbox: remove caching idea --- static/js/utils/checkAll.js | 74 +++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/static/js/utils/checkAll.js b/static/js/utils/checkAll.js index 6e2048ce8..5decca2de 100644 --- a/static/js/utils/checkAll.js +++ b/static/js/utils/checkAll.js @@ -1,4 +1,4 @@ -(function collonadeClosure() { +(function() { 'use strict'; window.utils = window.utils || {}; @@ -20,17 +20,12 @@ var columns = []; var checkboxColumn = []; var checkAllCheckbox = null; - var lastInputWasCheckAllCheckbox = false; function init() { columns = gatherColumns(wrapper); - var checkboxColumnId = findCheckboxColumn(columns); - if (checkboxColumnId !== null) { - checkboxColumn = columns[checkboxColumnId]; - setupCheckAllCheckbox(checkboxColumnId); - } + setupCheckAllCheckbox(findCheckboxColumn(columns)); wrapper.classList.add(JS_INITIALIZED_CLASS); } @@ -40,24 +35,24 @@ var cols = []; rows.forEach(function(tr) { var cells = Array.from(tr.querySelectorAll('td')); - cells.forEach(function(cell, iCell) { - if (!cols[iCell]) { - cols[iCell] = []; + cells.forEach(function(cell, cellIndex) { + if (!cols[cellIndex]) { + cols[cellIndex] = []; } - cols[iCell].push(cell); + cols[cellIndex].push(cell); }); }); return cols; } - function findCheckboxColumn(cols) { - var checkboxColumn = null; - cols.forEach(function(col, i) { + function findCheckboxColumn(columns) { + var checkboxColumnId = null; + columns.forEach(function(col, i) { if (isCheckboxColumn(col)) { - checkboxColumn = i; + checkboxColumnId = i; } }); - return checkboxColumn; + return checkboxColumnId; } function isCheckboxColumn(col) { @@ -71,6 +66,11 @@ } function setupCheckAllCheckbox(columnId) { + if (columnId === null) { + return; + } + + checkboxColumn = columns[columnId]; var firstRow = wrapper.querySelector('tr'); var th = Array.from(firstRow.querySelectorAll('th, td'))[columnId]; th.innerHTML = 'test'; @@ -81,41 +81,35 @@ th.insertBefore(checkAllCheckbox, null); window.utils.setup('checkboxRadio', checkAllCheckbox); - // attach event listener to new checkbox - checkAllCheckbox.addEventListener('input', function(event) { - lastInputWasCheckAllCheckbox = true; - toggleAll(checkAllCheckbox.checked); - }); + checkAllCheckbox.addEventListener('input', onCheckAllCheckboxInput); + setupCheckboxListeners(); + } - // attach event listeners to each checkbox in column - columns[columnId] - .reduce(function(acc, cell) { - acc.push(cell.querySelector(CHECKBOX_SELECTOR)); - return acc; - }, []) + function onCheckAllCheckboxInput() { + toggleAll(checkAllCheckbox.checked); + } + + function setupCheckboxListeners() { + checkboxColumn + .map(function(cell) { + return cell.querySelector(CHECKBOX_SELECTOR); + }) .forEach(function(checkbox) { - checkbox.addEventListener('input', function(event) { - lastInputWasCheckAllCheckbox = false; - updateCheckboxState(); - }); + checkbox.addEventListener('input', updateCheckAllCheckboxState); }); } - function updateCheckboxState() { - checkAllCheckbox.checked = checkboxColumn.reduce(function(acc, cell) { + function updateCheckAllCheckboxState() { + var allChecked = checkboxColumn.reduce(function(acc, cell) { return acc && cell.querySelector(CHECKBOX_SELECTOR).checked; }, true); + checkAllCheckbox.checked = allChecked; } - function toggleAll() { - // remember current state and maybe apply it later if no other checkbox got clicked inbetween + function toggleAll(checked) { checkboxColumn.forEach(function(cell) { - cell.querySelector(CHECKBOX_SELECTOR).checked = checkAllCheckbox.checked; + cell.querySelector(CHECKBOX_SELECTOR).checked = checked; }); - - if (lastInputWasCheckAllCheckbox) { - // restore previous state - } } init();