From 2ab07f427587087da45483685fb86b69101a8fd3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 23 Aug 2017 18:36:47 +0530 Subject: [PATCH] [feature] autoname prompt, refactor control.js, fixes frappe/erpnext#8940 --- frappe/hooks.py | 1 + frappe/public/build.json | 63 +- frappe/public/js/frappe/form/control.js | 2270 ----------------- .../public/js/frappe/form/controls/attach.js | 187 ++ .../js/frappe/form/controls/attach_image.js | 66 + .../js/frappe/form/controls/base_control.js | 167 ++ .../js/frappe/form/controls/base_input.js | 180 ++ .../public/js/frappe/form/controls/button.js | 38 + .../public/js/frappe/form/controls/check.js | 38 + frappe/public/js/frappe/form/controls/code.js | 8 + .../public/js/frappe/form/controls/color.js | 83 + .../js/frappe/form/controls/currency.js | 20 + frappe/public/js/frappe/form/controls/data.js | 138 + frappe/public/js/frappe/form/controls/date.js | 106 + .../js/frappe/form/controls/date_range.js | 62 + .../js/frappe/form/controls/datetime.js | 23 + .../js/frappe/form/controls/dynamic_link.js | 21 + .../public/js/frappe/form/controls/float.js | 27 + .../public/js/frappe/form/controls/heading.js | 5 + frappe/public/js/frappe/form/controls/html.js | 26 + .../public/js/frappe/form/controls/image.js | 23 + frappe/public/js/frappe/form/controls/int.js | 25 + frappe/public/js/frappe/form/controls/link.js | 385 +++ .../js/frappe/form/controls/password.js | 52 + .../js/frappe/form/controls/read_only.js | 8 + .../public/js/frappe/form/controls/select.js | 64 + .../js/frappe/form/controls/signature.js | 109 + .../public/js/frappe/form/controls/table.js | 30 + frappe/public/js/frappe/form/controls/text.js | 20 + .../js/frappe/form/controls/text_editor.js | 298 +++ frappe/public/js/frappe/form/controls/time.js | 44 + frappe/website/js/website.js | 2 +- 32 files changed, 2315 insertions(+), 2274 deletions(-) delete mode 100755 frappe/public/js/frappe/form/control.js create mode 100644 frappe/public/js/frappe/form/controls/attach.js create mode 100644 frappe/public/js/frappe/form/controls/attach_image.js create mode 100644 frappe/public/js/frappe/form/controls/base_control.js create mode 100644 frappe/public/js/frappe/form/controls/base_input.js create mode 100644 frappe/public/js/frappe/form/controls/button.js create mode 100644 frappe/public/js/frappe/form/controls/check.js create mode 100644 frappe/public/js/frappe/form/controls/code.js create mode 100644 frappe/public/js/frappe/form/controls/color.js create mode 100644 frappe/public/js/frappe/form/controls/currency.js create mode 100644 frappe/public/js/frappe/form/controls/data.js create mode 100644 frappe/public/js/frappe/form/controls/date.js create mode 100644 frappe/public/js/frappe/form/controls/date_range.js create mode 100644 frappe/public/js/frappe/form/controls/datetime.js create mode 100644 frappe/public/js/frappe/form/controls/dynamic_link.js create mode 100644 frappe/public/js/frappe/form/controls/float.js create mode 100644 frappe/public/js/frappe/form/controls/heading.js create mode 100644 frappe/public/js/frappe/form/controls/html.js create mode 100644 frappe/public/js/frappe/form/controls/image.js create mode 100644 frappe/public/js/frappe/form/controls/int.js create mode 100644 frappe/public/js/frappe/form/controls/link.js create mode 100644 frappe/public/js/frappe/form/controls/password.js create mode 100644 frappe/public/js/frappe/form/controls/read_only.js create mode 100644 frappe/public/js/frappe/form/controls/select.js create mode 100644 frappe/public/js/frappe/form/controls/signature.js create mode 100644 frappe/public/js/frappe/form/controls/table.js create mode 100644 frappe/public/js/frappe/form/controls/text.js create mode 100644 frappe/public/js/frappe/form/controls/text_editor.js create mode 100644 frappe/public/js/frappe/form/controls/time.js diff --git a/frappe/hooks.py b/frappe/hooks.py index bf990a9f72..f5d98f0421 100755 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -27,6 +27,7 @@ app_include_js = [ "assets/js/desk.min.js", "assets/js/list.min.js", "assets/js/form.min.js", + "assets/js/control.min.js", "assets/js/report.min.js", "assets/js/d3.min.js", "assets/frappe/js/frappe/toolbar.js" diff --git a/frappe/public/build.json b/frappe/public/build.json index 75dbf5063a..b17d3bb22c 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -22,16 +22,74 @@ "website/js/website.js", "public/js/frappe/misc/rating_icons.html" ], + "js/control.min.js": [ + "public/js/frappe/form/controls/base_control.js", + "public/js/frappe/form/controls/base_input.js", + "public/js/frappe/form/controls/data.js", + "public/js/frappe/form/controls/int.js", + "public/js/frappe/form/controls/float.js", + "public/js/frappe/form/controls/currency.js", + "public/js/frappe/form/controls/date.js", + "public/js/frappe/form/controls/time.js", + "public/js/frappe/form/controls/datetime.js", + "public/js/frappe/form/controls/date_range.js", + "public/js/frappe/form/controls/select.js", + "public/js/frappe/form/controls/link.js", + "public/js/frappe/form/controls/dynamic_link.js", + "public/js/frappe/form/controls/text.js", + "public/js/frappe/form/controls/code.js", + "public/js/frappe/form/controls/text_editor.js", + "public/js/frappe/form/controls/check.js", + "public/js/frappe/form/controls/image.js", + "public/js/frappe/form/controls/attach.js", + "public/js/frappe/form/controls/attach_image.js", + "public/js/frappe/form/controls/table.js", + "public/js/frappe/form/controls/color.js", + "public/js/frappe/form/controls/signature.js", + "public/js/frappe/form/controls/password.js", + "public/js/frappe/form/controls/read_only.js", + "public/js/frappe/form/controls/button.js", + "public/js/frappe/form/controls/html.js", + "public/js/frappe/form/controls/heading.js" + ], "js/dialog.min.js": [ "public/js/frappe/dom.js", "public/js/frappe/ui/modal.html", "public/js/frappe/form/formatters.js", "public/js/frappe/form/layout.js", "public/js/frappe/ui/field_group.js", - "public/js/frappe/form/control.js", "public/js/frappe/form/link_selector.js", "public/js/frappe/form/multi_select_dialog.js", - "public/js/frappe/ui/dialog.js" + "public/js/frappe/ui/dialog.js", + + "public/js/frappe/form/controls/base_control.js", + "public/js/frappe/form/controls/base_input.js", + "public/js/frappe/form/controls/data.js", + "public/js/frappe/form/controls/int.js", + "public/js/frappe/form/controls/float.js", + "public/js/frappe/form/controls/currency.js", + "public/js/frappe/form/controls/date.js", + "public/js/frappe/form/controls/time.js", + "public/js/frappe/form/controls/datetime.js", + "public/js/frappe/form/controls/date_range.js", + "public/js/frappe/form/controls/select.js", + "public/js/frappe/form/controls/link.js", + "public/js/frappe/form/controls/dynamic_link.js", + "public/js/frappe/form/controls/text.js", + "public/js/frappe/form/controls/code.js", + "public/js/frappe/form/controls/text_editor.js", + "public/js/frappe/form/controls/check.js", + "public/js/frappe/form/controls/image.js", + "public/js/frappe/form/controls/attach.js", + "public/js/frappe/form/controls/attach_image.js", + "public/js/frappe/form/controls/table.js", + "public/js/frappe/form/controls/color.js", + "public/js/frappe/form/controls/signature.js", + "public/js/frappe/form/controls/password.js", + "public/js/frappe/form/controls/read_only.js", + "public/js/frappe/form/controls/button.js", + "public/js/frappe/form/controls/html.js", + "public/js/frappe/form/controls/heading.js" ], "css/desk.min.css": [ "public/js/lib/datepicker/datepicker.min.css", @@ -108,7 +166,6 @@ "public/js/frappe/ui/iconbar.js", "public/js/frappe/form/layout.js", "public/js/frappe/ui/field_group.js", - "public/js/frappe/form/control.js", "public/js/frappe/form/link_selector.js", "public/js/frappe/form/multi_select_dialog.js", "public/js/frappe/ui/dialog.js", diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js deleted file mode 100755 index e81cd876dd..0000000000 --- a/frappe/public/js/frappe/form/control.js +++ /dev/null @@ -1,2270 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// MIT License. See license.txt - -frappe.ui.form.make_control = function (opts) { - var control_class_name = "Control" + opts.df.fieldtype.replace(/ /g, ""); - if(frappe.ui.form[control_class_name]) { - return new frappe.ui.form[control_class_name](opts); - } else { - console.log("Invalid Control Name: " + opts.df.fieldtype); - } -}; - -frappe.ui.form.Control = Class.extend({ - init: function(opts) { - $.extend(this, opts); - this.make(); - - // if developer_mode=1, show fieldname as tooltip - if(frappe.boot.user && frappe.boot.user.name==="Administrator" && - frappe.boot.developer_mode===1 && this.$wrapper) { - this.$wrapper.attr("title", __(this.df.fieldname)); - } - - if(this.render_input) { - this.refresh(); - } - }, - make: function() { - this.make_wrapper(); - this.$wrapper - .attr("data-fieldtype", this.df.fieldtype) - .attr("data-fieldname", this.df.fieldname); - this.wrapper = this.$wrapper.get(0); - this.wrapper.fieldobj = this; // reference for event handlers - }, - - make_wrapper: function() { - this.$wrapper = $("
").appendTo(this.parent); - - // alias - this.wrapper = this.$wrapper; - }, - - toggle: function(show) { - this.df.hidden = show ? 0 : 1; - this.refresh(); - }, - - // returns "Read", "Write" or "None" - // as strings based on permissions - get_status: function(explain) { - if(!this.doctype && !this.docname) { - // like in case of a dialog box - if (cint(this.df.hidden)) { - if(explain) console.log("By Hidden: None"); - return "None"; - - } else if (cint(this.df.hidden_due_to_dependency)) { - if(explain) console.log("By Hidden Dependency: None"); - return "None"; - - } else if (cint(this.df.read_only)) { - if(explain) console.log("By Read Only: Read"); - return "Read"; - - } - - return "Write"; - } - - var status = frappe.perm.get_field_display_status(this.df, - frappe.model.get_doc(this.doctype, this.docname), this.perm || (this.frm && this.frm.perm), explain); - - // hide if no value - if (this.doctype && status==="Read" && !this.only_input - && is_null(frappe.model.get_value(this.doctype, this.docname, this.df.fieldname)) - && !in_list(["HTML", "Image"], this.df.fieldtype)) { - - if(explain) console.log("By Hide Read-only, null fields: None"); - status = "None"; - } - - return status; - }, - refresh: function() { - this.disp_status = this.get_status(); - this.$wrapper - && this.$wrapper.toggleClass("hide-control", this.disp_status=="None") - && this.refresh_input - && this.refresh_input(); - }, - get_doc: function() { - return this.doctype && this.docname - && locals[this.doctype] && locals[this.doctype][this.docname] || {}; - }, - get_model_value: function() { - if(this.doc) { - return this.doc[this.df.fieldname]; - } - }, - set_value: function(value) { - return this.validate_and_set_in_model(value); - }, - parse_validate_and_set_in_model: function(value, e) { - if(this.parse) { - value = this.parse(value); - } - return this.validate_and_set_in_model(value, e); - }, - validate_and_set_in_model: function(value, e) { - var me = this; - if(this.inside_change_event) { - return new Promise.resolve(); - } - this.inside_change_event = true; - var set = function(value) { - me.inside_change_event = false; - return frappe.run_serially([ - () => me.set_model_value(value), - () => { - me.set_mandatory && me.set_mandatory(value); - - if(me.df.change || me.df.onchange) { - // onchange event specified in df - return (me.df.change || me.df.onchange).apply(me, [e]); - } - } - ]); - }; - - value = this.validate(value); - if (value && value.then) { - // got a promise - return value.then((value) => set(value)); - } else { - // all clear - return set(value); - } - }, - get_value: function() { - if(this.get_status()==='Write') { - return this.get_input_value ? - (this.parse ? this.parse(this.get_input_value()) : this.get_input_value()) : - undefined; - } else if(this.get_status()==='Read') { - return this.value || undefined; - } else { - return undefined; - } - }, - set_model_value: function(value) { - if(this.doctype && this.docname) { - this.last_value = value; - return frappe.model.set_value(this.doctype, this.docname, this.df.fieldname, - value, this.df.fieldtype); - } else { - if(this.doc) { - this.doc[this.df.fieldname] = value; - } - this.set_input(value); - return Promise.resolve(); - } - }, - set_focus: function() { - if(this.$input) { - this.$input.get(0).focus(); - return true; - } - } -}); - -frappe.ui.form.ControlHTML = frappe.ui.form.Control.extend({ - make: function() { - this._super(); - this.disp_area = this.wrapper; - }, - refresh_input: function() { - var content = this.get_content(); - if(content) this.$wrapper.html(content); - }, - get_content: function() { - return this.df.options || ""; - }, - html: function(html) { - this.$wrapper.html(html || this.get_content()); - }, - set_value: function(html) { - if(html.appendTo) { - // jquery object - html.appendTo(this.$wrapper.empty()); - } else { - // html - this.df.options = html; - this.html(html); - } - } -}); - -frappe.ui.form.ControlHeading = frappe.ui.form.ControlHTML.extend({ - get_content: function() { - return "

