var NewMTable = (function(){ 'use strict'; var tmpl = new Tmpl; return function(t, o, scb){ return new MTable(t, o, scb); }; function MTable(t, obj, selectCB){ let rowSelect = obj.rowSelect !== false, events = new EventManager, tableObj = new TableObj(obj, rowSelect), tableTemplate = tmpl.index, pagination = null, rowsArray = [], masterSelect = null, activeSort = null, tableReference = null, rowsReference = null, table = null, maxPerPage = null, currentPage = 1, checkboxList = [], searchActive = false, searchKey = '', searchValue = '', onPageChange = obj.onPageChange || function() {}; this.getTableReference = getTableReference; this.getSelectedRows = getSelectedRows; this.getAllRows = getAllRows; this.setTable = setTable; this.sort = sort; this.exit = exit; this.search = search; this.qSA= t.querySelectorAll.bind(t); function initialize(){ table = render(tableTemplate, tableObj); if(table) initTable(table); } function initTable(table){ setTable(table); processMaster(getHeader(t), getRows(t), getSelectColumns(t)); } // Controller-level helper fns function getTableReference(){ return tableReference; } function getSelectedRows(){ var d = []; loop(rowsArray, function(k, v){ if(!!v.getState && v.getState()){ d.push(v); } }); return d; } function getActiveRowsCount(){ var c = 0; loop(rowsArray, function(k,v){ if(v.disabled !== true){ c++; } }); return c; } function getAllRows(){ var d = []; loop(rowsArray, function(k, v){ d.push(v); }); return d; } function setTable(table){ t.innerHTML = table; tableReference = t.childNodes[0]; rowsReference = tableReference.querySelector('rows'); } function setPagination(t, l, mpp){ if(isDefined(pagination)){ pagination.updatePageCount(l, mpp); } else { pagination = new Pagination(t, l/mpp, 10, paginationUpdate); } shuffleRows(); } function setMaxPerPage(o){ return maxPerPage = o.maxPerPage; } function isShuffleItem(i, p){ return !p || (p && isInSet(i)); } function isSearchItem(item){ return item.getData()[searchKey].toLowerCase().indexOf(searchValue) > -1; } function isInSet(i){ return (Math.floor(i / maxPerPage) + 1) == currentPage; } function searchRows(){ loop(rowsArray, function(k,v){ v.disabled = !isSearchItem(v); }); } function processPagination(){ var mpp = setMaxPerPage(obj), l = getActiveRowsCount(); if(isDefined(mpp)) setPagination(t, l, mpp); } function processMaster(header, rows, selectCols){ processHeader(header); if(rowSelect === true){ processRows(header, rows, selectCols); } else { processNonSelectRows(header, rows); } processPagination(); } function processRows(h, r, s){ loop(s, function(k,v){ if(k > 0){ var i = k-1; rowsArray.push(new Row(r[i], v, i)); } else { masterSelect = new MasterSelect(h, v); } }); } function processNonSelectRows(h, r){ loop(r, function(k,v){ rowsArray.push(new Row(v, null, k)); }); } function processHeader(h){ loop(h.querySelectorAll('cell-block'), function(k,v){ new Column(v, tableObj.columns[k], k); }); } function search(key, value){ if(isDefined(key) && isDefined(value) && isDefined(obj.columns[key])){ searchActive = true; searchKey = key; searchValue = value.toLowerCase(); } else { searchActive = false; searchKey = ''; searchValue = ''; } searchRows(); processPagination(); //shuffleRows(); } function shuffleRows(){ var pA = isDefined(pagination); if(pA) removeRows(); rowsReference.appendChild(shuffleAction(getFragment(), pA)); onPageChange(t); } function shuffleAction(f, pA){ var sCount = 0; loop(rowsArray, function(k,v){ if(v.disabled === true) return; if(isShuffleItem(sCount, pA)){ f.appendChild(v.getElement()); defer(v.refresh); } sCount++; }); return f; } function sort(key, direction){ sortByColumn(key, direction, obj.columns[key].valueType); } function sortByColumn(key, direction, valueType){ rowsArray.sort(getSortFn(key, direction, valueType)); shuffleRows(); } function removeRows(){ loop(Array.prototype.slice.call(rowsReference.childNodes).reverse(), function(k,v){ rowsReference.removeChild(v); }); } function paginationUpdate(e){ currentPage = e; shuffleRows(); } var Column = function(c, d, i){ var state = 1, obj = { 'i' : i, 'unset' : unset }; bindColumn(); this.unset = unset; function bindColumn(){ if(d.sortable !== false) events.add(c, 'click', clickAction); } function clickAction(e){ if(e && e.preventDefault) e.preventDefault(); if(state === 0 || state === -1) setAscending(); else if(state === 1) setDescending(); } function setAscending(){ if(!isActiveSort()) updateActiveSort(); state = 1; sortByColumn(d.key, state, d.valueType); setAscClass(); } function setDescending(){ if(!isActiveSort()) updateActiveSort(); state = -1; sortByColumn(d.key, state, d.valueType); setDescClass(); } function isActiveSort(){ return activeSort != null ? i == activeSort.i : false; } function updateActiveSort(){ if(activeSort != null) activeSort.unset(); activeSort = obj; } function unset(){ state = 0; unsetClasses(); } function setAscClass(){ c.classList.add('asc'); c.classList.remove('desc'); } function setDescClass(){ c.classList.add('desc'); c.classList.remove('asc'); } function unsetClasses(){ c.classList.remove('asc'); c.classList.remove('desc'); } }; var Row = function(t, s, i){ var input = isDefined(s) ? new Checkbox(s, inputUpdate) : null, state = false, cells = []; if(input) checkboxList.push(input); loop(t.querySelectorAll('cell-block'), function(k,v){ if(!!input && k === '0') return; cells.push(new CellBlock(k, v)); }); this.getElement = getElement; this.getData = getData; this.exit = exit; this.disabled = false; this.refresh = refresh; if(input !== null){ this.set = externalSet; this.unset = externalunset; this.getState = getState; } function inputUpdate(e){ if(e) set(true); else unset(true); } function externalSet(){ input.set(); set(); } function externalunset(){ input.unset(); unset(); } function set(internal){ if(internal && selectCB) sendCB(); state = true; t.classList.add('selected'); } function unset(internal){ if(internal && selectCB) sendCB(); state = false; t.classList.remove('selected'); } function getState(){ return state; } function getElement(){ return t; } function getData(){ return JSON.parse(JSON.stringify(obj.rows[i])); } function refresh(){ loop(cells, function(k,v){ v.refresh(); }); } function exit(){ if(input) input.exit(); input = null; t = null; s = null; i = null; } function sendCB(){ setTimeout(selectCB, 1); } }; function CellBlock(k, v){ var cellCss = null, spn = v.querySelector('span'), owidth = 0, ewidth = 0, delta = 0, tDur = 0, // Transition duration expanded = false, incPadding = 12, locked = false, loaded = false; this.refresh = refresh; this.expand = expand; this.minimize = minimize; function refresh(){ if(locked || loaded) return; // If only I could do, 'if locked AND loaded'.. locked = true; defer(function(){ locked = false; }); cellCss = window.getComputedStyle(v); owidth = v.offsetWidth; ewidth = getEWidth(); delta = ewidth - owidth; if(owidth === 0 || delta <= 0){ return; } delta += incPadding; ewidth += incPadding; setPadding(); var expnd = document.createElement('expand'); tDur = Math.ceil(delta / 100) * 100; v.setAttribute('cssTransition', 'linear' + tDur); v.appendChild(expnd); events.add(expnd, 'click', toggle); loaded = true; } function toggle(){ if(!expanded){ expand(); } else { minimize(); } } function expand(){ if(locked) return; locked = expanded = true; v.classList.add('expanded'); v.style.width = ewidth + 'px'; v.style.marginRight = ((ewidth - owidth) * -1) + 'px'; setTimeout(function(){ locked = false; }, tDur); } function minimize(){ if(locked) return; locked = true; v.style.width = owidth + 'px'; v.style.marginRight = ''; setTimeout(function(){ locked = expanded = false; v.classList.remove('expanded'); }, tDur); } function setPadding(){ v.style.paddingRight = parseFloat(cellCss.paddingRight) + incPadding + 'px'; cellCss = window.getComputedStyle(v); } function getEWidth(){ var spnCss = window.getComputedStyle(spn); return Math.ceil(getPaddingValue(cellCss) + getPaddingValue(spnCss) + measureText(spn.textContent, spnCss.font)); } function getPaddingValue(css){ var v = 0; v += parseFloat(css.borderLeftWidth); v += parseFloat(css.paddingLeft); v += parseFloat(css.paddingRight); v += parseFloat(css.borderRightWidth); return v; } } var MasterSelect = function(t, s){ var input = isDefined(s) ? new Checkbox(s, inputUpdate) : null; if(input) checkboxList.push(input); this.exit = exit; function inputUpdate(e){ if(e) set(true); else unset(true); } function set(internal){ if(internal && selectCB) sendCB(); state = true; t.classList.add('selected'); setRows(); } function unset(internal){ if(internal && selectCB) sendCB(); state = false; t.classList.remove('selected'); unsetRows(); } function setRows(){ loop(rowsArray, function(k,v){ v.set(); }); } function unsetRows(){ loop(rowsArray, function(k,v){ v.unset(); }); } function exit(){ if(input) input.exit(); input = null; t = null; s = null; } function sendCB(){ setTimeout(selectCB, 1); } }; function exit(){ if(events) events.reset(); if(tableReference) removeChild(t, tableReference); if(rowsArray) exitRows(); if(checkboxList) exitCheckboxes(); tableObj = null; tableTemplate = null; masterSelect = null; activeSort = null; tableReference = null; rowsReference = null; table = null; checkboxList = rowsArray = null; } function exitCheckboxes(){ forEach(checkboxList, p, true); function p(t, d, i){ if(t.exit) t.exit(); d.splice(i, 1); } } function exitRows(){ loop(rowsArray, function(k,v){ v.exit(); }); } initialize(); } function Tmpl(){ var s = '{{# sortable }}sortable{{/ sortable }}', c = '{{# centered }}centered{{/ centered }}', w = '{{# width }}style="width: {{ . }}px"{{/ width }}', t = '{{# title }}{{ . }}{{/ title }}', si = '{{# sortable }}{{/ sortable }}'; var rc = '{{# centered }}centered{{/ centered }}', rw = '{{# width }}style="width: {{ . }}px"{{/ width }}', rs = '{{ html }}'; this.headerCell = ''+ t + si + ''; this.header = '
{{# columns }}' + this.headerCell + '{{/ columns }}
'; this.rowCell = '' + rs + ''; this.row = '{{# . }}' + this.rowCell + '{{/ . }}'; this.rows = '{{# rows }}' + this.row + '{{/ rows }}'; this.index = '' + this.header + this.rows + ''; } function TableObj(o, rs){ this.columns = getColumnArray(o.columns, rs); this.rows = getRowsArray(o.rows, this.columns, rs); } function RowObj(o, k, col, c){ var t = getRowItemKey(k, o), html = null; if(t != null && typeof t === 'object' && 'title' in t) { if('noTitle' in t) this.noTitle = true; this.value = t.value; html = t.html || t.title; t = t.title; } this.title = getFormattedValue(t, col[c].formatType); this.html = html || this.title; this.value = isDefined(this.value) ? this.value : this.title; this.width = col[c].width; this.key = col[c].key; this.centered = col[c].centered || false; } function getRowItemKey(k, o){ if(k === '#') return o.displayOrder; return o[k]; } function getFormattedValue(s, formatType){ if(!isDefined(s)) return ''; if(!isDefined(formatType)) return s; if(formatType == 'locale') return s.toLocaleString(); if(formatType == 'currency' && typeof s === 'number') return s.toFixed(2); return s; } function getHeader(t){ return t.querySelector('header'); } function getRows(t){ return t.querySelectorAll('row'); } function getSelectColumns(t){ return t.querySelectorAll('.selectColumn'); } function getRowsArray(d, col, rs){ var a = []; loop(d, function(k, v){ a.push(getRowArray(v, col, rs)); }); return a; } function getRowArray(o, col, rs){ var a = [], c = 0; if(rs === true){ a.push({ 'width' : col[c].width, 'key' : col[c++].key }); } loop(getKeyOrder(col, rs), function(k){ a.push(new RowObj(o, k, col, c++)); }); return a; } function getSortFn(key, direction, valueType){ if(valueType == 'number') { return getNumberSortClosure(key, direction); } else { return getStringSortClosure(key, direction); } } function getKeyOrder(a, rs){ var o = {}, si = (rs === true) ? 1 : 0; loop(a, function(k,v){ if(k >= si){ o[v.key] = null; } }); return o; } function getRowSelectColumn(){ return { 'sortable' : false, 'width' : '60', 'key' : 'select' }; } function getNumberSortClosure(k, d){ var key = k != '#' ? k : 'displayOrder'; return getTemplateSortClosure(key, d === 1 ? sortNumberAsc : sortNumberDesc); } function getStringSortClosure(k, d){ return getTemplateSortClosure(k, d === 1 ? sortStringAsc : sortStringDesc); } function getTemplateSortClosure(k, fn){ return function(k, fn){ return function(a, b){ if(a.getData()['__ignore__']) return 1000; // hacky, I know... a = a.getData()[k]; b = b.getData()[k]; if(typeof a == 'object' && 'value' in a) { a = a.value; } if(typeof b == 'object' && 'value' in b) { b = b.value; } return fn(a, b); }; }(k, fn); } function getColumnArray(o, rs){ var a = []; if(rs === true){ a.push(getRowSelectColumn()); } loop(o, function(k,v){ processColumn(v, k, a); }); return a; } function sortNumberAsc(a, b){ return a - b; } function sortNumberDesc(a, b){ return b - a; } function sortStringAsc(a, b){ return sortString(a, b, 1, -1); } function sortStringDesc(a, b){ return sortString(a, b, -1, 1); } function sortString(a, b, f, s){ if(a>b) return f; else if(a