resolved merged conflicts

This commit is contained in:
Saurabh 2018-01-29 16:15:56 +05:30
commit 8498bf8ea2
4 changed files with 1248 additions and 4 deletions

View file

@ -14,7 +14,7 @@ import os, sys, importlib, inspect, json
from .exceptions import *
from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template
__version__ = '10.0.15'
__version__ = '10.0.16'
__title__ = "Frappe Framework"
local = Local()

View file

@ -3,9 +3,10 @@
frappe.provide('frappe.views');
// Renders customized list
// usually based on `in_list_view` property
/**
* Renders customized list. Usually based on `in_list_view` property.
* It carries information that is used in frappe.views.ListView
*/
frappe.views.ListRenderer = Class.extend({
name: 'List',
init: function (opts) {
@ -38,6 +39,7 @@ frappe.views.ListRenderer = Class.extend({
// default settings
this.order_by = this.order_by || 'modified desc';
this.group_by = this.group_by || '';
this.filters = this.filters || [];
this.or_filters = this.or_filters || [];
this.page_length = this.page_length || 20;
@ -54,6 +56,7 @@ frappe.views.ListRenderer = Class.extend({
this.init_user_settings();
this.order_by = this.user_settings.order_by || this.settings.order_by;
this.group_by = this.get_group_by();
this.filters = this.user_settings.filters || this.settings.filters;
this.page_length = this.settings.page_length;
@ -62,6 +65,16 @@ frappe.views.ListRenderer = Class.extend({
this.filters = [[this.doctype, "docstatus", "!=", 2]];
}
},
/**
* Get the name of the column to use in SQL `group by`.
* It defaults to 'creation'
*/
get_group_by: function() {
const default_column = this.settings.group_by || 'creation';
const group_by = $.format('`tab{0}`.`{1}`', [this.doctype, default_column]);
return group_by;
},
init_user_settings: function () {
frappe.provide('frappe.model.user_settings.' + this.doctype + '.' + this.name);
this.user_settings = frappe.get_user_settings(this.doctype)[this.name];

View file

@ -0,0 +1,540 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
// new re-re-factored Listing object
// now called BaseList
//
// opts:
// parent
// method (method to call on server)
// args (additional args to method)
// get_args (method to return args as dict)
// show_filters [false]
// doctype
// filter_fields (if given, this list is rendered, else built from doctype)
// query or get_query (will be deprecated)
// query_max
// buttons_in_frame
// no_result_message ("No result")
// page_length (20)
// hide_refresh (False)
// no_toolbar
// new_doctype
// [function] render_row(parent, data)
// [function] onrun
// no_loading (no ajax indicator)
frappe.provide('frappe.ui');
frappe.ui.BaseList = Class.extend({
init: function (opts) {
this.opts = opts || {};
this.set_defaults();
if (opts) {
this.make();
}
},
set_defaults: function () {
this.page_length = 20;
this.start = 0;
this.data = [];
},
make: function (opts) {
if (opts) {
this.opts = opts;
}
this.prepare_opts();
$.extend(this, this.opts);
// make dom
this.wrapper = $(frappe.render_template('listing', this.opts));
this.parent.append(this.wrapper);
this.set_events();
if (this.page) {
this.wrapper.find('.list-toolbar-wrapper').hide();
}
if (this.show_filters) {
this.make_filters();
}
},
prepare_opts: function () {
if (this.opts.new_doctype) {
if (!frappe.boot.user.can_create.includes(this.opts.new_doctype)) {
this.opts.new_doctype = null;
}
}
if (!this.opts.no_result_message) {
this.opts.no_result_message = __('Nothing to show');
}
if (!this.opts.page_length) {
this.opts.page_length = this.user_settings && this.user_settings.limit || 20;
}
this.opts._more = __('More');
},
add_button: function (label, click, icon) {
if (this.page) {
return this.page.add_menu_item(label, click, icon)
} else {
this.wrapper.find('.list-toolbar-wrapper').removeClass('hide');
return $('<button class="btn btn-default"></button>')
.appendTo(this.wrapper.find('.list-toolbar'))
.html((icon ? ('<i class="' + icon + '"></i> ') : '') + label)
.click(click);
}
},
set_events: function () {
var me = this;
// next page
this.wrapper.find('.btn-more').click(function () {
me.run(true);
});
this.wrapper.find(".btn-group-paging").on('click', '.btn', function () {
me.page_length = cint($(this).attr("data-value"));
me.wrapper.find(".btn-group-paging .btn-info").removeClass("btn-info");
$(this).addClass("btn-info");
// always reset when changing list page length
me.run();
});
// select the correct page length
if (this.opts.page_length !== 20) {
this.wrapper.find(".btn-group-paging .btn-info").removeClass("btn-info");
this.wrapper
.find(".btn-group-paging .btn[data-value='" + this.opts.page_length + "']")
.addClass('btn-info');
}
// title
if (this.title) {
this.wrapper.find('h3').html(this.title).show();
}
// new
this.set_primary_action();
if (me.no_toolbar || me.hide_toolbar) {
me.wrapper.find('.list-toolbar-wrapper').hide();
}
},
set_primary_action: function () {
var me = this;
if (this.new_doctype) {
this.page.set_primary_action(
__("New"),
me.make_new_doc.bind(me, me.new_doctype),
"octicon octicon-plus"
);
} else {
this.page.clear_primary_action();
}
},
make_new_doc: function (doctype) {
var me = this;
frappe.model.with_doctype(doctype, function () {
if (me.custom_new_doc) {
me.custom_new_doc(doctype);
} else {
if (me.filter_list) {
frappe.route_options = {};
me.filter_list.get_filters().forEach(function (f, i) {
if (f[2] === "=" && !frappe.model.std_fields_list.includes(f[1])) {
frappe.route_options[f[1]] = f[3];
}
});
}
frappe.new_doc(doctype, true);
}
});
},
make_filters: function () {
this.make_standard_filters();
this.filter_list = new frappe.ui.FilterList({
base_list: this,
parent: this.wrapper.find('.list-filters').show(),
doctype: this.doctype,
filter_fields: this.filter_fields,
default_filters: this.default_filters || []
});
// default filter for submittable doctype
if (frappe.model.is_submittable(this.doctype)) {
this.filter_list.add_filter(this.doctype, "docstatus", "!=", 2);
}
},
make_standard_filters: function() {
var me = this;
if (this.standard_filters_added) {
return;
}
if (this.meta) {
var filter_count = 1;
if(this.is_list_view) {
$(`<span class="octicon octicon-search text-muted small"></span>`)
.prependTo(this.page.page_form);
}
this.page.add_field({
fieldtype: 'Data',
label: 'ID',
condition: 'like',
fieldname: 'name',
onchange: () => { me.refresh(true); }
});
this.meta.fields.forEach(function(df, i) {
if(df.in_standard_filter && !frappe.model.no_value_type.includes(df.fieldtype)) {
let options = df.options;
let condition = '=';
let fieldtype = df.fieldtype;
if (['Text', 'Small Text', 'Text Editor', 'Data'].includes(fieldtype)) {
fieldtype = 'Data';
condition = 'like';
}
if(df.fieldtype == "Select" && df.options) {
options = df.options.split("\n");
if(options.length > 0 && options[0] != "") {
options.unshift("");
options = options.join("\n");
}
}
let f = me.page.add_field({
fieldtype: fieldtype,
label: __(df.label),
options: options,
fieldname: df.fieldname,
condition: condition,
onchange: () => {me.refresh(true);}
});
filter_count ++;
if (filter_count > 3) {
$(f.wrapper).addClass('hidden-sm').addClass('hidden-xs');
}
if (filter_count > 5) {
return false;
}
}
});
}
this.standard_filters_added = true;
},
update_standard_filters: function(filters) {
let me = this;
for(let key in this.page.fields_dict) {
let field = this.page.fields_dict[key];
let value = field.get_value();
if (value) {
if (field.df.condition==='like' && !value.includes('%')) {
value = '%' + value + '%';
}
filters.push([
me.doctype,
field.df.fieldname,
field.df.condition || '=',
value
]);
}
}
},
clear: function () {
this.data = [];
this.wrapper.find('.result-list').empty();
this.wrapper.find('.result').show();
this.wrapper.find('.no-result').hide();
this.start = 0;
this.onreset && this.onreset();
},
/*
* Uses the value of `frappe.route_options` to automatically set
* a filter in a list view.
*/
set_filters_from_route_options: function ({clear_filters=true} = {}) {
var me = this;
if(this.filter_list && clear_filters) {
this.filter_list.clear_filters();
}
for(var field in frappe.route_options) {
var value = frappe.route_options[field];
var doctype = null;
// if `Child DocType.fieldname`
if (field.includes(".")) {
doctype = field.split(".")[0];
field = field.split(".")[1];
}
// find the table in which the key exists
// for example the filter could be {"item_code": "X"}
// where item_code is in the child table.
// we can search all tables for mapping the doctype
if (!doctype) {
doctype = frappe.meta.get_doctype_for_field(me.doctype, field);
}
if (doctype && me.filter_list) {
if ($.isArray(value)) {
me.filter_list.add_filter(doctype, field, value[0], value[1]);
} else {
me.filter_list.add_filter(doctype, field, "=", value);
}
}
}
frappe.route_options = null;
},
run: function(more) {
setTimeout(() => this._run(more), 100);
},
_run: function (more) {
var me = this;
if (!more) {
this.start = 0;
this.onreset && this.onreset();
}
var args = this.get_call_args();
this.save_user_settings_locally(args);
// user_settings are saved by db_query.py when dirty
$.extend(args, {
user_settings: frappe.model.user_settings[this.doctype]
});
return frappe.call({
method: this.opts.method || 'frappe.desk.query_builder.runquery',
type: "GET",
freeze: this.opts.freeze !== undefined ? this.opts.freeze : true,
args: args,
callback: function (r) {
me.dirty = false;
me.render_results(r);
},
no_spinner: this.opts.no_loading
});
},
save_user_settings_locally: function (args) {
if (this.opts.save_user_settings && this.doctype && !this.docname) {
// save list settings locally
var user_settings = frappe.model.user_settings[this.doctype];
var different = false;
if (!user_settings) {
return;
}
if (!frappe.utils.arrays_equal(args.filters, user_settings.filters)) {
// settings are dirty if filters change
user_settings.filters = args.filters;
different = true;
}
if (user_settings.order_by !== args.order_by) {
user_settings.order_by = args.order_by;
different = true;
}
if (user_settings.limit !== args.limit_page_length) {
user_settings.limit = args.limit_page_length || 20
different = true;
}
// save fields in list settings
if (args.save_user_settings_fields) {
user_settings.fields = args.fields;
}
if (different) {
user_settings.updated_on = moment().toString();
}
}
},
/*
* Prepares arguments that will be used to query the database to
* return the desired records for the list view
*/
get_call_args: function () {
if (!this.method) {
var query = this.get_query && this.get_query() || this.query;
query = this.add_limits(query);
var args = {
query_max: this.query_max,
as_dict: 1
}
args.simple_query = query;
} else {
var args = {
start: this.start,
page_length: this.page_length
}
}
// append user-defined arguments
if (this.args)
$.extend(args, this.args)
if (this.get_args) {
$.extend(args, this.get_args());
}
return args;
},
render_results: function (r) {
if (this.start === 0)
this.clear();
this.wrapper.find('.btn-more, .list-loading').hide();
var values = [];
if (r.message) {
values = this.get_values_from_response(r.message);
}
var show_results = true;
if(this.show_no_result) {
if($.isFunction(this.show_no_result)) {
show_results = !this.show_no_result()
} else {
show_results = !this.show_no_result;
}
}
// render result view when
// length > 0 OR
// explicitly set by flag
if (values.length || show_results) {
this.data = this.data.concat(values);
this.render_view(values);
this.update_paging(values);
} else if (this.start === 0) {
// show no result message
this.wrapper.find('.result').hide();
var msg = '';
var no_result_message = this.no_result_message;
if(no_result_message && $.isFunction(no_result_message)) {
msg = no_result_message();
} else if(typeof no_result_message === 'string') {
msg = no_result_message;
} else {
msg = __('No Results')
}
this.wrapper.find('.no-result').html(msg).show();
}
this.wrapper.find('.list-paging-area')
.toggle(values.length > 0|| this.start > 0);
// callbacks
if (this.onrun) this.onrun();
if (this.callback) this.callback(r);
this.wrapper.trigger("render-complete");
},
get_values_from_response: function (data) {
// make dictionaries from keys and values
if (data.keys && $.isArray(data.keys)) {
return frappe.utils.dict(data.keys, data.values);
} else {
return data;
}
},
render_view: function (values) {
// override this method in derived class
},
update_paging: function (values) {
if (values.length >= this.page_length) {
this.wrapper.find('.btn-more').show();
this.start += this.page_length;
}
},
refresh: function () {
this.run();
},
add_limits: function (query) {
return query + ' LIMIT ' + this.start + ',' + (this.page_length + 1);
},
set_filter: function (fieldname, label, no_run, no_duplicate) {
var filter = this.filter_list.get_filter(fieldname);
if (filter) {
var value = cstr(filter.field.get_value());
if (value.includes(label)) {
// already set
return false
} else if (no_duplicate) {
filter.set_values(this.doctype, fieldname, "=", label);
} else {
// second filter set for this field
if (fieldname == '_user_tags' || fieldname == "_liked_by") {
// and for tags
this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label + '%');
} else {
// or for rest using "in"
filter.set_values(this.doctype, fieldname, 'in', value + ', ' + label);
}
}
} else {
// no filter for this item,
// setup one
if (['_user_tags', '_comments', '_assign', '_liked_by'].includes(fieldname)) {
this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label + '%');
} else {
this.filter_list.add_filter(this.doctype, fieldname, '=', label);
}
}
if (!no_run)
this.run();
},
init_user_settings: function () {
this.user_settings = frappe.model.user_settings[this.doctype] || {};
},
call_for_selected_items: function (method, args) {
var me = this;
args.names = this.get_checked_items().map(function (item) {
return item.name;
});
frappe.call({
method: method,
args: args,
freeze: true,
callback: function (r) {
if (!r.exc) {
if (me.list_header) {
me.list_header.find(".list-select-all").prop("checked", false);
}
me.refresh(true);
}
}
});
}
});

View file

@ -0,0 +1,691 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
frappe.ui.FilterList = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.filters = [];
this.wrapper = this.parent;
this.stats = [];
this.make();
this.set_events();
},
make: function() {
this.wrapper.find('.show_filters, .filter_area').remove();
this.wrapper.append(`
<div class="show_filters">
<div class="set-filters">
<button
style="margin-right: 10px;"
class="btn btn-default btn-xs new-filter text-muted">
${__("Add Filter")}</button>
</div>
</div>
<div class="filter_area"></div>`);
},
set_events: function() {
var me = this;
// show filters
this.wrapper.find('.new-filter').bind('click', function() {
me.add_filter();
});
this.wrapper.find('.clear-filters').bind('click', function() {
me.clear_filters();
$('.date-range-picker').val('')
me.base_list.run();
$(this).addClass("hide");
});
},
show_filters: function() {
this.wrapper.find('.show_filters').toggle();
if(!this.filters.length) {
this.add_filter(this.doctype, 'name');
this.filters[0].wrapper.find(".filter_field input").focus();
}
},
/*
* Removes all filters.
*/
clear_filters: function() {
$.each(this.filters, function(i, f) { f.remove(true); });
if(this.base_list.page.fields_dict) {
$.each(this.base_list.page.fields_dict, (key, value) => {
value.set_input('');
});
}
this.filters = [];
},
/*
* Adds a new filter.
* @param {string} doctype
* @param {string} fieldname
* @param {string} condition
* @param {string} value
* @param {string} hidden
* @returns {Boolean} - Returns true if filter is added
*/
add_filter: function(doctype, fieldname, condition, value, hidden) {
// adds a new filter, returns true if filter has been added
// allow equal to be used as like
let base_filter = this.base_list.page.fields_dict[fieldname];
if (base_filter
&& (base_filter.df.condition==condition
|| (condition==='=' && base_filter.df.condition==='like'))) {
// if filter exists in base_list, then exit
this.base_list.page.fields_dict[fieldname].set_input(value);
return true;
}
if(doctype && fieldname
&& !frappe.meta.has_field(doctype, fieldname)
&& !in_list(frappe.model.std_fields_list, fieldname)) {
frappe.msgprint({
message: __('Filter {0} missing', [fieldname.bold()]),
title: 'Invalid Filter',
indicator: 'red'
});
return false;
}
this.wrapper.find('.show_filters').toggle(true);
var is_new_filter = arguments.length===0;
if (is_new_filter && this.wrapper.find(".is-new-filter:visible").length) {
// only allow 1 new filter at a time!
return false;
}
var filter = this.push_new_filter(doctype, fieldname, condition, value);
if (!filter) return;
if(this.wrapper.find('.clear-filters').hasClass("hide")) {
this.wrapper.find('.clear-filters').removeClass("hide");
}
if (filter && is_new_filter) {
filter.wrapper.addClass("is-new-filter");
} else {
filter.freeze();
}
if (hidden) {
filter.$btn_group.addClass("hide");
}
return true;
},
push_new_filter: function(doctype, fieldname, condition, value) {
if(this.filter_exists(doctype, fieldname, condition, value)) {
return;
}
// if standard filter exists, then clear it.
if(this.base_list.page.fields_dict[fieldname]) {
this.base_list.page.fields_dict[fieldname].set_input('');
}
var filter = new frappe.ui.Filter({
flist: this,
_doctype: doctype,
fieldname: fieldname,
condition: condition,
value: value
});
this.filters.push(filter);
return filter;
},
remove: function(filter) {
// remove `filter` from flist
for (var i in this.filters) {
if (this.filters[i] === filter) {
break;
}
}
if (i!==undefined) {
// remove index
this.filters.splice(i, 1);
}
},
filter_exists: function(doctype, fieldname, condition, value) {
var flag = false;
for(var i in this.filters) {
if(this.filters[i].field) {
var f = this.filters[i].get_value();
if(f[0]==doctype && f[1]==fieldname && f[2]==condition && f[3]==value) {
flag = true;
} else if($.isArray(value) && frappe.utils.arrays_equal(value, f[3])) {
flag = true;
}
}
}
return flag;
},
get_filters: function() {
// get filter values as dict
var values = [];
$.each(this.filters, function(i, filter) {
if(filter.field) {
filter.freeze();
values.push(filter.get_value());
}
});
this.base_list.update_standard_filters(values);
return values;
},
// remove hidden filters
update_filters: function() {
var fl = [];
$.each(this.filters, function(i, f) {
if(f.field) fl.push(f);
})
this.filters = fl;
if(this.filters.length === 0) {
this.wrapper.find('.clear-filters').addClass("hide");
}
},
get_filter: function(fieldname) {
for(var i in this.filters) {
if(this.filters[i].field && this.filters[i].field.df.fieldname==fieldname)
return this.filters[i];
}
},
get_formatted_value: function(field, val){
var value = val;
if(field.df.fieldname==="docstatus") {
value = {0:"Draft", 1:"Submitted", 2:"Cancelled"}[value] || value;
} else if(field.df.original_type==="Check") {
value = {0:"No", 1:"Yes"}[cint(value)];
}
value = frappe.format(value, field.df, {only_value: 1});
return value;
}
});
frappe.ui.Filter = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.doctype = this.flist.doctype;
this.make();
this.make_select();
this.set_events();
},
make: function() {
this.wrapper = $(frappe.render_template("edit_filter", {}))
.appendTo(this.flist.wrapper.find('.filter_area'));
},
make_select: function() {
var me = this;
this.fieldselect = new frappe.ui.FieldSelect({
parent: this.wrapper.find('.fieldname_select_area'),
doctype: this.doctype,
filter_fields: this.filter_fields,
select: function(doctype, fieldname) {
me.set_field(doctype, fieldname);
}
});
if(this.fieldname) {
this.fieldselect.set_value(this._doctype || this.doctype, this.fieldname);
}
},
set_events: function() {
var me = this;
this.wrapper.find("a.remove-filter").on("click", function() {
me.remove();
});
this.wrapper.find(".set-filter-and-run").on("click", function() {
me.wrapper.removeClass("is-new-filter");
me.flist.base_list.run();
me.apply();
});
// add help for "in" codition
me.wrapper.find('.condition').change(function() {
if(!me.field) return;
var condition = $(this).val();
if(in_list(["in", "like", "not in", "not like"], condition)) {
me.set_field(me.field.df.parent, me.field.df.fieldname, 'Data', condition);
if(!me.field.desc_area) {
me.field.desc_area = $('<div class="text-muted small">').appendTo(me.field.wrapper);
}
// set description
me.field.desc_area.html((in_list(["in", "not in"], condition)==="in"
? __("values separated by commas")
: __("use % as wildcard"))+'</div>');
} else {
//if condition selected after refresh
me.set_field(me.field.df.parent, me.field.df.fieldname, null, condition);
}
});
// set the field
if(me.fieldname) {
// pre-sets given (could be via tags!)
return this.set_values(me._doctype, me.fieldname, me.condition, me.value);
} else {
me.set_field(me.doctype, 'name');
}
},
apply: function() {
var f = this.get_value();
this.flist.remove(this);
this.flist.push_new_filter(f[0], f[1], f[2], f[3]);
this.wrapper.remove();
this.flist.update_filters();
},
remove: function(dont_run) {
this.wrapper.remove();
this.$btn_group && this.$btn_group.remove();
this.field = null;
this.flist.update_filters();
if(!dont_run) {
this.flist.base_list.refresh(true);
}
},
set_values: function(doctype, fieldname, condition, value) {
// presents given (could be via tags!)
this.set_field(doctype, fieldname);
// change 0,1 to Yes, No for check field type
if(this.field.df.original_type==='Check') {
if(value==0) value = 'No';
else if(value==1) value = 'Yes';
}
if(condition) {
this.wrapper.find('.condition').val(condition).change();
}
if(value!=null) {
return this.field.set_value(value);
}
},
set_field: function(doctype, fieldname, fieldtype, condition) {
var me = this;
// set in fieldname (again)
var cur = me.field ? {
fieldname: me.field.df.fieldname,
fieldtype: me.field.df.fieldtype,
parent: me.field.df.parent,
} : {};
var original_docfield = me.fieldselect.fields_by_name[doctype][fieldname];
if(!original_docfield) {
frappe.msgprint(__("Field {0} is not selectable.", [fieldname]));
return;
}
var df = copy_dict(me.fieldselect.fields_by_name[doctype][fieldname]);
// filter field shouldn't be read only or hidden
df.read_only = 0;
df.hidden = 0;
if(!condition) this.set_default_condition(df, fieldtype);
this.set_fieldtype(df, fieldtype);
// called when condition is changed,
// don't change if all is well
if(me.field && cur.fieldname == fieldname && df.fieldtype == cur.fieldtype &&
df.parent == cur.parent) {
return;
}
// clear field area and make field
me.fieldselect.selected_doctype = doctype;
me.fieldselect.selected_fieldname = fieldname;
// save old text
var old_text = null;
if(me.field) {
old_text = me.field.get_value();
}
var field_area = me.wrapper.find('.filter_field').empty().get(0);
var f = frappe.ui.form.make_control({
df: df,
parent: field_area,
only_input: true,
})
f.refresh();
me.field = f;
if(old_text && me.field.df.fieldtype===cur.fieldtype) {
me.field.set_value(old_text);
}
// run on enter
$(me.field.wrapper).find(':input').keydown(function(ev) {
if(ev.which==13) {
me.flist.base_list.run();
}
})
},
set_fieldtype: function(df, fieldtype) {
// reset
if(df.original_type)
df.fieldtype = df.original_type;
else
df.original_type = df.fieldtype;
df.description = ''; df.reqd = 0;
df.ignore_link_validation = true;
// given
if(fieldtype) {
df.fieldtype = fieldtype;
return;
}
// scrub
if(df.fieldname=="docstatus") {
df.fieldtype="Select",
df.options=[
{value:0, label:__("Draft")},
{value:1, label:__("Submitted")},
{value:2, label:__("Cancelled")}
]
} else if(df.fieldtype=='Check') {
df.fieldtype='Select';
df.options='No\nYes';
} else if(['Text','Small Text','Text Editor','Code','Tag','Comments',
'Dynamic Link','Read Only','Assign'].indexOf(df.fieldtype)!=-1) {
df.fieldtype = 'Data';
} else if(df.fieldtype=='Link' && ['=', '!='].indexOf(this.wrapper.find('.condition').val())==-1) {
df.fieldtype = 'Data';
}
if(df.fieldtype==="Data" && (df.options || "").toLowerCase()==="email") {
df.options = null;
}
if(this.wrapper.find('.condition').val()== "Between" && (df.fieldtype == 'Date' || df.fieldtype == 'Datetime')){
df.fieldtype = 'DateRange';
}
},
set_default_condition: function(df, fieldtype) {
if(!fieldtype) {
// set as "like" for data fields
if (df.fieldtype == 'Data') {
this.wrapper.find('.condition').val('like');
} else if (df.fieldtype == 'Date' || df.fieldtype == 'Datetime'){
this.wrapper.find('.condition').val('Between');
}else{
this.wrapper.find('.condition').val('=');
}
}
},
get_value: function() {
return [this.fieldselect.selected_doctype,
this.field.df.fieldname, this.get_condition(), this.get_selected_value()];
},
get_selected_value: function() {
var val = this.field.get_value();
if(typeof val==='string') {
val = strip(val);
}
if(this.field.df.original_type == 'Check') {
val = (val=='Yes' ? 1 :0);
}
if(this.get_condition().indexOf('like', 'not like')!==-1) {
// automatically append wildcards
if(val) {
if(val.slice(0,1) !== "%") {
val = "%" + val;
}
if(val.slice(-1) !== "%") {
val = val + "%";
}
}
} else if(in_list(["in", "not in"], this.get_condition())) {
if(val) {
val = $.map(val.split(","), function(v) { return strip(v); });
}
} if(val === '%') {
val = "";
}
return val;
},
get_condition: function() {
return this.wrapper.find('.condition').val();
},
freeze: function() {
if(this.$btn_group) {
// already made, just hide the condition setter
this.set_filter_button_text();
this.wrapper.toggle(false);
return;
}
var me = this;
// add a button for new filter if missing
this.$btn_group = $(`<div class="btn-group">
<button class="btn btn-default btn-xs toggle-filter"
title="${ __("Edit Filter") }">
</button>
<button class="btn btn-default btn-xs remove-filter"
title="${ __("Remove Filter") }">
<i class="fa fa-remove text-muted"></i>
</button></div>`)
.insertAfter(this.flist.wrapper.find(".set-filters .new-filter"));
this.set_filter_button_text();
this.$btn_group.find(".remove-filter").on("click", function() {
me.remove();
});
this.$btn_group.find(".toggle-filter").on("click", function() {
$(this).closest('.show_filters').find('.filter_area').show()
me.wrapper.toggle();
})
this.wrapper.toggle(false);
},
set_filter_button_text: function() {
var value = this.get_selected_value();
value = this.flist.get_formatted_value(this.field, value);
// for translations
// __("like"), __("not like"), __("in")
this.$btn_group.find(".toggle-filter")
.html(repl('%(label)s %(condition)s "%(value)s"', {
label: __(this.field.df.label),
condition: __(this.get_condition()),
value: __(value),
}));
}
});
// <select> widget with all fields of a doctype as options
frappe.ui.FieldSelect = Class.extend({
// opts parent, doctype, filter_fields, with_blank, select
init: function(opts) {
var me = this;
$.extend(this, opts);
this.fields_by_name = {};
this.options = [];
this.$select = $('<input class="form-control">')
.appendTo(this.parent)
.on("click", function () { $(this).select(); });
this.select_input = this.$select.get(0);
this.awesomplete = new Awesomplete(this.select_input, {
minChars: 0,
maxItems: 99,
autoFirst: true,
list: me.options,
item: function(item, input) {
return $(repl('<li class="filter-field-select"><p>%(label)s</p></li>', item))
.data("item.autocomplete", item)
.get(0);
}
});
this.$select.on("awesomplete-select", function(e) {
var o = e.originalEvent;
var value = o.text.value;
var item = me.awesomplete.get_item(value);
me.selected_doctype = item.doctype;
me.selected_fieldname = item.fieldname;
if(me.select) me.select(item.doctype, item.fieldname);
});
this.$select.on("awesomplete-selectcomplete", function(e) {
var o = e.originalEvent;
var value = o.text.value;
var item = me.awesomplete.get_item(value);
me.$select.val(item.label);
});
if(this.filter_fields) {
for(var i in this.filter_fields)
this.add_field_option(this.filter_fields[i])
} else {
this.build_options();
}
this.set_value(this.doctype, "name");
window.last_filter = this;
},
get_value: function() {
return this.selected_doctype ? this.selected_doctype + "." + this.selected_fieldname : null;
},
val: function(value) {
if(value===undefined) {
return this.get_value();
} else {
this.set_value(value);
}
},
clear: function() {
this.selected_doctype = null;
this.selected_fieldname = null;
this.$select.val("");
},
set_value: function(doctype, fieldname) {
var me = this;
this.clear();
if(!doctype) return;
// old style
if(doctype.indexOf(".")!==-1) {
var parts = doctype.split(".");
doctype = parts[0];
fieldname = parts[1];
}
$.each(this.options, function(i, v) {
if(v.doctype===doctype && v.fieldname===fieldname) {
me.selected_doctype = doctype;
me.selected_fieldname = fieldname;
me.$select.val(v.label);
return false;
}
});
},
build_options: function() {
var me = this;
me.table_fields = [];
var std_filters = $.map(frappe.model.std_fields, function(d) {
var opts = {parent: me.doctype}
if(d.fieldname=="name") opts.options = me.doctype;
return $.extend(copy_dict(d), opts);
});
// add parenttype column
var doctype_obj = locals['DocType'][me.doctype];
if(doctype_obj && cint(doctype_obj.istable)) {
std_filters = std_filters.concat([{
fieldname: 'parent',
fieldtype: 'Data',
label: 'Parent',
parent: me.doctype,
}]);
}
// blank
if(this.with_blank) {
this.options.push({
label:"",
value:"",
})
}
// main table
var main_table_fields = std_filters.concat(frappe.meta.docfield_list[me.doctype]);
$.each(frappe.utils.sort(main_table_fields, "label", "string"), function(i, df) {
// show fields where user has read access and if report hide flag is not set
if(frappe.perm.has_perm(me.doctype, df.permlevel, "read") && !df.report_hide)
me.add_field_option(df);
});
// child tables
$.each(me.table_fields, function(i, table_df) {
if(table_df.options) {
var child_table_fields = [].concat(frappe.meta.docfield_list[table_df.options]);
$.each(frappe.utils.sort(child_table_fields, "label", "string"), function(i, df) {
// show fields where user has read access and if report hide flag is not set
if(frappe.perm.has_perm(me.doctype, df.permlevel, "read") && !df.report_hide)
me.add_field_option(df);
});
}
});
},
add_field_option: function(df) {
var me = this;
if(me.doctype && df.parent==me.doctype) {
var label = __(df.label);
var table = me.doctype;
if(df.fieldtype=='Table') me.table_fields.push(df);
} else {
var label = __(df.label) + ' (' + __(df.parent) + ')';
var table = df.parent;
}
if(frappe.model.no_value_type.indexOf(df.fieldtype) == -1 &&
!(me.fields_by_name[df.parent] && me.fields_by_name[df.parent][df.fieldname])) {
this.options.push({
label: label,
value: table + "." + df.fieldname,
fieldname: df.fieldname,
doctype: df.parent
});
if(!me.fields_by_name[df.parent]) me.fields_by_name[df.parent] = {};
me.fields_by_name[df.parent][df.fieldname] = df;
}
},
})