class Statistics { static Modes = { ALL: 'all', USER: 'user', CLASS: 'class' }; static Response = { COUNT: 'count', RECORDS: 'records' }; static RowFields = { USER: 'user', CLASS: 'class', PROPERTY: 'property', ACTION: 'action', TIMESTAMP: 'timestamp', CREATED: 'created', UPDATED: 'updated', REMOVED: 'removed', TOTAL: 'total' }; static TableHeaders = { USER: 'User', CLASS: 'Class', PROPERTY: 'Property', ACTION: 'Action', TIME: 'Time', CREATED: 'Created', UPDATED: 'Updated', REMOVED: 'Removed', TOTAL: 'Total' }; static DefaultPage = 1; static DefaultPageSize = 50; static init(container, mode, page, pageSize) { return new Statistics(container, mode, page, pageSize).load(); } constructor(container, mode, page, pageSize) { this.mode = mode || Statistics.Modes.ALL; this.page = page || Statistics.DefaultPage; this.pageSize = pageSize || Statistics.DefaultPageSize; this.container = DOM.create({ tag: DOM.Tags.Div, cls: 'statistics-module' }, container); this.statistics = []; this.pagers = []; this.pagerPages = []; this.pagerPageSizeSelectors = []; } renderStatistics() { if(this.statisticsTable) this.statisticsTable.remove(); const table = this.statisticsTable = DOM.create({ tag: DOM.Tags.Table, cls: 'statistics-table' }); const headers = this.statisticsTableHeaders = DOM.create({ tag: DOM.Tags.Tr }, table); const tbody = this.statisticsTableTbody = DOM.create({ tag: DOM.Tags.Tbody }, table); if(!this.isAllMode()) { if(this.isUserMode()) DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.CLASS }, headers); else DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.USER }, headers); DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.PROPERTY }, headers); DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.ACTION }, headers); DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.TIME }, headers); for(const statRow of this.statistics) { const row = DOM.create({ tag: DOM.Tags.Tr }, tbody); if(this.isUserMode()) { const classLink = DOM.create({ tag: DOM.Tags.A, innerHTML: statRow[Statistics.RowFields.CLASS], attr: { 'href': `/class/${statRow[Statistics.RowFields.CLASS]}` } }); DOM.create({ tag: DOM.Tags.Td, cn: [classLink] }, row); } else { const userLink = DOM.create({ tag: DOM.Tags.A, innerHTML: statRow[Statistics.RowFields.USER], attr: { 'href': `/statistics/${statRow[Statistics.RowFields.USER]}` } }); DOM.create({ tag: DOM.Tags.Td, cn: [userLink] }, row); } DOM.create({ tag: DOM.Tags.Td, innerHTML: statRow[Statistics.RowFields.PROPERTY] }, row); DOM.create({ tag: DOM.Tags.Td, innerHTML: statRow[Statistics.RowFields.ACTION] }, row); DOM.create({ tag: DOM.Tags.Td, innerHTML: CDUtils.dateFormatUTC(parseInt(statRow[Statistics.RowFields.TIMESTAMP]), 3, 'D.M.Y, H:I:S') }, row); } } else { DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.USER }, headers); DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.CREATED }, headers); DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.UPDATED }, headers); DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.REMOVED }, headers); DOM.create({ tag: DOM.Tags.Th, innerHTML: Statistics.TableHeaders.TOTAL }, headers); for(const statRow of this.statistics) { const row = DOM.create({ tag: DOM.Tags.Tr }, tbody); const userLink = DOM.create({ tag: DOM.Tags.A, innerHTML: statRow[Statistics.RowFields.USER], attr: { 'href': `/statistics/${statRow[Statistics.RowFields.USER]}` } }); DOM.create({ tag: DOM.Tags.Td, cn: [userLink] }, row); DOM.create({ tag: DOM.Tags.Td, innerHTML: statRow[Statistics.RowFields.CREATED] }, row); DOM.create({ tag: DOM.Tags.Td, innerHTML: statRow[Statistics.RowFields.UPDATED] }, row); DOM.create({ tag: DOM.Tags.Td, innerHTML: statRow[Statistics.RowFields.REMOVED] }, row); DOM.create({ tag: DOM.Tags.Td, innerHTML: statRow[Statistics.RowFields.TOTAL] }, row); } } this.container.append(this.statisticsTable); return this; } renderPager(pagerIndex) { if(this.pagers[pagerIndex]) { this.pagerPages[pagerIndex].forEach((page) => { page.un(DOM.Events.Click, this.onPageClick.bind(this)); page.remove(); }); const selector = this.pagerPageSizeSelectors[pagerIndex]; selector.un(DOM.Events.Change, this.onPageSizeSelectChange.bind(this)); selector.remove(); this.pagers[pagerIndex].remove(); } const page = this.page; const pageCount = this.pageCount; const pager = this.pagers[pagerIndex] = DOM.create({ tag: DOM.Tags.Div, cls: 'statistics-pager' }); const pagerPages = this.pagerPages[pagerIndex] = []; pager.append(DOM.create({ tag: DOM.Tags.Span, innerHTML: 'Page:', cls: 'pager-page-label' })); const startPage = Math.max(1, page - 2); const endPage = Math.min(pageCount > 0 ? pageCount : 1, page + 2); if(startPage > 1) { const firstPage = DOM.create({ tag: DOM.Tags.Span, innerHTML: 1, cls: 'pager-page' }).on(DOM.Events.Click, this.onPageClick.bind(this)); pagerPages.push(firstPage); pager.append(firstPage); pager.append(DOM.create({ tag: DOM.Tags.Span, innerHTML: '..' })); } for (let i = startPage; i <= endPage; i++) { const pageElement = DOM.create({ tag: DOM.Tags.Span, innerHTML: i, cls: 'pager-page' }); if(page === i) { pageElement.addClass('current'); } else { pageElement.on(DOM.Events.Click, this.onPageClick.bind(this)); pagerPages.push(pageElement); } pager.append(pageElement); } if(endPage < pageCount) { pager.append(DOM.create({ tag: DOM.Tags.Span, innerHTML: '..' })); const lastPage = DOM.create({ tag: DOM.Tags.Span, innerHTML: pageCount, cls: 'pager-page' }).on(DOM.Events.Click, this.onPageClick.bind(this)); pager.append(lastPage); pagerPages.push(lastPage); } const pageSizeSelector = DOM.create({ tag: DOM.Tags.Select, cls: 'pager-page-size-selector', cn: [ DOM.create({ tag: DOM.Tags.Option, innerHTML: '1', attr: { 'selected': (this.pageSize === 1 ? 'selected' : undefined) } }), DOM.create({ tag: DOM.Tags.Option, innerHTML: '5', attr: { 'selected': (this.pageSize === 5 ? 'selected' : undefined) } }), DOM.create({ tag: DOM.Tags.Option, innerHTML: '25', attr: { 'selected': (this.pageSize === 25 ? 'selected' : undefined) } }), DOM.create({ tag: DOM.Tags.Option, innerHTML: '50', attr: { 'selected': (this.pageSize === 50 ? 'selected' : undefined) } }), DOM.create({ tag: DOM.Tags.Option, innerHTML: '100', attr: { 'selected': (this.pageSize === 100 ? 'selected' : undefined) } }), DOM.create({ tag: DOM.Tags.Option, innerHTML: '500', attr: { 'selected': (this.pageSize === 500 ? 'selected' : undefined) } }) ]}); pageSizeSelector.on(DOM.Events.Change, this.onPageSizeSelectChange.bind(this)); pager.append(DOM.create({ tag: DOM.Tags.Span, innerHTML: '|' })); pager.append(DOM.create({ tag: DOM.Tags.Span, innerHTML: 'Page size:', cls: 'pager-page-size-label' })); pager.append(pageSizeSelector); this.pagerPageSizeSelectors[pagerIndex] = pageSizeSelector; this.container.append(pager); } onPageSizeSelectChange(e) { this.page = Statistics.DefaultPage; this.pageSize = parseInt(CDElement.get(e.target).getValue()); this.load(); } onPageClick(e) { this.page = parseInt(CDElement.get(e.target).getValue()); this.load(); } isAllMode() { return this.mode === Statistics.Modes.ALL; } isUserMode() { return this.mode === Statistics.Modes.USER; } isClassMode() { return this.mode === Statistics.Modes.CLASS; } load() { let url = '/data/statistics'; if(this.isUserMode()) url = `/data/statistics/user/${StatisticsUser}`; if(this.isClassMode()) url = `/data/statistics/class/${Class.name}`; fetch(`${url}?page=${this.page}&pageSize=${this.pageSize}`, { method: 'GET' }).then(res => res.json()).then(res => { this.statistics = res[Statistics.Response.RECORDS]; this.pageCount = Math.ceil(res[Statistics.Response.COUNT] / this.pageSize); this.renderPager(0); // top this.renderStatistics(); this.renderPager(1); // bottom }); return this; } }