tableSorter, dataBinder 제거

master
mjkhan21 3 months ago
parent 6ab376e055
commit f502c0db1a

@ -65,6 +65,10 @@
.current-row {background-color: rgba(105, 108, 255, 0.16);} .current-row {background-color: rgba(105, 108, 255, 0.16);}
.current-row td:not(:last-child) {border-right: 1px solid white;} .current-row td:not(:last-child) {border-right: 1px solid white;}
.table thead {
background-color: #fcfdfd;
}
.table th {font-size:1rem;} .table th {font-size:1rem;}
.col-form-label {font-size:0.9375rem;} .col-form-label {font-size:0.9375rem;}

@ -13,7 +13,8 @@ class DatasetSupport {
*/ */
constructor(conf) { constructor(conf) {
this.selector = conf.selector || null; this.selector = conf.selector || null;
this.dataset = conf.ctrl.dataset; this.ctrl = conf.ctrl;
this.dataset = this.ctrl.dataset;
this._doq = conf.ctrl.doq; this._doq = conf.ctrl.doq;
} }
@ -51,6 +52,8 @@ class TableSupport extends DatasetSupport {
this.selector = conf.table; this.selector = conf.table;
this.tr = conf.tr; this.tr = conf.tr;
this.notFound = conf.notFound; this.notFound = conf.notFound;
this.parent = null;
this.next = false;
this.formatter = conf.formatter; this.formatter = conf.formatter;
this.selectionToggler = conf.selectionToggler || ""; this.selectionToggler = conf.selectionToggler || "";
@ -58,10 +61,10 @@ class TableSupport extends DatasetSupport {
this.init(); this.init();
} }
init() { init() {
this.body = this.find(this.selector + " tbody"); this.body = this.find(this.selector + " tbody");
if (this.tr) { if (this.tr) {
let template = this.find(this.tr); let template = this.find(this.tr);
this.tr = (template || {}).innerHTML || ""; this.tr = (template || {}).innerHTML || "";
@ -70,7 +73,7 @@ class TableSupport extends DatasetSupport {
let template = this.find(this.notFound); let template = this.find(this.notFound);
this.notFound = (template || {}).innerHTML || ""; this.notFound = (template || {}).innerHTML || "";
} }
if (!this.tr && !this.notFound) { if (!this.tr && !this.notFound) {
let templates = this.findAll(this.selector + " template"); let templates = this.findAll(this.selector + " template");
if (templates.length < 1) if (templates.length < 1)
@ -78,14 +81,33 @@ class TableSupport extends DatasetSupport {
this.tr = (templates[0] || {}).innerHTML; this.tr = (templates[0] || {}).innerHTML;
this.notFound = (templates[1] || {}).innerHTML; this.notFound = (templates[1] || {}).innerHTML;
} }
this.setLoadNext();
let sort = evt => { let sort = evt => {
let th = evt.target; let th = evt.target;
this.dataset.sort(th.getAttribute("data-sort")); this.dataset.sort(th.getAttribute("data-sort"));
}; };
this.sortables().forEach(th => th.addEventListener("click", sort)); this.sortables().forEach(th => th.addEventListener("click", sort));
} }
setLoadNext() {
if (!this.ctrl.appendData) return;
let table = this.find(this.selector),
parent = table ? table.parentElement : null;
if (!parent) return;
parent.style["overflow-y"] = "auto";
this.parent = parent;
this.parent.addEventListener("scrollend", (evt) => {
if (!this.next) return;
let pageNum = this.ctrl.query.pageNum || 0;
this.ctrl.load(pageNum + 1);
});
}
sortables() { sortables() {
return this.findAll(this.selector + " thead th[data-sort]"); return this.findAll(this.selector + " thead th[data-sort]");
} }
@ -116,13 +138,26 @@ class TableSupport extends DatasetSupport {
this.findAll(".enable-onfound").forEach(e => e.disabled = this.dataset.empty); this.findAll(".enable-onfound").forEach(e => e.disabled = this.dataset.empty);
} }
getTop(option) {
return this.ctrl.appendData && option.reloaded && this.parent ? this.parent.scrollTop : 0;
}
draw(option = {}) { draw(option = {}) {
let empty = this.dataset.empty, if (!option.reloaded && option.pagination) {
this.next = option.pagination.next;
}
let prevTop = this.getTop(option),
empty = this.dataset.empty,
trs = !empty ? this.dataset.inStrings(this.tr, this.formatter) : [this.notFound]; trs = !empty ? this.dataset.inStrings(this.tr, this.formatter) : [this.notFound];
this.body.innerHTML = trs.join(""); this.body.innerHTML = trs.join("");
let curTop = this.getTop(option);
if (prevTop != curTop)
this.parent.scrollTo(curTop, this.parent.scrollLeft);
if (!this.selectionToggler) return; if (!this.selectionToggler) return;
let toggler = this.find(this.selectionToggler); let toggler = this.find(this.selectionToggler);
toggler.checked = false; toggler.checked = false;
toggler.disabled = empty; toggler.disabled = empty;
@ -133,7 +168,7 @@ class TableSupport extends DatasetSupport {
*/ */
setCurrentRow(item) { setCurrentRow(item) {
if (!item) return; if (!item) return;
let index = item.index; let index = item.index;
this.findAll(this.selector + " tbody tr").forEach(tr => { this.findAll(this.selector + " tbody tr").forEach(tr => {
let dataIndex = tr.getAttribute("data-index"), let dataIndex = tr.getAttribute("data-index"),
@ -144,7 +179,7 @@ class TableSupport extends DatasetSupport {
tr.classList.remove(TableSupport.cssClass.current); tr.classList.remove(TableSupport.cssClass.current);
}); });
} }
/**Handler called back on the selection change event /**Handler called back on the selection change event
* @param {array} selected selected DataItems * @param {array} selected selected DataItems
*/ */
@ -154,11 +189,11 @@ class TableSupport extends DatasetSupport {
.forEach(input => { .forEach(input => {
input.checked = selectedIndex.includes(input.value) input.checked = selectedIndex.includes(input.value)
}); });
this.findAll(".enable-onselect") this.findAll(".enable-onselect")
.forEach(e => e.disabled = selected.length < 1); .forEach(e => e.disabled = selected.length < 1);
} }
/**Handler called back on the modify event /**Handler called back on the modify event
* @param {array} changed names of the changed properties * @param {array} changed names of the changed properties
* @param {DataItem} item owner DataItem of the changed properties * @param {DataItem} item owner DataItem of the changed properties
@ -174,7 +209,7 @@ class TableSupport extends DatasetSupport {
break; break;
} }
if (!refresh) return; if (!refresh) return;
this.draw(); this.draw();
this.dataset.setState(); this.dataset.setState();
} }
@ -206,7 +241,7 @@ class CurrentDataSupport extends DatasetSupport {
|| input.name || input.name
|| input.id; || input.id;
} }
update(input, value) { update(input, value) {
switch (this.type(input)) { switch (this.type(input)) {
case "radio": case "radio":
@ -263,7 +298,7 @@ class CurrentDataSupport extends DatasetSupport {
case 1: case 1:
let cb = inputs[0]; let cb = inputs[0];
if (cb.checked) break; if (cb.checked) break;
switch (val) { switch (val) {
case "true": val = "false"; break; case "true": val = "false"; break;
case "y": val = "n"; break; case "y": val = "n"; break;
@ -285,14 +320,14 @@ class CurrentDataSupport extends DatasetSupport {
setCurrent(item) { setCurrent(item) {
if (!item) return; if (!item) return;
this.findAll(this.selector).forEach(input => { this.findAll(this.selector).forEach(input => {
let prop = this.property(input); let prop = this.property(input);
if (!prop) return; if (!prop) return;
let evt = !["checkbox", "radio"].includes(this.type(input)) ? "change" : "click", let evt = !["checkbox", "radio"].includes(this.type(input)) ? "change" : "click",
handler = (evt) => this.setChanged(evt) handler = (evt) => this.setChanged(evt)
input.removeEventListener(evt, handler); input.removeEventListener(evt, handler);
this.update(input, item.getValue(prop)); this.update(input, item.getValue(prop));
input.addEventListener(evt, handler); input.addEventListener(evt, handler);
@ -307,7 +342,7 @@ class CurrentDataSupport extends DatasetSupport {
this.findAll(this.selector).forEach(input => { this.findAll(this.selector).forEach(input => {
let prop = this.property(input); let prop = this.property(input);
if (!changed.includes(prop)) return; if (!changed.includes(prop)) return;
this.update(input, item.getValue(prop)); this.update(input, item.getValue(prop));
}); });
this.enableOnDirty(item); this.enableOnDirty(item);
@ -318,7 +353,7 @@ class CurrentDataSupport extends DatasetSupport {
*/ */
enableOnDirty(item) { enableOnDirty(item) {
let dirty = item.dirty; let dirty = item.dirty;
this.findAll(".enable-ondirtyitem") this.findAll(".enable-ondirtyitem")
.forEach(e => e.disabled = !dirty); .forEach(e => e.disabled = !dirty);
} }
@ -328,11 +363,11 @@ class CurrentDataSupport extends DatasetSupport {
*/ */
enableOnNew(item) { enableOnNew(item) {
let isnew = item.isNew(); let isnew = item.isNew();
this.findAll(".enable-onnewitem") this.findAll(".enable-onnewitem")
.forEach(e => e.disabled = !isnew); .forEach(e => e.disabled = !isnew);
} }
newData(init) { newData(init) {
let data = this.findAll(this.selector).reduce((data, input) => { let data = this.findAll(this.selector).reduce((data, input) => {
let prop = this.property(input); let prop = this.property(input);
@ -344,7 +379,7 @@ class CurrentDataSupport extends DatasetSupport {
init(data); init(data);
return data; return data;
} }
getData(item = this.dataset.getCurrent("item")) { getData(item = this.dataset.getCurrent("item")) {
return this.findAll(this.selector).reduce((data, input) => { return this.findAll(this.selector).reduce((data, input) => {
let dataField = this.dataField(input), let dataField = this.dataField(input),

@ -404,7 +404,6 @@ class Dataset {
this._formats = new ValueFormat(conf.formats); this._formats = new ValueFormat(conf.formats);
this._sorter = {by: ""}; this._sorter = {by: ""};
this.dataBinder = dataBinder.create(this, conf.doctx);
if (!conf.trace) if (!conf.trace)
this.log = () => {}; this.log = () => {};
@ -729,7 +728,6 @@ class Dataset {
} else { } else {
if (found && current) { if (found && current) {
this._current = found; this._current = found;
this.dataBinder.onCurrentChange(found);
this.onCurrentChange(found); this.onCurrentChange(found);
} }
} }
@ -751,7 +749,6 @@ class Dataset {
this._current = item; this._current = item;
if (diff || fire) { if (diff || fire) {
this.dataBinder.onCurrentChange(item);
this.onCurrentChange(item); this.onCurrentChange(item);
} }
} }
@ -794,12 +791,21 @@ class Dataset {
this.onDirtiesChange(false); this.onDirtiesChange(false);
} else { } else {
state = state || this.state; state = state || this.state;
let current = this.getData(state.currentKey, "item") || this.getDataset("item")[0], if (!state.byKeyValue) {
currentKey = this.getKey(current); let current = this.getData(state.currentKey, "item") || this.getDataset("item")[0],
currentKey = this.getKey(current);
this.onSort(this.sorter);
this.setCurrent(currentKey, true); this.onSort(this.sorter);
this.select(state.selectedKeys || [], true, true); this.setCurrent(currentKey, true);
this.select(state.selectedKeys || [], true, true);
} else {
let currentKey = this.indexOf(state.currentKey)[0],
selectedKeys = this.indexOf(...state.selectedKeys);
this.onSort(this.sorter);
this.setCurrent(currentKey, true);
this.select(selectedKeys, true, true);
}
} }
return this; return this;
} }
@ -1072,13 +1078,11 @@ class Dataset {
if (changed.length > 0) { if (changed.length > 0) {
if (!item.state) if (!item.state)
item.state = "modified"; item.state = "modified";
this.dataBinder.onModify(changed, item);
this.onModify(changed, item, current); this.onModify(changed, item, current);
if (notDirty) if (notDirty)
this.onDirtiesChange(true); this.onDirtiesChange(true);
} else if (revert) { } else if (revert) {
changed = Object.getOwnPropertyNames(data); changed = Object.getOwnPropertyNames(data);
this.dataBinder.onModify(changed, item);
this.onModify(changed, item, current); this.onModify(changed, item, current);
} }
@ -1361,6 +1365,39 @@ class Dataset {
return item.setValue(property, value); return item.setValue(property, value);
}); });
} }
keyValues(...args) {
return args.map(arg =>
this.keys.reduce((obj, k) => {
obj[k] = arg[k];
return obj;
}, {})
);
}
indexOf(...keyValues) {
let ofKeys = item => {
let data = item.data;
for (let kv of keyValues) {
let equal = true;
for (let entry of Object.entries(kv)) {
let k = entry[0],
v = entry[1];
equal = equal && data[k] == v;
if (!equal)
break;
}
if (equal)
return equal;
}
return false;
};
return this._items
.filter(item => ofKeys(item))
.map(item => item.index);
}
/**Called back when user data are set. /**Called back when user data are set.
* @param {object|array} obj object that has user data or an array of user data * @param {object|array} obj object that has user data or an array of user data
@ -1498,14 +1535,29 @@ class DatasetControl {
let all = option.all, let all = option.all,
prev = option.prev, prev = option.prev,
state = this.dataset.state; state = this.dataset.keymapped ? this.dataset.state : null;
if (!state) {
state = this.empty ? {currentKey: null, selectedKeys: []} : null;
if (!state) {
state = {};
let current = this.getCurrent(),
selected = this.getDataset("selected");
current = this.dataset.keyValues(current);
selected = this.dataset.keyValues(...selected);
state.currentKey = current.length > 0 ? current[0] : null;
state.selectedKeys = selected;
state.byKeyValue = true;
}
}
option.state = state; option.state = state;
if (!all) { if (!all) {
this._load(option); this._load(option);
} else { } else {
let query = Object.assign({}, this.query); let query = Object.assign({}, this.query);
this.query.fetchSize = (query.pageNum || 1) * query.fetchSize; this.query.fetchSize = this.dataset.length; //(query.pageNum || 1) * query.fetchSize;
this.query.pageNum = 1; this.query.pageNum = 1;
option.callback = () => {this.query = query;}; option.callback = () => {this.query = query;};
this._load(option); this._load(option);
@ -1556,15 +1608,6 @@ class DatasetControl {
getCurrent(option) { getCurrent(option) {
return this.dataset.getCurrent(option); return this.dataset.getCurrent(option);
} }
toObject(item = this.getCurrent("item")) {
if (this.dataset.keymapped)
return this.dataBinder().toObject(item);
}
dataBinder() {
return this.dataset.dataBinder;
}
setCurrent(key) { setCurrent(key) {
this.dataset.setCurrent(key); this.dataset.setCurrent(key);
@ -1597,7 +1640,6 @@ class DatasetControl {
size:this.infoSize, size:this.infoSize,
init:() => { init:() => {
let current = this.getCurrent("item"); let current = this.getCurrent("item");
this.dataBinder().onCurrentChange(current);
this.setInfo(current); this.setInfo(current);
} }
}); });
@ -1695,174 +1737,4 @@ class DatasetControl {
findAll(...args) { findAll(...args) {
return this.doq.findAll(...args); return this.doq.findAll(...args);
} }
}
var dataBinder = {
type: input => input ? (input.getAttribute("type") || input.tagName).toLowerCase() : "",
dataMap: input => input.getAttribute("data-map"),
property: input => input.name || input.id,
toArray(val) {
if (isEmpty(val))
return [];
if (Array.isArray(val))
return val;
if ("string" == typeof val)
return val.split(",");
return [val];
},
setValue: (input, value) => {
value = value || "";
switch (dataBinder.type(input)) {
case "radio":
case "checkbox":
input.checked = dataBinder.toArray(value).includes(input.value);
break;
case "select":
for (let option of input.options) {
option.selected = option.value == value;
}
break;
case "img":
if (!(input.src || "").endsWith(value))
input.src = value; break;
default:
if (input.value !== undefined)
input.value = value;
else
input.innerHTML = value;
}
},
create: (dataset, doctx) => {
if (!dataset || isEmpty(doctx) || !dataset.keymapped)
return {
onCurrentChange: item => {},
onModify: (changed, item) => {},
toObject: () => null
};
let obj = {
selector: (selector) => doctx ? doctx.split(",").map(str => str + " " + selector).join(",") : selector,
querySelector: (selector) => document.querySelector(obj.selector(selector)),
querySelectorAll: (selector) => Array.from(document.querySelectorAll(obj.selector(selector))),
inputs: () => obj.querySelectorAll("[data-map]"),
inputValue: (input) => {
let val = input.value;
switch (dataBinder.type(input)) {
case "radio":
return input.checked ? val : undefined;
case "checkbox":
let checks = obj.querySelectorAll("[name='" + input.name + "']");
switch (checks.length) {
case 0: return undefined;
case 1:
if (input.checked)
return val;
if ("Y" == val)
return "N";
if ('true' == val)
return 'false';
return undefined;
default:
return checks
.filter(input => input.checked)
.map(input => input.value)
.join(",");
}
case "img": return input.src;
default: return val !== undefined ? val : input.innerHTML;
}
},
setChanged: (evt) => {
let input = evt.target,
prop = dataBinder.dataMap(input) || dataBinder.property(input),
inputVal = obj.inputValue(input);
if (undefined === inputVal) return;
dataset.setValue(prop, inputVal);
}
};
obj.onCurrentChange = (current) => {
if (!current) return;
obj.inputs().forEach(input => {
let prop = dataBinder.dataMap(input) || dataBinder.property(input);
if (!prop) return;
let evt = !["checkbox", "radio"].includes(dataBinder.type(input)) ? "change" : "click";
input.removeEventListener(evt, obj.setChanged);
dataBinder.setValue(input, current.getValue(prop));
input.addEventListener(evt, obj.setChanged);
});
};
obj.onModify = (changed, item) => {
return;
obj.inputs().forEach(input => {
let prop = dataBinder.dataMap(input) || dataBinder.property(input);
if (!changed.includes(prop)) return;
dataBinder.setValue(input, item.getValue(prop));
});
};
obj.toObject = (item) => {
let result = {};
obj.inputs().forEach(input => {
let dataMap = dataBinder.dataMap(input),
property = dataBinder.property(input) || dataMap,
value = item.data[dataMap || property];
if (value !== undefined)
result[property] = value;
});
return result;
}
return obj;
},
};
/**<table../> 표시되는 데이터셋의 데이터를 정렬하고 UI에 반영되도록 설정한다.
* @param ctrl {DatasetControl} DatasetControl
* @param selector 테이블 헤더에 대한 selector
*/
function tableSorter(ctrl, selector) {
let obj = {
asc: "sort-asc",
desc: "sort-desc",
sortable: "sortable",
ctrl: ctrl,
headers: () => ctrl.findAll(selector),
sort: (evt) => {
let th = evt.target;
ctrl.sort(th.getAttribute("data-sort"));
}
};
obj.setHeaders = (sorter) => {
obj.headers().forEach(th => {
th.classList.remove(obj.sortable, obj.asc, obj.desc);
if (th.getAttribute("data-sort") == sorter.by)
th.classList.add(obj[sorter.order]);
else
th.classList.add(obj.sortable);
});
};
ctrl.onSort = (sorter) => {
if (ctrl.renderList)
ctrl.renderList();
obj.setHeaders(sorter);
};
obj.headers().forEach(th => {
th.removeEventListener("click", obj.sort);
th.addEventListener("click", obj.sort);
});
return obj;
} }
Loading…
Cancel
Save