2
0
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:
Rushabh Mehta 2018-01-11 15:30:51 +05:30
parent 9ae2b84805
commit f89c6e778e
27 changed files with 269 additions and 46 deletions

View File

@ -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

View File

@ -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();

View 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;

View File

@ -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});
}
}

View File

@ -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;
}

View File

@ -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 = {

View 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();
```

View 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);
```

View File

@ -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)

View File

@ -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());

View File

@ -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);

View File

@ -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'}
});
}

View File

@ -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);

View File

@ -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'}});
}