2
0
mirror of https://github.com/frappe/books.git synced 2024-11-10 15:50:56 +00:00
books/client/view/list.js

269 lines
7.8 KiB
JavaScript
Raw Normal View History

2018-01-16 06:09:17 +00:00
const frappe = require('frappejs');
2018-02-20 06:39:41 +00:00
const keyboard = require('frappejs/client/ui/keyboard');
2018-01-12 12:25:07 +00:00
2018-01-24 11:52:05 +00:00
module.exports = class BaseList {
2018-02-08 09:38:47 +00:00
constructor({doctype, parent, fields, page}) {
Object.assign(this, arguments[0]);
2018-01-12 12:25:07 +00:00
this.meta = frappe.getMeta(this.doctype);
2018-01-12 12:25:07 +00:00
this.start = 0;
2018-02-08 09:38:47 +00:00
this.pageLength = 20;
2018-01-12 12:25:07 +00:00
this.body = null;
this.rows = [];
this.data = [];
2018-02-19 16:41:10 +00:00
frappe.db.on(`change:${this.doctype}`, (params) => {
this.dirty = true;
});
setInterval(() => {
if (this.dirty) this.refresh();
}, 500);
2018-01-12 12:25:07 +00:00
}
2018-02-20 06:39:41 +00:00
makeBody() {
if (!this.body) {
this.makeToolbar();
this.parent.classList.add('list-page');
this.body = frappe.ui.add('div', 'list-body', this.parent);
this.body.setAttribute('data-doctype', this.doctype);
this.makeMoreBtn();
this.bindKeys();
}
}
2018-02-08 09:38:47 +00:00
async refresh() {
return await this.run();
}
2018-01-12 12:25:07 +00:00
async run() {
2018-02-08 09:38:47 +00:00
this.makeBody();
2018-02-19 16:41:10 +00:00
this.dirty = false;
2018-01-12 12:25:07 +00:00
2018-02-08 09:38:47 +00:00
let data = await this.getData();
2018-01-12 12:25:07 +00:00
2018-02-08 09:38:47 +00:00
for (let i=0; i< Math.min(this.pageLength, data.length); i++) {
this.renderRow(this.start + i, data[i]);
2018-01-12 12:25:07 +00:00
}
if (this.start > 0) {
this.data = this.data.concat(data);
} else {
this.data = data;
}
2018-02-08 09:38:47 +00:00
this.clearEmptyRows();
this.updateMore(data.length > this.pageLength);
2018-02-20 06:39:41 +00:00
this.selectDefaultRow();
this.setActiveListRow();
2018-01-12 12:25:07 +00:00
}
2018-02-08 09:38:47 +00:00
async getData() {
return await frappe.db.getAll({
2018-01-24 11:52:05 +00:00
doctype: this.doctype,
2018-02-08 09:38:47 +00:00
fields: this.getFields(),
filters: this.getFilters(),
2018-01-24 11:52:05 +00:00
start: this.start,
2018-02-08 09:38:47 +00:00
limit: this.pageLength + 1
2018-01-24 11:52:05 +00:00
});
}
2018-02-08 09:38:47 +00:00
getFields() {
2018-01-24 11:52:05 +00:00
return ['name'];
}
2018-01-12 12:25:07 +00:00
async append() {
2018-02-08 09:38:47 +00:00
this.start += this.pageLength;
2018-01-12 12:25:07 +00:00
await this.run();
}
2018-02-08 09:38:47 +00:00
getFilters() {
2018-01-24 11:52:05 +00:00
let filters = {};
2018-02-08 09:38:47 +00:00
if (this.searchInput.value) {
filters.keywords = ['like', '%' + this.searchInput.value + '%'];
2018-01-12 12:25:07 +00:00
}
2018-01-24 11:52:05 +00:00
return filters;
2018-01-12 12:25:07 +00:00
}
2018-02-20 06:39:41 +00:00
renderRow(i, data) {
let row = this.getRow(i);
row.innerHTML = this.getRowBodyHTML(data);
row.docName = data.name;
row.setAttribute('data-name', data.name);
row.style.display = 'flex';
// make element focusable
row.setAttribute('tabindex', -1);
}
getRowBodyHTML(data) {
return `<div class="col-1">
<input class="checkbox" type="checkbox" data-name="${data.name}">
</div>` + this.getRowHTML(data);
}
getRowHTML(data) {
return `<div class="col-11">${data.name}</div>`;
}
getRow(i) {
if (!this.rows[i]) {
this.rows[i] = frappe.ui.add('div', 'list-row row no-gutters', this.body);
// open on click
let me = this;
this.rows[i].addEventListener('click', async function(e) {
if (!e.target.tagName !== 'input') {
await me.showItem(this.docName);
}
});
}
return this.rows[i];
}
async showItem(name) {
if (this.meta.print) {
await frappe.router.setRoute('print', this.doctype, name);
} else {
await frappe.router.setRoute('edit', this.doctype, name);
}
2018-02-20 06:39:41 +00:00
}
getCheckedRowNames() {
return [...this.body.querySelectorAll('.checkbox:checked')].map(check => check.getAttribute('data-name'));
}
clearEmptyRows() {
if (this.rows.length > this.data.length) {
for (let i=this.data.length; i < this.rows.length; i++) {
let row = this.getRow(i);
row.innerHTML = '';
row.style.display = 'none';
}
}
}
selectDefaultRow() {
if (!frappe.desk.body.activePage && this.rows.length) {
this.showItem(this.rows[0].docName);
2018-01-12 12:25:07 +00:00
}
}
2018-02-08 09:38:47 +00:00
makeToolbar() {
this.makeSearch();
2018-02-15 09:53:28 +00:00
this.btnNew = this.page.addButton(frappe._('New'), 'btn-primary', async () => {
await frappe.router.setRoute('new', this.doctype);
2018-02-08 09:38:47 +00:00
})
2018-02-15 09:53:28 +00:00
this.btnDelete = this.page.addButton(frappe._('Delete'), 'btn-secondary hide', async () => {
2018-02-08 09:38:47 +00:00
await frappe.db.deleteMany(this.doctype, this.getCheckedRowNames());
await this.refresh();
});
this.page.body.addEventListener('click', (event) => {
if(event.target.classList.contains('checkbox')) {
this.btnDelete.classList.toggle('hide', this.getCheckedRowNames().length===0);
}
})
}
makeSearch() {
2018-01-23 08:00:29 +00:00
this.toolbar = frappe.ui.add('div', 'list-toolbar', this.parent);
this.toolbar.innerHTML = `
2018-02-15 09:53:28 +00:00
<div class="input-group list-search">
<input class="form-control" type="text" placeholder="Search...">
<div class="input-group-append">
<button class="btn btn-outline-secondary btn-search">Search</button>
2018-01-23 08:00:29 +00:00
</div>
</div>
`;
2018-02-08 09:38:47 +00:00
this.searchInput = this.toolbar.querySelector('input');
this.searchInput.addEventListener('keypress', (event) => {
2018-01-12 12:25:07 +00:00
if (event.keyCode===13) {
2018-02-08 09:38:47 +00:00
this.refresh();
2018-01-12 12:25:07 +00:00
}
});
2018-02-08 09:38:47 +00:00
this.btnSearch = this.toolbar.querySelector('.btn-search');
this.btnSearch.addEventListener('click', (event) => {
this.refresh();
2018-01-12 12:25:07 +00:00
});
}
2018-02-20 06:39:41 +00:00
bindKeys() {
keyboard.bindKey(this.body, 'up', () => this.move('up'));
keyboard.bindKey(this.body, 'down', () => this.move('down'))
2018-02-20 06:39:41 +00:00
keyboard.bindKey(this.body, 'right', () => {
if (frappe.desk.body.activePage) {
frappe.desk.body.activePage.body.querySelector('input').focus();
}
});
keyboard.bindKey(this.body, 'n', (e) => {
frappe.router.setRoute('new', this.doctype);
e.preventDefault();
});
keyboard.bindKey(this.body, 'x', async (e) => {
let activeListRow = this.getActiveListRow();
if (activeListRow && activeListRow.docName) {
e.preventDefault();
await frappe.db.delete(this.doctype, activeListRow.docName);
frappe.desk.body.activePage.hide();
}
});
2018-02-20 06:39:41 +00:00
}
async move(direction) {
let elementRef = direction === 'up' ? 'previousSibling' : 'nextSibling';
if (document.activeElement && document.activeElement.classList.contains('list-row')) {
let next = document.activeElement[elementRef];
if (next && next.docName) {
await this.showItem(next.docName);
}
}
}
2018-02-08 09:38:47 +00:00
makeMoreBtn() {
this.btnMore = frappe.ui.add('button', 'btn btn-secondary hide', this.parent);
this.btnMore.textContent = 'More';
this.btnMore.addEventListener('click', () => {
2018-01-12 12:25:07 +00:00
this.append();
})
}
2018-02-20 06:39:41 +00:00
updateMore(show) {
if (show) {
this.btnMore.classList.remove('hide');
} else {
this.btnMore.classList.add('hide');
}
2018-01-24 11:52:05 +00:00
}
2018-02-20 06:39:41 +00:00
setActiveListRow(name) {
let activeListRow = this.getActiveListRow();
2018-02-20 06:39:41 +00:00
if (activeListRow) {
activeListRow.classList.remove('active');
2018-01-12 12:25:07 +00:00
}
2018-02-20 06:39:41 +00:00
if (!name) {
// get name from active page
name = frappe.desk.activeDoc && frappe.desk.activeDoc.name;
2018-02-20 06:39:41 +00:00
}
2018-02-08 09:38:47 +00:00
2018-02-20 06:39:41 +00:00
if (name) {
let myListRow = this.body.querySelector(`.list-row[data-name="${name}"]`);
if (myListRow) {
myListRow.classList.add('active');
myListRow.focus();
2018-01-12 12:25:07 +00:00
}
}
}
getActiveListRow() {
return this.body.querySelector('.list-row.active');
}
2018-01-12 12:25:07 +00:00
};