" + __(this.df.label) + "

"; - } -}); - -frappe.ui.form.ControlImage = frappe.ui.form.Control.extend({ - make: function() { - this._super(); - var me = this; - this.$wrapper.css({"margin": "0px"}); - this.$body = $("
").appendTo(this.$wrapper) - .css({"margin-bottom": "10px"}); - $('
').appendTo(this.$wrapper); - }, - refresh_input: function() { - this.$body.empty(); - - var doc = this.get_doc(); - if(doc && this.df.options && doc[this.df.options]) { - this.$img = $("") - .appendTo(this.$body); - } else { - this.$buffer = $("
") - .appendTo(this.$body); - } - return false; - } -}); - -frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({ - horizontal: true, - make: function() { - // parent element - this._super(); - this.set_input_areas(); - - // set description - this.set_max_width(); - }, - make_wrapper: function() { - if(this.only_input) { - this.$wrapper = $('
').appendTo(this.parent); - } else { - this.$wrapper = $('
\ -
\ -
\ - \ -
\ -
\ -
\ - \ - \ -
\ -
\ -
').appendTo(this.parent); - } - }, - toggle_label: function(show) { - this.$wrapper.find(".control-label").toggleClass("hide", !show); - }, - toggle_description: function(show) { - this.$wrapper.find(".help-box").toggleClass("hide", !show); - }, - set_input_areas: function() { - if(this.only_input) { - this.input_area = this.wrapper; - } else { - this.label_area = this.label_span = this.$wrapper.find("label").get(0); - this.input_area = this.$wrapper.find(".control-input").get(0); - // keep a separate display area to rendered formatted values - // like links, currencies, HTMLs etc. - this.disp_area = this.$wrapper.find(".control-value").get(0); - } - }, - set_max_width: function() { - if(this.horizontal) { - this.$wrapper.addClass("input-max-width"); - } - }, - - // update input value, label, description - // display (show/hide/read-only), - // mandatory style on refresh - refresh_input: function() { - var me = this; - var make_input = function() { - if(!me.has_input) { - me.make_input(); - if(me.df.on_make) { - me.df.on_make(me); - } - } - }; - - var update_input = function() { - if(me.doctype && me.docname) { - me.set_input(me.value); - } else { - me.set_input(me.value || null); - } - }; - - if(me.disp_status != "None") { - // refresh value - if(me.doctype && me.docname) { - me.value = frappe.model.get_value(me.doctype, me.docname, me.df.fieldname); - } - - if(me.disp_status=="Write") { - me.disp_area && $(me.disp_area).toggle(false); - $(me.input_area).toggle(true); - me.$input && me.$input.prop("disabled", false); - make_input(); - update_input(); - } else { - if(me.only_input) { - make_input(); - update_input(); - } else { - $(me.input_area).toggle(false); - if (me.disp_area) { - me.set_disp_area(me.value); - $(me.disp_area).toggle(true); - } - } - me.$input && me.$input.prop("disabled", true); - } - - me.set_description(); - me.set_label(); - me.set_mandatory(me.value); - me.set_bold(); - } - }, - - set_disp_area: function(value) { - if(in_list(["Currency", "Int", "Float"], this.df.fieldtype) - && (this.value === 0 || value === 0)) { - // to set the 0 value in readonly for currency, int, float field - value = 0; - } else { - value = this.value || value; - } - this.disp_area && $(this.disp_area) - .html(frappe.format(value, this.df, {no_icon:true, inline:true}, - this.doc || (this.frm && this.frm.doc))); - }, - - bind_change_event: function() { - var me = this; - this.$input && this.$input.on("change", this.change || function(e) { - me.parse_validate_and_set_in_model(me.get_input_value(), e); - }); - }, - bind_focusout: function() { - // on touchscreen devices, scroll to top - // so that static navbar and page head don't overlap the input - if (frappe.dom.is_touchscreen()) { - var me = this; - this.$input && this.$input.on("focusout", function() { - if (frappe.dom.is_touchscreen()) { - frappe.utils.scroll_to(me.$wrapper); - } - }); - } - }, - set_label: function(label) { - if(label) this.df.label = label; - - if(this.only_input || this.df.label==this._label) - return; - - var icon = ""; - this.label_span.innerHTML = (icon ? ' ' : "") + - __(this.df.label) || " "; - this._label = this.df.label; - }, - set_description: function() { - if(this.only_input || this.df.description===this._description) - return; - if(this.df.description) { - this.$wrapper.find(".help-box").html(__(this.df.description)); - } else { - this.set_empty_description(); - } - this._description = this.df.description; - }, - set_new_description: function(description) { - this.$wrapper.find(".help-box").html(description); - }, - set_empty_description: function() { - this.$wrapper.find(".help-box").html(""); - }, - set_mandatory: function(value) { - this.$wrapper.toggleClass("has-error", (this.df.reqd && is_null(value)) ? true : false); - }, - set_bold: function() { - if(this.$input) { - this.$input.toggleClass("bold", !!(this.df.bold || this.df.reqd)); - } - if(this.disp_area) { - $(this.disp_area).toggleClass("bold", !!(this.df.bold || this.df.reqd)); - } - } -}); - -frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({ - html_element: "input", - input_type: "text", - make_input: function() { - if(this.$input) return; - - this.$input = $("<"+ this.html_element +">") - .attr("type", this.input_type) - .attr("autocomplete", "off") - .addClass("input-with-feedback form-control") - .prependTo(this.input_area); - - if (in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image'], - this.df.fieldtype)) { - this.$input.attr("maxlength", this.df.length || 140); - } - - this.set_input_attributes(); - this.input = this.$input.get(0); - this.has_input = true; - this.bind_change_event(); - this.bind_focusout(); - - // somehow this event does not bubble up to document - // after v7, if you can debug, remove this - }, - set_input_attributes: function() { - this.$input - .attr("data-fieldtype", this.df.fieldtype) - .attr("data-fieldname", this.df.fieldname) - .attr("placeholder", this.df.placeholder || ""); - if(this.doctype) { - this.$input.attr("data-doctype", this.doctype); - } - if(this.df.input_css) { - this.$input.css(this.df.input_css); - } - if(this.df.input_class) { - this.$input.addClass(this.df.input_class); - } - }, - set_input: function(value) { - this.last_value = this.value; - this.value = value; - this.set_formatted_input(value); - this.set_disp_area(value); - this.set_mandatory && this.set_mandatory(value); - }, - set_formatted_input: function(value) { - this.$input && this.$input.val(this.format_for_input(value)); - }, - get_input_value: function() { - return this.$input ? this.$input.val() : undefined; - }, - format_for_input: function(val) { - return val==null ? "" : val; - }, - validate: function(v) { - if(this.df.options == 'Phone') { - if(v+''=='') { - return ''; - } - var v1 = ''; - // phone may start with + and must only have numbers later, '-' and ' ' are stripped - v = v.replace(/ /g, '').replace(/-/g, '').replace(/\(/g, '').replace(/\)/g, ''); - - // allow initial +,0,00 - if(v && v.substr(0,1)=='+') { - v1 = '+'; v = v.substr(1); - } - if(v && v.substr(0,2)=='00') { - v1 += '00'; v = v.substr(2); - } - if(v && v.substr(0,1)=='0') { - v1 += '0'; v = v.substr(1); - } - v1 += cint(v) + ''; - return v1; - } else if(this.df.options == 'Email') { - if(v+''=='') { - return ''; - } - - var email_list = frappe.utils.split_emails(v); - if (!email_list) { - // invalid email - return ''; - } else { - var invalid_email = false; - email_list.forEach(function(email) { - if (!validate_email(email)) { - frappe.msgprint(__("Invalid Email: {0}", [email])); - invalid_email = true; - } - }); - - if (invalid_email) { - // at least 1 invalid email - return ''; - } else { - // all good - return v; - } - } - - } else { - return v; - } - } -}); - -frappe.ui.form.ControlReadOnly = frappe.ui.form.ControlData.extend({ - get_status: function(explain) { - var status = this._super(explain); - if(status==="Write") - status = "Read"; - return; - }, -}); - -frappe.ui.form.ControlPassword = frappe.ui.form.ControlData.extend({ - input_type: "password", - make: function() { - this._super(); - }, - make_input: function() { - var me = this; - this._super(); - this.$input.parent().append($('')); - this.$wrapper.find('.control-input-wrapper').append($('')); - - this.indicator = this.$wrapper.find('.password-strength-indicator'); - this.message = this.$wrapper.find('.help-box'); - - this.$input.on('input', () => { - var $this = $(this); - clearTimeout($this.data('timeout')); - $this.data('timeout', setTimeout(() => { - var txt = me.$input.val(); - me.get_password_strength(txt); - }), 300); - }); - }, - get_password_strength: function(value) { - var me = this; - frappe.call({ - type: 'GET', - method: 'frappe.core.doctype.user.user.test_password_strength', - args: { - new_password: value || '' - }, - callback: function(r) { - if (r.message && r.message.entropy) { - var score = r.message.score, - feedback = r.message.feedback; - - feedback.crack_time_display = r.message.crack_time_display; - - var indicators = ['grey', 'red', 'orange', 'yellow', 'green']; - me.set_strength_indicator(indicators[score]); - - } - } - - }); - }, - set_strength_indicator: function(color) { - var message = __("Include symbols, numbers and capital letters in the password"); - this.indicator.removeClass().addClass('password-strength-indicator indicator ' + color); - this.message.html(message).removeClass('hidden'); - } -}); - -frappe.ui.form.ControlInt = frappe.ui.form.ControlData.extend({ - make: function() { - this._super(); - // $(this.label_area).addClass('pull-right'); - // $(this.disp_area).addClass('text-right'); - }, - make_input: function() { - var me = this; - this._super(); - this.$input - // .addClass("text-right") - .on("focus", function() { - setTimeout(function() { - if(!document.activeElement) return; - document.activeElement.value - = me.validate(document.activeElement.value); - document.activeElement.select(); - }, 100); - return false; - }); - }, - parse: function(value) { - return cint(value, null); - } -}); - -frappe.ui.form.ControlFloat = frappe.ui.form.ControlInt.extend({ - parse: function(value) { - return isNaN(parseFloat(value)) ? null : flt(value, this.get_precision()); - }, - - format_for_input: function(value) { - var number_format; - if (this.df.fieldtype==="Float" && this.df.options && this.df.options.trim()) { - number_format = this.get_number_format(); - } - var formatted_value = format_number(parseFloat(value), number_format, this.get_precision()); - return isNaN(parseFloat(value)) ? "" : formatted_value; - }, - - // even a float field can be formatted based on currency format instead of float format - get_number_format: function() { - var currency = frappe.meta.get_field_currency(this.df, this.get_doc()); - return get_number_format(currency); - }, - - get_precision: function() { - // round based on field precision or float precision, else don't round - return this.df.precision || cint(frappe.boot.sysdefaults.float_precision, null); - } -}); - -frappe.ui.form.ControlCurrency = frappe.ui.form.ControlFloat.extend({ - format_for_input: function(value) { - var formatted_value = format_number(parseFloat(value), this.get_number_format(), this.get_precision()); - return isNaN(parseFloat(value)) ? "" : formatted_value; - }, - - get_precision: function() { - // always round based on field precision or currency's precision - // this method is also called in this.parse() - if (!this.df.precision) { - if(frappe.boot.sysdefaults.currency_precision) { - this.df.precision = frappe.boot.sysdefaults.currency_precision; - } else { - this.df.precision = get_number_format_info(this.get_number_format()).precision; - } - } - - return this.df.precision; - } -}); - -frappe.ui.form.ControlPercent = frappe.ui.form.ControlFloat; - -frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({ - make_input: function () { - this._super(); - this.colors = [ - "#ffc4c4", "#ff8989", "#ff4d4d", "#a83333", - "#ffe8cd", "#ffd19c", "#ffb868", "#a87945", - "#ffd2c2", "#ffa685", "#ff7846", "#a85b5b", - "#ffd7d7", "#ffb1b1", "#ff8989", "#a84f2e", - "#fffacd", "#fff168", "#fff69c", "#a89f45", - "#ebf8cc", "#d9f399", "#c5ec63", "#7b933d", - "#cef6d1", "#9deca2", "#6be273", "#428b46", - "#d2f8ed", "#a4f3dd", "#77ecca", "#49937e", - "#d2f1ff", "#a6e4ff", "#78d6ff", "#4f8ea8", - "#d2d2ff", "#a3a3ff", "#7575ff", "#4d4da8", - "#dac7ff", "#b592ff", "#8e58ff", "#5e3aa8", - "#f8d4f8", "#f3aaf0", "#ec7dea", "#934f92" - ]; - this.make_color_input(); - }, - make_color_input: function () { - this.$wrapper - .find('.control-input-wrapper') - .append(`
-
-
`); - this.$color_pallete = this.$wrapper.find('.color-picker-pallete'); - - var color_html = this.colors.map(this.get_color_box).join(""); - this.$color_pallete.append(color_html); - this.$color_pallete.hide(); - this.bind_events(); - }, - get_color_box: function (hex) { - return `
`; - }, - set_formatted_input: function(value) { - this._super(value); - - if(!value) value = '#ffffff'; - this.$input.css({ - "background-color": value - }); - }, - bind_events: function () { - var mousedown_happened = false; - this.$wrapper.on("click", ".color-box", (e) => { - mousedown_happened = false; - - var color_val = $(e.target).data("color"); - this.set_value(color_val); - // set focus so that we can blur it later - this.set_focus(); - }); - - this.$wrapper.find(".color-box").mousedown(() => { - mousedown_happened = true; - }); - - this.$input.on("focus", () => { - this.$color_pallete.show(); - }); - this.$input.on("blur", () => { - if (mousedown_happened) { - // cancel the blur event - mousedown_happened = false; - } else { - // blur event is okay - $(this.$color_pallete).hide(); - } - }); - }, - validate: function (value) { - if(value === '') { - return ''; - } - var is_valid = /^#[0-9A-F]{6}$/i.test(value); - if(is_valid) { - return value; - } - frappe.msgprint(__("{0} is not a valid hex color", [value])); - return null; - } -}); - -frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({ - make_input: function() { - this._super(); - this.set_date_options(); - this.set_datepicker(); - this.set_t_for_today(); - }, - set_formatted_input: function(value) { - this._super(value); - if(!value) return; - - let should_refresh = this.last_value && this.last_value !== value; - - if (!should_refresh) { - if(this.datepicker.selectedDates.length > 0) { - // if date is selected but different from value, refresh - const selected_date = - moment(this.datepicker.selectedDates[0]) - .format(moment.defaultDateFormat); - should_refresh = selected_date !== value; - } else { - // if datepicker has no selected date, refresh - should_refresh = true; - } - } - - if(should_refresh) { - this.datepicker.selectDate(frappe.datetime.str_to_obj(value)); - } - }, - set_date_options: function() { - var me = this; - var lang = frappe.boot.user.language; - if(!$.fn.datepicker.language[lang]) { - lang = 'en'; - } - this.today_text = __("Today"); - this.datepicker_options = { - language: lang, - autoClose: true, - todayButton: frappe.datetime.now_date(true), - dateFormat: (frappe.boot.sysdefaults.date_format || 'yyyy-mm-dd'), - startDate: frappe.datetime.now_date(true), - onSelect: () => { - this.$input.trigger('change'); - }, - onShow: () => { - this.datepicker.$datepicker - .find('.datepicker--button:visible') - .text(me.today_text); - - this.update_datepicker_position(); - } - }; - }, - update_datepicker_position: function() { - if(!this.frm) return; - // show datepicker above or below the input - // based on scroll position - var window_height = $(window).height(); - var window_scroll_top = $(window).scrollTop(); - var el_offset_top = this.$input.offset().top + 280; - var position = 'top left'; - if(window_height + window_scroll_top >= el_offset_top) { - position = 'bottom left'; - } - this.datepicker.update('position', position); - }, - set_datepicker: function() { - this.$input.datepicker(this.datepicker_options); - this.datepicker = this.$input.data('datepicker'); - }, - set_t_for_today: function() { - var me = this; - this.$input.on("keydown", function(e) { - if(e.which===84) { // 84 === t - if(me.df.fieldtype=='Date') { - me.set_value(frappe.datetime.nowdate()); - } if(me.df.fieldtype=='Datetime') { - me.set_value(frappe.datetime.now_datetime()); - } if(me.df.fieldtype=='Time') { - me.set_value(frappe.datetime.now_time()); - } - return false; - } - }); - }, - parse: function(value) { - if(value) { - return frappe.datetime.user_to_str(value); - } - }, - format_for_input: function(value) { - if(value) { - return frappe.datetime.str_to_user(value); - } - return ""; - }, - validate: function(value) { - if(value && !frappe.datetime.validate(value)) { - frappe.msgprint(__("Date must be in format: {0}", [frappe.sys_defaults.date_format || "yyyy-mm-dd"])); - return ''; - } - return value; - } -}); - -frappe.ui.form.ControlDatetime = frappe.ui.form.ControlDate.extend({ - set_date_options: function() { - this._super(); - this.today_text = __("Now"); - $.extend(this.datepicker_options, { - timepicker: true, - timeFormat: "hh:ii:ss", - todayButton: frappe.datetime.now_datetime(true) - }); - }, - set_description: function() { - const { description } = this.df; - const { time_zone } = frappe.sys_defaults; - if (!frappe.datetime.is_timezone_same()) { - if (!description) { - this.df.description = time_zone; - } else if (!description.includes(time_zone)) { - this.df.description += '
' + time_zone; - } - } - this._super(); - } -}); - -frappe.ui.form.ControlTime = frappe.ui.form.ControlData.extend({ - make_input: function() { - var me = this; - this._super(); - this.$input.datepicker({ - language: "en", - timepicker: true, - onlyTimepicker: true, - timeFormat: "hh:ii:ss", - startDate: frappe.datetime.now_time(true), - onSelect: function() { - me.$input.trigger('change'); - }, - onShow: function() { - $('.datepicker--button:visible').text(__('Now')); - }, - todayButton: frappe.datetime.now_time(true) - }); - this.datepicker = this.$input.data('datepicker'); - this.refresh(); - }, - set_input: function(value) { - this._super(value); - if(value - && ((this.last_value && this.last_value !== this.value) - || (!this.datepicker.selectedDates.length))) { - - var date_obj = frappe.datetime.moment_to_date_obj(moment(value, 'hh:mm:ss')); - this.datepicker.selectDate(date_obj); - } - }, - set_description: function() { - const { description } = this.df; - const { time_zone } = frappe.sys_defaults; - if (!frappe.datetime.is_timezone_same()) { - if (!description) { - this.df.description = time_zone; - } else if (!description.includes(time_zone)) { - this.df.description += '
' + time_zone; - } - } - this._super(); - } -}); - -frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({ - make_input: function() { - this._super(); - this.set_date_options(); - this.set_datepicker(); - this.refresh(); - }, - set_date_options: function() { - var me = this; - this.datepicker_options = { - language: "en", - range: true, - autoClose: true, - toggleSelected: false - }; - this.datepicker_options.dateFormat = - (frappe.boot.sysdefaults.date_format || 'yyyy-mm-dd'); - this.datepicker_options.onSelect = function() { - me.$input.trigger('change'); - }; - }, - set_datepicker: function() { - this.$input.datepicker(this.datepicker_options); - this.datepicker = this.$input.data('datepicker'); - }, - set_input: function(value, value2) { - this.last_value = this.value; - if (value && value2) { - this.value = [value, value2]; - } else { - this.value = value; - } - if (this.value) { - let formatted = this.format_for_input(this.value[0], this.value[1]); - this.$input && this.$input.val(formatted); - } else { - this.$input && this.$input.val(""); - } - this.set_disp_area(value || ''); - this.set_mandatory && this.set_mandatory(value); - }, - parse: function(value) { - // replace the separator (which can be in user language) with comma - const to = __('{0} to {1}').replace('{0}', '').replace('{1}', ''); - value = value.replace(to, ','); - - if(value && value.includes(',')) { - var vals = value.split(','); - var from_date = moment(frappe.datetime.user_to_obj(vals[0])).format('YYYY-MM-DD'); - var to_date = moment(frappe.datetime.user_to_obj(vals[vals.length-1])).format('YYYY-MM-DD'); - return [from_date, to_date]; - } - }, - format_for_input: function(value1, value2) { - if(value1 && value2) { - value1 = frappe.datetime.str_to_user(value1); - value2 = frappe.datetime.str_to_user(value2); - return __("{0} to {1}").format([value1, value2]); - } - return ""; - } -}); - -frappe.ui.form.ControlText = frappe.ui.form.ControlData.extend({ - html_element: "textarea", - horizontal: false, - make_wrapper: function() { - this._super(); - this.$wrapper.find(".like-disabled-input").addClass("for-description"); - }, - make_input: function() { - this._super(); - this.$input.css({'height': '300px'}); - } -}); - -frappe.ui.form.ControlLongText = frappe.ui.form.ControlText; -frappe.ui.form.ControlSmallText = frappe.ui.form.ControlText.extend({ - make_input: function() { - this._super(); - this.$input.css({'height': '150px'}); - } -}); - -frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({ - input_type: "checkbox", - make_wrapper: function() { - this.$wrapper = $('
\ -
\ - \ -

\ -
\ -
').appendTo(this.parent); - }, - set_input_areas: function() { - this.label_area = this.label_span = this.$wrapper.find(".label-area").get(0); - this.input_area = this.$wrapper.find(".input-area").get(0); - this.disp_area = this.$wrapper.find(".disp-area").get(0); - }, - make_input: function() { - this._super(); - this.$input.removeClass("form-control"); - }, - get_input_value: function() { - return this.input && this.input.checked ? 1 : 0; - }, - validate: function(value) { - return cint(value); - }, - set_input: function(value) { - if(this.input) { - this.input.checked = (value ? 1 : 0); - } - this.last_value = value; - this.set_mandatory(value); - this.set_disp_area(value); - } -}); - -frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({ - make_input: function() { - var me = this; - this.$input = $('