From 5c3a52186e0ce07a2b78791556eb6a0d634128fb Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 22 Feb 2018 13:06:28 +0530 Subject: [PATCH] updated docs --- client/desk/formpage.js | 2 +- client/desk/printpage.js | 3 +- client/view/controls/base.js | 2 +- client/view/form.js | 4 +- client/view/page.js | 4 +- docs/index.md | 9 ++ docs/models/controllers.md | 12 +-- docs/models/fields.md | 77 +++++++++++++++ docs/models/formula.md | 65 +++++++++++++ docs/models/index.md | 19 +++- docs/models/parent-child.md | 40 ++++++++ docs/models/singles.md | 21 ++++ docs/server/backends.md | 2 +- docs/utilities/number-series.md | 25 +++++ docs/utilities/observable.md | 29 ++++++ docs/utilities/print-format.md | 102 ++++++++++++++++++++ docs/utilities/single-value.md | 11 +++ docs/utilities/system-settings.md | 11 +++ models/doctype/NumberSeries/NumberSeries.js | 2 +- models/doctype/ToDo/ToDo.js | 2 +- 20 files changed, 418 insertions(+), 24 deletions(-) create mode 100644 docs/models/fields.md create mode 100644 docs/models/formula.md create mode 100644 docs/models/parent-child.md create mode 100644 docs/models/singles.md create mode 100644 docs/utilities/number-series.md create mode 100644 docs/utilities/observable.md create mode 100644 docs/utilities/print-format.md create mode 100644 docs/utilities/single-value.md create mode 100644 docs/utilities/system-settings.md diff --git a/client/desk/formpage.js b/client/desk/formpage.js index 82607e49..823c30d8 100644 --- a/client/desk/formpage.js +++ b/client/desk/formpage.js @@ -5,7 +5,7 @@ const frappe = require('frappejs'); module.exports = class FormPage extends Page { constructor(doctype) { let meta = frappe.getMeta(doctype) - super({title: `Edit ${meta.name}`}); + super({title: `Edit ${meta.name}`, hasRoute: true}); this.meta = meta; this.doctype = doctype; diff --git a/client/desk/printpage.js b/client/desk/printpage.js index dce03267..d6c05ae0 100644 --- a/client/desk/printpage.js +++ b/client/desk/printpage.js @@ -7,7 +7,7 @@ nunjucks.configure({ autoescape: false }); module.exports = class PrintPage extends Page { constructor(doctype) { let meta = frappe.getMeta(doctype); - super({title: `View ${meta.name}`}); + super({title: `${meta.name}`, hasRoute: true}); this.meta = meta; this.doctype = doctype; @@ -35,6 +35,7 @@ module.exports = class PrintPage extends Page { try { this.body.innerHTML = ``; + this.setTitle(doc.name); } catch (e) { this.renderError('Template Error', e); throw e; diff --git a/client/view/controls/base.js b/client/view/controls/base.js index 08d13823..ff100a1d 100644 --- a/client/view/controls/base.js +++ b/client/view/controls/base.js @@ -87,7 +87,7 @@ class BaseControl { } setDisabled() { - if (this.readonly || this.disabled) { + if (this.disabled) { this.input.disabled = true; } } diff --git a/client/view/form.js b/client/view/form.js index 583690cc..5984974d 100644 --- a/client/view/form.js +++ b/client/view/form.js @@ -106,12 +106,12 @@ module.exports = class BaseForm extends Observable { setTitle() { const doctypeLabel = this.doc.meta.label || this.doc.meta.name; - if (this.doc.meta.isSingle || !this.doc.meta.showTitle) { + if (this.doc.meta.isSingle || this.doc.meta.naming == 'random') { this.container.setTitle(doctypeLabel); } else if (this.doc._notInserted) { this.container.setTitle(frappe._('New {0}', doctypeLabel)); } else { - this.container.setTitle(`${doctypeLabel} ${this.doc.name}`); + this.container.setTitle(this.doc.name); } } diff --git a/client/view/page.js b/client/view/page.js index 1650ab0c..0cd9b3cb 100644 --- a/client/view/page.js +++ b/client/view/page.js @@ -3,7 +3,7 @@ const Observable = require('frappejs/utils/observable'); const Dropdown = require('frappejs/client/ui/dropdown'); module.exports = class Page extends Observable { - constructor({title, parent, hasRoute=true}) { + constructor({title, parent, hasRoute=true} = {}) { super(); Object.assign(this, arguments[0]); if (!this.parent) { @@ -20,7 +20,7 @@ module.exports = class Page extends Observable { make() { this.wrapper = frappe.ui.add('div', 'page hide', this.parent); this.wrapper.innerHTML = `
- +
` this.head = this.wrapper.querySelector('.page-head'); diff --git a/docs/index.md b/docs/index.md index dc0fcd80..68bb5178 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,9 +7,13 @@ Frappe.js is a meta-data driven framework that enables rapid application develop - [Making a new App](app.md) - Models and Documents - [Declaring Models](models/index.md) + - [Fields](models/fields.md) - [Controllers](models/controllers.md) + - [Formula](models/fields.md) - [Metadata](models/metadata.md) - [Managing Documents](models/document.md) + - [Single Documents](models/singles.md) + - [Parent Child](models/parent-child.md) - [Server](server/index.md) - [REST API](server/rest.md) - [Client](client/index.md) @@ -21,6 +25,11 @@ Frappe.js is a meta-data driven framework that enables rapid application develop - [UI](client/ui/index.md) - [Dropdown](client/ui/dropdown.md) - [Desk](client/desk.md) +- Utilities + - [Observable](utilities/observable.md) + - [Print Format](utilities/print-format.md) + - [Number Series](utilities/number-series.md) + - [System Settings](utilities/system-settings.md) - [Backends](server/backends.md) - [Errors](errors.md) - [Testing](testing.md) diff --git a/docs/models/controllers.md b/docs/models/controllers.md index 099b758e..7914bf9f 100644 --- a/docs/models/controllers.md +++ b/docs/models/controllers.md @@ -4,6 +4,8 @@ In Frappe.js you can extend the metadata class as well as the document class for You can write event handlers in controllers, by declaring a `.js` file in the `models/doctype/` folder along with the model file. +You must also mind the controller to the model file by the `documentClass` property. + ## Naming 1. The name of the controller class must be the slugged name of the DocType (example `todo`) @@ -22,9 +24,6 @@ const frappe = require('frappejs'); // extend the document and add event handlers class todo extends frappe.document.Document { - setup() { - this.add_handler('validate'); - } validate() { if (!this.status) { this.status = 'Open'; @@ -40,16 +39,9 @@ The `meta` class contains actions that are done on a group of objects and a docu ```js // extend the meta class class todo_meta extends frappe.meta.Meta { - setupMeta() { - Object.assign(this, require('./todo.json')); - this.name = 'ToDo'; - this.list_options.fields = ['name', 'subject', 'status', 'description']; - } - getRowHTML(data) { return `${data.subject}`; } - } ``` diff --git a/docs/models/fields.md b/docs/models/fields.md new file mode 100644 index 00000000..20abe208 --- /dev/null +++ b/docs/models/fields.md @@ -0,0 +1,77 @@ +# Fields + +Fields are properties a the document instance that are defined in its DocType. + +## Field Types + +### Data + +Small, single line text (140 chars) + +### Text + +Long multi-line text + +### Int + +Integer + +### Float + +Number + +### Currency + +Number with currency + +### Code + +Code string (like Text but monospaced) + +### Date + +Date (formatted by [SystemSetings.dateFormat](../utilities/system-settings.md)) + +### Select + +Dropdown with fixed options. Options must be set in the `options` property + +``` +{ + fieldtype: "Select", + fieldname: "status", + label: "Status", + options: [ + "Open", + "Closed", + "Pending" + ] + +} +``` + +### Link + +Reference to another document set by `target` + +``` +{ + fieldtype: "Link", + fieldname: "customer", + label: "Customer", + target: "Customer" +} +``` + +### Table + +Property with child documents, the type of children is defined by `childtype` property + +``` +{ + fieldtype: "Table", + fieldname: "items", + label: "Items", + target: "InvoiceItem" +} +``` \ No newline at end of file diff --git a/docs/models/formula.md b/docs/models/formula.md new file mode 100644 index 00000000..6323d46b --- /dev/null +++ b/docs/models/formula.md @@ -0,0 +1,65 @@ +# Formula + +Formulas are dynamic document properties that can be set on the fields + +Forumlas are defined as javascript functions and are called whenever any property of the document is updated using the `set` method, or just before inserting or updating the document. + +### Example + +```js +module.exports = { + name: "FormulaExample" + fields: [ + { + fieldtype: "Float", + fieldname: "a" + }, + { + fieldtype: "Float", + fieldname: "b" + } + { + fieldtype: "Float", + fieldname: "c", + formula: doc => doc.a + doc.b + } + ] +} +``` + +## Formula on child tables + +In child tables, both the parent and the child records are passed + +### Example + +```js +{ + fieldname: "amount", + fieldtype: "Float", + formula: (doc, row) => row.qty * row.rate +} +``` + +## Sequence + +All child tables are executed first and all fields are executed in the sequence as defined in the DocType + +## Fetching Values + +You can use the `getFrom` function to fetch values from another document + +Example: + +``` +{ + "fieldname": "rate", + "label": "Rate", + "fieldtype": "Currency", + formula: (row, doc) => row.rate || doc.getFrom('Item', row.item, 'rate') +} +``` + +## Async + +Forumlas are evaluated as promises, so you can either directly pass a value or a `Promise` \ No newline at end of file diff --git a/docs/models/index.md b/docs/models/index.md index 46786a40..e588ebee 100644 --- a/docs/models/index.md +++ b/docs/models/index.md @@ -1,14 +1,25 @@ # Declaring Models -Models are declared by adding a `.json` model file in the `models/doctype` folder of the module/app. +Models are declared by adding a `.js` model file in the `models/doctype` folder of the module/app. Note: A model is called `DocType` in Frappe.js +### Fields + +Every model must have a set of fields (these become database columns). All fields must have + +- `fieldname`: Column name in database / property name +- `fieldtype`: Data type ([see details](fields.md)) +- `label`: Display label +- `required`: Is mandatory +- `hidden`: Is hidden +- `disabled`: Is disabled + ### Example -```json -{ - "autoname": "hash", +```js +module.exports = { + "naming": "random", "name": "ToDo", "doctype": "DocType", "issingle": 0, diff --git a/docs/models/parent-child.md b/docs/models/parent-child.md new file mode 100644 index 00000000..05abef91 --- /dev/null +++ b/docs/models/parent-child.md @@ -0,0 +1,40 @@ +# Parent Child Relationship + +All documents can have child documents, identified by the `Table` field. + +Though child documents have their own DocType and database table, but are not to handled or viewed on their own. FrappeJS will automatically load child documents along with the parent when you use the `frappe.getDoc` method. + +### Example + +A sample parent-child records looks like this: + +``` +{ + doctype: "Invoice", + customer: "Harry Potter", + items: [ + { + item: "Wand", + qty: 1, + rate: 300, + amount: 300 + },{ + item: "Invisibility Cloak", + qty: 1, + rate: 3000, + amount: 3000 + } + ] +} +``` + +## Child Properties + +Child documents have special properties that define their relationship to their parent + +- `parent`: name of the parent +- `parenttype`: DocType of the parent +- `parentfield`: Field in the parent that links this child to it +- `idx`: Sequence (row) + +These properties are maintained in the table automatically by FrappeJS \ No newline at end of file diff --git a/docs/models/singles.md b/docs/models/singles.md new file mode 100644 index 00000000..804af836 --- /dev/null +++ b/docs/models/singles.md @@ -0,0 +1,21 @@ +# Single Documents + +Single doctypes have only one instance. They are useful for using DocTypes as views or for settings. + +To make a Single DocType, set the `isSingle` property as true. + +Single documents are best viewed in a modal since they do not have a corresponding list view. + +Values of single documents are stored in the table `SingleValue` + +## API + +### frappe.getSingle + +Load a single document + +```js +let systemSettings = frappe.getSingle('SystemSettings'); +``` + +Since Single documents are also documents, you can update them with the `update()` method. diff --git a/docs/server/backends.md b/docs/server/backends.md index 5253353a..283ded7b 100644 --- a/docs/server/backends.md +++ b/docs/server/backends.md @@ -24,7 +24,7 @@ Connection paramter required for the sqlite backend is the path of the file ```js sqllite = require('frappejs/frappe/backends/sqlite'); -frappe.db = await new sqlite.Database({db_path: db_path}) +frappe.db = await new sqlite.Database({dbPath: dbPath}) ``` ### SQL Queries diff --git a/docs/utilities/number-series.md b/docs/utilities/number-series.md new file mode 100644 index 00000000..dd1c0325 --- /dev/null +++ b/docs/utilities/number-series.md @@ -0,0 +1,25 @@ +# Number Series + +A number series is used to maintain a series for numbering documents (like invoices) + +Properties: + +- `name`: Prefix of the series example `INV-` +- `current`: Its current (or starting) value. This will be auto updated everytime the series is updated. + +### API + +You can get the next number in the series by using the utiltiy function + +```js +const model = require("frappejs/model") +let nextValue = model.getSeriesNext("INV-"); +``` + +### Setting naming series in a document + +To setup a number series for a DocType: + +- It must have its own "Settings" [single document](../models/singles.md. For example (InvoiceSettings for Invoice). +- The settings document must be set via the `settings` property in the DocType +- The settings document must have a `numberSeries` property with value of the number series \ No newline at end of file diff --git a/docs/utilities/observable.md b/docs/utilities/observable.md new file mode 100644 index 00000000..38f4b293 --- /dev/null +++ b/docs/utilities/observable.md @@ -0,0 +1,29 @@ +# Observable Base Class + +The `Observable` base class makes and subclass trigger events and accept event listeners. + +### Example + +```js +class Test extends Observable { + doSomething() { + // work + this.trigger('work-done', {some: params}) + } +} + +let test = new Test(); +test.on('work-done', (params) => yay()); +``` + +### With Sockets + +You can also bind sockets (SocketIO) to an `Observable` and all events will also be emitted or received via the socket. See the API below for binding sockets. + +### Methods + +- `on(event, listener)`: Listen to an event +- `trigger(event)`: trigger an event +- `once(event, listener)`: trigger an event once +- `bindSocketServer(socket)`: Emit triggers on this socket +- `bindSocketClient(socket)`: Listen for events on this socket \ No newline at end of file diff --git a/docs/utilities/print-format.md b/docs/utilities/print-format.md new file mode 100644 index 00000000..7dfb12aa --- /dev/null +++ b/docs/utilities/print-format.md @@ -0,0 +1,102 @@ +# Print Format + +A PrintFormat represents an HTML template that is used to create a printer-friendly version of the DocType + +## Creating a Print Format + +To make a printer friendly version, you must create a "PrintFormat" for the doctype + +Example: + +```js +module.exports = { + doctype: "PrintFormat", + name: "Standard Invoice Format", + for: "Invoice", + template: require('./invoice.html') +} +``` + +This must be referenced in the `print.printFormat` property of the DocType. + +```js + "print": { + "printFormat": "Standard Invoice Format", + }, +``` + +## Templating + +The templating system used by frappe is [nunjucks](https://mozilla.github.io/nunjucks/) and is very similar to Jinja2 system from Python + +### Example + +Example of a print format for an Invoice + +```html +

{{ doc.name }}

+
+
+
{{ frappe._("Customer") }}
+
{{ doc.customer }}
+
+
+
{{ frappe._("Date") }}
+
{{ frappe.format(doc.date, 'Date') }}
+
+
+ + + + + + + + + + + + {% for row in doc.items %} + + + + + + + + {% endfor %} + +
{{ frappe._("Item") }}{{ frappe._("Qty") }}{{ frappe._("Rate") }}{{ frappe._("Amount") }}
{{ row.idx + 1 }}{{ row.item }}
{{ frappe.format(row.description, 'Text') }}
{{ row.quantity }}{{ frappe.format(row.rate, 'Currency') }}{{ frappe.format(row.amount, 'Currency') }}
+
+
+
+
+
+ {{ frappe._("Total") }} +
+
+ {{ frappe.format(doc.netTotal, 'Currency')}} +
+
+ {% for tax in doc.taxes %} +
+
+ {{ tax.account }} ({{ tax.rate }}%) +
+
+ {{ frappe.format(tax.amount, 'Currency')}} +
+
+ {% endfor %} +
+
+
{{ frappe._("Grand Total") }}
+
+
+
{{ frappe.format(doc.grandTotal, 'Currency')}}
+
+
+
+
+ +``` \ No newline at end of file diff --git a/docs/utilities/single-value.md b/docs/utilities/single-value.md new file mode 100644 index 00000000..9f95575d --- /dev/null +++ b/docs/utilities/single-value.md @@ -0,0 +1,11 @@ +# Single Value + +The SingleValue table is where all [Single documents](../model/singles.md) are stored. + +A `SingleValue` record is created for each property of the doctype + +Properties: + +- `parent`: name of single document +- `fieldname`: name of the field (property) +- `value`: value of the field \ No newline at end of file diff --git a/docs/utilities/system-settings.md b/docs/utilities/system-settings.md new file mode 100644 index 00000000..e862d29a --- /dev/null +++ b/docs/utilities/system-settings.md @@ -0,0 +1,11 @@ +# System Settings + +SystemSettings is a [Single document](../models/singles.md) that has system defaults like + +- `dateFormat`: default date format + +You can get system settings as + +```js +frappe.getSingle("SystemSettings") +``` \ No newline at end of file diff --git a/models/doctype/NumberSeries/NumberSeries.js b/models/doctype/NumberSeries/NumberSeries.js index 4b94f623..7498d3c2 100644 --- a/models/doctype/NumberSeries/NumberSeries.js +++ b/models/doctype/NumberSeries/NumberSeries.js @@ -8,7 +8,7 @@ module.exports = { "fields": [ { "fieldname": "name", - "label": "Name", + "label": "Prefix", "fieldtype": "Data", "required": 1 }, diff --git a/models/doctype/ToDo/ToDo.js b/models/doctype/ToDo/ToDo.js index 053820db..059e44fd 100644 --- a/models/doctype/ToDo/ToDo.js +++ b/models/doctype/ToDo/ToDo.js @@ -1,5 +1,5 @@ module.exports = { - "autoname": "random", + "naming": "random", "name": "ToDo", "doctype": "DocType", "isSingle": 0,