6 коммитов

Автор SHA1 Сообщение Дата
  Bing Sun 374a17bc53
add initial Table component 5 лет назад
  Bing Sun 51bb88779b
make_model: add data() method for synchrorized data fetching 5 лет назад
  Bing Sun b4bdd7ed67
make_model: selects should not be set to [] 5 лет назад
  Bing Sun 6aae4ef9cb
Layout: a POJO component is sufficient 5 лет назад
  Bing Sun ed1a1c4478
Layout should be a component 5 лет назад
  Bing Sun 5c1165a1e9
make_model: rename 'filter' to 'process' 5 лет назад
4 измененных файлов: 167 добавлений и 21 удалений
  1. +7
    -0
      src/components/Layout.js
  2. +153
    -0
      src/components/Table.js
  3. +7
    -6
      src/util/make_model.js
  4. +0
    -15
      src/util/with_layout.js

+ 7
- 0
src/components/Layout.js Просмотреть файл

@@ -0,0 +1,7 @@
export default {
view: vnode => [
vnode.attrs.prologue,
m('main', vnode.children),
vnode.attrs.epilogue
]
}

+ 153
- 0
src/components/Table.js Просмотреть файл

@@ -0,0 +1,153 @@
/*
columns: <displayed columns>,
serial: true/false,
model_options: <model.options>
*/

export default initial_vnode => {
// component state
let model = initial_vnode.attrs.model

let columns = initial_vnode.attrs.columns
if (!columns) {
if (model.configs().selects) {
_columns = model.configs().selects.map(select => ({
label: select.alias || select.label
}))
}
}

let offset = 0
let limit = initial_vnode.attrs.pagination && initial_vnode.attrs.pagination.size
console.log(limit)
return {
view: vnode => {
// try to generate columns if it is still undefined
if (typeof columns == 'undefined' || columns.length == 0) {
columns = model.data() && model.data().length && Object.keys(model.data()[0]).map(key => ({label: key})) || []
}

return [
m('table', [
// always show table header
m('thead', m('tr', [
vnode.attrs.serial ? m('th.centered', '序号') : undefined,
...columns.map(column => m('th.centered', column.label))
])),
model.data(offset).length ? m('tbody', model.data(offset).map((row, i) => m('tr', [
vnode.attrs.serial ? m('td.centered', offset+i+1) : undefined,
...columns.map(column => {
let v = row[column.label] || ''

if (typeof column.tag != 'undefined')
v = m(column.tag, v)

return m(`td${column.class || ''}`, v)
})
]))) : m('', 'Empty')
]),
/* _pages.length > 1 ?
m('.centered',
m('.pagination.centered', _pages.map((page, i) => page.show ? m('a', {
class: page.active ? 'active' : '',
onclick: e => {
_offset = i * vnode.attrs.options.paging.size
vnode.attrs.options.model.load({begin: i * vnode.attrs.options.paging.size, end: (i+1) * vnode.attrs.options.paging.size})
}
}, i + 1) : undefined))
)
: undefined*/
]
}
}
}

export const default1 = _ => {
let _columns = []
let _offset= 0
let _pages = []
let _model_slice = []

return {
view: vnode => {
// prepare columns by merging model.selects and columns config
_columns = Array.from(vnode.attrs.options.model.configs().selects, ([label, select]) => ({
label: select.alias || label,
tag: vnode.attrs.options.columns[label] && vnode.attrs.options.columns[label].tag
}))

if (vnode.attrs.options.model.ambient_changed())
_offset = 0

// prepare pages
if (vnode.attrs.options.paging && vnode.attrs.options.model.count) {
_offset = ~~_offset
let _active_page = _offset / vnode.attrs.options.paging.size
_pages = Array.from(Array(vnode.attrs.options.paging.size ? Math.floor(~~vnode.attrs.options.model.count / vnode.attrs.options.paging.size) + 1 : 0)).map((_,i) => _active_page == i ? {active: true} : {active: false})

if (_pages.length <= 10) {
_pages.forEach((page, i, pages) => pages[i].show = true)
} else {
let _showed_pages = new Set([0, _active_page, _pages.length -1])
let l = _active_page, r = _active_page
while (_showed_pages.size < 10) {
l -= 1
if (l < 0) {
_showed_pages.add(r+1)
r += 1
} else {
_showed_pages.add(l)
}
if (_showed_pages.size < 10) {
r += 1
if (r >= _pages.length) {
_showed_pages.add(l-1)
l -= 1
} else {
_showed_pages.add(r)
}
}
}
_showed_pages.forEach(v => _pages[v].show = true)
}
}

// visible model
function get_model_slice() {
return vnode.attrs.options.model.list.slice(_offset, _offset + ~~(vnode.attrs.options.paging && vnode.attrs.options.paging.size || 200))
}

return [
m('table', [
// always show table header
m('thead', m('tr', [
vnode.attrs.options.prepend_serial ? m('th.centered', '序号') : undefined,
..._columns.map(col => m('th.centered', col.label))
])),
get_model_slice().length ? m('tbody', get_model_slice().map((row, i) => m('tr', [
vnode.attrs.options.prepend_serial ? m('td.centered', _offset+i+1) : undefined,
..._columns.map(col => {
let v = row[col.label] || ''

if (typeof col.tag != 'undefined')
v = m(col.tag, v)

return m(`td${col.class || ''}`, v)
})
]))) : m('', 'Empty')
]),
_pages.length > 1 ?
m('.centered',
m('.pagination.centered', _pages.map((page, i) => page.show ? m('a', {
class: page.active ? 'active' : '',
onclick: e => {
_offset = i * vnode.attrs.options.paging.size
vnode.attrs.options.model.load({begin: i * vnode.attrs.options.paging.size, end: (i+1) * vnode.attrs.options.paging.size})
}
}, i + 1) : undefined))
)
: undefined
]
}
}
}

+ 7
- 6
src/util/make_model.js Просмотреть файл

@@ -9,7 +9,7 @@
* {
* 'label': 'column name',
* 'alias': 'displayed name',
* 'filter': v => value_processor(v)
* 'processor': v => process(v)
* }
* ]
* }
@@ -30,7 +30,7 @@ export default (options={}) => {
endpoint: options.endpoint,
endpoint_type: options.endpoint.startsWith('/rpc') ? 'function' : 'relation',
// query part
selects: options.selects || [],
selects: options.selects
}

// private model cache & meta-info
@@ -49,6 +49,7 @@ export default (options={}) => {
// reflection methods
configs() { return _configs },
cache() { return _cache },
data(offset=0, limit=Infinity) { return _cache.data && _cache.data.slice(offset, offset+limit) || [] },

// main methods
select(offset=0, limit=Infinity) {
@@ -104,10 +105,10 @@ export default (options={}) => {

// fill the data cache
response.forEach((data, i) => {
// filter values
_configs.selects
.filter(select => select.filter)
.forEach(select => data[select.alias || select.label] = select.filter(data[select.alias || select.label]))
// process values
_configs.selects && _configs.selects
.filter(select => select.processor)
.forEach(select => data[select.alias || select.label] = select.processor(data[select.alias || select.label]))

// save the data
_cache.data[_begin + i] = data


+ 0
- 15
src/util/with_layout.js Просмотреть файл

@@ -1,15 +0,0 @@
export default options => {
if (typeof options == 'undefined')
options = {}

if (!options.hasOwnProperty('content'))
options = {'content': options}

return {
view: vnode => [
options.prologue,
m('main', options.content),
options.epilogue
]
}
}

Загрузка…
Отмена
Сохранить