mirror of
https://github.com/frappe/books.git
synced 2024-11-08 14:50:56 +00:00
dropdown object and delete action in form
This commit is contained in:
parent
9ae2b84805
commit
f89c6e778e
@ -41,16 +41,18 @@ class RESTClient {
|
||||
|
||||
async get_all({doctype, fields, filters, start, limit, sort_by, order}) {
|
||||
let url = this.protocol + '://' + path.join(this.server, `/api/resource/${frappe.slug(doctype)}`);
|
||||
|
||||
url = url + "?" + this.get_query_string({
|
||||
fields: JSON.stringify(fields),
|
||||
filters: JSON.stringify(filters),
|
||||
start: start,
|
||||
limit: limit,
|
||||
sort_by: sort_by,
|
||||
order: order
|
||||
});
|
||||
|
||||
let response = await frappe.fetch(url, {
|
||||
method: 'GET',
|
||||
params: {
|
||||
fields: JSON.stringify(fields),
|
||||
filters: JSON.stringify(filters),
|
||||
start: start,
|
||||
limit: limit,
|
||||
sort_by: sort_by,
|
||||
order: order
|
||||
},
|
||||
headers: this.json_headers
|
||||
});
|
||||
return await response.json();
|
||||
@ -80,6 +82,13 @@ class RESTClient {
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
get_query_string(params) {
|
||||
return Object.keys(params)
|
||||
.map(k => params[k] != null ? encodeURIComponent(k) + '=' + encodeURIComponent(params[k]) : null)
|
||||
.filter(v => v)
|
||||
.join('&');
|
||||
}
|
||||
|
||||
init_type_map() {
|
||||
this.type_map = {
|
||||
'Currency': true
|
||||
|
@ -11,10 +11,8 @@ module.exports = {
|
||||
frappe.init();
|
||||
common.init_libs(frappe);
|
||||
|
||||
frappe.db = await new Database({
|
||||
server: server,
|
||||
fetch: window.fetch.bind()
|
||||
});
|
||||
frappe.fetch = window.fetch.bind();
|
||||
frappe.db = await new Database({server: server});
|
||||
|
||||
frappe.view.init({container: container});
|
||||
frappe.router = new Router();
|
||||
|
89
frappe/client/ui/dropdown.js
Normal file
89
frappe/client/ui/dropdown.js
Normal file
@ -0,0 +1,89 @@
|
||||
const frappe = require('frappe-core');
|
||||
|
||||
class Dropdown {
|
||||
constructor({parent, label, btn_class = 'btn-secondary', items = []}) {
|
||||
Object.assign(this, arguments[0]);
|
||||
|
||||
this.dropdown_items = [];
|
||||
this.setup_background_click();
|
||||
this.make();
|
||||
|
||||
// init items
|
||||
if (this.items) {
|
||||
for (item of this.items) {
|
||||
this.add_item(item.label, item.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setup_background_click() {
|
||||
if (!document.dropdown_setup) {
|
||||
frappe.dropdowns = [];
|
||||
// setup hiding all dropdowns on click
|
||||
document.addEventListener('click', (event) => {
|
||||
for (let d of frappe.dropdowns) {
|
||||
if (d.button !== event.target) {
|
||||
d.collapse();
|
||||
}
|
||||
}
|
||||
});
|
||||
document.dropdown_setup = true;
|
||||
}
|
||||
frappe.dropdowns.push(this);
|
||||
}
|
||||
|
||||
make() {
|
||||
this.dropdown = frappe.ui.add('div', 'dropdown', this.parent);
|
||||
this.make_button();
|
||||
this.dropdown_menu = frappe.ui.add('div', 'dropdown-menu', this.dropdown);
|
||||
}
|
||||
|
||||
make_button() {
|
||||
this.button = frappe.ui.add('button', 'btn ' + this.btn_class,
|
||||
this.dropdown);
|
||||
frappe.ui.add_class(this.button, 'dropdown-toggle');
|
||||
this.button.textContent = this.label;
|
||||
this.button.addEventListener('click', () => {
|
||||
this.toggle();
|
||||
});
|
||||
}
|
||||
|
||||
expand() {
|
||||
this.dropdown.classList.add('show');
|
||||
this.dropdown_menu.classList.add('show');
|
||||
}
|
||||
|
||||
collapse() {
|
||||
this.dropdown.classList.remove('show');
|
||||
this.dropdown_menu.classList.remove('show');
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.dropdown.classList.toggle('show');
|
||||
this.dropdown_menu.classList.toggle('show');
|
||||
}
|
||||
|
||||
add_item(label, action) {
|
||||
let item = frappe.ui.add('a', 'dropdown-item', this.dropdown_menu);
|
||||
item.textContent = label;
|
||||
if (typeof action === 'string') {
|
||||
item.src = action;
|
||||
item.addEventListener('click', () => {
|
||||
this.toggle();
|
||||
});
|
||||
} else {
|
||||
item.addEventListener('click', async () => {
|
||||
await action();
|
||||
this.toggle();
|
||||
});
|
||||
}
|
||||
this.dropdown_items.push(item);
|
||||
}
|
||||
|
||||
float_right() {
|
||||
frappe.ui.add_class(this.dropdown, 'float-right');
|
||||
frappe.ui.add_class(this.dropdown_menu, 'dropdown-menu-right');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Dropdown;
|
@ -1,4 +1,5 @@
|
||||
const frappe = require('frappe-core');
|
||||
const Dropdown = require('./dropdown');
|
||||
|
||||
module.exports = {
|
||||
add(tag, className, parent) {
|
||||
@ -32,6 +33,14 @@ module.exports = {
|
||||
} else {
|
||||
element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
|
||||
}
|
||||
},
|
||||
|
||||
toggle(element, default_display = '') {
|
||||
element.style.display = element.style.display === 'none' ? default_display : 'none';
|
||||
},
|
||||
|
||||
make_dropdown(label, parent, btn_class = 'btn-secondary') {
|
||||
return new Dropdown({parent: parent, label:label, btn_class:btn_class});
|
||||
}
|
||||
|
||||
}
|
@ -18,10 +18,14 @@ class Form {
|
||||
if (this.body || !this.parent) {
|
||||
return;
|
||||
}
|
||||
this.body = frappe.ui.add('form', null, this.parent);
|
||||
|
||||
this.body = frappe.ui.add('div', 'form-body', this.parent);
|
||||
this.make_actions();
|
||||
|
||||
this.form = frappe.ui.add('form', null, this.body);
|
||||
for(let df of this.meta.fields) {
|
||||
if (controls.get_control_class(df.fieldtype)) {
|
||||
let control = controls.make_control(df, this.body);
|
||||
let control = controls.make_control(df, this.form);
|
||||
this.controls_list.push(control);
|
||||
this.controls[df.fieldname] = control;
|
||||
}
|
||||
@ -29,8 +33,22 @@ class Form {
|
||||
this.make_submit();
|
||||
}
|
||||
|
||||
make_actions() {
|
||||
this.toolbar = frappe.ui.add('div', 'form-toolbar', this.body);
|
||||
this.actions = frappe.ui.make_dropdown('Actions', this.toolbar);
|
||||
|
||||
// delete
|
||||
this.actions.add_item('Delete', async () => {
|
||||
await this.doc.delete();
|
||||
this.show_alert('Deleted', 'success');
|
||||
});
|
||||
|
||||
this.actions.float_right();
|
||||
}
|
||||
|
||||
make_submit() {
|
||||
this.submit_btn = frappe.ui.add('button', 'btn btn-outline-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) => {
|
||||
@ -40,6 +58,7 @@ class Form {
|
||||
}
|
||||
|
||||
show_alert(message, type) {
|
||||
this.clear_alert();
|
||||
this.alert = frappe.ui.add('div', `alert alert-${type}`, this.body);
|
||||
this.alert.textContent = message;
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
const frappe = require('frappe-core');
|
||||
|
||||
class ListView {
|
||||
constructor({doctype, parent}) {
|
||||
constructor({doctype, parent, fields}) {
|
||||
this.doctype = doctype;
|
||||
this.parent = parent;
|
||||
this.fields = fields;
|
||||
|
||||
this.meta = frappe.get_meta(this.doctype);
|
||||
|
||||
this.start = 0;
|
||||
@ -15,11 +17,16 @@ class ListView {
|
||||
|
||||
async run() {
|
||||
this.make_body();
|
||||
let data = await this.meta.get_list({start:this.start, limit:this.page_length});
|
||||
let data = await this.meta.get_list({
|
||||
start:this.start,
|
||||
limit:this.page_length
|
||||
});
|
||||
|
||||
for (let i=0; i< data.length; i++) {
|
||||
this.render_row(this.start + i, data[i]);
|
||||
}
|
||||
|
||||
this.clear_empty_rows(data.length);
|
||||
}
|
||||
|
||||
make_body() {
|
||||
@ -40,6 +47,15 @@ class ListView {
|
||||
return this.rows[i];
|
||||
}
|
||||
|
||||
clear_empty_rows(start) {
|
||||
if (this.rows.length > start) {
|
||||
for (let i=start; i < this.rows.length; i++) {
|
||||
let row = this.get_row(i);
|
||||
row.innerHTML = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
41
frappe/docs/client/ui/dropdown.md
Normal file
41
frappe/docs/client/ui/dropdown.md
Normal file
@ -0,0 +1,41 @@
|
||||
# Dropdown
|
||||
|
||||
Creates a Dropdown button with JS events
|
||||
|
||||
## API
|
||||
|
||||
Methods
|
||||
|
||||
- `add_item`
|
||||
- `float_right`
|
||||
- `expand`
|
||||
- `collapse`
|
||||
- `toggle`
|
||||
|
||||
## Usage
|
||||
|
||||
### Create
|
||||
|
||||
```js
|
||||
const Dropdown = require('frappe-core/frappe/client/ui/dropdown');
|
||||
|
||||
let dropdown = new Dropdown({label:'Actions', parent:this.toolbar});
|
||||
```
|
||||
|
||||
### Add Item
|
||||
|
||||
Add a new link to the dropdown
|
||||
|
||||
```js
|
||||
dropdown.add_item('Delete', async () => {
|
||||
this.show_alert('Deleted', 'success');
|
||||
});
|
||||
```
|
||||
|
||||
### Float Right
|
||||
|
||||
Move the element to the right
|
||||
|
||||
```js
|
||||
dropdown.float_right();
|
||||
```
|
35
frappe/docs/client/ui/index.md
Normal file
35
frappe/docs/client/ui/index.md
Normal file
@ -0,0 +1,35 @@
|
||||
# UI
|
||||
|
||||
Frappe.js UI library helps create elements from the Native DOM
|
||||
|
||||
### frappe.ui.add
|
||||
|
||||
Add a new HTMLElement
|
||||
|
||||
```js
|
||||
let div = frappe.ui.add('div', 'box', parentElement);
|
||||
```
|
||||
|
||||
### frappe.ui.remove
|
||||
|
||||
Remove a new HTMLElement from its parent
|
||||
|
||||
```js
|
||||
frappe.ui.remove(element);
|
||||
```
|
||||
|
||||
### frappe.ui.add_class
|
||||
|
||||
Add a class to an existing document
|
||||
|
||||
```js
|
||||
frappe.ui.add_class(element, 'box');
|
||||
```
|
||||
|
||||
### frappe.ui.make_dropdown
|
||||
|
||||
Create and return a new dropdown element
|
||||
|
||||
```js
|
||||
let dropdown = frappe.ui.make_dropdown('Actions', this.toolbar);
|
||||
```
|
@ -5,17 +5,19 @@ Frappe.js is a meta-data driven framework that enables rapid application develop
|
||||
## Contents
|
||||
|
||||
- Models and Documents
|
||||
- [Declaring Models](models.md)
|
||||
- [Controllers](controllers.md)
|
||||
- [Metadata](metadata.md)
|
||||
- [Managing Documents](document.md)
|
||||
- [Server](server.md)
|
||||
- [REST API](rest.md)
|
||||
- [Client](client.md)
|
||||
- [Routing](router.md)
|
||||
- [Page](page.md)
|
||||
- [Lists](lists.md)
|
||||
- [Forms](forms.md)
|
||||
- [Controls](controls.md)
|
||||
- [Declaring Models](models/index.md)
|
||||
- [Controllers](models/controllers.md)
|
||||
- [Metadata](models/metadata.md)
|
||||
- [Managing Documents](models/document.md)
|
||||
- [Server](server/index.md)
|
||||
- [REST API](server/rest.md)
|
||||
- [Client](client/index.md)
|
||||
- [Routing](client/router.md)
|
||||
- [Page](client/page.md)
|
||||
- [Lists](client/lists.md)
|
||||
- [Forms](client/forms.md)
|
||||
- [Controls](client/controls.md)
|
||||
- [UI](client/ui/index.md)
|
||||
- [Dropdown](client/ui/dropdown.md)
|
||||
- [Backends](backends.md)
|
||||
- [Testing](testing.md)
|
@ -1,5 +1,5 @@
|
||||
const backends = {};
|
||||
backends.sqllite = require('frappe-core/frappe/backends/sqlite');
|
||||
backends.sqlite = require('frappe-core/frappe/backends/sqlite');
|
||||
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
@ -20,13 +20,16 @@ module.exports = {
|
||||
|
||||
},
|
||||
|
||||
async start({backend, connection_params, static}) {
|
||||
await this.init();
|
||||
|
||||
// database
|
||||
async init_db({backend, connection_params}) {
|
||||
frappe.db = await new backends[backend].Database(connection_params);
|
||||
await frappe.db.connect();
|
||||
await frappe.db.migrate();
|
||||
},
|
||||
|
||||
async start({backend, connection_params, static}) {
|
||||
await this.init();
|
||||
await this.init_db({backend:backend, connection_params:connection_params});
|
||||
// database
|
||||
|
||||
// app
|
||||
app.use(bodyParser.json());
|
||||
|
@ -6,19 +6,19 @@ module.exports = {
|
||||
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]);
|
||||
if (request.query[key]) {
|
||||
request.query[key] = JSON.parse(request.query[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
|
||||
fields: request.query.fields || ['name', 'subject'],
|
||||
filters: request.query.filters,
|
||||
start: request.query.start || 0,
|
||||
limit: request.query.limit || 20,
|
||||
order_by: request.query.order_by,
|
||||
order: request.query.order
|
||||
});
|
||||
|
||||
return response.json(data);
|
||||
|
@ -2,8 +2,9 @@ const server = require('frappe-core/frappe/server');
|
||||
|
||||
module.exports = {
|
||||
async init_sqlite() {
|
||||
server.init({
|
||||
backend: 'sqllite',
|
||||
server.init()
|
||||
server.init_db({
|
||||
backend: 'sqlite',
|
||||
connection_params: {db_path: 'test.db'}
|
||||
});
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ describe('REST', () => {
|
||||
await frappe.init();
|
||||
await frappe.login();
|
||||
|
||||
frappe.db = await new Database({server: 'localhost:8000', fetch: fetch});
|
||||
frappe.db = await new Database({server: 'localhost:8000'});
|
||||
frappe.fetch = fetch;
|
||||
|
||||
// wait for server to start
|
||||
await frappe.sleep(1);
|
||||
|
@ -1,5 +1,5 @@
|
||||
const server = require('frappe-core/frappe/server');
|
||||
|
||||
if (require.main === module) {
|
||||
server.start({backend: 'sqllite', connection_params: {db_path: 'test.db'}});
|
||||
server.start({backend: 'sqlite', connection_params: {db_path: 'test.db'}});
|
||||
}
|
Loading…
Reference in New Issue
Block a user