mirror of
https://github.com/frappe/books.git
synced 2024-11-09 23:30:56 +00:00
added text, select controls and fixes to form.js
This commit is contained in:
parent
d9e306b641
commit
234eb9dea1
@ -5,6 +5,9 @@ class RESTClient {
|
||||
constructor({server, protocol='http', fetch}) {
|
||||
this.server = server;
|
||||
this.protocol = protocol;
|
||||
|
||||
this.init_type_map();
|
||||
|
||||
frappe.fetch = fetch;
|
||||
this.json_headers = {
|
||||
'Accept': 'application/json',
|
||||
@ -78,6 +81,36 @@ class RESTClient {
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
init_type_map() {
|
||||
this.type_map = {
|
||||
'Currency': true
|
||||
,'Int': true
|
||||
,'Float': true
|
||||
,'Percent': true
|
||||
,'Check': true
|
||||
,'Small Text': true
|
||||
,'Long Text': true
|
||||
,'Code': true
|
||||
,'Text Editor': true
|
||||
,'Date': true
|
||||
,'Datetime': true
|
||||
,'Time': true
|
||||
,'Text': true
|
||||
,'Data': true
|
||||
,'Link': true
|
||||
,'Dynamic Link':true
|
||||
,'Password': true
|
||||
,'Select': true
|
||||
,'Read Only': true
|
||||
,'Attach': true
|
||||
,'Attach Image':true
|
||||
,'Signature': true
|
||||
,'Color': true
|
||||
,'Barcode': true
|
||||
,'Geolocation': true
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ class sqliteDatabase {
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
this.conn = new sqlite3.Database(this.db_path, () => {
|
||||
// debug
|
||||
// this.conn.on('trace', (trace) => console.log(trace));
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
@ -32,10 +34,14 @@ class sqliteDatabase {
|
||||
async create_table(doctype) {
|
||||
let meta = frappe.get_meta(doctype);
|
||||
let columns = [];
|
||||
let values = [];
|
||||
|
||||
for (let df of this.get_fields(meta)) {
|
||||
if (this.type_map[df.fieldtype]) {
|
||||
columns.push(`${df.fieldname} ${this.type_map[df.fieldtype]} ${df.reqd ? "not null" : ""} ${df.default ? ("default " + frappe.sqlescape(df.default)) : ""}`);
|
||||
columns.push(`${df.fieldname} ${this.type_map[df.fieldtype]} ${df.reqd ? "not null" : ""} ${df.default ? "default ?" : ""}`);
|
||||
if (df.default) {
|
||||
values.push(df.default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,18 +76,29 @@ class sqliteDatabase {
|
||||
}
|
||||
|
||||
async insert(doctype, doc) {
|
||||
let placeholders = Object.keys(doc).map(d => '?').join(', ');
|
||||
return await this.run(`insert into ${frappe.slug(doctype)}
|
||||
(${Object.keys(doc).join(", ")})
|
||||
values (${Object.values(doc).map(d => frappe.db.escape(d)).join(", ")})`);
|
||||
values (${placeholders})`, this.get_formatted_values(doc));
|
||||
}
|
||||
|
||||
async update(doctype, doc) {
|
||||
let assigns = [];
|
||||
for (let key in doc) {
|
||||
assigns.push(`${key} = ${this.escape(doc[key])}`);
|
||||
}
|
||||
let assigns = Object.keys(doc).map(key => `${key} = ?`);
|
||||
let values = this.get_formatted_values(doc);
|
||||
values.push(doc.name);
|
||||
|
||||
return await this.run(`update ${frappe.slug(doctype)}
|
||||
set ${assigns.join(", ")}`);
|
||||
set ${assigns.join(", ")} where name=?`, values);
|
||||
}
|
||||
|
||||
get_formatted_values(doc) {
|
||||
return Object.values(doc).map(value => {
|
||||
if (value instanceof Date) {
|
||||
return value.toISOString();
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async delete(doctype, name) {
|
||||
@ -89,14 +106,20 @@ class sqliteDatabase {
|
||||
}
|
||||
|
||||
get_all({doctype, fields=['name'], filters, start, limit, order_by='modified', order='desc'} = {}) {
|
||||
return new Promise(resolve => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let conditions = this.get_filter_conditions(filters);
|
||||
|
||||
this.conn.all(`select ${fields.join(", ")}
|
||||
from ${frappe.slug(doctype)}
|
||||
${filters ? "where" : ""} ${this.get_filter_conditions(filters)}
|
||||
${conditions.conditions ? "where" : ""} ${conditions.conditions}
|
||||
${order_by ? ("order by " + order_by) : ""} ${order_by ? (order || "asc") : ""}
|
||||
${limit ? ("limit " + limit) : ""} ${start ? ("offset " + start) : ""}`,
|
||||
${limit ? ("limit " + limit) : ""} ${start ? ("offset " + start) : ""}`, conditions.values,
|
||||
(err, rows) => {
|
||||
resolve(rows);
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rows);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -106,22 +129,27 @@ class sqliteDatabase {
|
||||
// {"status": "Open", "name": ["like", "apple%"]}
|
||||
// => `status="Open" and name like "apple%"
|
||||
let conditions = [];
|
||||
let values = [];
|
||||
for (let key in filters) {
|
||||
const value = filters[key];
|
||||
if (value instanceof Array) {
|
||||
conditions.push(`${key} ${value[0]} ${this.escape(value)}`);
|
||||
conditions.push(`${key} ${value[0]} ?`);
|
||||
} else {
|
||||
conditions.push(`${key} = ${this.escape(value)}`);
|
||||
conditions.push(`${key} = ?`);
|
||||
}
|
||||
values.push(value);
|
||||
}
|
||||
return conditions.join(" and ");
|
||||
return {
|
||||
conditions: conditions.length ? conditions.join(" and ") : "",
|
||||
values: values
|
||||
};
|
||||
}
|
||||
|
||||
run(query, params) {
|
||||
//console.log(query);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.conn.run(query, params, (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
@ -131,7 +159,6 @@ class sqliteDatabase {
|
||||
}
|
||||
|
||||
sql(query, params) {
|
||||
//console.log(query);
|
||||
return new Promise((resolve) => {
|
||||
this.conn.all(query, params, (err, rows) => {
|
||||
resolve(rows);
|
||||
@ -163,10 +190,6 @@ class sqliteDatabase {
|
||||
return row.length ? row[0][fieldname] : null;
|
||||
}
|
||||
|
||||
escape(value) {
|
||||
return frappe.sqlescape(value);
|
||||
}
|
||||
|
||||
get_fields(meta) {
|
||||
// add standard fields
|
||||
let fields = frappe.model.standard_fields.slice();
|
||||
|
@ -18,6 +18,7 @@ module.exports = {
|
||||
|
||||
frappe.view.init({container: container});
|
||||
frappe.router = new Router();
|
||||
await frappe.login();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,10 @@ module.exports = {
|
||||
return element;
|
||||
},
|
||||
|
||||
remove(element) {
|
||||
element.parentNode.removeChild(element);
|
||||
},
|
||||
|
||||
add_class(element, className) {
|
||||
if (element.classList) {
|
||||
element.classList.add(className);
|
||||
|
@ -38,6 +38,7 @@ class BaseControl {
|
||||
this.make_form_group();
|
||||
this.make_label();
|
||||
this.make_input();
|
||||
this.set_input_name();
|
||||
this.make_description();
|
||||
this.bind_change_event();
|
||||
}
|
||||
@ -54,7 +55,10 @@ class BaseControl {
|
||||
|
||||
make_input() {
|
||||
this.input = frappe.ui.add('input', 'form-control', this.form_group);
|
||||
this.input.setAttribute('type', this.fieldname);
|
||||
}
|
||||
|
||||
set_input_name() {
|
||||
this.input.setAttribute('name', this.fieldname);
|
||||
}
|
||||
|
||||
make_description() {
|
||||
@ -65,6 +69,9 @@ class BaseControl {
|
||||
}
|
||||
|
||||
set_input_value(value) {
|
||||
if (value === undefined || value === null) {
|
||||
value = '';
|
||||
}
|
||||
this.input.value = value;
|
||||
}
|
||||
|
||||
@ -76,8 +83,12 @@ class BaseControl {
|
||||
return value;
|
||||
}
|
||||
|
||||
async validate(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
bind_change_event() {
|
||||
this.input.addEventListener('change', () => this.handle_change(e));
|
||||
this.input.addEventListener('change', (e) => this.handle_change(e));
|
||||
}
|
||||
|
||||
async handle_change(e) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
const control_classes = {
|
||||
Data: require('./data')
|
||||
Data: require('./data'),
|
||||
Text: require('./text'),
|
||||
Select: require('./select')
|
||||
}
|
||||
|
||||
|
||||
|
24
frappe/client/view/controls/select.js
Normal file
24
frappe/client/view/controls/select.js
Normal file
@ -0,0 +1,24 @@
|
||||
const BaseControl = require('./base');
|
||||
|
||||
class SelectControl extends BaseControl {
|
||||
make_input() {
|
||||
this.input = frappe.ui.add('select', 'form-control', this.form_group);
|
||||
|
||||
let options = this.options;
|
||||
if (typeof options==='string') {
|
||||
options = options.split('\n');
|
||||
}
|
||||
|
||||
for (let value of options) {
|
||||
let option = frappe.ui.add('option', null, this.input);
|
||||
option.textContent = value;
|
||||
option.setAttribute('value', value);
|
||||
}
|
||||
}
|
||||
make() {
|
||||
super.make();
|
||||
this.input.setAttribute('row', '3');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = SelectControl;
|
13
frappe/client/view/controls/text.js
Normal file
13
frappe/client/view/controls/text.js
Normal file
@ -0,0 +1,13 @@
|
||||
const BaseControl = require('./base');
|
||||
|
||||
class TextControl extends BaseControl {
|
||||
make_input() {
|
||||
this.input = frappe.ui.add('textarea', 'form-control', this.form_group);
|
||||
}
|
||||
make() {
|
||||
super.make();
|
||||
this.input.setAttribute('rows', '8');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = TextControl;
|
@ -26,19 +26,33 @@ class Form {
|
||||
}
|
||||
|
||||
make_submit() {
|
||||
this.submit_btn = frappe.ui.add('button', 'btn btn-primary', this.body);
|
||||
this.submit_btn = frappe.ui.add('button', 'btn btn-outline-primary', this.body);
|
||||
this.submit_btn.setAttribute('type', 'submit');
|
||||
this.submit_btn.textContent = this.submit_label;
|
||||
this.submit_btn.addEventListener('click', (event) => {
|
||||
this.submit();
|
||||
event.preventDefault();
|
||||
})
|
||||
}
|
||||
|
||||
show_alert(message, type) {
|
||||
this.alert = frappe.ui.add('div', `alert alert-${type}`, this.body);
|
||||
this.alert.textContent = message;
|
||||
}
|
||||
|
||||
clear_alert() {
|
||||
if (this.alert) {
|
||||
frappe.ui.remove(this.alert);
|
||||
this.alert = null;
|
||||
}
|
||||
}
|
||||
|
||||
async use(doc, is_new = false) {
|
||||
if (this.doc) {
|
||||
// clear handlers of outgoing doc
|
||||
this.doc.clear_handlers();
|
||||
}
|
||||
this.clear_alert();
|
||||
this.doc = doc;
|
||||
this.is_new = is_new;
|
||||
for (let control of this.controls_list) {
|
||||
@ -47,12 +61,17 @@ class Form {
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (this.is_new) {
|
||||
await this.doc.insert();
|
||||
} else {
|
||||
await this.doc.update();
|
||||
try {
|
||||
if (this.is_new) {
|
||||
await this.doc.insert();
|
||||
} else {
|
||||
await this.doc.update();
|
||||
}
|
||||
await this.refresh();
|
||||
this.show_alert('Saved', 'success');
|
||||
} catch (e) {
|
||||
this.show_alert('Failed', 'danger');
|
||||
}
|
||||
await this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
|
@ -8,7 +8,7 @@ class todo_meta extends frappe.meta.Meta {
|
||||
}
|
||||
|
||||
get_row_html(data) {
|
||||
return `<a href="#todo/${data.name}">${data.subject}</a>`;
|
||||
return `<a href="#edit/todo/${data.name}">${data.subject}</a>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ backends.sqllite = require('frappe-core/frappe/backends/sqlite');
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const frappe = require('frappe-core');
|
||||
const rest_server = require('frappe-core/frappe/server/rest_server')
|
||||
const rest_api = require('./rest_api')
|
||||
const models = require('frappe-core/frappe/server/models');
|
||||
const common = require('frappe-core/frappe/common');
|
||||
const bodyParser = require('body-parser');
|
||||
@ -33,8 +33,12 @@ module.exports = {
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
app.use(express.static('./'));
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
console.error(err.stack);
|
||||
res.status(500).send('Something broke!');
|
||||
})
|
||||
// routes
|
||||
rest_server.setup(app);
|
||||
rest_api.setup(app);
|
||||
|
||||
// listen
|
||||
frappe.app = app;
|
||||
|
61
frappe/server/rest_api.js
Normal file
61
frappe/server/rest_api.js
Normal file
@ -0,0 +1,61 @@
|
||||
const frappe = require('frappe-core');
|
||||
|
||||
module.exports = {
|
||||
setup(app) {
|
||||
// get list
|
||||
app.get('/api/resource/:doctype', frappe.async_handler(async function(request, response) {
|
||||
let fields, filters;
|
||||
for (key of ['fields', 'filters']) {
|
||||
if (request.params[key]) {
|
||||
request.params[key] = JSON.parse(request.params[key]);
|
||||
}
|
||||
}
|
||||
|
||||
let data = await frappe.db.get_all({
|
||||
doctype: request.params.doctype,
|
||||
fields: request.params.fields || ['name', 'subject'],
|
||||
filters: request.params.filters,
|
||||
start: request.params.start || 0,
|
||||
limit: request.params.limit || 20,
|
||||
order_by: request.params.order_by,
|
||||
order: request.params.order
|
||||
});
|
||||
|
||||
return response.json(data);
|
||||
}));
|
||||
|
||||
// create
|
||||
app.post('/api/resource/:doctype', frappe.async_handler(async function(request, response) {
|
||||
data = request.body;
|
||||
data.doctype = request.params.doctype;
|
||||
let doc = await frappe.get_doc(data);
|
||||
await doc.insert();
|
||||
await frappe.db.commit();
|
||||
return response.json(doc.get_valid_dict());
|
||||
}));
|
||||
|
||||
// update
|
||||
app.put('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) {
|
||||
data = request.body;
|
||||
let doc = await frappe.get_doc(request.params.doctype, request.params.name);
|
||||
Object.assign(doc, data);
|
||||
await doc.update();
|
||||
await frappe.db.commit();
|
||||
return response.json(doc.get_valid_dict());
|
||||
}));
|
||||
|
||||
|
||||
// get document
|
||||
app.get('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) {
|
||||
let doc = await frappe.get_doc(request.params.doctype, request.params.name);
|
||||
return response.json(doc.get_valid_dict());
|
||||
}));
|
||||
|
||||
// delete
|
||||
app.delete('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) {
|
||||
let doc = await frappe.get_doc(request.params.doctype, request.params.name)
|
||||
await doc.delete();
|
||||
return response.json({});
|
||||
}));
|
||||
}
|
||||
};
|
@ -1,82 +0,0 @@
|
||||
const frappe = require('frappe-core');
|
||||
|
||||
module.exports = {
|
||||
setup(app) {
|
||||
// get list
|
||||
app.get('/api/resource/:doctype', async function(request, response) {
|
||||
try {
|
||||
let fields, filters;
|
||||
for (key of ['fields', 'filters']) {
|
||||
if (request.params[key]) {
|
||||
request.params[key] = JSON.parse(request.params[key]);
|
||||
}
|
||||
}
|
||||
|
||||
let data = await frappe.db.get_all({
|
||||
doctype: request.params.doctype,
|
||||
fields: request.params.fields || ['name', 'subject'],
|
||||
filters: request.params.filters,
|
||||
start: request.params.start || 0,
|
||||
limit: request.params.limit || 20,
|
||||
order_by: request.params.order_by,
|
||||
order: request.params.order
|
||||
});
|
||||
|
||||
return response.json(data);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
// create
|
||||
app.post('/api/resource/:doctype', async function(request, response) {
|
||||
try {
|
||||
data = request.body;
|
||||
data.doctype = request.params.doctype;
|
||||
let doc = await frappe.get_doc(data);
|
||||
await doc.insert();
|
||||
await frappe.db.commit();
|
||||
return response.json(doc.get_valid_dict());
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
// update
|
||||
app.put('/api/resource/:doctype/:name', async function(request, response) {
|
||||
try {
|
||||
data = request.body;
|
||||
let doc = await frappe.get_doc(request.params.doctype, request.params.name);
|
||||
Object.assign(doc, data);
|
||||
await doc.update();
|
||||
await frappe.db.commit();
|
||||
return response.json(doc.get_valid_dict());
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// get document
|
||||
app.get('/api/resource/:doctype/:name', async function(request, response) {
|
||||
try {
|
||||
let doc = await frappe.get_doc(request.params.doctype, request.params.name);
|
||||
return response.json(doc.get_valid_dict());
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
// delete
|
||||
app.delete('/api/resource/:doctype/:name', async function(request, response) {
|
||||
try {
|
||||
let doc = await frappe.get_doc(request.params.doctype, request.params.name)
|
||||
await doc.delete();
|
||||
return response.json({});
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
@ -2,24 +2,12 @@ module.exports = {
|
||||
slug(text) {
|
||||
return text.toLowerCase().replace(/ /g, '_');
|
||||
},
|
||||
sqlescape(value) {
|
||||
if (value===null || value===undefined) {
|
||||
// null
|
||||
return 'null';
|
||||
|
||||
} else if (value instanceof Date) {
|
||||
// date
|
||||
return `'${value.toISOString()}'`;
|
||||
|
||||
} else if (typeof value==='string') {
|
||||
// text
|
||||
return "'" + value.replace(/'/g, '\'').replace(/"/g, '\"') + "'";
|
||||
|
||||
} else {
|
||||
// number
|
||||
return value + '';
|
||||
}
|
||||
async_handler(fn) {
|
||||
return (req, res, next) => Promise.resolve(fn(req, res, next))
|
||||
.catch(next);
|
||||
},
|
||||
|
||||
async sleep(seconds) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, seconds * 1000);
|
||||
|
Loading…
Reference in New Issue
Block a user