{ "version": 3, "sources": ["../../../../../apps/frappe/frappe/public/js/frappe/form/formatters.js", "../../../../../apps/frappe/frappe/public/js/frappe/form/section.js", "../../../../../apps/frappe/frappe/public/js/frappe/form/tab.js", "../../../../../apps/frappe/frappe/public/js/frappe/form/column.js", "../../../../../apps/frappe/frappe/public/js/frappe/form/layout.js", "../../../../../apps/frappe/frappe/public/js/frappe/ui/field_group.js", "../../../../../apps/frappe/frappe/public/js/website_forms.bundle.js"], "sourcesContent": ["// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors\n// MIT License. See license.txt\n\n// for license information please see license.txt\n\nfrappe.provide(\"frappe.form.formatters\");\n\nfrappe.form.link_formatters = {};\n\nfrappe.form.formatters = {\n\t_right: function(value, options) {\n\t\tif(options && (options.inline || options.only_value)) {\n\t\t\treturn value;\n\t\t} else {\n\t\t\treturn \"
\" + value + \"
\";\n\t\t}\n\t},\n\tData: function(value, df) {\n\t\tif (df && df.options == \"URL\") {\n\t\t\treturn `${value}`;\n\t\t}\n\t\treturn value==null ? \"\" : value;\n\t},\n\tSelect: function(value) {\n\t\treturn __(frappe.form.formatters[\"Data\"](value));\n\t},\n\tFloat: function(value, docfield, options, doc) {\n\t\t// don't allow 0 precision for Floats, hence or'ing with null\n\t\tvar precision = docfield.precision\n\t\t\t|| cint(frappe.boot.sysdefaults && frappe.boot.sysdefaults.float_precision)\n\t\t\t|| null;\n\t\tif (docfield.options && docfield.options.trim()) {\n\t\t\t// options points to a currency field, but expects precision of float!\n\t\t\tdocfield.precision = precision;\n\t\t\treturn frappe.form.formatters.Currency(value, docfield, options, doc);\n\n\t\t} else {\n\t\t\t// show 1.000000 as 1\n\t\t\tif (!(options || {}).always_show_decimals && !is_null(value)) {\n\t\t\t\tvar temp = cstr(value).split(\".\");\n\t\t\t\tif (temp[1]==undefined || cint(temp[1])===0) {\n\t\t\t\t\tprecision = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn frappe.form.formatters._right(\n\t\t\t\t((value==null || value===\"\")\n\t\t\t\t\t? \"\"\n\t\t\t\t\t: format_number(value, null, precision)), options);\n\t\t}\n\t},\n\tInt: function(value, docfield, options) {\n\t\treturn frappe.form.formatters._right(value==null ? \"\" : cint(value), options)\n\t},\n\tPercent: function(value, docfield, options) {\n\t\tconst precision = (\n\t\t\tdocfield.precision\n\t\t\t|| cint(\n\t\t\t\tfrappe.boot.sysdefaults\n\t\t\t\t&& frappe.boot.sysdefaults.float_precision\n\t\t\t)\n\t\t\t|| 2\n\t\t);\n\t\treturn frappe.form.formatters._right(flt(value, precision) + \"%\", options);\n\t},\n\tRating: function(value, docfield) {\n\t\tlet rating_html = '';\n\t\tlet number_of_stars = docfield.options || 5;\n\t\tvalue = value * number_of_stars;\n\t\tArray.from({length: cint(number_of_stars)}, (_, i) => i + 1).forEach(i => {\n\t\t\trating_html += `\n\t\t\t\t\n\t\t\t\t\n\t\t\t`;\n\t\t});\n\t\treturn `
\n\t\t\t${rating_html}\n\t\t
`;\n\t},\n\tCurrency: function (value, docfield, options, doc) {\n\t\tvar currency = frappe.meta.get_field_currency(docfield, doc);\n\t\tvar precision = window.currency_precision || docfield.precision || cint(frappe.boot.sysdefaults.currency_precision) || 2;\n\n\t\t// If you change anything below, it's going to hurt a company in UAE, a bit.\n\t\tif (precision > 2) {\n\t\t\tvar parts\t = cstr(value).split(\".\"); // should be minimum 2, comes from the DB\n\t\t\tvar decimals = parts.length > 1 ? parts[1] : \"\"; // parts.length == 2 ???\n\n\t\t\tif ( decimals.length < 3 || decimals.length < precision ) {\n\t\t\t\tconst fraction = frappe.model.get_value(\":Currency\", currency, \"fraction_units\") || 100; // if not set, minimum 2.\n\n\t\t\t\tif (decimals.length < cstr(fraction).length) {\n\t\t\t\t\tprecision = cstr(fraction).length - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvalue = (value == null || value === \"\") ? \"\" : format_currency(value, currency, precision);\n\n\t\tif ( options && options.only_value ) {\n\t\t\treturn value;\n\t\t} else {\n\t\t\treturn frappe.form.formatters._right(value, options);\n\t\t}\n\t},\n\tCheck: function(value) {\n\t\treturn ``;\n\t},\n\tLink: function(value, docfield, options, doc) {\n\t\tvar doctype = docfield._options || docfield.options;\n\t\tvar original_value = value;\n\t\tif(value && value.match && value.match(/^['\"].*['\"]$/)) {\n\t\t\tvalue.replace(/^.(.*).$/, \"$1\");\n\t\t}\n\n\t\tif(options && (options.for_print || options.only_value)) {\n\t\t\treturn value;\n\t\t}\n\n\t\tif(frappe.form.link_formatters[doctype]) {\n\t\t\t// don't apply formatters in case of composite (parent field of same type)\n\t\t\tif (doc && doctype !== doc.doctype) {\n\t\t\t\tvalue = frappe.form.link_formatters[doctype](value, doc, docfield);\n\t\t\t}\n\t\t} else if (doc && doc[docfield.fieldname + '__name']) {\n\t\t\tvalue = doc && doc[docfield.fieldname + '__name'];\n\t\t}\n\n\t\tif(!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\tif(value[0] == \"'\" && value[value.length -1] == \"'\") {\n\t\t\treturn value.substring(1, value.length - 1);\n\t\t}\n\t\tif(docfield && docfield.link_onclick) {\n\t\t\treturn repl('%(value)s',\n\t\t\t\t{onclick: docfield.link_onclick.replace(/\"/g, '"'), value:value});\n\t\t} else if(docfield && doctype) {\n\t\t\tif (frappe.model.can_read(doctype)) {\n\t\t\t\treturn `\n\t\t\t\t\t${__(options && options.label || value)}`;\n\t\t\t} else {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t},\n\tDate: function(value) {\n\t\tif (!frappe.datetime.str_to_user) {\n\t\t\treturn value;\n\t\t}\n\t\tif (value) {\n\t\t\tvalue = frappe.datetime.str_to_user(value);\n\t\t\t// handle invalid date\n\t\t\tif (value===\"Invalid date\") {\n\t\t\t\tvalue = null;\n\t\t\t}\n\t\t}\n\n\t\treturn value || \"\";\n\t},\n\tDateRange: function(value) {\n\t\tif (Array.isArray(value)) {\n\t\t\treturn __(\"{0} to {1}\", [frappe.datetime.str_to_user(value[0]), frappe.datetime.str_to_user(value[1])]);\n\t\t} else {\n\t\t\treturn value || \"\";\n\t\t}\n\t},\n\tDatetime: function(value) {\n\t\tif(value) {\n\t\t\treturn moment(frappe.datetime.convert_to_user_tz(value))\n\t\t\t\t.format(frappe.boot.sysdefaults.date_format.toUpperCase() + ' ' + frappe.boot.sysdefaults.time_format || 'HH:mm:ss');\n\t\t} else {\n\t\t\treturn \"\";\n\t\t}\n\t},\n\tText: function(value) {\n\t\tif(value) {\n\t\t\tvar tags = [\"\n\t\t\t\t\t${v}\n\t\t\t\t`;\n\t\t});\n\t\treturn html;\n\t},\n\tComment: function(value) {\n\t\treturn value;\n\t},\n\tAssign: function(value) {\n\t\tvar html = \"\";\n\t\t$.each(JSON.parse(value || \"[]\"), function(i, v) {\n\t\t\tif(v) html+= ''+v+'';\n\t\t});\n\t\treturn html;\n\t},\n\tSmallText: function(value) {\n\t\treturn frappe.form.formatters.Text(value);\n\t},\n\tTextEditor: function(value) {\n\t\tlet formatted_value = frappe.form.formatters.Text(value);\n\t\t// to use ql-editor styles\n\t\ttry {\n\t\t\tif (!$(formatted_value).find('.ql-editor').length) {\n\t\t\t\tformatted_value = `
${formatted_value}
`;\n\t\t\t}\n\t\t} catch(e) {\n\t\t\tformatted_value = `
${formatted_value}
`;\n\t\t}\n\n\t\treturn formatted_value;\n\t},\n\tCode: function(value) {\n\t\treturn \"
\" + (value==null ? \"\" : $(\"
\").text(value).html()) + \"
\"\n\t},\n\tWorkflowState: function(value) {\n\t\tvar workflow_state = frappe.get_doc(\"Workflow State\", value);\n\t\tif(workflow_state) {\n\t\t\treturn repl(\"\\\n\t\t\t\t %(value)s\", {\n\t\t\t\t\tvalue: value,\n\t\t\t\t\tstyle: workflow_state.style.toLowerCase(),\n\t\t\t\t\ticon: workflow_state.icon\n\t\t\t\t});\n\t\t} else {\n\t\t\treturn \"\" + value + \"\";\n\t\t}\n\t},\n\tEmail: function(value) {\n\t\treturn $(\"
\").text(value).html();\n\t},\n\tFileSize: function(value) {\n\t\tif(value > 1048576) {\n\t\t\tvalue = flt(flt(value) / 1048576, 1) + \"M\";\n\t\t} else if (value > 1024) {\n\t\t\tvalue = flt(flt(value) / 1024, 1) + \"K\";\n\t\t}\n\t\treturn value;\n\t},\n\tTableMultiSelect: function(rows, df, options) {\n\t\trows = rows || [];\n\t\tconst meta = frappe.get_meta(df.options);\n\t\tconst link_field = meta.fields.find(df => df.fieldtype === 'Link');\n\t\tconst formatted_values = rows.map(row => {\n\t\t\tconst value = row[link_field.fieldname];\n\t\t\treturn frappe.format(value, link_field, options, row);\n\t\t});\n\t\treturn formatted_values.join(', ');\n\t},\n\tColor: (value) => {\n\t\treturn value ? `
\n\t\t\t
\n\t\t\t${value}\n\t\t
` : '';\n\t},\n\tIcon: (value) => {\n\t\treturn value ? `
\n\t\t\t
${frappe.utils.icon(value, \"md\")}
\n\t\t\t${value}\n\t\t
` : '';\n\t}\n};\n\nfrappe.form.get_formatter = function(fieldtype) {\n\tif(!fieldtype)\n\t\tfieldtype = \"Data\";\n\treturn frappe.form.formatters[fieldtype.replace(/ /g, \"\")] || frappe.form.formatters.Data;\n}\n\nfrappe.format = function(value, df, options, doc) {\n\tif(!df) df = {\"fieldtype\":\"Data\"};\n\tif (df.fieldname == '_user_tags') df.fieldtype = 'Tag';\n\tvar fieldtype = df.fieldtype || \"Data\";\n\n\t// format Dynamic Link as a Link\n\tif(fieldtype===\"Dynamic Link\") {\n\t\tfieldtype = \"Link\";\n\t\tdf._options = doc ? doc[df.options] : null;\n\t}\n\n\tvar formatter = df.formatter || frappe.form.get_formatter(fieldtype);\n\n\tvar formatted = formatter(value, df, options, doc);\n\n\tif (typeof formatted == \"string\")\n\t\tformatted = frappe.dom.remove_script_and_style(formatted);\n\n\treturn formatted;\n};\n\nfrappe.get_format_helper = function(doc) {\n\tvar helper = {\n\t\tget_formatted: function(fieldname) {\n\t\t\tvar df = frappe.meta.get_docfield(doc.doctype, fieldname);\n\t\t\tif(!df) { console.log(\"fieldname not found: \" + fieldname); }\n\t\t\treturn frappe.format(doc[fieldname], df, {inline:1}, doc);\n\t\t}\n\t};\n\t$.extend(helper, doc);\n\treturn helper;\n};\n\nfrappe.form.link_formatters['User'] = function(value, doc, docfield) {\n\tlet full_name = doc && (doc.full_name || (docfield && doc[`${docfield.fieldname}_full_name`]));\n\treturn full_name || value;\n};\n", "export default class Section {\n\tconstructor(parent, df, card_layout, layout) {\n\t\tthis.layout = layout;\n\t\tthis.card_layout = card_layout;\n\t\tthis.parent = parent;\n\t\tthis.df = df || {};\n\t\tthis.fields_list = [];\n\t\tthis.fields_dict = {};\n\n\t\tthis.make();\n\n\t\tif (this.df.label && this.df.collapsible && localStorage.getItem(df.css_class + '-closed')) {\n\t\t\tthis.collapse();\n\t\t}\n\n\t\tthis.row = {\n\t\t\twrapper: this.wrapper\n\t\t};\n\n\t\tthis.refresh();\n\t}\n\n\tmake() {\n\t\tlet make_card = this.card_layout;\n\t\tthis.wrapper = $(`
\n\t\t\t`).appendTo(this.parent);\n\t\tthis.layout && this.layout.sections.push(this);\n\n\t\tif (this.df) {\n\t\t\tif (this.df.label) {\n\t\t\t\tthis.make_head();\n\t\t\t}\n\t\t\tif (this.df.description) {\n\t\t\t\tthis.description_wrapper = $(\n\t\t\t\t\t`
\n\t\t\t\t\t\t${__(this.df.description)}\n\t\t\t\t\t
`\n\t\t\t\t);\n\n\t\t\t\tthis.wrapper.append(this.description_wrapper);\n\t\t\t}\n\t\t\tif (this.df.css_class) {\n\t\t\t\tthis.wrapper.addClass(this.df.css_class);\n\t\t\t}\n\t\t\tif (this.df.hide_border) {\n\t\t\t\tthis.wrapper.toggleClass(\"hide-border\", true);\n\t\t\t}\n\t\t}\n\n\t\tthis.body = $('
').appendTo(this.wrapper);\n\n\t\tif (this.df.body_html) {\n\t\t\tthis.body.append(this.df.body_html);\n\t\t}\n\t}\n\n\tmake_head() {\n\t\tthis.head = $(`\n\t\t\t
\n\t\t\t\t${__(this.df.label)}\n\t\t\t\t\n\t\t\t
\n\t\t`);\n\n\t\tthis.head.appendTo(this.wrapper);\n\t\tthis.indicator = this.head.find('.collapse-indicator');\n\t\tthis.indicator.hide();\n\n\t\tif (this.df.collapsible) {\n\t\t\t// show / hide based on status\n\t\t\tthis.collapse_link = this.head.on(\"click\", () => {\n\t\t\t\tthis.collapse();\n\t\t\t});\n\t\t\tthis.set_icon();\n\t\t\tthis.indicator.show();\n\t\t}\n\t}\n\n\trefresh(hide) {\n\t\tif (!this.df) return;\n\t\t// hide if explicitly hidden\n\t\thide = hide || this.df.hidden || this.df.hidden_due_to_dependency;\n\t\tthis.wrapper.toggleClass(\"hide-control\", !!hide);\n\t}\n\n\tcollapse(hide) {\n\t\t// unknown edge case\n\t\tif (!(this.head && this.body)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (hide === undefined) {\n\t\t\thide = !this.body.hasClass(\"hide\");\n\t\t}\n\n\t\tthis.body.toggleClass(\"hide\", hide);\n\t\tthis.head && this.head.toggleClass(\"collapsed\", hide);\n\n\t\tthis.set_icon(hide);\n\n\t\t// refresh signature fields\n\t\tthis.fields_list.forEach((f) => {\n\t\t\tif (f.df.fieldtype == 'Signature') {\n\t\t\t\tf.refresh();\n\t\t\t}\n\t\t});\n\n\t\t// save state for next reload ('' is falsy)\n\t\tif (this.df.css_class)\n\t\t\tlocalStorage.setItem(this.df.css_class + '-closed', hide ? '1' : '');\n\t}\n\n\tset_icon(hide) {\n\t\tlet indicator_icon = hide ? 'down' : 'up-line';\n\t\tthis.indicator && this.indicator.html(frappe.utils.icon(indicator_icon, 'sm', 'mb-1'));\n\t}\n\n\tis_collapsed() {\n\t\treturn this.body.hasClass('hide');\n\t}\n\n\thas_missing_mandatory () {\n\t\tlet missing_mandatory = false;\n\t\tfor (let j = 0, l = this.fields_list.length; j < l; j++) {\n\t\t\tconst section_df = this.fields_list[j].df;\n\t\t\tif (section_df.reqd && this.layout.doc[section_df.fieldname] == null) {\n\t\t\t\tmissing_mandatory = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn missing_mandatory;\n\t}\n\n\thide() {\n\t\tthis.on_section_toggle(false);\n\t}\n\n\tshow() {\n\t\tthis.on_section_toggle(true);\n\t}\n\n\ton_section_toggle(show) {\n\t\tthis.wrapper.toggleClass(\"hide-control\", !show);\n\t\t// this.on_section_toggle && this.on_section_toggle(show);\n\t}\n}\n", "export default class Tab {\n\tconstructor(parent, df, frm, tabs_list, tabs_content) {\n\t\tthis.parent = parent;\n\t\tthis.df = df || {};\n\t\tthis.frm = frm;\n\t\tthis.doctype = 'User';\n\t\tthis.label = this.df && this.df.label;\n\t\tthis.tabs_list = tabs_list;\n\t\tthis.tabs_content = tabs_content;\n\t\tthis.fields_list = [];\n\t\tthis.fields_dict = {};\n\t\tthis.make();\n\t\tthis.refresh();\n\t}\n\n\tmake() {\n\t\tconst id = `${frappe.scrub(this.doctype, '-')}-${this.df.fieldname}`;\n\t\tthis.parent = $(`\n\t\t\t
  • \n\t\t\t\t\n\t\t\t\t\t\t${__(this.label)}\n\t\t\t\t\n\t\t\t
  • \n\t\t`).appendTo(this.tabs_list);\n\n\t\tthis.wrapper = $(`
    `).appendTo(this.tabs_content);\n\t}\n\n\trefresh() {\n\t\tif (!this.df) return;\n\n\t\t// hide if explicitly hidden\n\t\tlet hide = this.df.hidden || this.df.hidden_due_to_dependency;\n\t\tif (!hide && this.frm && !this.frm.get_perm(this.df.permlevel || 0, \"read\")) {\n\t\t\thide = true;\n\t\t}\n\n\t\thide && this.toggle(false);\n\t}\n\n\ttoggle(show) {\n\t\tthis.parent.toggleClass('hide', !show);\n\t\tthis.wrapper.toggleClass('hide', !show);\n\t\tthis.parent.toggleClass('show', show);\n\t\tthis.wrapper.toggleClass('show', show);\n\t\tthis.hidden = !show;\n\t}\n\n\tshow() {\n\t\tthis.parent.show();\n\t}\n\n\thide() {\n\t\tthis.parent.hide();\n\t}\n\n\tset_active() {\n\t\tthis.parent.find('.nav-link').tab('show');\n\t\tthis.wrapper.addClass('show');\n\t}\n\n\tis_active() {\n\t\treturn this.wrapper.hasClass('active');\n\t}\n\n\tis_hidden() {\n\t\tthis.wrapper.hasClass('hide')\n\t\t\t&& this.parent.hasClass('hide');\n\t}\n}\n", "export default class Column {\n\tconstructor(section, df) {\n\t\tif (!df) df = {};\n\n\t\tthis.df = df;\n\t\tthis.section = section;\n\t\tthis.make();\n\t\tthis.resize_all_columns();\n\t}\n\n\tmake() {\n\t\tthis.wrapper = $(`\n\t\t\t
    \n\t\t\t\t
    \n\t\t\t\t
    \n\t\t\t
    \n\t\t`)\n\t\t\t.appendTo(this.section.body)\n\t\t\t.find(\"form\")\n\t\t\t.on(\"submit\", function () {\n\t\t\t\treturn false;\n\t\t\t});\n\n\t\tif (this.df.label) {\n\t\t\t$(`\n\t\t\t\t\n\t\t\t`)\n\t\t\t\t.appendTo(this.wrapper);\n\t\t}\n\t}\n\n\tresize_all_columns() {\n\t\t// distribute all columns equally\n\t\tlet colspan = cint(12 / this.section.wrapper.find(\".form-column\").length);\n\n\t\tthis.section.wrapper\n\t\t\t.find(\".form-column\")\n\t\t\t.removeClass()\n\t\t\t.addClass(\"form-column\")\n\t\t\t.addClass(\"col-sm-\" + colspan);\n\n\t}\n\n\trefresh() {\n\t\tthis.section.refresh();\n\t}\n}", "import Section from \"./section.js\";\nimport Tab from \"./tab.js\";\nimport Column from \"./column.js\";\n\nfrappe.ui.form.Layout = class Layout {\n\tconstructor (opts) {\n\t\tthis.views = {};\n\t\tthis.pages = [];\n\t\tthis.tabs = [];\n\t\tthis.sections = [];\n\t\tthis.fields_list = [];\n\t\tthis.fields_dict = {};\n\n\t\t$.extend(this, opts);\n\t}\n\n\tmake() {\n\t\tif (!this.parent && this.body) {\n\t\t\tthis.parent = this.body;\n\t\t}\n\t\tthis.wrapper = $('
    ').appendTo(this.parent);\n\t\tthis.message = $('
    ').appendTo(this.wrapper);\n\t\tthis.page = $('
    ').appendTo(this.wrapper);\n\n\t\tif (!this.fields) {\n\t\t\tthis.fields = this.get_doctype_fields();\n\t\t}\n\n\t\tif (this.is_tabbed_layout()) {\n\t\t\tthis.setup_tabbed_layout();\n\t\t}\n\n\t\tthis.setup_tab_events();\n\t\tthis.render();\n\t}\n\n\tsetup_tabbed_layout() {\n\t\t$(`\n\t\t\t
    \n\t\t\t\t
      \n\t\t\t
      \n\t\t`).appendTo(this.page);\n\t\tthis.tabs_list = this.page.find('.form-tabs');\n\t\tthis.tabs_content = $(`
      `).appendTo(this.page);\n\t\tthis.setup_events();\n\t}\n\n\tshow_empty_form_message() {\n\t\tif (!(this.wrapper.find(\".frappe-control:visible\").length || this.wrapper.find(\".section-head.collapsed\").length)) {\n\t\t\tthis.show_message(__(\"This form does not have any input\"));\n\t\t}\n\t}\n\n\tget_doctype_fields() {\n\t\tlet fields = [\n\t\t\tthis.get_new_name_field()\n\t\t];\n\t\tif (this.doctype_layout) {\n\t\t\tfields = fields.concat(this.get_fields_from_layout());\n\t\t} else {\n\t\t\tfields = fields.concat(frappe.meta.sort_docfields(frappe.meta.docfield_map[this.doctype]));\n\t\t}\n\n\t\treturn fields;\n\t}\n\n\tget_new_name_field() {\n\t\treturn {\n\t\t\tparent: this.frm.doctype,\n\t\t\tfieldtype: 'Data',\n\t\t\tfieldname: '__newname',\n\t\t\treqd: 1,\n\t\t\thidden: 1,\n\t\t\tlabel: __('Name'),\n\t\t\tget_status: function(field) {\n\t\t\t\tif (field.frm && field.frm.is_new()\n\t\t\t\t\t&& field.frm.meta.autoname\n\t\t\t\t\t&& ['prompt', 'name'].includes(field.frm.meta.autoname.toLowerCase())) {\n\t\t\t\t\treturn 'Write';\n\t\t\t\t}\n\t\t\t\treturn 'None';\n\t\t\t}\n\t\t};\n\t}\n\n\tget_fields_from_layout() {\n\t\tconst fields = [];\n\t\tfor (let f of this.doctype_layout.fields) {\n\t\t\tconst docfield = copy_dict(frappe.meta.docfield_map[this.doctype][f.fieldname]);\n\t\t\tdocfield.label = f.label;\n\t\t\tfields.push(docfield);\n\t\t}\n\t\treturn fields;\n\t}\n\n\tshow_message(html, color) {\n\t\tif (this.message_color) {\n\t\t\t// remove previous color\n\t\t\tthis.message.removeClass(this.message_color);\n\t\t}\n\t\tthis.message_color = (color && ['yellow', 'blue'].includes(color)) ? color : 'blue';\n\t\tif (html) {\n\t\t\tif (html.substr(0, 1)!=='<') {\n\t\t\t\t// wrap in a block\n\t\t\t\thtml = '
      ' + html + '
      ';\n\t\t\t}\n\t\t\tthis.message.removeClass('hidden').addClass(this.message_color);\n\t\t\t$(html).appendTo(this.message);\n\t\t} else {\n\t\t\tthis.message.empty().addClass('hidden');\n\t\t}\n\t}\n\n\trender(new_fields) {\n\t\tlet fields = new_fields || this.fields;\n\n\t\tthis.section = null;\n\t\tthis.column = null;\n\n\t\tif (this.no_opening_section() && !this.is_tabbed_layout()) {\n\t\t\tthis.fields.unshift({fieldtype: 'Section Break'});\n\t\t}\n\n\t\tif (this.is_tabbed_layout()) {\n\t\t\tlet default_tab = {label: __('Details'), fieldname: 'details', fieldtype: \"Tab Break\"};\n\t\t\tlet first_tab = this.fields[1].fieldtype === \"Tab Break\" ? this.fields[1] : null;\n\t\t\tif (!first_tab) {\n\t\t\t\tthis.fields.splice(1, 0, default_tab);\n\t\t\t}\n\t\t}\n\n\t\tfields.forEach(df => {\n\t\t\tswitch (df.fieldtype) {\n\t\t\t\tcase \"Fold\":\n\t\t\t\t\tthis.make_page(df);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Section Break\":\n\t\t\t\t\tthis.make_section(df);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Column Break\":\n\t\t\t\t\tthis.make_column(df);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Tab Break\":\n\t\t\t\t\tthis.make_tab(df);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.make_field(df);\n\t\t\t}\n\t\t});\n\t}\n\n\tno_opening_section() {\n\t\treturn (this.fields[0] && this.fields[0].fieldtype != \"Section Break\") || !this.fields.length;\n\t}\n\n\tno_opening_tab() {\n\t\treturn (this.fields[1] && this.fields[1].fieldtype != \"Tab Break\") || !this.fields.length;\n\t}\n\n\tis_tabbed_layout() {\n\t\treturn this.fields.find(f => f.fieldtype === \"Tab Break\");\n\t}\n\n\treplace_field(fieldname, df, render) {\n\t\tdf.fieldname = fieldname; // change of fieldname is avoided\n\t\tif (this.fields_dict[fieldname] && this.fields_dict[fieldname].df) {\n\t\t\tconst fieldobj = this.init_field(df, render);\n\t\t\tthis.fields_dict[fieldname].$wrapper.remove();\n\t\t\tthis.fields_list.splice(this.fields_dict[fieldname], 1, fieldobj);\n\t\t\tthis.fields_dict[fieldname] = fieldobj;\n\t\t\tif (this.frm) {\n\t\t\t\tfieldobj.perm = this.frm.perm;\n\t\t\t}\n\t\t\tthis.section.fields_list.splice(this.section.fields_dict[fieldname], 1, fieldobj);\n\t\t\tthis.section.fields_dict[fieldname] = fieldobj;\n\t\t\tthis.refresh_fields([df]);\n\t\t}\n\t}\n\n\tmake_field(df, colspan, render) {\n\t\t!this.section && this.make_section();\n\t\t!this.column && this.make_column();\n\n\t\tconst fieldobj = this.init_field(df, render);\n\t\tthis.fields_list.push(fieldobj);\n\t\tthis.fields_dict[df.fieldname] = fieldobj;\n\t\tif (this.frm) {\n\t\t\tfieldobj.perm = this.frm.perm;\n\t\t}\n\n\t\tthis.section.fields_list.push(fieldobj);\n\t\tthis.section.fields_dict[df.fieldname] = fieldobj;\n\t\tfieldobj.section = this.section;\n\n\t\tif (this.current_tab) {\n\t\t\tfieldobj.tab = this.current_tab;\n\t\t\tthis.current_tab.fields_list.push(fieldobj);\n\t\t\tthis.current_tab.fields_dict[df.fieldname] = fieldobj;\n\t\t}\n\t}\n\n\tinit_field(df, render=false) {\n\t\tconst fieldobj = frappe.ui.form.make_control({\n\t\t\tdf: df,\n\t\t\tdoctype: this.doctype,\n\t\t\tparent: this.column.wrapper.get(0),\n\t\t\tfrm: this.frm,\n\t\t\trender_input: render,\n\t\t\tdoc: this.doc,\n\t\t\tlayout: this\n\t\t});\n\n\t\tfieldobj.layout = this;\n\t\treturn fieldobj;\n\t}\n\n\tmake_page(df) { // eslint-disable-line no-unused-vars\n\t\tlet me = this,\n\t\t\thead = $('
      \\\n\t\t\t\t' + __(\"Show more details\") + '\\\n\t\t\t
      ').appendTo(this.wrapper);\n\n\t\tthis.page = $('
      ').appendTo(this.wrapper);\n\n\t\tthis.fold_btn = head.find(\".btn-fold\").on(\"click\", function () {\n\t\t\tlet page = $(this).parent().next();\n\t\t\tif (page.hasClass(\"hide\")) {\n\t\t\t\t$(this).removeClass(\"btn-fold\").html(__(\"Hide details\"));\n\t\t\t\tpage.removeClass(\"hide\");\n\t\t\t\tfrappe.utils.scroll_to($(this), true, 30);\n\t\t\t\tme.folded = false;\n\t\t\t} else {\n\t\t\t\t$(this).addClass(\"btn-fold\").html(__(\"Show more details\"));\n\t\t\t\tpage.addClass(\"hide\");\n\t\t\t\tme.folded = true;\n\t\t\t}\n\t\t});\n\n\t\tthis.section = null;\n\t\tthis.folded = true;\n\t}\n\n\tunfold() {\n\t\tthis.fold_btn.trigger('click');\n\t}\n\n\tmake_section(df) {\n\t\tthis.section = new Section(this.current_tab ? this.current_tab.wrapper : this.page, df, this.card_layout, this);\n\n\t\t// append to layout fields\n\t\tif (df) {\n\t\t\tthis.fields_dict[df.fieldname] = this.section;\n\t\t\tthis.fields_list.push(this.section);\n\t\t}\n\n\t\tthis.column = null;\n\t}\n\n\tmake_column(df) {\n\t\tthis.column = new Column(this.section, df);\n\t\tif (df && df.fieldname) {\n\t\t\tthis.fields_list.push(this.column);\n\t\t}\n\t}\n\n\tmake_tab(df) {\n\t\tthis.section = null;\n\t\tlet tab = new Tab(this, df, this.frm, this.tabs_list, this.tabs_content);\n\t\tthis.current_tab = tab;\n\t\tthis.make_section({fieldtype: 'Section Break'});\n\t\tthis.tabs.push(tab);\n\t\treturn tab;\n\t}\n\n\trefresh(doc) {\n\t\tif (doc) this.doc = doc;\n\n\t\tif (this.frm) {\n\t\t\tthis.wrapper.find(\".empty-form-alert\").remove();\n\t\t}\n\n\t\t// NOTE this might seem redundant at first, but it needs to be executed when frm.refresh_fields is called\n\t\tthis.attach_doc_and_docfields(true);\n\n\t\tif (this.frm && this.frm.wrapper) {\n\t\t\t$(this.frm.wrapper).trigger(\"refresh-fields\");\n\t\t}\n\n\t\t// dependent fields\n\t\tthis.refresh_dependency();\n\n\t\t// refresh sections\n\t\tthis.refresh_sections();\n\n\t\t// refresh tabs\n\t\tthis.tabbed_layout && this.refresh_tabs();\n\n\t\tif (this.frm) {\n\t\t\t// collapse sections\n\t\t\tthis.refresh_section_collapse();\n\t\t}\n\n\t\tif (document.activeElement) {\n\t\t\tif (document.activeElement.tagName == 'INPUT' && this.is_numeric_field_active()) {\n\t\t\t\tdocument.activeElement.select();\n\t\t\t}\n\t\t}\n\t}\n\n\tis_numeric_field_active() {\n\t\tconst control = $(document.activeElement).closest(\".frappe-control\");\n\t\tconst fieldtype = (control.data() || {}).fieldtype;\n\t\treturn frappe.model.numeric_fieldtypes.includes(fieldtype);\n\t}\n\n\trefresh_sections() {\n\t\t// hide invisible sections\n\t\tthis.wrapper.find(\".form-section:not(.hide-control)\").each(function() {\n\t\t\tconst section = $(this).removeClass(\"empty-section visible-section\");\n\t\t\tif (section.find(\".frappe-control:not(.hide-control)\").length) {\n\t\t\t\tsection.addClass(\"visible-section\");\n\t\t\t} else {\n\t\t\t\t// nothing visible, hide the section\n\t\t\t\tsection.addClass(\"empty-section\");\n\t\t\t}\n\t\t});\n\t}\n\n\trefresh_tabs() {\n\t\tthis.tabs.forEach(tab => {\n\t\t\tif (!tab.wrapper.hasClass('hide') || !tab.parent.hasClass('hide')) {\n\t\t\t\ttab.parent.removeClass('show hide');\n\t\t\t\ttab.wrapper.removeClass('show hide');\n\t\t\t\tif (\n\t\t\t\t\ttab.wrapper.find(\n\t\t\t\t\t\t\".form-section:not(.hide-control, .empty-section), .form-dashboard-section:not(.hide-control, .empty-section)\"\n\t\t\t\t\t).length\n\t\t\t\t) {\n\t\t\t\t\ttab.toggle(true);\n\t\t\t\t} else {\n\t\t\t\t\ttab.toggle(false);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tconst visible_tabs = this.tabs.filter(tab => !tab.hidden);\n\t\tif (visible_tabs && visible_tabs.length == 1) {\n\t\t\tvisible_tabs[0].parent.toggleClass('hide show');\n\t\t}\n\t}\n\n\trefresh_fields(fields) {\n\t\tlet fieldnames = fields.map((field) => {\n\t\t\tif (field.fieldname) return field.fieldname;\n\t\t});\n\n\t\tthis.fields_list.map(fieldobj => {\n\t\t\tif (fieldnames.includes(fieldobj.df.fieldname)) {\n\t\t\t\tfieldobj.refresh();\n\t\t\t\tif (fieldobj.df[\"default\"]) {\n\t\t\t\t\tfieldobj.set_input(fieldobj.df[\"default\"]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tadd_fields(fields) {\n\t\tthis.render(fields);\n\t\tthis.refresh_fields(fields);\n\t}\n\n\trefresh_section_collapse () {\n\t\tif (!(this.sections && this.sections.length)) return;\n\n\t\tfor (let i = 0; i < this.sections.length; i++) {\n\t\t\tlet section = this.sections[i];\n\t\t\tlet df = section.df;\n\t\t\tif (df && df.collapsible) {\n\t\t\t\tlet collapse = true;\n\n\t\t\t\tif (df.collapsible_depends_on) {\n\t\t\t\t\tcollapse = !this.evaluate_depends_on_value(df.collapsible_depends_on);\n\t\t\t\t}\n\n\t\t\t\tif (collapse && section.has_missing_mandatory()) {\n\t\t\t\t\tcollapse = false;\n\t\t\t\t}\n\n\t\t\t\tsection.collapse(collapse);\n\t\t\t}\n\t\t}\n\t}\n\n\tattach_doc_and_docfields(refresh) {\n\t\tlet me = this;\n\t\tfor (let i = 0, l = this.fields_list.length; i < l; i++) {\n\t\t\tlet fieldobj = this.fields_list[i];\n\t\t\tif (me.doc) {\n\t\t\t\tfieldobj.doc = me.doc;\n\t\t\t\tfieldobj.doctype = me.doc.doctype;\n\t\t\t\tfieldobj.docname = me.doc.name;\n\t\t\t\tfieldobj.df = frappe.meta.get_docfield(me.doc.doctype,\n\t\t\t\t\tfieldobj.df.fieldname, me.doc.name) || fieldobj.df;\n\n\t\t\t\t// on form change, permissions can change\n\t\t\t\tif (me.frm) {\n\t\t\t\t\tfieldobj.perm = me.frm.perm;\n\t\t\t\t}\n\t\t\t}\n\t\t\trefresh && fieldobj.df && fieldobj.refresh && fieldobj.refresh();\n\t\t}\n\t}\n\n\trefresh_section_count() {\n\t\tthis.wrapper.find(\".section-count-label:visible\").each(function (i) {\n\t\t\t$(this).html(i + 1);\n\t\t});\n\t}\n\n\tsetup_events() {\n\t\tthis.tabs_list.off('click').on('click', '.nav-link', (e) => {\n\t\t\te.preventDefault();\n\t\t\te.stopImmediatePropagation();\n\t\t\t$(e.currentTarget).tab('show');\n\t\t});\n\t}\n\n\tsetup_tab_events() {\n\t\tthis.wrapper.on(\"keydown\", (ev) => {\n\t\t\tif (ev.which == 9) {\n\t\t\t\tlet current = $(ev.target);\n\t\t\t\tlet doctype = current.attr(\"data-doctype\");\n\t\t\t\tlet fieldname = current.attr(\"data-fieldname\");\n\t\t\t\tif (doctype) {\n\t\t\t\t\treturn this.handle_tab(doctype, fieldname, ev.shiftKey);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\thandle_tab(doctype, fieldname, shift) {\n\t\tlet\tgrid_row = null,\n\t\t\tprev = null,\n\t\t\tfields = this.fields_list,\n\t\t\tfocused = false;\n\n\t\t// in grid\n\t\tif (doctype != this.doctype) {\n\t\t\tgrid_row = this.get_open_grid_row();\n\t\t\tif (!grid_row || !grid_row.layout) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfields = grid_row.layout.fields_list;\n\t\t}\n\n\t\tfor (let i = 0, len = fields.length; i < len; i++) {\n\t\t\tif (fields[i].df.fieldname == fieldname) {\n\t\t\t\tif (shift) {\n\t\t\t\t\tif (prev) {\n\t\t\t\t\t\tthis.set_focus(prev);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$(this.primary_button).focus();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (i < len - 1) {\n\t\t\t\t\tfocused = this.focus_on_next_field(i, fields);\n\t\t\t\t}\n\n\t\t\t\tif (focused) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.is_visible(fields[i]))\n\t\t\t\tprev = fields[i];\n\t\t}\n\n\t\tif (!focused) {\n\t\t\t// last field in this group\n\t\t\tif (grid_row) {\n\t\t\t\t// in grid\n\t\t\t\tif (grid_row.doc.idx == grid_row.grid.grid_rows.length) {\n\t\t\t\t\t// last row, close it and find next field\n\t\t\t\t\tgrid_row.toggle_view(false, function () {\n\t\t\t\t\t\tgrid_row.grid.frm.layout.handle_tab(grid_row.grid.df.parent, grid_row.grid.df.fieldname);\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// next row\n\t\t\t\t\tgrid_row.grid.grid_rows[grid_row.doc.idx].toggle_view(true);\n\t\t\t\t}\n\t\t\t} else if (!shift) {\n\t\t\t\t// End of tab navigation\n\t\t\t\t$(this.primary_button).focus();\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfocus_on_next_field(start_idx, fields) {\n\t\t// loop to find next eligible fields\n\t\tfor (let i = start_idx + 1, len = fields.length; i < len; i++) {\n\t\t\tlet field = fields[i];\n\t\t\tif (this.is_visible(field)) {\n\t\t\t\tif (field.df.fieldtype === \"Table\") {\n\t\t\t\t\t// open table grid\n\t\t\t\t\tif (!(field.grid.grid_rows && field.grid.grid_rows.length)) {\n\t\t\t\t\t\t// empty grid, add a new row\n\t\t\t\t\t\tfield.grid.add_new_row();\n\t\t\t\t\t}\n\t\t\t\t\t// show grid row (if exists)\n\t\t\t\t\tfield.grid.grid_rows[0].show_form();\n\t\t\t\t\treturn true;\n\n\t\t\t\t} else if (!in_list(frappe.model.no_value_type, field.df.fieldtype)) {\n\t\t\t\t\tthis.set_focus(field);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tis_visible(field) {\n\t\treturn field.disp_status === \"Write\" && (field.df && \"hidden\" in field.df && !field.df.hidden);\n\t}\n\n\tset_focus(field) {\n\t\tif (field.tab) {\n\t\t\tfield.tab.set_active();\n\t\t}\n\t\t// next is table, show the table\n\t\tif (field.df.fieldtype==\"Table\") {\n\t\t\tif (!field.grid.grid_rows.length) {\n\t\t\t\tfield.grid.add_new_row(1);\n\t\t\t} else {\n\t\t\t\tfield.grid.grid_rows[0].toggle_view(true);\n\t\t\t}\n\t\t} else if (field.editor) {\n\t\t\tfield.editor.set_focus();\n\t\t} else if (field.$input) {\n\t\t\tfield.$input.focus();\n\t\t}\n\t}\n\n\tget_open_grid_row() {\n\t\treturn $(\".grid-row-open\").data(\"grid_row\");\n\t}\n\n\trefresh_dependency() {\n\t\t// Resolve \"depends_on\" and show / hide accordingly\n\n\t\t// build dependants' dictionary\n\t\tlet has_dep = false;\n\n\t\tfor (let fkey in this.fields_list) {\n\t\t\tlet f = this.fields_list[fkey];\n\t\t\tf.dependencies_clear = true;\n\t\t\tif (f.df.depends_on || f.df.mandatory_depends_on || f.df.read_only_depends_on) {\n\t\t\t\thas_dep = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!has_dep) return;\n\n\t\t// show / hide based on values\n\t\tfor (let i = this.fields_list.length - 1; i >= 0; i--) {\n\t\t\tlet f = this.fields_list[i];\n\t\t\tf.guardian_has_value = true;\n\t\t\tif (f.df.depends_on) {\n\t\t\t\t// evaluate guardian\n\n\t\t\t\tf.guardian_has_value = this.evaluate_depends_on_value(f.df.depends_on);\n\n\t\t\t\t// show / hide\n\t\t\t\tif (f.guardian_has_value) {\n\t\t\t\t\tif (f.df.hidden_due_to_dependency) {\n\t\t\t\t\t\tf.df.hidden_due_to_dependency = false;\n\t\t\t\t\t\tf.refresh();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (!f.df.hidden_due_to_dependency) {\n\t\t\t\t\t\tf.df.hidden_due_to_dependency = true;\n\t\t\t\t\t\tf.refresh();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (f.df.mandatory_depends_on) {\n\t\t\t\tthis.set_dependant_property(f.df.mandatory_depends_on, f.df.fieldname, 'reqd');\n\t\t\t}\n\n\t\t\tif (f.df.read_only_depends_on) {\n\t\t\t\tthis.set_dependant_property(f.df.read_only_depends_on, f.df.fieldname, 'read_only');\n\t\t\t}\n\t\t}\n\n\t\tthis.refresh_section_count();\n\t}\n\n\tset_dependant_property(condition, fieldname, property) {\n\t\tlet set_property = this.evaluate_depends_on_value(condition);\n\t\tlet value = set_property ? 1 : 0;\n\t\tlet form_obj;\n\n\t\tif (this.frm) {\n\t\t\tform_obj = this.frm;\n\t\t} else if (this.is_dialog || this.doctype === 'Web Form') {\n\t\t\tform_obj = this;\n\t\t}\n\t\tif (form_obj) {\n\t\t\tif (this.doc && this.doc.parent && this.doc.parentfield) {\n\t\t\t\tform_obj.setting_dependency = true;\n\t\t\t\tform_obj.set_df_property(this.doc.parentfield, property, value, this.doc.parent, fieldname, this.doc.name);\n\t\t\t\tform_obj.setting_dependency = false;\n\t\t\t\t// refresh child fields\n\t\t\t\tthis.fields_dict[fieldname] && this.fields_dict[fieldname].refresh();\n\t\t\t} else {\n\t\t\t\tform_obj.set_df_property(fieldname, property, value);\n\t\t\t}\n\t\t}\n\t}\n\n\tevaluate_depends_on_value(expression) {\n\t\tlet out = null;\n\t\tlet doc = this.doc;\n\n\t\tif (!doc && this.get_values) {\n\t\t\tdoc = this.get_values(true);\n\t\t}\n\n\t\tif (!doc) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet parent = this.frm ? this.frm.doc : this.doc || null;\n\n\t\tif (typeof (expression) === 'boolean') {\n\t\t\tout = expression;\n\n\t\t} else if (typeof (expression) === 'function') {\n\t\t\tout = expression(doc);\n\n\t\t} else if (expression.substr(0, 5)=='eval:') {\n\t\t\ttry {\n\t\t\t\tout = frappe.utils.eval(expression.substr(5), { doc, parent });\n\t\t\t\tif (parent && parent.istable && expression.includes('is_submittable')) {\n\t\t\t\t\tout = true;\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tfrappe.throw(__('Invalid \"depends_on\" expression'));\n\t\t\t}\n\n\t\t} else if (expression.substr(0, 3)=='fn:' && this.frm) {\n\t\t\tout = this.frm.script_manager.trigger(expression.substr(3), this.doctype, this.docname);\n\t\t} else {\n\t\t\tvar value = doc[expression];\n\t\t\tif ($.isArray(value)) {\n\t\t\t\tout = !!value.length;\n\t\t\t} else {\n\t\t\t\tout = !!value;\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t}\n};\n", "import '../form/layout';\n\nfrappe.provide('frappe.ui');\n\nfrappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {\n\tconstructor(opts) {\n\t\tsuper(opts);\n\t\tthis.dirty = false;\n\t\t$.each(this.fields || [], function(i, f) {\n\t\t\tif(!f.fieldname && f.label) {\n\t\t\t\tf.fieldname = f.label.replace(/ /g, \"_\").toLowerCase();\n\t\t\t}\n\t\t})\n\t\tif(this.values) {\n\t\t\tthis.set_values(this.values);\n\t\t}\n\t}\n\n\tmake() {\n\t\tvar me = this;\n\t\tif(this.fields) {\n\t\t\tsuper.make();\n\t\t\tthis.refresh();\n\t\t\t// set default\n\t\t\t$.each(this.fields_list, function(i, field) {\n\t\t\t\tif (field.df[\"default\"]) {\n\t\t\t\t\tlet def_value = field.df[\"default\"];\n\n\t\t\t\t\tif (def_value == 'Today' && field.df[\"fieldtype\"] == 'Date') {\n\t\t\t\t\t\tdef_value = frappe.datetime.get_today();\n\t\t\t\t\t}\n\n\t\t\t\t\tfield.set_input(def_value);\n\t\t\t\t\t// if default and has depends_on, render its fields.\n\t\t\t\t\tme.refresh_dependency();\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tif(!this.no_submit_on_enter) {\n\t\t\t\tthis.catch_enter_as_submit();\n\t\t\t}\n\n\t\t\t$(this.wrapper).find('input, select').on(\n\t\t\t\t'change awesomplete-selectcomplete',\n\t\t\t\t() => {\n\t\t\t\t\tthis.dirty = true;\n\t\t\t\t\tfrappe.run_serially([\n\t\t\t\t\t\t() => frappe.timeout(0.1),\n\t\t\t\t\t\t() => me.refresh_dependency()\n\t\t\t\t\t]);\n\t\t\t\t}\n\t\t\t);\n\n\t\t}\n\t}\n\n\tfocus_on_first_input() {\n\t\tif(this.no_focus) return;\n\t\t$.each(this.fields_list, function(i, f) {\n\t\t\tif(!in_list(['Date', 'Datetime', 'Time', 'Check'], f.df.fieldtype) && f.set_focus) {\n\t\t\t\tf.set_focus();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n\tcatch_enter_as_submit() {\n\t\tvar me = this;\n\t\t$(this.body).find('input[type=\"text\"], input[type=\"password\"], select').keypress(function(e) {\n\t\t\tif(e.which==13) {\n\t\t\t\tif(me.has_primary_action) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tme.get_primary_btn().trigger(\"click\");\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tget_input(fieldname) {\n\t\tvar field = this.fields_dict[fieldname];\n\t\treturn $(field.txt ? field.txt : field.input);\n\t}\n\n\tget_field(fieldname) {\n\t\treturn this.fields_dict[fieldname];\n\t}\n\n\tget_values(ignore_errors) {\n\t\tvar ret = {};\n\t\tvar errors = [];\n\t\tfor (var key in this.fields_dict) {\n\t\t\tvar f = this.fields_dict[key];\n\t\t\tif (f.get_value) {\n\t\t\t\tvar v = f.get_value();\n\t\t\t\tif (\n\t\t\t\t\tf.df.reqd &&\n\t\t\t\t\tis_null(typeof v === 'string' ? strip_html(v) : v)\n\t\t\t\t)\n\t\t\t\t\terrors.push(__(f.df.label));\n\n\t\t\t\tif (f.df.reqd\n\t\t\t\t\t&& f.df.fieldtype === 'Text Editor'\n\t\t\t\t\t&& is_null(strip_html(cstr(v))))\n\t\t\t\t\terrors.push(__(f.df.label));\n\n\t\t\t\tif (!is_null(v)) ret[f.df.fieldname] = v;\n\t\t\t}\n\t\t}\n\t\tif (errors.length && !ignore_errors) {\n\t\t\tfrappe.msgprint({\n\t\t\t\ttitle: __('Missing Values Required'),\n\t\t\t\tmessage: __('Following fields have missing values:') +\n\t\t\t\t\t'

      • ' + errors.join('
      • ') + '
      ',\n\t\t\t\tindicator: 'orange'\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\t\treturn ret;\n\t}\n\n\tget_value(key) {\n\t\tvar f = this.fields_dict[key];\n\t\treturn f && (f.get_value ? f.get_value() : null);\n\t}\n\n\tset_value(key, val) {\n\t\treturn new Promise(resolve => {\n\t\t\tvar f = this.fields_dict[key];\n\t\t\tif (f) {\n\t\t\t\tf.set_value(val).then(() => {\n\t\t\t\t\tf.set_input(val);\n\t\t\t\t\tthis.refresh_dependency();\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t}\n\n\tset_input(key, val) {\n\t\treturn this.set_value(key, val);\n\t}\n\n\tset_values(dict) {\n\t\tlet promises = [];\n\t\tfor(var key in dict) {\n\t\t\tif(this.fields_dict[key]) {\n\t\t\t\tif (this.fields_dict[key].df.fieldtype === 'Table' && !this.fields_dict[key].frm) {\n\t\t\t\t\tthis.fields_dict[key].df.data = dict[key];\n\t\t\t\t\tpromises.push(this.fields_dict[key].refresh());\n\t\t\t\t} else {\n\t\t\t\t\tpromises.push(this.set_value(key, dict[key]));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all(promises);\n\t}\n\n\tclear() {\n\t\tfor(var key in this.fields_dict) {\n\t\t\tvar f = this.fields_dict[key];\n\t\t\tif(f && f.set_input) {\n\t\t\t\tf.set_input(f.df['default'] || '');\n\t\t\t}\n\t\t}\n\t}\n\n\tset_df_property (fieldname, prop, value) {\n\t\tconst field = this.get_field(fieldname);\n\t\tfield.df[prop] = value;\n\t\tfield.refresh();\n\t}\n};\n", "import './frappe/form/formatters.js';\nimport './frappe/ui/field_group.js';\n\nclass WebsiteForm extends frappe.ui.FieldGroup {\n addButton(text, action, type = 'default') {\n const form = this;\n\n $(this.wrapper).find('form')\n .append(\n $(\n `