diff --git a/backends/sqlite.js b/backends/sqlite.js
index 2db3a19a..88a538e4 100644
--- a/backends/sqlite.js
+++ b/backends/sqlite.js
@@ -23,11 +23,15 @@ class sqliteDatabase {
}
async migrate() {
- for (let doctype in frappe.models.data.doctype) {
- if (await this.table_exists(doctype)) {
- await this.alter_table(doctype);
- } else {
- await this.create_table(doctype);
+ for (let doctype in frappe.modules) {
+ // check if controller module
+ if (frappe.modules[doctype].Meta) {
+ if (await this.table_exists(doctype)) {
+ await this.alter_table(doctype);
+ } else {
+ await this.create_table(doctype);
+ }
+
}
}
await this.commit();
diff --git a/client/desk/index.js b/client/desk/index.js
index d62d4c81..74287dfa 100644
--- a/client/desk/index.js
+++ b/client/desk/index.js
@@ -2,8 +2,8 @@ const frappe = require('frappejs');
const Search = require('./search');
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');
+const BaseList = require('frappejs/client/view/list');
+const BaseForm = require('frappejs/client/view/form');
const Navbar = require('./navbar');
module.exports = class Desk {
@@ -58,8 +58,8 @@ module.exports = class Desk {
get_list_page(doctype) {
if (!this.pages.lists[doctype]) {
- let page = new Page('List ' + doctype);
- page.list = new List({
+ let page = new Page('List ' + frappe.get_meta(doctype).name);
+ page.list = new (this.get_view_class(doctype, 'List', BaseList))({
doctype: doctype,
parent: page.body
});
@@ -73,8 +73,8 @@ module.exports = class Desk {
get_form_page(doctype) {
if (!this.pages.forms[doctype]) {
- let page = new Page('Edit ' + doctype);
- page.form = new Form({
+ let page = new Page('Edit ' + frappe.get_meta(doctype).name);
+ page.form = new (this.get_view_class(doctype, 'Form', BaseForm))({
doctype: doctype,
parent: page.body
});
@@ -91,6 +91,20 @@ module.exports = class Desk {
return this.pages.forms[doctype];
}
+ get_view_class(doctype, class_name, default_class) {
+ let client_module = this.get_client_module(doctype);
+ if (client_module && client_module[class_name]) {
+ return client_module[class_name];
+ } else {
+ return default_class;
+ }
+
+ }
+
+ get_client_module(doctype) {
+ return frappe.modules[`${doctype}_client`];
+ }
+
add_sidebar_item(label, action) {
let item = frappe.ui.add('a', '', frappe.ui.add('p', null, frappe.desk.sidebar));
item.textContent = label;
diff --git a/client/view/controls/base.js b/client/view/controls/base.js
index 41c44db4..cc3fd30d 100644
--- a/client/view/controls/base.js
+++ b/client/view/controls/base.js
@@ -97,6 +97,14 @@ class BaseControl {
value = await this.validate(value);
await this.doc.set(this.fieldname, value);
}
+
+ disable() {
+ this.input.setAttribute('disabled', 'disabled');
+ }
+
+ enable() {
+ this.input.removeAttribute('disabled');
+ }
}
module.exports = BaseControl;
\ No newline at end of file
diff --git a/client/view/form.js b/client/view/form.js
index e69e86a7..21179c36 100644
--- a/client/view/form.js
+++ b/client/view/form.js
@@ -1,7 +1,7 @@
const frappe = require('frappejs');
const controls = require('./controls');
-module.exports = class Form {
+module.exports = class BaseForm {
constructor({doctype, parent, submit_label='Submit'}) {
this.parent = parent;
this.doctype = doctype;
@@ -11,6 +11,9 @@ module.exports = class Form {
this.controls_list = [];
this.meta = frappe.get_meta(this.doctype);
+ if (this.setup) {
+ this.setup();
+ }
this.make();
}
diff --git a/client/view/list.js b/client/view/list.js
index fcf9239c..9fef6bba 100644
--- a/client/view/list.js
+++ b/client/view/list.js
@@ -1,6 +1,6 @@
const frappe = require('frappejs');
-module.exports = class List {
+module.exports = class BaseList {
constructor({doctype, parent, fields}) {
this.doctype = doctype;
this.parent = parent;
@@ -18,13 +18,8 @@ module.exports = class List {
async run() {
this.make_body();
- this.set_filters();
- let data = await this.meta.get_list({
- filters: this.filters,
- start:this.start,
- limit:this.page_length + 1
- });
+ let data = await this.get_data();
for (let i=0; i< Math.min(this.page_length, data.length); i++) {
this.render_row(this.start + i, data[i]);
@@ -40,16 +35,31 @@ module.exports = class List {
this.update_more(data.length > this.page_length);
}
+ async get_data() {
+ return await frappe.db.get_all({
+ doctype: this.doctype,
+ fields: this.get_fields(),
+ filters: this.get_filters(),
+ start: this.start,
+ limit: this.page_length + 1
+ });
+ }
+
+ get_fields() {
+ return ['name'];
+ }
+
async append() {
this.start += this.page_length;
await this.run();
}
- set_filters() {
- this.filters = {};
+ get_filters() {
+ let filters = {};
if (this.search_input.value) {
- this.filters.keywords = ['like', '%' + this.search_input.value + '%'];
+ filters.keywords = ['like', '%' + this.search_input.value + '%'];
}
+ return filters;
}
make_body() {
@@ -104,10 +114,14 @@ module.exports = class List {
render_row(i, data) {
let row = this.get_row(i);
- row.innerHTML = this.meta.get_row_html(data);
+ row.innerHTML = this.get_row_html(data);
row.style.display = 'block';
}
+ get_row_html(data) {
+ return `${data.name}`;
- }
-
-}
-
-module.exports = { Meta: Meta }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/model/models.js b/model/models.js
deleted file mode 100644
index 1339ba5c..00000000
--- a/model/models.js
+++ /dev/null
@@ -1,25 +0,0 @@
-const process = require('process');
-const frappe = require('frappejs');
-
-class Models {
- constructor() {
- this.data = {doctype: {}};
- this.controllers = {};
- this.meta_classes = {};
- }
-
- get(doctype, name) {
- return this.data[frappe.slug(doctype)][frappe.slug(name)];
- }
-
- get_controller(doctype) {
- return this.controllers[frappe.slug(doctype)];
- }
-
- get_meta_class(doctype) {
- return this.meta_classes[frappe.slug(doctype)] || frappe.meta.Meta;
- }
-
-}
-
-module.exports = { Models: Models }
\ No newline at end of file
diff --git a/models/doctype/todo/todo.js b/models/doctype/todo/todo.js
index b06a9227..f378d236 100644
--- a/models/doctype/todo/todo.js
+++ b/models/doctype/todo/todo.js
@@ -1,19 +1,13 @@
-const frappe = require('frappejs');
+const BaseMeta = require('frappejs/model/meta');
+const BaseDocument = require('frappejs/model/document');
-class todo_meta extends frappe.meta.Meta {
+class ToDoMeta extends BaseMeta {
setup_meta() {
Object.assign(this, require('./todo.json'));
- this.list_options.fields = ['name', 'subject', 'status'];
}
-
- get_row_html(data) {
- const sign = data.status === 'Open' ? '' : '✔';
- return `${sign} ${data.subject}`;
- }
-
}
-class todo extends frappe.document.Document {
+class ToDo extends BaseDocument {
setup() {
this.add_handler('validate');
}
@@ -24,4 +18,7 @@ class todo extends frappe.document.Document {
}
}
-module.exports = {todo:todo, todo_meta:todo_meta};
+module.exports = {
+ Document: ToDo,
+ Meta: ToDoMeta
+};
diff --git a/models/doctype/todo/todo_client.js b/models/doctype/todo/todo_client.js
new file mode 100644
index 00000000..1394727f
--- /dev/null
+++ b/models/doctype/todo/todo_client.js
@@ -0,0 +1,16 @@
+const BaseList = require('frappejs/client/view/list');
+const BaseForm = require('frappejs/client/view/form');
+
+class ToDoList extends BaseList {
+ get_fields() {
+ return ['name', 'subject', 'status'];
+ }
+ get_row_html(data) {
+ return `${data.subject}`;
+ }
+}
+
+module.exports = {
+ Form: BaseForm,
+ List: ToDoList
+}
\ No newline at end of file
diff --git a/server/index.js b/server/index.js
index 0428cf32..c48205a4 100644
--- a/server/index.js
+++ b/server/index.js
@@ -5,7 +5,7 @@ const express = require('express');
const app = express();
const frappe = require('frappejs');
const rest_api = require('./rest_api')
-const models = require('frappejs/server/models');
+const init_models = require('frappejs/server/init_models');
const common = require('frappejs/common');
const bodyParser = require('body-parser');
const path = require('path');
@@ -13,11 +13,11 @@ const path = require('path');
module.exports = {
async start({backend, connection_params, static, models_path}) {
await this.init();
- models.init_models(path.resolve('node_modules', 'frappejs', 'models'));
- models.init_models(models_path);
- await this.init_db({backend:backend, connection_params:connection_params});
+ this.init_models(models_path);
+
// database
+ await this.init_db({backend:backend, connection_params:connection_params});
// app
app.use(bodyParser.json());
@@ -30,7 +30,14 @@ module.exports = {
// listen
frappe.app = app;
frappe.server = app.listen(frappe.config.port);
+ },
+ init_models(models_path) {
+ // import frappe modules
+ init_models(path.join(path.dirname(require.resolve('frappejs')), 'models'));
+
+ // import modules from the app
+ init_models(models_path);
},
async init() {
diff --git a/server/init_models.js b/server/init_models.js
new file mode 100644
index 00000000..519f1b0f
--- /dev/null
+++ b/server/init_models.js
@@ -0,0 +1,23 @@
+const frappe = require('frappejs');
+const walk = require('walk');
+const path = require('path');
+
+module.exports = function(models_path) {
+ if (!models_path) {
+ return;
+ }
+
+ walk.walkSync(models_path, {
+ listeners: {
+ file: (basepath, file_data, next) => {
+ const doctype = path.basename(path.dirname(basepath));
+ const name = path.basename(basepath);
+ const file_path = path.resolve(basepath, file_data.name);
+ if (doctype==='doctype' && file_data.name.endsWith('.js')) {
+ frappe.modules[file_data.name.slice(0, -3)] = require(file_path);
+ }
+ next();
+ }
+ }
+ });
+}
diff --git a/server/models.js b/server/models.js
deleted file mode 100644
index 812c8a70..00000000
--- a/server/models.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const frappe = require('frappejs');
-const walk = require('walk');
-const path = require('path');
-
-module.exports = {
- init_models(models_path) {
- const setup_model = (doctype, name, file_path) => {
- // add to frappe.models.data
- if (!frappe.models[doctype]) {
- frappe.models[doctype] = {};
- }
- frappe.models.data[doctype][name] = require(file_path);
- }
-
- const setup_controller = (doctype, file_path) => {
- let _module = require(file_path);
- frappe.models.controllers[doctype] = _module[doctype];
- if (_module[doctype + '_meta']) {
- frappe.models.meta_classes[doctype] = _module[doctype + '_meta'];
- }
- }
-
- walk.walkSync(models_path, {
- listeners: {
- file: (basepath, file_data, next) => {
- const doctype = path.basename(path.dirname(basepath));
- const name = path.basename(basepath);
- const file_path = path.resolve(basepath, file_data.name);
- if (file_data.name.endsWith('.json')) {
- setup_model(doctype, name, file_path)
- }
- if (doctype==='doctype' && file_data.name.endsWith('.js')) {
- setup_controller(path.basename(basepath), file_path);
- }
- next();
- }
- }
- });
-
- }
-
-}
\ No newline at end of file
diff --git a/server/rest_api.js b/server/rest_api.js
index 6996f49d..ed81aaa5 100644
--- a/server/rest_api.js
+++ b/server/rest_api.js
@@ -4,7 +4,6 @@ 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.query[key]) {
request.query[key] = JSON.parse(request.query[key]);
diff --git a/tests/helpers.js b/tests/helpers.js
index c5c65091..dcbd6505 100644
--- a/tests/helpers.js
+++ b/tests/helpers.js
@@ -2,7 +2,8 @@ const server = require('frappejs/server');
module.exports = {
async init_sqlite() {
- server.init()
+ server.init();
+ server.init_models();
server.init_db({
backend: 'sqlite',
connection_params: {db_path: 'test.db'}
diff --git a/tests/test_models.js b/tests/test_models.js
index 67ceb25d..4016d764 100644
--- a/tests/test_models.js
+++ b/tests/test_models.js
@@ -8,7 +8,7 @@ describe('Models', () => {
});
it('should get todo json', () => {
- let todo = frappe.models.get('DocType', 'ToDo');
+ let todo = frappe.get_meta('todo');
assert.equal(todo.issingle, 0);
});
});
\ No newline at end of file
diff --git a/tests/test_server.js b/tests/test_server.js
index d6957ced..bb3d5cd6 100644
--- a/tests/test_server.js
+++ b/tests/test_server.js
@@ -1,5 +1,8 @@
const server = require('frappejs/server');
if (require.main === module) {
- server.start({backend: 'sqlite', connection_params: {db_path: 'test.db'}});
+ server.start({
+ backend: 'sqlite',
+ connection_params: {db_path: 'test.db'}
+ });
}
\ No newline at end of file