feat: show title links in Link Fields
This commit is contained in:
parent
757a07251a
commit
d056beb0ef
18 changed files with 404 additions and 61 deletions
|
|
@ -65,16 +65,49 @@ context('Control Link', () => {
|
|||
cy.intercept('POST', '/api/method/frappe.desk.search.search_link').as('search_link');
|
||||
|
||||
cy.get('@todos').then(todos => {
|
||||
cy.get('.frappe-control[data-fieldname=link] input').as('input');
|
||||
cy.get('@input').focus();
|
||||
cy.get('.frappe-control[data-fieldname=link] input').focus().as('input');
|
||||
cy.wait('@search_link');
|
||||
cy.get('@input').type(todos[0]).blur();
|
||||
cy.get('@input').type(todos[0]);
|
||||
cy.wait('@search_link');
|
||||
cy.get('.frappe-control[data-fieldname=link] ul').should('be.visible');
|
||||
cy.get('.frappe-control[data-fieldname=link] input').type('{enter}', { delay: 100 });
|
||||
cy.wait('@validate_link');
|
||||
cy.get('@input').focus();
|
||||
cy.get('.frappe-control[data-fieldname=link] .link-btn')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.location('pathname').should('eq', `/app/todo/${todos[0]}`);
|
||||
cy.location('hash').should('eq', `#Form/ToDo/${todos[0]}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('show title field in link', () => {
|
||||
get_dialog_with_link().as('dialog');
|
||||
|
||||
cy.server();
|
||||
cy.insert_doc("Property Setter", {
|
||||
property: "show_title_field_in_link",
|
||||
doc_type: "ToDo",
|
||||
value: 1,
|
||||
doctype_or_field: "DocType"
|
||||
}, true);
|
||||
cy.route('POST', '/api/method/frappe.desk.search.search_link').as('search_link');
|
||||
|
||||
cy.get('.frappe-control[data-fieldname=link] input').focus().as('input');
|
||||
cy.wait('@search_link');
|
||||
cy.get('@input').type('todo for link');
|
||||
cy.wait('@search_link');
|
||||
cy.get('.frappe-control[data-fieldname=link] ul').should('be.visible');
|
||||
cy.get('.frappe-control[data-fieldname=link] input').type('{enter}', { delay: 100 });
|
||||
cy.get('.frappe-control[data-fieldname=link] input').blur();
|
||||
cy.get('@dialog').then(dialog => {
|
||||
cy.get('@todos').then(todos => {
|
||||
let field = dialog.get_field('link');
|
||||
let value = field.get_value();
|
||||
let label = field.get_label_value();
|
||||
|
||||
expect(value).to.eq(todos[0]);
|
||||
expect(label).to.eq('this is a test todo for link');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ def get_bootinfo():
|
|||
bootinfo.additional_filters_config = get_additional_filters_from_hooks()
|
||||
bootinfo.desk_settings = get_desk_settings()
|
||||
bootinfo.app_logo_url = get_app_logo()
|
||||
bootinfo.doctypes_with_show_link_field_title = doctypes_with_show_link_field_title()
|
||||
|
||||
return bootinfo
|
||||
|
||||
|
|
@ -324,3 +325,9 @@ def get_desk_settings():
|
|||
|
||||
def get_notification_settings():
|
||||
return frappe.get_cached_doc('Notification Settings', frappe.session.user)
|
||||
|
||||
def doctypes_with_show_link_field_title():
|
||||
dts = frappe.get_all("DocType", {"show_title_field_in_link": 1})
|
||||
custom_dts = frappe.get_all("Property Setter", {"field_name": "show_title_field_in_link", "value": 1})
|
||||
|
||||
return [d.name for d in dts + custom_dts if d]
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
"allow_auto_repeat",
|
||||
"view_settings",
|
||||
"title_field",
|
||||
"show_title_field_in_link",
|
||||
"search_fields",
|
||||
"default_print_format",
|
||||
"sort_field",
|
||||
|
|
@ -554,6 +555,12 @@
|
|||
"fieldname": "website_search_field",
|
||||
"fieldtype": "Data",
|
||||
"label": "Website Search Field"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "show_title_field_in_link",
|
||||
"fieldtype": "Check",
|
||||
"label": "Show Title in Link and Table MultiSelect Field"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-bolt",
|
||||
|
|
@ -635,7 +642,7 @@
|
|||
"link_fieldname": "reference_doctype"
|
||||
}
|
||||
],
|
||||
"modified": "2021-06-17 23:31:44.974199",
|
||||
"modified": "2021-08-03 13:41:50.319555",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocType",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
"autoname",
|
||||
"view_settings_section",
|
||||
"title_field",
|
||||
"show_title_field_in_link",
|
||||
"image_field",
|
||||
"default_print_format",
|
||||
"column_break_29",
|
||||
|
|
@ -280,6 +281,12 @@
|
|||
"fieldname": "autoname",
|
||||
"fieldtype": "Data",
|
||||
"label": "Auto Name"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "show_title_field_in_link",
|
||||
"fieldtype": "Check",
|
||||
"label": "Show Title in Link and Table MultiSelect Field"
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
|
|
@ -288,7 +295,7 @@
|
|||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2021-06-21 19:01:06.920663",
|
||||
"modified": "2021-08-03 13:43:27.938781",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Customize Form",
|
||||
|
|
|
|||
|
|
@ -495,7 +495,8 @@ doctype_properties = {
|
|||
'email_append_to': 'Check',
|
||||
'subject_field': 'Data',
|
||||
'sender_field': 'Data',
|
||||
'autoname': 'Data'
|
||||
'autoname': 'Data',
|
||||
'show_title_field_in_link': 'Check'
|
||||
}
|
||||
|
||||
docfield_properties = {
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ CREATE TABLE `tabDocType` (
|
|||
`email_append_to` int(1) NOT NULL DEFAULT 0,
|
||||
`subject_field` varchar(255) DEFAULT NULL,
|
||||
`sender_field` varchar(255) DEFAULT NULL,
|
||||
`show_title_field_in_link` int(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`name`),
|
||||
KEY `parent` (`parent`)
|
||||
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ CREATE TABLE "tabDocType" (
|
|||
"email_append_to" smallint NOT NULL DEFAULT 0,
|
||||
"subject_field" varchar(255) DEFAULT NULL,
|
||||
"sender_field" varchar(255) DEFAULT NULL,
|
||||
"show_title_field_in_link" smallint NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY ("name")
|
||||
) ;
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ def getdoc(doctype, name, user=None):
|
|||
raise
|
||||
|
||||
doc.add_seen()
|
||||
|
||||
set_link_titles(doc)
|
||||
frappe.response.docs.append(doc)
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
|
|
@ -310,3 +310,55 @@ def get_additional_timeline_content(doctype, docname):
|
|||
contents.extend(frappe.get_attr(method)(doctype, docname) or [])
|
||||
|
||||
return contents
|
||||
|
||||
def set_link_titles(doc):
|
||||
meta = frappe.get_meta(doc.doctype)
|
||||
link_titles = {}
|
||||
link_titles.update(get_title_values_for_link_and_dynamic_link_fields(meta, doc))
|
||||
link_titles.update(get_title_values_for_table_and_multiselect_fields(meta, doc))
|
||||
|
||||
send_link_titles(link_titles)
|
||||
|
||||
def get_title_values_for_link_and_dynamic_link_fields(meta, doc, link_fields=None):
|
||||
link_titles = {}
|
||||
|
||||
if not link_fields:
|
||||
link_fields = meta.get_link_fields() + meta.get_dynamic_link_fields()
|
||||
|
||||
for field in link_fields:
|
||||
if not doc.get(field.fieldname):
|
||||
continue
|
||||
|
||||
doctype = field.options if field.fieldtype == "Link" else doc.get(field.options)
|
||||
|
||||
meta = frappe.get_meta(doctype)
|
||||
if not meta or not (meta.title_field and meta.show_title_field_in_link):
|
||||
continue
|
||||
|
||||
link_title = frappe.get_cached_value(doctype, doc.get(field.fieldname), meta.title_field)
|
||||
link_titles.update({doctype + "::" + doc.get(field.fieldname): link_title})
|
||||
|
||||
return link_titles
|
||||
|
||||
def get_title_values_for_table_and_multiselect_fields(meta, doc, table_fields=None):
|
||||
link_titles = {}
|
||||
|
||||
if not table_fields:
|
||||
table_fields = meta.get_table_fields()
|
||||
|
||||
for field in table_fields:
|
||||
if not doc.get(field.fieldname):
|
||||
continue
|
||||
|
||||
_meta = frappe.get_meta(field.options)
|
||||
for value in doc.get(field.fieldname):
|
||||
link_titles.update(get_title_values_for_link_and_dynamic_link_fields(_meta, value))
|
||||
|
||||
return link_titles
|
||||
|
||||
def send_link_titles(link_titles):
|
||||
"""Append link titles dict in `frappe.local.response`."""
|
||||
if "_link_titles" not in frappe.local.response:
|
||||
frappe.local.response["_link_titles"] = {}
|
||||
|
||||
frappe.local.response["_link_titles"].update(link_titles)
|
||||
|
|
|
|||
|
|
@ -49,8 +49,11 @@ def sanitize_searchfield(searchfield):
|
|||
# this is called by the Link Field
|
||||
@frappe.whitelist()
|
||||
def search_link(doctype, txt, query=None, filters=None, page_length=20, searchfield=None, reference_doctype=None, ignore_user_permissions=False):
|
||||
search_widget(doctype, txt.strip(), query, searchfield=searchfield, page_length=page_length, filters=filters, reference_doctype=reference_doctype, ignore_user_permissions=ignore_user_permissions)
|
||||
frappe.response['results'] = build_for_autosuggest(frappe.response["values"])
|
||||
search_widget(doctype, txt.strip(), query, searchfield=searchfield, page_length=page_length, filters=filters,
|
||||
reference_doctype=reference_doctype, ignore_user_permissions=ignore_user_permissions)
|
||||
|
||||
frappe.response["results"] = build_for_autosuggest(frappe.response["values"], doctype=doctype,
|
||||
is_query=True if query else False)
|
||||
del frappe.response["values"]
|
||||
|
||||
# this is called by the search box
|
||||
|
|
@ -138,6 +141,11 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
|
|||
fields = list(set(fields + json.loads(filter_fields)))
|
||||
formatted_fields = ['`tab%s`.`%s`' % (meta.name, f.strip()) for f in fields]
|
||||
|
||||
title_field_query = get_title_field_query(meta)
|
||||
|
||||
# Insert title field query after name
|
||||
formatted_fields.insert(1, title_field_query)
|
||||
|
||||
# find relevance as location of search term from the beginning of string `name`. used for sorting results.
|
||||
formatted_fields.append("""locate({_txt}, `tab{doctype}`.`name`) as `_relevance`""".format(
|
||||
_txt=frappe.db.escape((txt or "").replace("%", "").replace("@", "")), doctype=doctype))
|
||||
|
|
@ -205,10 +213,32 @@ def get_std_fields_list(meta, key):
|
|||
|
||||
return sflist
|
||||
|
||||
def build_for_autosuggest(res):
|
||||
def get_title_field_query(meta):
|
||||
title_field = meta.title_field if meta.title_field else None
|
||||
show_title_field_in_link = meta.show_title_field_in_link if meta.show_title_field_in_link else None
|
||||
field = "NULL as `label`"
|
||||
|
||||
if title_field and show_title_field_in_link:
|
||||
field = "`tab{0}`.{1} as `label`".format(meta.name, title_field)
|
||||
|
||||
return field
|
||||
|
||||
def build_for_autosuggest(res, doctype, is_query):
|
||||
results = []
|
||||
for r in res:
|
||||
out = {"value": r[0], "description": ", ".join(unique(cstr(d) for d in r if d)[1:])}
|
||||
r = list(r)
|
||||
if is_query or doctype in (frappe.get_hooks().standard_queries or {}):
|
||||
out = {
|
||||
"value": r[0],
|
||||
"description": ", ".join(unique(cstr(d) for d in r[1:] if d))
|
||||
}
|
||||
else:
|
||||
out = {
|
||||
"value": r[0],
|
||||
"label": r[1],
|
||||
"description": ", ".join(unique(cstr(d) for d in r[2:] if d))
|
||||
}
|
||||
|
||||
results.append(out)
|
||||
return results
|
||||
|
||||
|
|
@ -271,3 +301,12 @@ def get_user_groups():
|
|||
return frappe.get_all('User Group', fields=['name as id', 'name as value'], update={
|
||||
'is_group': True
|
||||
})
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_link_title(doctype, docname):
|
||||
meta = frappe.get_meta(doctype)
|
||||
|
||||
if meta.title_field and meta.show_title_field_in_link:
|
||||
return frappe.get_cached_value(doctype, docname, meta.title_field)
|
||||
|
||||
return docname
|
||||
|
|
@ -16,3 +16,4 @@ import "air-datepicker/dist/js/i18n/datepicker.sk.js";
|
|||
import "air-datepicker/dist/js/i18n/datepicker.zh.js";
|
||||
import "./frappe/ui/capture.js";
|
||||
import "./frappe/form/controls/control.js";
|
||||
import "./frappe/link_title.js";
|
||||
|
|
|
|||
|
|
@ -29,12 +29,14 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
setTimeout(function() {
|
||||
if(me.$input.val() && me.get_options()) {
|
||||
let doctype = me.get_options();
|
||||
let name = me.$input.val();
|
||||
let name = me.get_input_value();
|
||||
me.$link.toggle(true);
|
||||
me.$link_open.attr('href', frappe.utils.get_form_link(doctype, name));
|
||||
}
|
||||
|
||||
if(!me.$input.val()) {
|
||||
me.reset_value();
|
||||
me.reset_fetch_values(me.df, me.docname);
|
||||
me.$input.val("").trigger("input");
|
||||
}
|
||||
}, 500);
|
||||
|
|
@ -69,6 +71,76 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
this.$input_area.find(".link-btn").remove();
|
||||
}
|
||||
}
|
||||
set_formatted_input(value) {
|
||||
super.set_formatted_input();
|
||||
if (!value) return;
|
||||
let doctype = this.get_options();
|
||||
this.set_data_value(frappe.get_link_title(doctype, value) || value, value);
|
||||
}
|
||||
set_data_value(link_display, value) {
|
||||
if (!this.$input) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$input.val(__(link_display));
|
||||
this.data_value = value;
|
||||
}
|
||||
parse_validate_and_set_in_model(value, label, e) {
|
||||
if (this.parse) value = this.parse(value, label);
|
||||
if (label) {
|
||||
this.label = label;
|
||||
frappe.add_link_title(this.doctype, value, label);
|
||||
}
|
||||
|
||||
return this.validate_and_set_in_model(value, e);
|
||||
}
|
||||
validate_and_set_in_model(value, e) {
|
||||
var me = this;
|
||||
if (this.inside_change_event) {
|
||||
return 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
|
||||
frappe.set_link_title(me);
|
||||
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_input_value() {
|
||||
return (this.$input && this.data_value && this.$input.val()) ? this.data_value : "";
|
||||
}
|
||||
get_label_value() {
|
||||
return this.$input ? this.$input.val() : "";
|
||||
}
|
||||
set_input_label(label) {
|
||||
this.$input && this.$input.val(__(label));
|
||||
}
|
||||
reset_value() {
|
||||
if (!this.$input) {
|
||||
return;
|
||||
}
|
||||
this.$input.val("");
|
||||
this.data_value = null;
|
||||
}
|
||||
open_advanced_search() {
|
||||
var doctype = this.get_options();
|
||||
if(!doctype) return;
|
||||
|
|
@ -98,7 +170,7 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
}
|
||||
|
||||
// partially entered name field
|
||||
frappe.route_options.name_field = this.get_value();
|
||||
frappe.route_options.name_field = this.get_label_value();
|
||||
|
||||
// reference to calling link
|
||||
frappe._from_link = this;
|
||||
|
|
@ -120,6 +192,11 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
maxItems: 99,
|
||||
autoFirst: true,
|
||||
list: [],
|
||||
replace: function (suggestion) {
|
||||
// Override Awesomeplete replace function as it is used to set the input value
|
||||
// https://github.com/LeaVerou/awesomplete/issues/17104#issuecomment-359185403
|
||||
this.input.value = suggestion.label || suggestion.value;
|
||||
},
|
||||
data: function (item) {
|
||||
return {
|
||||
label: item.label || item.value,
|
||||
|
|
@ -236,9 +313,11 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
me.selected = false;
|
||||
return;
|
||||
}
|
||||
var value = me.get_input_value();
|
||||
if(value!==me.last_value) {
|
||||
me.parse_validate_and_set_in_model(value);
|
||||
let value = me.get_input_value();
|
||||
let label = me.get_label_value();
|
||||
|
||||
if (value !== me.last_value || me.label !== label) {
|
||||
me.parse_validate_and_set_in_model(value, label);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -258,14 +337,15 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
|
||||
// prevent selection on tab
|
||||
var TABKEY = 9;
|
||||
if(e.keyCode === TABKEY) {
|
||||
if (e.keyCode === TABKEY) {
|
||||
e.preventDefault();
|
||||
me.awesomplete.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(item.action) {
|
||||
if (item.action) {
|
||||
item.value = "";
|
||||
item.label = "";
|
||||
item.action.apply(me);
|
||||
}
|
||||
|
||||
|
|
@ -277,13 +357,14 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
frappe.boot.user.last_selected_values[me.df.options] = item.value;
|
||||
}
|
||||
|
||||
me.parse_validate_and_set_in_model(item.value);
|
||||
me.parse_validate_and_set_in_model(item.value, item.label);
|
||||
});
|
||||
|
||||
this.$input.on("awesomplete-selectcomplete", function(e) {
|
||||
var o = e.originalEvent;
|
||||
if(o.text.value.indexOf("__link_option") !== -1) {
|
||||
me.$input.val("");
|
||||
let o = e.originalEvent;
|
||||
if (o.text.value.indexOf("__link_option") !== -1) {
|
||||
me.reset_value();
|
||||
me.reset_fetch_values(me.df, me.docname);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -452,10 +533,13 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
this.docname, value);
|
||||
}
|
||||
validate_link_and_fetch(df, doctype, docname, value) {
|
||||
if(value) {
|
||||
let me = this;
|
||||
|
||||
if (value) {
|
||||
return new Promise((resolve) => {
|
||||
var fetch = '';
|
||||
if(this.frm && this.frm.fetch_dict[df.fieldname]) {
|
||||
let fetch = '';
|
||||
|
||||
if (this.frm && this.frm.fetch_dict[df.fieldname]) {
|
||||
fetch = this.frm.fetch_dict[df.fieldname].columns.join(', ');
|
||||
}
|
||||
// if default and no fetch, no need to validate
|
||||
|
|
@ -465,10 +549,14 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
|
||||
this.fetch_and_validate_link(resolve, df, doctype, docname, value, fetch);
|
||||
});
|
||||
} else {
|
||||
me.reset_value();
|
||||
me.reset_fetch_values(df, docname);
|
||||
}
|
||||
}
|
||||
|
||||
fetch_and_validate_link(resolve, df, doctype, docname, value, fetch) {
|
||||
let me = this;
|
||||
|
||||
frappe.call({
|
||||
method: 'frappe.desk.form.utils.validate_link',
|
||||
type: "GET",
|
||||
|
|
@ -485,18 +573,27 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat
|
|||
}
|
||||
resolve(r.valid_value);
|
||||
} else {
|
||||
me.reset_value();
|
||||
me.reset_fetch_values(df, docname);
|
||||
resolve("");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
set_fetch_values(df, docname, fetch_values) {
|
||||
var fl = this.frm.fetch_dict[df.fieldname].fields;
|
||||
for(var i=0; i < fl.length; i++) {
|
||||
let fl = this.frm.fetch_dict[df.fieldname].fields;
|
||||
|
||||
for (var i=0; i < fl.length; i++) {
|
||||
frappe.model.set_value(df.parent, docname, fl[i], fetch_values[i], df.fieldtype);
|
||||
}
|
||||
}
|
||||
reset_fetch_values(df, docname) {
|
||||
let fields = this.frm && this.frm.fetch_dict && this.frm.fetch_dict[df.fieldname] ? this.frm.fetch_dict[df.fieldname].fields : [];
|
||||
|
||||
fields.forEach(field => {
|
||||
frappe.model.set_value(df.parent, docname, field, null, df.fieldtype);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (Awesomplete) {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ frappe.ui.form.ControlTableMultiSelect = class ControlTableMultiSelect extends f
|
|||
[link_field.fieldname]: value
|
||||
});
|
||||
}
|
||||
frappe.add_link_title(link_field.options, value, label);
|
||||
}
|
||||
this._rows_list = this.rows.map(row => row[link_field.fieldname]);
|
||||
return this.rows;
|
||||
|
|
@ -126,10 +127,12 @@ frappe.ui.form.ControlTableMultiSelect = class ControlTableMultiSelect extends f
|
|||
this.$input_area.prepend(html);
|
||||
}
|
||||
get_pill_html(value) {
|
||||
const encoded_value = encodeURIComponent(value);
|
||||
const link_field = this.get_link_field();
|
||||
const encoded_value = encodeURIComponent(value.name);
|
||||
const pill_name = frappe.get_link_title(link_field.options, value[link_field.fieldname]) || value.name;
|
||||
return `
|
||||
<button class="data-pill btn tb-selected-value" data-value="${encoded_value}">
|
||||
<span class="btn-link-to-form">${__(value)}</span>
|
||||
<span class="btn-link-to-form">${__(pill_name)}</span>
|
||||
<span class="btn-remove">${frappe.utils.icon('close')}</span>
|
||||
</button>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -106,12 +106,14 @@ frappe.form.formatters = {
|
|||
Link: function(value, docfield, options, doc) {
|
||||
var doctype = docfield._options || docfield.options;
|
||||
var original_value = value;
|
||||
let link_title = frappe.get_link_title(doctype, value);
|
||||
|
||||
if(value && value.match && value.match(/^['"].*['"]$/)) {
|
||||
value.replace(/^.(.*).$/, "$1");
|
||||
}
|
||||
|
||||
if(options && (options.for_print || options.only_value)) {
|
||||
return value;
|
||||
return link_title || value;
|
||||
}
|
||||
|
||||
if(frappe.form.link_formatters[doctype]) {
|
||||
|
|
@ -135,13 +137,14 @@ frappe.form.formatters = {
|
|||
return `<a
|
||||
href="/app/${encodeURIComponent(frappe.router.slug(doctype))}/${encodeURIComponent(original_value)}"
|
||||
data-doctype="${doctype}"
|
||||
data-name="${original_value}">
|
||||
${__(options && options.label || value)}</a>`;
|
||||
data-name="${original_value}"
|
||||
data-value="${original_value}">
|
||||
${__(options && options.label || link_title || value)}</a>`;
|
||||
} else {
|
||||
return value;
|
||||
return link_title || value;
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
return link_title || value;
|
||||
}
|
||||
},
|
||||
Date: function(value) {
|
||||
|
|
|
|||
|
|
@ -249,31 +249,40 @@ frappe.ui.form.update_calling_link = (newdoc) => {
|
|||
};
|
||||
|
||||
if (is_valid_doctype()) {
|
||||
// set value
|
||||
if (doc && doc.parentfield) {
|
||||
//update values for child table
|
||||
$.each(frappe._from_link.frm.fields_dict[doc.parentfield].grid.grid_rows, function (index, field) {
|
||||
if (field.doc && field.doc.name === frappe._from_link.docname) {
|
||||
frappe._from_link.set_value(newdoc.name);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
frappe._from_link.set_value(newdoc.name);
|
||||
}
|
||||
|
||||
// refresh field
|
||||
frappe._from_link.refresh();
|
||||
|
||||
// if from form, switch
|
||||
if (frappe._from_link.frm) {
|
||||
frappe.set_route("Form",
|
||||
frappe._from_link.frm.doctype, frappe._from_link.frm.docname)
|
||||
.then(() => {
|
||||
frappe.utils.scroll_to(frappe._from_link_scrollY);
|
||||
frappe.model.with_doctype(newdoc.doctype, () => {
|
||||
let meta = frappe.get_meta(newdoc.doctype);
|
||||
// set value
|
||||
if (doc && doc.parentfield) {
|
||||
//update values for child table
|
||||
$.each(frappe._from_link.frm.fields_dict[doc.parentfield].grid.grid_rows, function (index, field) {
|
||||
if (field.doc && field.doc.name === frappe._from_link.docname) {
|
||||
if (meta.title_field && meta.show_title_field_in_link) {
|
||||
frappe.add_link_title(newdoc.doctype, newdoc.name, newdoc[meta.title_field]);
|
||||
}
|
||||
frappe._from_link.set_value(newdoc.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (meta.title_field && meta.show_title_field_in_link) {
|
||||
frappe.add_link_title(newdoc.doctype, newdoc.name, newdoc[meta.title_field]);
|
||||
}
|
||||
frappe._from_link.set_value(newdoc.name);
|
||||
}
|
||||
|
||||
frappe._from_link = null;
|
||||
// refresh field
|
||||
frappe._from_link.refresh();
|
||||
|
||||
// if from form, switch
|
||||
if (frappe._from_link.frm) {
|
||||
frappe.set_route("Form",
|
||||
frappe._from_link.frm.doctype, frappe._from_link.frm.docname)
|
||||
.then(() => {
|
||||
frappe.utils.scroll_to(frappe._from_link_scrollY);
|
||||
});
|
||||
}
|
||||
|
||||
frappe._from_link = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
34
frappe/public/js/frappe/link_title.js
Normal file
34
frappe/public/js/frappe/link_title.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// for link titles
|
||||
frappe._link_titles = {};
|
||||
|
||||
frappe.get_link_title = function(doctype, name) {
|
||||
if (!doctype || !name) {
|
||||
return;
|
||||
}
|
||||
|
||||
return frappe._link_titles[doctype + "::" + name];
|
||||
};
|
||||
|
||||
frappe.add_link_title = function (doctype, name, value) {
|
||||
if (!doctype || !name) {
|
||||
return;
|
||||
}
|
||||
|
||||
frappe._link_titles[doctype + "::" + name] = value;
|
||||
};
|
||||
|
||||
frappe.set_link_title = function(f) {
|
||||
let doctype = f.get_options();
|
||||
let docname = f.get_input_value();
|
||||
|
||||
if ((!in_list(frappe.boot.doctypes_with_show_link_field_title, doctype)) || (!doctype || !docname) ||
|
||||
(frappe.get_link_title(doctype, docname))) {
|
||||
return;
|
||||
}
|
||||
|
||||
frappe.xcall("frappe.desk.search.get_link_title", {"doctype": doctype, "docname": docname}).then((r) => {
|
||||
if (r && docname !== r) {
|
||||
f.set_input_label(r);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -241,6 +241,11 @@ frappe.request.call = function(opts) {
|
|||
$.extend(frappe._messages, data.__messages);
|
||||
}
|
||||
|
||||
// sync link titles
|
||||
if (data._link_titles) {
|
||||
$.extend(frappe._link_titles, data._link_titles);
|
||||
}
|
||||
|
||||
// callbacks
|
||||
var status_code_handler = statusCode[xhr.statusCode().status];
|
||||
if (status_code_handler) {
|
||||
|
|
|
|||
|
|
@ -313,6 +313,10 @@ frappe.ui.Filter = class {
|
|||
return this.utils.get_selected_value(this.field, this.get_condition());
|
||||
}
|
||||
|
||||
get_selected_label() {
|
||||
return this.utils.get_selected_label(this.field);
|
||||
}
|
||||
|
||||
get_condition() {
|
||||
return this.filter_edit_area.find('.condition').val();
|
||||
}
|
||||
|
|
@ -360,7 +364,7 @@ frappe.ui.Filter = class {
|
|||
get_filter_button_text() {
|
||||
let value = this.utils.get_formatted_value(
|
||||
this.field,
|
||||
this.get_selected_value()
|
||||
this.get_selected_label() || this.get_selected_value()
|
||||
);
|
||||
return `${__(this.field.df.label)} ${__(this.get_condition())} ${__(
|
||||
value
|
||||
|
|
@ -448,6 +452,12 @@ frappe.ui.filter_utils = {
|
|||
return val;
|
||||
},
|
||||
|
||||
get_selected_label(field) {
|
||||
if (in_list(["Link", "Dynamic Link"], field.df.fieldtype)) {
|
||||
return field.get_label_value();
|
||||
}
|
||||
},
|
||||
|
||||
get_default_condition(df) {
|
||||
if (df.fieldtype == 'Data') {
|
||||
return 'like';
|
||||
|
|
|
|||
|
|
@ -170,6 +170,38 @@ def get_rendered_template(doc, name=None, print_format=None, meta=None,
|
|||
|
||||
return html
|
||||
|
||||
def set_link_titles(doc):
|
||||
# Replaces name with title of link field doctype
|
||||
|
||||
meta = frappe.get_meta(doc.doctype)
|
||||
set_title_values_for_link_and_dynamic_link_fields(meta, doc)
|
||||
set_title_values_for_table_and_multiselect_fields(meta, doc)
|
||||
|
||||
def set_title_values_for_link_and_dynamic_link_fields(meta, doc):
|
||||
for field in meta.get_link_fields() + meta.get_dynamic_link_fields():
|
||||
if not doc.get(field.fieldname):
|
||||
continue
|
||||
|
||||
# If link field, then get doctype from options
|
||||
# If dynamic link field, then get doctype from dependent field
|
||||
doctype = field.options if field.fieldtype == "Link" else doc.get(field.options)
|
||||
|
||||
meta = frappe.get_meta(doctype)
|
||||
if not meta or not (meta.title_field and meta.show_title_field_in_link):
|
||||
continue
|
||||
|
||||
link_title = frappe.get_cached_value(doctype, doc.get(field.fieldname), meta.title_field)
|
||||
setattr(doc, field.fieldname, link_title)
|
||||
|
||||
def set_title_values_for_table_and_multiselect_fields(meta, doc):
|
||||
for field in meta.get_table_fields():
|
||||
if not doc.get(field.fieldname):
|
||||
continue
|
||||
|
||||
_meta = frappe.get_meta(field.options)
|
||||
for value in doc.get(field.fieldname):
|
||||
set_title_values_for_link_and_dynamic_link_fields(_meta, value)
|
||||
|
||||
def convert_markdown(doc, meta):
|
||||
'''Convert text field values to markdown if necessary'''
|
||||
for field in meta.fields:
|
||||
|
|
@ -191,6 +223,7 @@ def get_html_and_style(doc, name=None, print_format=None, meta=None,
|
|||
doc = frappe.get_doc(json.loads(doc))
|
||||
|
||||
print_format = get_print_format_doc(print_format, meta=meta or frappe.get_meta(doc.doctype))
|
||||
set_link_titles(doc)
|
||||
|
||||
try:
|
||||
html = get_rendered_template(doc, name=name, print_format=print_format, meta=meta,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue