Created
December 6, 2010 04:22
-
-
Save gifnksm/729855 to your computer and use it in GitHub Desktop.
簡易的な DataGrid
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
const NAMESPACE = 'mfp.xrea.jp'; | |
if (!(NAMESPACE in window)) | |
window[NAMESPACE] = {}; | |
if (window[NAMESPACE].DataGrid !== undefined) | |
return; | |
const DataGrid = function(property, namePrefix) { | |
this._property = new DataGrid.Property(property); | |
this._namePrefix = namePrefix || ''; | |
this._table = document.createElement('table'); | |
this._table.id = namePrefix + 'table'; | |
this._table.appendChild(this._createCols()); | |
this._thead = new DataGrid.Header(this, this._property, namePrefix); | |
this._table.appendChild(this._thead.element); | |
this._tbody = document.createElement('tbody'); | |
this._table.appendChild(this._tbody); | |
}; | |
DataGrid.prototype = { | |
_property: null, _namePrefix: null, | |
_table: null, get element() this._table, | |
_thead: null, _tbody: null, | |
_rows: null, _filteredRows: null, _visibleRows: null, | |
_rowPerPage: 0, get rowPerPage() this._rowPerPage, | |
set rowPerPage(value) this._rowPerPage = value, | |
get length() this._rows ? this._rows.length : 0, | |
get availableLength() this._filteredRows ? this._filteredRows.length : 0, | |
get visibleLength() this._visibleRows ? this._visibleRows.length : 0, | |
_page: 0, get page() this._page, | |
set page(value) this._page = value, | |
get pageLength() this.rowPerPage > 0 | |
? Math.ceil(this.availableLength / this.rowPerPage) | |
: 1, | |
_filter: null, get filter() this._filter, | |
set filter(value) this._filter = value, | |
_createCols: function() { | |
let cols = document.createDocumentFragment(); | |
let prefix = this._namePrefix; | |
this._property.forEach(function(prop) { | |
let col = document.createElement('col'); | |
col.className = prefix + 'col-' + prop.id; | |
cols.appendChild(col); | |
}); | |
return cols; | |
}, | |
setData: function(data) { | |
let prop = this._property, prefix = this._namePrefix; | |
this._rows = data.map(function(d) new DataGrid.Row(d, prop, prefix)); | |
this._thead.setSortOrder(-1); | |
}, | |
sort: function(colId, reverse) { | |
let prop = this._property.getPropertyById(colId); | |
if (prop === null) return; | |
let order; | |
if (reverse === undefined) { | |
let cur = this._thead.getSortOrder(colId, order); | |
if (cur !== 0) order = -cur; | |
else order = prop.sortDefaultOrder; | |
} else { | |
order = reverse ? -1 : 1; | |
} | |
this._thead.setSortOrder(colId, order); | |
let comparer = prop.comparer; | |
this._rows.sort(function(r1, r2) order * comparer(r1.data, r2.data)); | |
}, | |
update: function() { | |
let filter = this.filter; | |
this._filteredRows = filter == null | |
? this._rows | |
: this._rows.filter(function(r) filter(r.data)); | |
let rowPerPage = this.rowPerPage; | |
this._visibleRows = rowPerPage === 0 | |
? this._filteredRows | |
: this._filteredRows.slice( | |
this.page * rowPerPage, (this.page + 1) * rowPerPage - 1); | |
let df = document.createDocumentFragment(); | |
this._visibleRows.forEach(function(d) df.appendChild(d.element)); | |
this._tbody.textContent = ''; | |
this._tbody.appendChild(df); | |
}, | |
setCaption: function(content) { | |
let caption = this._table.querySelector('caption'); | |
if (content === null) { | |
if (caption !== null) | |
caption.parentNode.removeChild(caption); | |
return; | |
} | |
if (caption === null) | |
caption = document.createElement('caption'); | |
caption.textContent = ''; | |
caption.appendChild(content); | |
this._table.insertBefore(caption, this._table.firstChild); | |
}, | |
getRowByData: function(data) { | |
for (let i = 0, len = this.length; i < len; i++) { | |
if (this._rows[i].data === data) | |
return this._rows[i]; | |
} | |
return null; | |
} | |
}; | |
DataGrid.Property = function(property) { | |
let result = []; | |
result.__proto__ = DataGrid.Property.prototype; | |
for (let i = 0, len = property.length; i < len; i++) | |
result[i] = new DataGrid.Property.Item(property[i]); | |
return result; | |
}; | |
DataGrid.Property.prototype = { | |
getPropertyById: function(id) { | |
for (let i = 0, len = this.length; i < len; i++) | |
if (this[i].id === id) | |
return this[i]; | |
return null; | |
}, | |
getIndexById: function(id) { | |
for (let i = 0, len = this.length; i < len; i++) | |
if (this[i].id === id) | |
return i; | |
return -1; | |
} | |
}; | |
DataGrid.Property.prototype.__proto__ = Array.prototype; | |
DataGrid.Property.Item = function(prop) { | |
this._id = String(prop.id); | |
this._hidden = Boolean(prop.hidden); | |
this._title = prop.title; | |
this._content = prop.content; | |
this._sortable = Boolean(prop.sortable); | |
this._sortDefaultOrder = Number(prop.sortDefaultOrder) || 1; | |
this._updateLabel(prop.label); | |
this._updateComparer(prop.comparer); | |
}; | |
DataGrid.Property.Item.prototype = { | |
_id: null, get id() this._id, | |
_hidden: null, get hidden() this._hidden, | |
_label: null, get label() this._label, | |
_title: null, get title() this._title, | |
_content: null, | |
_sortable: null, get sortable() this._sortable, | |
_sortDefaultOrder: null, get sortDefaultOrder() this._sortDefaultOrder, | |
_comparer: null, get comparer() this._comparer, | |
_comparerType: null, get comparerType() this._comparerType, | |
_updateLabel: function(label) { | |
if (label && label.nodeType !== undefined) { | |
this._label = label; | |
return; | |
} | |
this._label = document.createTextNode( | |
label === undefined ? String(this.id) : String(label)); | |
}, | |
_updateComparer: function(comp) { | |
if (typeof comp === 'function') { | |
this._comparerType = 'function'; | |
this._comparer = comp; | |
return; | |
} | |
let cmp; | |
switch (comp) { | |
case 'date': | |
case 'number': | |
case 'bool': | |
cmp = function(a1, a2) a1 - a2; | |
this._comparerType = comp; | |
break; | |
case 'string': | |
default: | |
cmp = function(s1, s2) s1 === s2 ? 0 : s1 > s2 ? 1 : -1; | |
this._comparerType = 'string'; | |
break; | |
} | |
let id = this.id; | |
this._comparer = function(d1, d2) cmp(d1[id], d2[id]); | |
}, | |
createContent: function(data) { | |
if (this._content === undefined) { | |
let text = data[this.id] !== undefined ? String(data[this.id]) : ''; | |
return document.createTextNode(text);; | |
} | |
if (typeof this._content === 'function') { | |
let content = this._content(data); | |
if (content && content.nodeType !== undefined) | |
return content; | |
return document.createTextNode(content); | |
} | |
return null; | |
} | |
}; | |
DataGrid.Header = function(grid, property, namePrefix) { | |
this._grid = grid; | |
this._property = property; | |
this._namePrefix = namePrefix; | |
}; | |
DataGrid.Header.prototype = { | |
_grid: null, _property: null, _namePrefix: null, | |
_created: false, | |
_thead: null, get element() { | |
if (!this._created) this.update(); | |
return this._thead; | |
}, | |
__ths: null, get _ths() { | |
if (!this._created) this.update(); | |
return this.__ths; | |
}, | |
update: function() { | |
this._created = true; | |
let row = document.createElement('tr'); | |
let cols = null; | |
let prefix = this._namePrefix; | |
let ths = []; | |
this._property.forEach(function(prop) { | |
if (prop.hidden) return; | |
let th = document.createElement('th'); | |
th.className = prefix + 'head-' + prop.id; | |
ths.push(th); | |
if (prop.title !== undefined) | |
th.title = prop.title; | |
if (prop.sortable) { | |
let link = document.createElement('a'); | |
link.href = '#' + prop.id; | |
link.appendChild(prop.label); | |
th.appendChild(link); | |
} else { | |
th.appendChild(prop.label); | |
} | |
row.appendChild(th); | |
}); | |
this.__ths = ths; | |
this._thead = document.createElement('thead'); | |
this._thead.appendChild(row); | |
this._thead.addEventListener('click', this, false); | |
}, | |
get _ascending() this._namePrefix + 'sort-ascending', | |
get _descending() this._namePrefix + 'sort-descending', | |
getSortOrder: function(col, order) { | |
if (typeof col === 'string' || col instanceof String) | |
col = this._property.getIndexById(col); | |
if (col === -1) return 0; | |
let list = this._ths[col].classList; | |
if (list.contains(this._ascending)) return 1; | |
if (list.contains(this._descending)) return -1; | |
return 0; | |
}, | |
setSortOrder: function(col, order) { | |
if (typeof col === 'string' || col instanceof String) | |
col = this._property.getIndexById(col); | |
const ASCENDING = this._ascending; | |
const DESCENDING = this._descending; | |
this._ths.forEach(function(th) { | |
th.classList.remove(ASCENDING); | |
th.classList.remove(DESCENDING); | |
}); | |
if (col !== -1) | |
this._ths[col].classList.add((order > 0 ? ASCENDING : DESCENDING)); | |
}, | |
handleEvent: function(e) { | |
let { target } = e; | |
do { | |
if (target === this.element) return; | |
if (target.nodeName === 'A') break; | |
target = target.parentNode; | |
} while (target !== null); | |
e.preventDefault(); | |
let colname = target.getAttribute('href').slice('1'); | |
this._grid.sort(colname); | |
this._grid.update(); | |
} | |
}; | |
DataGrid.Row = function(data, property, namePrefix) { | |
this._data = data; | |
this._property = property; | |
this._namePrefix = namePrefix; | |
this._tr = document.createElement('tr'); | |
}; | |
DataGrid.Row.prototype = { | |
_data: null, get data() this._data, | |
_property: null, _namePrefix: null, | |
_created: false, | |
_tr: null, get element() { | |
if (!this._created) this.update(); | |
return this._tr ; | |
}, | |
update: function() { | |
this._created = true; | |
let df = document.createDocumentFragment(); | |
let data = this._data; | |
let prefix = this._namePrefix + 'cell-'; | |
this._property.forEach(function(prop) { | |
if (prop.hidden) return; | |
let td = document.createElement('td'); | |
td.className = prefix + prop.id; | |
td.appendChild(prop.createContent(data)); | |
df.appendChild(td); | |
}); | |
this._tr.textContent = ''; | |
this._tr.appendChild(df); | |
} | |
}; | |
window[NAMESPACE].DataGrid = DataGrid; | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const DataGrid = window['mfp.xrea.jp'].DataGrid; | |
let grid = new DataGrid([ | |
{ id: 'first_name', sortable: true }, | |
{ id: 'last_name', sortable: true }, | |
{ id: 'age', sortable: true, comparer: 'number' }, | |
{ id: 'sex', content: function(data) data.isMale ? 'Male' : 'Female' } | |
], 'grid'); | |
grid.setData([ | |
{ first_name: 'Taro', last_name: 'Yamada', age: 30, isMale: true }, | |
{ first_name: 'Hanako', last_name: 'Sato', age: 0, isMake: false } | |
]); | |
grid.update(); | |
document.body.appendChild(grid.element); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment