2
0
mirror of https://github.com/frappe/books.git synced 2024-11-08 14:50:56 +00:00

💥 frappejs

This commit is contained in:
Rushabh Mehta 2018-01-16 11:39:17 +05:30
parent df9fc91123
commit 328a9de7d4
45 changed files with 159 additions and 71 deletions

2
app.js
View File

@ -1,4 +1,4 @@
const server = require('frappe-core/server');
const server = require('frappejs/server');
server.start({
backend: 'sqllite',

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
const path = require('path');
module.exports = class RESTClient {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
const sqlite3 = require('sqlite3').verbose();
class sqliteDatabase {

View File

@ -1,9 +1,9 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
const Search = require('./search');
const Router = require('frappe-core/common/router');
const Page = require('frappe-core/client/view/page');
const List = require('frappe-core/client/view/list');
const Form = require('frappe-core/client/view/form');
const Router = require('frappejs/common/router');
const Page = require('frappejs/client/view/page');
const List = require('frappejs/client/view/list');
const Form = require('frappejs/client/view/form');
module.exports = class Desk {
constructor() {

10
client/desk/navbar.js Normal file
View File

@ -0,0 +1,10 @@
const frappe = require('frappejs');
module.exports = class Navbar {
constructor({brand_label = 'App'} = {}) {
Object.assign(this, arguments[0]);
this.navbar = frappe.ui.add('div', 'navbar', frappe.header);
this.brand = frappe.ui.add('div', 'navbar-brand', this.navbar);
this.brand.textContent = this.brand_label || 'App';
}
}

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
module.exports = class Search {
constructor(parent) {

View File

@ -1,6 +1,6 @@
const common = require('frappe-core/common');
const RESTClient = require('frappe-core/backends/rest_client');
const frappe = require('frappe-core');
const common = require('frappejs/common');
const RESTClient = require('frappejs/backends/rest_client');
const frappe = require('frappejs');
frappe.ui = require('./ui');
const Desk = require('./desk');

61
client/style/index.scss Normal file
View File

@ -0,0 +1,61 @@
@import "node_modules/bootstrap/scss/bootstrap";
// html {
// font-size: 14px;
// }
.desk {
padding: 0px;
}
.nav {
display: none;
border-bottom: 1px solid $border-color;
align-items: center;
justify-content: center;
}
.two-column {
display: grid;
grid-template-columns: 1fr 4fr;
grid-auto-rows: minmax(100%, auto);
}
.main, .sidebar {
padding: 2rem;
min-height: 100vh;
}
.sidebar {
border-right: 1px solid $border-color;
}
.hide {
display: none !important;
}
.page-error {
text-align: center;
padding: 200px 0px;
}
.form-body {
.form-toolbar {
height: 2rem;
margin-bottom: 1rem;
}
.alert {
margin-top: 1rem;
}
}
.dropdown-menu-right {
right: 0;
left: auto;
}
.list-search {
max-width: 400px;
margin-bottom: 1rem;
}

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
class Dropdown {
constructor({parent, label, btn_class = 'btn-secondary', items = []}) {
@ -64,11 +64,13 @@ class Dropdown {
}
add_item(label, action) {
let item = frappe.ui.add('a', 'dropdown-item', this.dropdown_menu);
let item = frappe.ui.add('button', 'dropdown-item', this.dropdown_menu);
item.textContent = label;
item.setAttribute('type', 'button');
if (typeof action === 'string') {
item.src = action;
item.addEventListener('click', () => {
item.addEventListener('click', async () => {
await frappe.router.set_route(action);
this.toggle();
});
} else {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
const Dropdown = require('./dropdown');
module.exports = {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
class BaseControl {
constructor(docfield, parent) {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
const controls = require('./controls');
module.exports = class Form {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
module.exports = class List {
constructor({doctype, parent, fields}) {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
module.exports = class Page {
constructor(title) {
@ -17,7 +17,7 @@ module.exports = class Page {
this.trigger('hide');
}
show(params) {
async show(params) {
if (frappe.router.current_page) {
frappe.router.current_page.hide();
}
@ -31,7 +31,7 @@ module.exports = class Page {
frappe.router.current_page = this;
document.title = this.title;
this.trigger('show', params);
await this.trigger('show', params);
}
render_error(status_code, message) {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
module.exports = class Router {
constructor() {
@ -16,6 +16,7 @@ module.exports = class Router {
if (page.param_keys) {
// make expression
// '/todo/:name/:place'.replace(/\/:([a-z1-9]+)/g, "\/([a-z0-9]+)");
page.depth = route.split('/').length;
page.expression = route.replace(/\/:([a-z1-9]+)/g, "\/([a-z0-9]+)");
this.dynamic_routes.push(page);
this.sort_dynamic_routes();
@ -26,14 +27,18 @@ module.exports = class Router {
}
sort_dynamic_routes() {
// routes with fewer parameters first
// routes with more parts first
this.dynamic_routes = this.dynamic_routes.sort((a, b) => {
if (a.param_keys.length > b.param_keys.length) {
if (a.depth < b.depth) {
return 1;
} else if (a.param_keys.length < b.param_keys.length) {
} else if (a.depth > b.depth) {
return -1;
} else {
return a.route.length > b.route.length ? 1 : -1;
if (a.param_keys.length !== b.param_keys.length) {
return a.param_keys.length > b.param_keys.length ? 1 : -1;
} else {
return a.route.length > b.route.length ? 1 : -1;
}
}
})
}

1
docs/app.md Normal file
View File

@ -0,0 +1 @@
# Creating a new App

View File

@ -9,8 +9,8 @@ Note: A single Form object can handle multiple documents.
### Example
```js
const Page = require('frappe-core/frappe/client/view/page').Page;
const Form = require('frappe-core/frappe/client/view/form').Form;
const Page = require('frappejs/frappe/client/view/page');
const Form = require('frappejs/frappe/client/view/form');
edit_page = new Page('Edit To Do');

View File

@ -23,13 +23,13 @@ You can setup your client by setting up the server and then importing your contr
### Example
```js
const client = require('frappe-core/frappe/client');
const client = require('frappejs/frappe/client');
client.start({
server: 'localhost:8000',
container: document.querySelector('.container'),
}).then(() => {
const todo = require('frappe-core/frappe/models/doctype/todo/todo.js');
const todo = require('frappejs/frappe/models/doctype/todo/todo.js');
frappe.init_controller('todo', todo);
// ....

View File

@ -5,14 +5,14 @@ A list object handles object listing and paging, for a standard model.
### Example
```js
const Page = require('frappe-core/frappe/client/view/page').Page;
const ListView = require('frappe-core/frappe/client/view/list').ListView;
const Page = require('frappejs/frappe/client/view/page');
const List = require('frappejs/frappe/client/view/list');
// create a new page
let todo_list = new Page('ToDo List');
// init a new list
todo_list.list = new ListView({
todo_list.list = new List({
doctype: 'ToDo',
parent: this.todo_list.body
});

View File

@ -5,7 +5,7 @@ A page is a basic container that fills up the `main` area of the Frappe.js SPA.
### Example
```js
const Page = require('frappe-core/frappe/client/view/page').Page;
const Page = require('frappejs/frappe/client/view/page').Page;
let todo_list = new Page('ToDo List');

View File

@ -11,7 +11,7 @@ Dynamic routes can be added by declaring each parameter as `:param` in the route
### Example
```js
const Page = require('frappe-core/frappe/client/view/page').Page;
const Page = require('frappejs/frappe/client/view/page').Page;
let todo_list = new Page('ToDo List');

View File

@ -17,7 +17,7 @@ Methods
### Create
```js
const Dropdown = require('frappe-core/frappe/client/ui/dropdown');
const Dropdown = require('frappejs/frappe/client/ui/dropdown');
let dropdown = new Dropdown({label:'Actions', parent:this.toolbar});
```

View File

@ -4,6 +4,7 @@ Frappe.js is a meta-data driven framework that enables rapid application develop
## Contents
- [Making a new App](app.md)
- Models and Documents
- [Declaring Models](models/index.md)
- [Controllers](models/controllers.md)
@ -19,5 +20,7 @@ Frappe.js is a meta-data driven framework that enables rapid application develop
- [Controls](client/controls.md)
- [UI](client/ui/index.md)
- [Dropdown](client/ui/dropdown.md)
- [Desk](client/desk.md)
- [Backends](backends.md)
- [Errors](errors.md)
- [Testing](testing.md)

View File

@ -18,7 +18,7 @@ You can bind events to the controller that will be called when an action is comp
The document controller represents a single record and is subclassed from the `frappe.document.Document` class
```js
const frappe = require('frappe-core');
const frappe = require('frappejs');
// extend the document and add event handlers
class todo extends frappe.document.Document {

View File

@ -22,7 +22,7 @@ The backend will implement the following `async` methods
Connection paramter required for the sqlite backend is the path of the file
```js
sqllite = require('frappe-core/frappe/backends/sqlite');
sqllite = require('frappejs/frappe/backends/sqlite');
frappe.db = await new sqlite.Database({db_path: db_path})
```
@ -42,7 +42,7 @@ For the client, the backend is the REST API that executes calls with web-request
Before using, you must initialize the `frappe.fetch` property with `window.fetch` or `node-fetch`
```js
const Database = require('frappe-core/frappe/backends/rest_client').Database;
const Database = require('frappejs/frappe/backends/rest_client').Database;
frappe.fetch = window.fetch.bind();
frappe.db = await new Database({server: server});

View File

@ -5,7 +5,7 @@ The framework comes bundles with an `express.js` web server with pre-built backe
### Example
```js
const server = require('frappe-core/frappe/server');
const server = require('frappejs/frappe/server');
server.start({
backend: 'sqllite',

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
class Document {
constructor(data) {

View File

@ -1,5 +1,5 @@
const Document = require('./document').Document;
const frappe = require('frappe-core');
const frappe = require('frappejs');
class Meta extends Document {
constructor(data) {

View File

@ -1,5 +1,5 @@
const process = require('process');
const frappe = require('frappe-core');
const frappe = require('frappejs');
class Models {
constructor() {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
class todo_meta extends frappe.meta.Meta {
setup_meta() {

View File

@ -1,7 +1,7 @@
{
"name": "frappe-core",
"name": "frappejs",
"version": "1.0.0",
"description": "Frappe Core",
"description": "Frappe.js",
"main": "index.js",
"scripts": {
"test": "mocha tests",
@ -9,15 +9,15 @@
},
"dependencies": {
"body-parser": "^1.18.2",
"bootstrap": "4.0.0-beta.3",
"express": "^4.16.2",
"node-fetch": "^1.7.3",
"sqlite3": "^3.1.13",
"walk": "^2.3.9",
"webpack-dev-server": "^2.9.7"
"walk": "^2.3.9"
},
"repository": {
"type": "git",
"url": "git+https://github.com/frappe/frappe-js.git"
"url": "git+https://github.com/frappe/frappejs.git"
},
"parserOptions": {
"ecmaVersion": 2017
@ -25,9 +25,9 @@
"author": "Frappe",
"license": "MIT",
"bugs": {
"url": "https://github.com/frappe/frappe-js/issues"
"url": "https://github.com/frappe/frappejs/issues"
},
"homepage": "https://github.com/frappe/frappe-js#readme",
"homepage": "https://github.com/frappe/frappejs#readme",
"devDependencies": {
"css-loader": "^0.28.7",
"eslint": "^4.9.0",

View File

@ -1,12 +1,12 @@
const backends = {};
backends.sqlite = require('frappe-core/backends/sqlite');
backends.sqlite = require('frappejs/backends/sqlite');
const express = require('express');
const app = express();
const frappe = require('frappe-core');
const frappe = require('frappejs');
const rest_api = require('./rest_api')
const models = require('frappe-core/server/models');
const common = require('frappe-core/common');
const models = require('frappejs/server/models');
const common = require('frappejs/common');
const bodyParser = require('body-parser');
module.exports = {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
const walk = require('walk');
const path = require('path');
@ -27,7 +27,7 @@ module.exports = {
frappe.config.apps = [];
}
frappe.config.apps.unshift('frappe-core');
frappe.config.apps.unshift('frappejs');
// walk and sync
for (let app_name of frappe.config.apps) {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
module.exports = {
setup(app) {

View File

@ -1,4 +1,4 @@
const frappe = require('frappe-core');
const frappe = require('frappejs');
class Session {
constructor(user, user_key) {

View File

@ -1,4 +1,4 @@
const server = require('frappe-core/server');
const server = require('frappejs/server');
module.exports = {
async init_sqlite() {

View File

@ -1,5 +1,5 @@
const assert = require('assert');
const frappe = require('frappe-core');
const frappe = require('frappejs');
const helpers = require('./helpers');
describe('Controller', () => {

View File

@ -1,5 +1,5 @@
const assert = require('assert');
const frappe = require('frappe-core');
const frappe = require('frappejs');
const helpers = require('./helpers');
describe('Database', () => {

View File

@ -1,5 +1,5 @@
const assert = require('assert');
const frappe = require('frappe-core');
const frappe = require('frappejs');
const helpers = require('./helpers');
describe('Document', () => {

View File

@ -1,5 +1,5 @@
const assert = require('assert');
const frappe = require('frappe-core');
const frappe = require('frappejs');
const helpers = require('./helpers');
describe('Meta', () => {

View File

@ -1,5 +1,5 @@
const assert = require('assert');
const frappe = require('frappe-core');
const frappe = require('frappejs');
const helpers = require('./helpers');
describe('Models', () => {

View File

@ -1,10 +1,10 @@
const assert = require('assert');
const frappe = require('frappe-core');
const frappe = require('frappejs');
const fetch = require('node-fetch');
const helpers = require('./helpers');
const { spawn } = require('child_process');
const process = require('process');
const RESTClient = require('frappe-core/backends/rest_client')
const RESTClient = require('frappejs/backends/rest_client')
// create a copy of frappe

View File

@ -1,4 +1,4 @@
const Router = require('frappe-core/common/router');
const Router = require('frappejs/common/router');
const assert = require('assert');
describe('Router', () => {
@ -15,13 +15,15 @@ describe('Router', () => {
it('router should sort dynamic routes', () => {
let router = new Router();
router.add('/edit/todo/mytest', 'static');
router.add('/edit/:doctype', 'catch');
router.add('/edit/:doctype/:name', 'all');
router.add('/edit/todo/:name', 'todo');
router.add('/edit/todo/mytest', 'static');
assert.equal(router.match('/edit/todo/test').handler, 'todo');
assert.equal(router.match('/edit/user/test').handler, 'all');
assert.equal(router.match('/edit/todo/mytest').handler, 'static');
assert.equal(router.match('/edit/user').handler, 'catch');
});

View File

@ -1,4 +1,4 @@
const server = require('frappe-core/server');
const server = require('frappejs/server');
if (require.main === module) {
server.start({backend: 'sqlite', connection_params: {db_path: 'test.db'}});

View File

@ -339,6 +339,10 @@ boom@5.x.x:
dependencies:
hoek "4.x.x"
bootstrap@4.0.0-beta.3:
version "4.0.0-beta.3"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.0.0-beta.3.tgz#60f0660bc3d121176514b361f6f83201c7ff8874"
boxen@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"