2
0
mirror of https://github.com/frappe/books.git synced 2024-09-20 03:29:00 +00:00

feat: TwoColumnForm

- Supports inline editing of links for e.g Address
This commit is contained in:
Faris Ansari 2019-11-19 23:08:08 +05:30
parent 6d624438de
commit 6994c2fa11
2 changed files with 190 additions and 103 deletions

View File

@ -2,37 +2,15 @@ module.exports = {
name: 'Address',
doctype: 'DocType',
isSingle: 0,
keywordFields: ['name'],
pageSettings: {
hideTitle: true
},
keywordFields: [
'addressLine1',
'addressLine2',
'city',
'state',
'country',
'postalCode'
],
fields: [
{
fieldname: 'name',
label: 'Address Title',
fieldtype: 'Data',
defaultValue: 'Work',
required: 1
},
{
fieldname: 'addressType',
label: 'Address Type',
fieldtype: 'Select',
options: [
'Billing',
'Shipping',
'Office',
'Personal',
'Plant',
'Postal',
'Shop',
'Subsidary',
'Warehouse',
'Current',
'Permanent',
'Other'
]
},
{
fieldname: 'addressLine1',
label: 'Address Line 1',
@ -82,60 +60,31 @@ module.exports = {
fieldtype: 'Data'
},
{
fieldname: 'isPreferredBilling',
label: 'Preferred Billing Address',
fieldtype: 'Check'
},
{
fieldname: 'isShippingBilling',
label: 'Preferred Shipping Address',
fieldtype: 'Check'
fieldname: 'addressDisplay',
fieldtype: 'Text',
label: 'Address Display',
readOnly: true,
formula: doc => {
return [
doc.addressLine1,
doc.addressLine2,
doc.city,
doc.state,
doc.country,
doc.postalCode
]
.filter(Boolean)
.join(', ');
}
}
],
// events: {
// validate: (doc) => {
// }
// },
listSettings: {
getFields(list) {
return ['name', 'addressType'];
},
getRowHTML(list, data) {
return `<div class="col-11">${list.getNameHTML(data)} (${
data.addressType
})</div>`;
}
},
layout: [
// section 1
{
columns: [
{
fields: [
'name',
'addressType',
'addressLine1',
'addressLine2',
'city',
'country',
'state',
'postalCode'
]
},
{
fields: [
'emailAddress',
'phone',
'fax',
'isPreferredBilling',
'isShippingBilling'
]
}
]
}
]
quickEditFields: [
'addressLine1',
'addressLine2',
'city',
'state',
'country',
'postalCode'
],
inlineEditDisplayField: 'addressDisplay'
};

View File

@ -1,40 +1,178 @@
<template>
<div class="border-t">
<div class="grid border-b text-xs" style="grid-template-columns: 1fr 1fr" v-for="df in fields">
<div class="py-2 pl-4 text-gray-600 flex items-center">{{ df.label }}</div>
<div class="py-2 pr-4">
<FormControl
size="small"
:df="df"
:value="doc[df.fieldname]"
@change="value => onChange(df, value)"
/>
</div>
</div>
<div class="text-sm" :class="{ 'border-t': !noBorder }">
<template v-for="df in fields">
<FormControl
v-if="df.fieldtype === 'Table'"
ref="controls"
size="small"
:df="df"
:value="doc[df.fieldname]"
@change="value => onChange(df, value)"
/>
<template v-else>
<template v-if="inlineEditField === df && inlineEditDoc">
<div class="border-b">
<TwoColumnForm
:doc="inlineEditDoc"
:fields="inlineEditFields"
:column-ratio="columnRatio"
:no-border="true"
:focus-first-input="true"
/>
<div class="flex px-4 pb-2">
<Button
class="w-1/2 text-gray-900"
@click="inlineEditField = null"
>
{{ _('Cancel') }}
</Button>
<Button
type="primary"
class="ml-2 w-1/2 text-white"
@click="saveInlineEditDoc"
>
{{ df.inlineSaveText || _('Save') }}
</Button>
</div>
</div>
</template>
<div
v-else
class="grid"
:class="{ 'border-b': !noBorder }"
:style="style"
>
<div
class="py-2 pl-4 flex items-center"
:class="validateForm && df.required ? 'text-red-600' : 'text-gray-600'"
>
{{ df.label }}
</div>
<div class="py-2 pr-4" @click="activateInlineEditing(df)">
<FormControl
ref="controls"
size="small"
:df="df"
:value="
df.inline && doc.getLink(df.fieldname)
? doc.getLink(df.fieldname)[
doc.getLink(df.fieldname).meta.inlineEditDisplayField ||
'name'
]
: doc[df.fieldname]
"
@change="value => onChange(df, value)"
@focus="activateInlineEditing(df)"
/>
</div>
</div>
</template>
</template>
</div>
</template>
<script>
import FormControl from '@/components/Controls/FormControl';
import Button from '@/components/Button';
export default {
let TwoColumnForm = {
name: 'TwoColumnForm',
props: ['doc', 'fields', 'autosave'],
props: {
doc: Object,
fields: Array,
autosave: Boolean,
columnRatio: {
type: Array,
default: () => [1, 1]
},
noBorder: Boolean,
focusFirstInput: Boolean,
validateForm: Boolean
},
data() {
return {
inlineEditField: null,
inlineEditDoc: null,
inlineEditFields: null,
inlineEditDisplayField: null
};
},
provide() {
return {
doctype: this.doc.doctype,
name: this.doc.name
}
};
},
components: {
FormControl
FormControl,
Button,
TwoColumnForm: () => TwoColumnForm
},
mounted() {
if (this.focusFirstInput) {
this.$refs['controls'][0].focus();
}
},
methods: {
onChange(df, value) {
if (value == null) {
return;
}
let oldValue = this.doc.get(df.fieldname);
if (oldValue === value) {
return;
}
// handle rename
if (this.autosave && df.fieldname === 'name' && !this.doc.isNew()) {
return this.doc.rename(value);
return;
}
this.doc.set(df.fieldname, value);
if (this.autosave) {
this.doc.update()
if (this.autosave && this.doc._dirty && !this.doc.isNew()) {
if (df.fieldtype === 'Table') {
return;
}
this.doc.update();
}
},
async activateInlineEditing(df) {
if (df.inline) {
this.inlineEditField = df;
if (!this.doc[df.fieldname]) {
this.inlineEditDoc = await frappe.getNewDoc(df.target);
this.inlineEditDoc.once('afterInsert', () => {
this.onChange(df, this.inlineEditDoc.name);
});
} else {
this.inlineEditDoc = this.doc.getLink(df.fieldname);
}
this.inlineEditDisplayField =
this.doc.meta.inlineEditDisplayField || 'name';
this.inlineEditFields = frappe.getMeta(df.target).getQuickEditFields();
}
},
async saveInlineEditDoc() {
if (this.inlineEditDoc) {
await this.inlineEditDoc.insertOrUpdate();
await this.doc.loadLinks();
this.inlineEditField = null;
}
}
},
computed: {
style() {
let templateColumns = (this.columnRatio || [1, 1])
.map(r => `${r}fr`)
.join(' ');
return {
'grid-template-columns': templateColumns
};
}
}
}
};
export default TwoColumnForm;
</script>