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 || "";
@ -79,6 +82,8 @@ class TableSupport extends DatasetSupport {
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"));
@ -86,6 +91,23 @@ class TableSupport extends DatasetSupport {
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,11 +138,24 @@ 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);

@ -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;
if (!state.byKeyValue) {
let current = this.getData(state.currentKey, "item") || this.getDataset("item")[0], let current = this.getData(state.currentKey, "item") || this.getDataset("item")[0],
currentKey = this.getKey(current); currentKey = this.getKey(current);
this.onSort(this.sorter); this.onSort(this.sorter);
this.setCurrent(currentKey, true); this.setCurrent(currentKey, true);
this.select(state.selectedKeys || [], true, 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);
} }
@ -1362,6 +1366,39 @@ class Dataset {
}); });
} }
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
* @param {object} obj optional information * @param {object} obj optional information
@ -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);
@ -1557,15 +1609,6 @@ class DatasetControl {
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);
} }
}); });
@ -1696,173 +1738,3 @@ class DatasetControl {
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