frappe_docker/frappe-bench/sites/assets/js/list.min.js
2017-07-31 15:51:51 +05:30

4183 lines
139 KiB
JavaScript

frappe.templates['listing'] = '<div class="frappe-list"> <div class="list-filters" style="display: none;"> </div> <div style="margin-bottom:9px" class="list-toolbar-wrapper hide"> <div class="list-toolbar btn-group" style="display:inline-block; margin-right: 10px;"> </div> </div> <div style="clear:both"></div> <div class="no-result text-center" style="display: none;"> {%= no_result_message %} </div> <div class="result"> <div class="list-headers"></div> <div class="list-loading text-center"> {%= frappe.messages.get_waiting_message(__("Loading") + "..." ) %} </div> <div class="result-list"></div> </div> <div class="list-paging-area"> <div class="row"> <div class="col-xs-6"> <div class="btn-group btn-group-paging"> <button type="button" class="btn btn-default btn-sm btn-info" data-value="20">20</button> <button type="button" class="btn btn-default btn-sm" data-value="100">100</button> <button type="button" class="btn btn-default btn-sm" data-value="500">500</button> </div> </div> <div class="col-xs-6 text-right"> <button class="btn btn-default btn-more btn-sm">{%= _more %}...</button> </div> </div> </div> </div> ';
frappe.provide('frappe.ui');
frappe.ui.BaseList = Class.extend({
init: function init(opts) {
this.opts = opts || {};
this.set_defaults();
if (opts) {
this.make();
}
},
set_defaults: function set_defaults() {
this.page_length = 20;
this.start = 0;
this.data = [];
},
make: function make(opts) {
if (opts) {
this.opts = opts;
}
this.prepare_opts();
$.extend(this, this.opts);
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 prepare_opts() {
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 add_button(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 set_events() {
var me = this;
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");
me.run();
});
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');
}
if (this.title) {
this.wrapper.find('h3').html(this.title).show();
}
this.set_primary_action();
if (me.no_toolbar || me.hide_toolbar) {
me.wrapper.find('.list-toolbar-wrapper').hide();
}
},
set_primary_action: function set_primary_action() {
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 make_new_doc(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 make_filters() {
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 || []
});
if (frappe.model.is_submittable(this.doctype)) {
this.filter_list.add_filter(this.doctype, "docstatus", "!=", 2);
}
},
make_standard_filters: function make_standard_filters() {
var me = this;
if (this.standard_filters_added) {
return;
}
if (this.meta) {
this.page.add_field({
fieldtype: 'Data',
label: 'ID',
condition: 'like',
fieldname: 'name',
onchange: function onchange() {
me.refresh(true);
}
});
this.meta.fields.forEach(function (df) {
if (df.in_standard_filter && !frappe.model.no_value_type.includes(df.fieldtype)) {
var options = df.options;
var condition = '=';
var 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");
}
}
me.page.add_field({
fieldtype: fieldtype,
label: __(df.label),
options: options,
fieldname: df.fieldname,
condition: condition,
onchange: function onchange() {
me.refresh(true);
}
});
}
});
}
this.standard_filters_added = true;
},
update_standard_filters: function update_standard_filters(filters) {
var me = this;
for (var key in this.page.fields_dict) {
var field = this.page.fields_dict[key];
var 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 clear() {
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();
},
set_filters_from_route_options: function set_filters_from_route_options() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$clear_filters = _ref.clear_filters,
clear_filters = _ref$clear_filters === undefined ? true : _ref$clear_filters;
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 (field.includes(".")) {
doctype = field.split(".")[0];
field = field.split(".")[1];
}
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 run(more) {
var _this = this;
setTimeout(function () {
return _this._run(more);
}, 100);
},
_run: function _run(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);
$.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 callback(r) {
me.dirty = false;
me.render_results(r);
},
no_spinner: this.opts.no_loading
});
},
save_user_settings_locally: function save_user_settings_locally(args) {
if (this.opts.save_user_settings && this.doctype && !this.docname) {
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)) {
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;
}
if (args.save_user_settings_fields) {
user_settings.fields = args.fields;
}
if (different) {
user_settings.updated_on = moment().toString();
}
}
},
get_call_args: function get_call_args() {
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
};
}
if (this.args) $.extend(args, this.args);
if (this.get_args) {
$.extend(args, this.get_args());
}
return args;
},
render_results: function render_results(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;
}
}
if (values.length || show_results) {
this.data = this.data.concat(values);
this.render_view(values);
this.update_paging(values);
} else if (this.start === 0) {
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);
if (this.onrun) this.onrun();
if (this.callback) this.callback(r);
this.wrapper.trigger("render-complete");
},
get_values_from_response: function get_values_from_response(data) {
if (data.keys && $.isArray(data.keys)) {
return frappe.utils.dict(data.keys, data.values);
} else {
return data;
}
},
render_view: function render_view(values) {},
update_paging: function update_paging(values) {
if (values.length >= this.page_length) {
this.wrapper.find('.btn-more').show();
this.start += this.page_length;
}
},
refresh: function refresh() {
this.run();
},
add_limits: function add_limits(query) {
return query + ' LIMIT ' + this.start + ',' + (this.page_length + 1);
},
set_filter: function set_filter(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)) {
return false;
} else if (no_duplicate) {
filter.set_values(this.doctype, fieldname, "=", label);
} else {
if (fieldname == '_user_tags' || fieldname == "_liked_by") {
this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label + '%');
} else {
filter.set_values(this.doctype, fieldname, 'in', value + ', ' + label);
}
}
} else {
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 init_user_settings() {
this.user_settings = frappe.model.user_settings[this.doctype] || {};
},
call_for_selected_items: function call_for_selected_items(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 callback(r) {
if (!r.exc) {
if (me.list_header) {
me.list_header.find(".list-select-all").prop("checked", false);
}
me.refresh();
}
}
});
}
});
frappe.has_indicator = function (doctype) {
if (frappe.model.is_submittable(doctype)) {
return true;
} else if ((frappe.listview_settings[doctype] || {}).get_indicator || frappe.workflow.get_state_fieldname(doctype)) {
return true;
} else if (frappe.meta.has_field(doctype, 'enabled') || frappe.meta.has_field(doctype, 'disabled')) {
return true;
}
return false;
};
frappe.get_indicator = function (doc, doctype) {
var without_workflow = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
if (doc.__unsaved) {
return [__("Not Saved"), "orange"];
}
if (!doctype) doctype = doc.doctype;
var settings = frappe.listview_settings[doctype] || {};
var is_submittable = frappe.model.is_submittable(doctype),
workflow_fieldname = frappe.workflow.get_state_fieldname(doctype);
if (workflow_fieldname && !without_workflow) {
var value = doc[workflow_fieldname];
if (value) {
var colour = "";
if (locals["Workflow State"][value] && locals["Workflow State"][value].style) {
var colour = {
"Success": "green",
"Warning": "orange",
"Danger": "red",
"Primary": "blue"
}[locals["Workflow State"][value].style];
}
if (!colour) colour = "darkgrey";
return [__(value), colour, workflow_fieldname + ',=,' + value];
}
}
if (is_submittable && doc.docstatus == 0 && !settings.has_indicator_for_draft) {
return [__("Draft"), "red", "docstatus,=,0"];
}
if (is_submittable && doc.docstatus == 2) {
return [__("Cancelled"), "red", "docstatus,=,2"];
}
if (settings.get_indicator) {
var indicator = settings.get_indicator(doc);
if (indicator) return indicator;
}
if (is_submittable && doc.docstatus == 1) {
return [__("Submitted"), "blue", "docstatus,=,1"];
}
if (doc.status) {
return [__(doc.status), frappe.utils.guess_colour(doc.status)];
}
if (frappe.meta.has_field(doctype, 'enabled')) {
if (doc.enabled) {
return [__('Enabled'), 'blue', 'enabled,=,1'];
} else {
return [__('Disabled'), 'grey', 'enabled,=,0'];
}
}
if (frappe.meta.has_field(doctype, 'disabled')) {
if (doc.disabled) {
return [__('Disabled'), 'grey', 'disabled,=,1'];
} else {
return [__('Enabled'), 'blue', 'disabled,=,0'];
}
}
};
frappe.ui.FilterList = Class.extend({
init: function init(opts) {
$.extend(this, opts);
this.filters = [];
this.wrapper = this.parent;
this.stats = [];
this.make();
this.set_events();
},
make: function make() {
this.wrapper.find('.show_filters, .filter_area').remove();
this.wrapper.append('\n\t\t\t<div class="show_filters">\n\t\t\t\t<div class="set-filters">\n\t\t\t\t\t<button\n\t\t\t\t\t\tstyle="margin-right: 10px;"\n\t\t\t\t\t\tclass="btn btn-default btn-xs new-filter text-muted">\n\t\t\t\t\t\t' + __("Add Filter") + '</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class="filter_area"></div>');
},
set_events: function set_events() {
var me = this;
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 show_filters() {
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();
}
},
clear_filters: function clear_filters() {
$.each(this.filters, function (i, f) {
f.remove(true);
});
if (this.base_list.page.fields_dict) {
$.each(this.base_list.page.fields_dict, function (key, value) {
value.set_input('');
});
}
this.filters = [];
},
add_filter: function add_filter(doctype, fieldname, condition, value, hidden) {
var base_filter = this.base_list.page.fields_dict[fieldname];
if (base_filter && (base_filter.df.condition == condition || condition === '=' && base_filter.df.condition === 'like')) {
this.base_list.page.fields_dict[fieldname].set_input(value);
return;
}
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;
}
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) {
return;
}
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 filter;
},
push_new_filter: function push_new_filter(doctype, fieldname, condition, value) {
if (this.filter_exists(doctype, fieldname, condition, value)) {
return;
}
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;
},
filter_exists: function filter_exists(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_filters() {
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;
},
update_filters: function update_filters() {
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 get_filter(fieldname) {
for (var i in this.filters) {
if (this.filters[i].field && this.filters[i].field.df.fieldname == fieldname) return this.filters[i];
}
}
});
frappe.ui.Filter = Class.extend({
init: function init(opts) {
$.extend(this, opts);
this.doctype = this.flist.doctype;
this.make();
this.make_select();
this.set_events();
},
make: function make() {
this.wrapper = $(frappe.render_template("edit_filter", {})).appendTo(this.flist.wrapper.find('.filter_area'));
},
make_select: function make_select() {
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 select(doctype, fieldname) {
me.set_field(doctype, fieldname);
}
});
if (this.fieldname) {
this.fieldselect.set_value(this._doctype || this.doctype, this.fieldname);
}
},
set_events: function set_events() {
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.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);
}
me.field.desc_area.html((in_list(["in", "not in"], condition) === "in" ? __("values separated by commas") : __("use % as wildcard")) + '</div>');
} else {
me.set_field(me.field.df.parent, me.field.df.fieldname, null, condition);
}
});
if (me.fieldname) {
return this.set_values(me._doctype, me.fieldname, me.condition, me.value);
} else {
me.set_field(me.doctype, 'name');
}
},
remove: function remove(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 set_values(doctype, fieldname, condition, value) {
this.set_field(doctype, fieldname);
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 set_field(doctype, fieldname, fieldtype, condition) {
var me = this;
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]);
df.read_only = 0;
df.hidden = 0;
if (!condition) this.set_default_condition(df, fieldtype);
this.set_fieldtype(df, fieldtype);
if (me.field && cur.fieldname == fieldname && df.fieldtype == cur.fieldtype && df.parent == cur.parent) {
return;
}
me.fieldselect.selected_doctype = doctype;
me.fieldselect.selected_fieldname = fieldname;
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);
}
$(me.field.wrapper).find(':input').keydown(function (ev) {
if (ev.which == 13) {
me.flist.base_list.run();
}
});
},
set_fieldtype: function set_fieldtype(df, fieldtype) {
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;
if (fieldtype) {
df.fieldtype = fieldtype;
return;
}
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 set_default_condition(df, fieldtype) {
if (!fieldtype) {
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 get_value() {
return [this.fieldselect.selected_doctype, this.field.df.fieldname, this.get_condition(), this.get_selected_value()];
},
get_selected_value: function get_selected_value() {
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) {
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 get_condition() {
return this.wrapper.find('.condition').val();
},
freeze: function freeze() {
if (this.$btn_group) {
this.set_filter_button_text();
this.wrapper.toggle(false);
return;
}
var me = this;
this.$btn_group = $('<div class="btn-group">\
<button class="btn btn-default btn-xs toggle-filter"\
title="' + __("Edit Filter") + '">\
%(label)s %(condition)s "%(value)s"\
</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 set_filter_button_text() {
var value = this.get_selected_value();
if (this.field.df.fieldname === "docstatus") {
value = { 0: "Draft", 1: "Submitted", 2: "Cancelled" }[value] || value;
} else if (this.field.df.original_type === "Check") {
value = { 0: "No", 1: "Yes" }[cint(value)];
}
value = frappe.format(value, this.field.df, { only_value: 1 });
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)
}));
}
});
frappe.ui.FieldSelect = Class.extend({
init: function init(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(_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 get_value() {
return this.selected_doctype ? this.selected_doctype + "." + this.selected_fieldname : null;
},
val: function val(value) {
if (value === undefined) {
return this.get_value();
} else {
this.set_value(value);
}
},
clear: function clear() {
this.selected_doctype = null;
this.selected_fieldname = null;
this.$select.val("");
},
set_value: function set_value(doctype, fieldname) {
var me = this;
this.clear();
if (!doctype) return;
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 build_options() {
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);
});
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
}]);
}
if (this.with_blank) {
this.options.push({
label: "",
value: ""
});
}
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) {
if (frappe.perm.has_perm(me.doctype, df.permlevel, "read") && !df.report_hide) me.add_field_option(df);
});
$.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) {
if (frappe.perm.has_perm(me.doctype, df.permlevel, "read") && !df.report_hide) me.add_field_option(df);
});
}
});
},
add_field_option: function add_field_option(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;
}
}
});frappe.templates['edit_filter'] = '<div class="filter-box"> <div class="list_filter row"> <div class="fieldname_select_area col-sm-4 form-group ui-front"></div> <div class="col-sm-2 form-group"> <select class="condition form-control"> <option value="=">{%= __("Equals") %}</option> <option value="like">{%= __("Like") %}</option> <option value="in">{%= __("In") %}</option> <option value="not in">{%= __("Not In") %}</option> <option value="!=">{%= __("Not Equals") %}</option> <option value="not like">{%= __("Not Like") %}</option> <option value=">">{%= __(">") %}</option> <option value="<">{%= __("<") %}</option> <option value=">=">{%= __(">=") %}</option> <option value="<=">{%= __("<=") %}</option> <option value="Between">{%= __("Between") %}</option> </select> </div> <div class="col-sm-6 col-xs-12"> <div class="filter_field pull-left" style="width: calc(100% - 70px)"></div> <div class="filter-actions pull-left"> <a class="set-filter-and-run btn btn-sm btn-primary pull-left"> <i class=" fa fa-check visible-xs"></i> <span class="hidden-xs">{%= __("Apply") %}</span></a> <a class="small grey remove-filter pull-left"> <i class="octicon octicon-trashcan visible-xs"></i> <span class="hidden-xs">{%= __("Remove") %}</span></a> </div> <div class="clearfix"></div> </div> </div> </div> ';
frappe.ui.TagEditor = Class.extend({
init: function init(opts) {
$.extend(this, opts);
var me = this;
this.wrapper = $('<div class="tag-line" style="position: relative">').appendTo(this.parent);
if (!this.wrapper.length) return;
var id = frappe.dom.set_unique_id(this.wrapper);
this.taggle = new Taggle(id, {
placeholder: __('Add a tag') + "...",
onTagAdd: function onTagAdd(e, tag) {
if (me.initialized && !me.refreshing) {
tag = toTitle(tag);
return frappe.call({
method: 'frappe.desk.tags.add_tag',
args: me.get_args(tag),
callback: function callback(r) {
var user_tags = me.user_tags.split(",");
user_tags.push(tag);
me.user_tags = user_tags.join(",");
me.on_change && me.on_change(me.user_tags);
}
});
}
},
onTagRemove: function onTagRemove(e, tag) {
if (!me.refreshing) {
return frappe.call({
method: 'frappe.desk.tags.remove_tag',
args: me.get_args(tag),
callback: function callback(r) {
var user_tags = me.user_tags.split(",");
user_tags.splice(user_tags.indexOf(tag), 1);
me.user_tags = user_tags.join(",");
me.on_change && me.on_change(me.user_tags);
}
});
}
}
});
if (!this.user_tags) {
this.user_tags = "";
}
this.initialized = true;
this.refresh(this.user_tags);
this.setup_awesomplete();
},
setup_awesomplete: function setup_awesomplete() {
var me = this;
var $input = this.wrapper.find("input.taggle_input");
var input = $input.get(0);
this.awesomplete = new Awesomplete(input, {
minChars: 0,
maxItems: 99,
list: []
});
$input.on("awesomplete-open", function (e) {
$input.attr('state', 'open');
});
$input.on("awesomplete-close", function (e) {
$input.attr('state', 'closed');
});
$input.on("input", function (e) {
var value = e.target.value;
frappe.call({
method: "frappe.desk.tags.get_tags",
args: {
doctype: me.frm.doctype,
txt: value.toLowerCase(),
cat_tags: JSON.stringify(me.list_sidebar.get_cat_tags())
},
callback: function callback(r) {
me.awesomplete.list = r.message;
}
});
});
$input.on("focus", function (e) {
if ($input.attr('state') != 'open') {
$input.trigger("input");
}
});
},
get_args: function get_args(tag) {
return {
tag: tag,
dt: this.frm.doctype,
dn: this.frm.docname
};
},
refresh: function refresh(user_tags) {
var me = this;
if (!me.initialized || me.refreshing) return;
me.refreshing = true;
try {
me.taggle.removeAll();
if (user_tags) {
me.taggle.add(user_tags.split(','));
}
} catch (e) {
me.refreshing = false;
setTimeout(function () {
me.refresh();
}, 100);
}
me.refreshing = false;
}
});
frappe.ui.is_liked = function (doc) {
var liked = frappe.ui.get_liked_by(doc);
return liked.indexOf(frappe.session.user) === -1 ? false : true;
};
frappe.ui.get_liked_by = function (doc) {
var liked = doc._liked_by;
if (liked) {
liked = JSON.parse(liked);
}
return liked || [];
};
frappe.ui.toggle_like = function ($btn, doctype, name, _callback) {
var add = $btn.hasClass("not-liked") ? "Yes" : "No";
$btn.css('pointer-events', 'none');
frappe.call({
method: "frappe.desk.like.toggle_like",
quiet: true,
args: {
doctype: doctype,
name: name,
add: add
},
callback: function callback(r) {
$btn.css('pointer-events', 'auto');
if (!r.exc) {
var action_buttons = $('.like-action[data-name="' + name.replace(/"/g, '\"') + '"][data-doctype="' + doctype.replace(/"/g, '\"') + '"]');
if (add === "Yes") {
action_buttons.removeClass("not-liked text-extra-muted");
} else {
action_buttons.addClass("not-liked text-extra-muted");
}
var doc = locals[doctype] && locals[doctype][name];
if (doc) {
var liked_by = JSON.parse(doc._liked_by || "[]"),
idx = liked_by.indexOf(frappe.session.user);
if (add === "Yes") {
if (idx === -1) liked_by.push(frappe.session.user);
} else {
if (idx !== -1) {
liked_by = liked_by.slice(0, idx).concat(liked_by.slice(idx + 1));
}
}
doc._liked_by = JSON.stringify(liked_by);
}
if (_callback) {
_callback();
}
}
}
});
};
frappe.ui.click_toggle_like = function () {
var $btn = $(this);
var $count = $btn.siblings(".likes-count");
var not_liked = $btn.hasClass("not-liked");
var doctype = $btn.attr("data-doctype");
var name = $btn.attr("data-name");
frappe.ui.toggle_like($btn, doctype, name, function () {
if (not_liked) {
$count.text(cint($count.text()) + 1);
} else {
$count.text(cint($count.text()) - 1);
}
});
return false;
};
frappe.ui.setup_like_popover = function ($parent, selector) {
if (frappe.dom.is_touchscreen()) {
return;
}
$parent.on("mouseover", selector, function () {
var $wrapper = $(this);
$wrapper.popover({
animation: true,
placement: "right",
content: function content() {
var liked_by = JSON.parse($wrapper.attr('data-liked-by') || "[]");
var user = frappe.session.user;
if ($wrapper.find(".not-liked").length) {
if (liked_by.indexOf(user) !== -1) {
liked_by.splice(liked_by.indexOf(user), 1);
}
} else {
if (liked_by.indexOf(user) === -1) {
liked_by.push(user);
}
}
if (!liked_by.length) {
return "";
}
return frappe.render_template("liked_by", { "liked_by": liked_by });
},
html: true,
container: 'body'
});
$wrapper.popover('show');
});
$parent.on("mouseout", selector, function () {
$(this).popover('destroy');
});
};frappe.templates['liked_by'] = '<ul class="list-unstyled liked-by-popover"> {% for (var i in liked_by) { var liked_by_user = liked_by[i]; %} <li> {%= frappe.avatar(liked_by_user) %} <span>{%= frappe.user.full_name(liked_by_user) %}</span> </li> {% } %} </ul> ';
frappe.templates['print_template'] = '<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <title>{{ title }}</title> <link href="{{ base_url }}/assets/frappe/css/bootstrap.css" rel="stylesheet"> <link type="text/css" rel="stylesheet" href="{{ base_url }}/assets/frappe/css/font-awesome.css"> <style> {{ print_css }} </style> </head> <body> <div class="print-format-gutter"> {% if print_settings.repeat_header_footer %} <div id="footer-html" class="visible-pdf"> {% if print_settings.letter_head && print_settings.letter_head.footer %} <div class="letter-head-footer"> {{ print_settings.letter_head.footer }} </div> {% endif %} <p class="text-center small page-number visible-pdf"> {{ __("Page {0} of {1}", [`<span class="page"></span>`, `<span class="topage"></span>`]) }} </p> </div> {% endif %} <div class="print-format {% if landscape %} landscape {% endif %}" {% if columns.length > 20 %} style="font-size: 4.0pt" {% endif %} > {% if print_settings.letter_head %} <div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}> <div class="letter-head">{{ print_settings.letter_head.header }}</div> </div> {% endif %} {{ content }} </div> </div> </body> </html> ';
frappe.provide('frappe.views.list_view');
frappe.provide('frappe.views.list_renderers');
cur_list = null;
frappe.views.ListFactory = frappe.views.Factory.extend({
make: function make(route) {
var me = this;
var doctype = route[1];
frappe.model.with_doctype(doctype, function () {
if (locals['DocType'][doctype].issingle) {
frappe.set_re_route('Form', doctype);
} else {
if (!frappe.views.list_view[doctype]) {
frappe.views.list_view[doctype] = new frappe.views.ListView({
doctype: doctype,
parent: me.make_page(true, 'List/' + doctype)
});
} else {
frappe.container.change_to(frappe.views.list_view[doctype].page_name);
}
me.set_cur_list();
}
});
},
show: function show() {
if (this.re_route_to_view()) {
return;
}
this.set_module_breadcrumb();
this._super();
this.set_cur_list();
cur_list && cur_list.refresh();
},
re_route_to_view: function re_route_to_view() {
var route = frappe.get_route();
var doctype = route[1];
var last_route = frappe.route_history.slice(-2)[0];
if (route[0] === 'List' && route.length === 2 && frappe.views.list_view[doctype]) {
if (last_route && last_route[0] === 'List' && last_route[1] === doctype) {
window.history.go(-1);
} else {
frappe.views.list_view[doctype].load_last_view();
}
return true;
}
},
set_module_breadcrumb: function set_module_breadcrumb() {
if (frappe.route_history.length > 1) {
var prev_route = frappe.route_history[frappe.route_history.length - 2];
if (prev_route[0] === 'modules') {
var doctype = frappe.get_route()[1],
module = prev_route[1];
if (frappe.module_links[module] && frappe.module_links[module].includes(doctype)) {
frappe.breadcrumbs.set_doctype_module(doctype, module);
}
}
}
},
set_cur_list: function set_cur_list() {
var route = frappe.get_route();
cur_list = frappe.container.page && frappe.container.page.list_view;
if (cur_list && cur_list.doctype !== route[1]) {
cur_list = null;
}
}
});
$(document).on('save', function (event, doc) {
frappe.views.set_list_as_dirty(doc.doctype);
});
frappe.views.set_list_as_dirty = function (doctype) {
if (frappe.views.trees[doctype]) {
frappe.views.trees[doctype].tree.refresh();
}
var route = frappe.get_route();
var current_view = route[2] || 'List';
var list_renderer = frappe.views.list_renderers[doctype];
if (list_renderer && list_renderer[current_view] && list_renderer[current_view].no_realtime) {
return;
}
var list_page = 'List/' + doctype;
if (frappe.pages[list_page]) {
if (frappe.pages[list_page].list_view) {
if (frappe.pages[list_page].list_view.dirty) {
return;
}
frappe.pages[list_page].list_view.dirty = true;
}
}
if (route[0] === 'List' && route[1] === doctype) {
setTimeout(function () {
frappe.pages[list_page].list_view.refresh();
}, 100);
}
};
frappe.views.view_modes = ['List', 'Gantt', 'Kanban', 'Calendar', 'Image', 'Inbox'];
frappe.views.ListView = frappe.ui.BaseList.extend({
init: function init(opts) {
$.extend(this, opts);
if (!frappe.boot.user.all_read.includes(this.doctype)) {
frappe.show_not_permitted(frappe.get_route_str());
return;
}
this.page_name = 'List/' + this.doctype;
this.dirty = true;
this.tags_shown = false;
this.page_title = __(this.doctype);
this.page_title = this.page_title.toLowerCase().substr(-4) == 'list' && __(this.page_title) || __(this.page_title) + ' ' + __('List');
this.make_page();
this.setup();
this.refresh();
},
make_page: function make_page() {
this.parent.list_view = this;
this.page = this.parent.page;
this.$page = $(this.parent).css({ 'min-height': '400px' });
$('<div class=\'frappe-list-area\'></div>').appendTo(this.page.main);
this.page.main.addClass('listview-main-section');
var module = locals.DocType[this.doctype].module;
frappe.breadcrumbs.add(module, this.doctype);
},
setup: function setup() {
this.can_delete = frappe.model.can_delete(this.doctype);
this.meta = frappe.get_meta(this.doctype);
this.wrapper = this.$page.find('.frappe-list-area').empty();
this.allow_delete = true;
this.load_last_view();
this.setup_view_variables();
this.setup_list_renderer();
this.init_base_list(false);
this.list_renderer.set_wrapper();
this.list_renderer_onload();
this.show_match_help();
this.init_menu();
this.init_sort_selector();
this.init_filters();
this.set_title();
this.init_headers();
},
refresh_surroundings: function refresh_surroundings() {
this.init_sort_selector();
this.init_filters();
this.set_title();
this.init_headers();
this.no_result_message = this.list_renderer.make_no_result();
},
setup_list_renderer: function setup_list_renderer() {
frappe.provide('frappe.views.list_renderers.' + this.doctype);
var list_renderer = frappe.views.list_renderers[this.doctype][this.current_view];
if (list_renderer) {
this.list_renderer = list_renderer;
this.list_renderer.init_settings();
return;
}
var opts = {
doctype: this.doctype,
list_view: this
};
if (this.current_view === 'List') {
this.list_renderer = new frappe.views.ListRenderer(opts);
} else if (this.current_view === 'Gantt') {
this.list_renderer = new frappe.views.GanttView(opts);
} else if (this.current_view === 'Calendar') {
this.list_renderer = new frappe.views.CalendarView(opts);
} else if (this.current_view === 'Image') {
this.list_renderer = new frappe.views.ImageView(opts);
} else if (this.current_view === 'Kanban') {
this.list_renderer = new frappe.views.KanbanView(opts);
} else if (this.current_view === 'Inbox') {
this.list_renderer = new frappe.views.InboxView(opts);
}
},
render_view: function render_view(values) {
this.list_renderer.render_view(values);
},
set_title: function set_title() {
if (this.list_renderer.page_title) {
this.page.set_title(this.list_renderer.page_title);
} else {
this.page.set_title(this.page_title);
}
},
load_last_view: function load_last_view() {
var us = frappe.get_user_settings(this.doctype);
var route = ['List', this.doctype];
if (us.last_view && frappe.views.view_modes.includes(us.last_view)) {
route.push(us.last_view);
if (us.last_view === 'Kanban') {
route.push(us['Kanban'].last_kanban_board);
}
if (us.last_view === 'Inbox') {
route.push(us['Inbox'].last_email_account);
}
} else {
route.push('List');
}
frappe.set_route(route);
},
init_headers: function init_headers() {
this.page.main.find('.list-headers > .list-item--head').hide();
this.list_header = this.page.main.find('.list-headers > ' + '.list-item--head[data-list-renderer="' + this.list_renderer.name + '"]');
if (this.list_header.length > 0) {
this.list_header.show();
return;
}
var html = this.list_renderer.get_header_html();
if (!html) {
this.list_header = $();
return;
}
this.list_header = $(html).appendTo(this.page.main.find('.list-headers'));
this.setup_like();
this.setup_select_all();
this.setup_delete();
},
list_renderer_onload: function list_renderer_onload() {
if (this.list_renderer.settings.onload) {
this.list_renderer.settings.onload(this);
}
},
set_sidebar_height: function set_sidebar_height() {
var h_main = this.page.sidebar.height();
var h_side = this.$page.find('.layout-side-section').height();
if (h_side > h_main) this.$page.find('.layout-main-section').css({ 'min-height': h_side });
},
init_filters: function init_filters() {
this.make_standard_filters();
this.filter_list = new frappe.ui.FilterList({
base_list: this,
parent: this.wrapper.find('.list-filters').show(),
doctype: this.doctype,
default_filters: []
});
this.set_filters(this.list_renderer.filters);
},
set_filters: function set_filters(filters) {
var me = this;
$.each(filters, function (i, f) {
var hidden = false;
if (f.length === 3) {
f = [me.doctype, f[0], f[1], f[2]];
} else if (f.length === 5) {
hidden = f.pop(4) || false;
}
me.filter_list.add_filter(f[0], f[1], f[2], f[3], hidden);
});
},
init_sort_selector: function init_sort_selector() {
var me = this;
var order_by = this.list_renderer.order_by;
this.sort_selector = new frappe.ui.SortSelector({
parent: this.wrapper.find('.list-filters'),
doctype: this.doctype,
args: order_by,
change: function change() {
me.run();
}
});
},
show_match_help: function show_match_help() {
var me = this;
var match_rules_list = frappe.perm.get_match_rules(this.doctype);
var perm = frappe.perm.get_perm(this.doctype);
if (match_rules_list.length) {
this.footnote_area = frappe.utils.set_footnote(this.footnote_area, this.$page.find('.layout-main-section'), frappe.render_template('list_permission_footer', {
condition_list: match_rules_list
}));
$(this.footnote_area).css({ 'margin-top': '0px' });
}
},
setup_view_variables: function setup_view_variables() {
var route = frappe.get_route();
this.last_view = this.current_view || '';
this.current_view = route[2] || 'List';
},
init_base_list: function init_base_list(auto_run) {
var me = this;
this.make({
method: 'frappe.desk.reportview.get',
save_user_settings: true,
get_args: this.get_args,
parent: this.wrapper,
freeze: true,
start: 0,
page_length: this.list_renderer.page_length,
show_filters: false,
new_doctype: this.doctype,
no_result_message: this.list_renderer.make_no_result(),
show_no_result: function show_no_result() {
return me.list_renderer.show_no_result;
}
});
this.setup_make_new_doc();
if (auto_run !== false && auto_run !== 0) this.refresh();
},
setup_make_new_doc: function setup_make_new_doc() {
var me = this;
if (this.list_renderer.settings.list_view_doc) {
this.list_renderer.settings.list_view_doc(this);
} else {
var doctype = this.list_renderer.no_result_doctype ? this.list_renderer.no_result_doctype : this.doctype;
$(this.wrapper).on('click', 'button[list_view_doc=\'' + doctype + '\']', function () {
if (me.list_renderer.make_new_doc) me.list_renderer.make_new_doc();else me.make_new_doc.apply(me, [me.doctype]);
});
}
},
refresh: function refresh(dirty) {
var me = this;
if (dirty !== undefined) this.dirty = dirty;
this.refresh_sidebar();
this.setup_view_variables();
if (this.list_renderer.should_refresh()) {
this.setup_list_renderer();
this.refresh_surroundings();
this.dirty = true;
}
if (this.list_renderer.settings.refresh) {
this.list_renderer.settings.refresh(this);
}
this.set_filters_before_run();
this.execute_run();
},
execute_run: function execute_run() {
if (this.dirty) {
this.run();
} else {
if (new Date() - (this.last_updated_on || 0) > 30000) {
this.run();
}
}
},
save_user_settings_locally: function save_user_settings_locally(args) {
frappe.provide('frappe.model.user_settings.' + this.doctype + '.' + this.list_renderer.name);
var user_settings_common = frappe.model.user_settings[this.doctype];
var user_settings = frappe.model.user_settings[this.doctype][this.list_renderer.name];
if (!user_settings) return;
var different = false;
if (!frappe.utils.arrays_equal(args.filters, user_settings.filters)) {
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 (args.save_user_settings_fields) {
user_settings.fields = args.fields;
}
if (user_settings_common.last_view !== this.current_view && frappe.views.view_modes.includes(this.current_view)) {
user_settings_common.last_view = this.current_view;
different = true;
}
if (different) {
user_settings_common.updated_on = moment().toString();
}
},
set_filters_before_run: function set_filters_before_run() {
var me = this;
if (frappe.route_options) {
this.set_filters_from_route_options();
this.dirty = true;
}
},
run: function run(more) {
var me = this;
if (this.fresh && !more) {
return;
}
if (this.list_renderer.settings.before_run) {
this.list_renderer.settings.before_run(this);
}
if (!this.list_renderer.settings.use_route) {
var route = frappe.get_route();
if (route[2] && !frappe.views.view_modes.includes(route[2])) {
$.each(frappe.utils.get_args_dict_from_url(route[2]), function (key, val) {
me.set_filter(key, val, true);
});
}
}
if (this.list_header) {
this.list_header.find('.list-liked-by-me').toggleClass('text-extra-muted not-liked', !this.is_star_filtered());
}
this.last_updated_on = new Date();
this.dirty = false;
this.fresh = true;
setTimeout(function () {
me.fresh = false;
}, 1000);
this._super(more);
if (this.list_renderer.settings.post_render) {
this.list_renderer.settings.post_render(this);
}
this.wrapper.on('render-complete', function () {
me.list_renderer.after_refresh();
});
},
get_args: function get_args() {
var args = {
doctype: this.doctype,
fields: this.list_renderer.fields,
filters: this.get_filters_args(),
order_by: this.get_order_by_args(),
with_comment_count: true
};
return args;
},
get_filters_args: function get_filters_args() {
var filters = [];
if (this.filter_list) {
filters = this.filter_list.get_filters();
} else {
filters = this.list_renderer.filters;
}
var uniq = filters.uniqBy(JSON.stringify);
return uniq;
},
get_order_by_args: function get_order_by_args() {
var order_by = '';
if (this.sort_selector) {
order_by = $.format('`tab{0}`.`{1}` {2}', [this.doctype, this.sort_selector.sort_by, this.sort_selector.sort_order]);
} else {
order_by = this.list_renderer.order_by;
}
return order_by;
},
assigned_to_me: function assigned_to_me() {
this.filter_list.add_filter(this.doctype, '_assign', 'like', '%' + frappe.session.user + '%');
this.run();
},
liked_by_me: function liked_by_me() {
this.filter_list.add_filter(this.doctype, '_liked_by', 'like', '%' + frappe.session.user + '%');
this.run();
},
remove_liked_by_me: function remove_liked_by_me() {
this.filter_list.get_filter('_liked_by').remove();
},
is_star_filtered: function is_star_filtered() {
return this.filter_list.filter_exists(this.doctype, '_liked_by', 'like', '%' + frappe.session.user + '%');
},
init_menu: function init_menu() {
var me = this;
this.$page.on('click', '.list-tag-preview', function () {
me.toggle_tags();
});
this.page.set_secondary_action(__('Refresh'), function () {
me.refresh(true);
}, 'octicon octicon-sync').addClass('hidden-xs');
this.page.add_menu_item(__('Refresh'), function () {
me.refresh(true);
}, 'octicon octicon-sync').addClass('visible-xs');
if (frappe.model.can_import(this.doctype)) {
this.page.add_menu_item(__('Import'), function () {
frappe.set_route('data-import-tool', {
doctype: me.doctype
});
}, true);
}
if (frappe.model.can_set_user_permissions(this.doctype)) {
this.page.add_menu_item(__('User Permissions'), function () {
frappe.set_route('List', 'User Permission', {
allow: me.doctype
});
}, true);
}
if (frappe.user_roles.includes('System Manager')) {
this.page.add_menu_item(__('Role Permissions Manager'), function () {
frappe.set_route('permission-manager', {
doctype: me.doctype
});
}, true);
this.page.add_menu_item(__('Customize'), function () {
frappe.set_route('Form', 'Customize Form', {
doc_type: me.doctype
});
}, true);
}
this.make_bulk_assignment();
this.make_bulk_printing();
this.page.add_menu_item(__('Add to Desktop'), function () {
frappe.add_to_desktop(me.doctype, me.doctype);
}, true);
if (frappe.user_roles.includes('System Manager') && frappe.boot.developer_mode === 1) {
this.page.add_menu_item(__('Edit DocType'), function () {
frappe.set_route('Form', 'DocType', me.doctype);
}, true);
}
},
make_bulk_assignment: function make_bulk_assignment() {
var me = this;
me.page.add_menu_item(__('Assign To'), function () {
var docnames = me.get_checked_items().map(function (doc) {
return doc.name;
});
if (docnames.length >= 1) {
me.dialog = new frappe.ui.form.AssignToDialog({
obj: me,
method: 'frappe.desk.form.assign_to.add_multiple',
doctype: me.doctype,
docname: docnames,
bulk_assign: true,
re_assign: true,
callback: function callback() {
me.refresh(true);
}
});
me.dialog.clear();
me.dialog.show();
} else {
frappe.msgprint(__('Select records for assignment'));
}
}, true);
},
make_bulk_printing: function make_bulk_printing() {
var me = this;
var print_settings = frappe.model.get_doc(':Print Settings', 'Print Settings');
var allow_print_for_draft = cint(print_settings.allow_print_for_draft);
var is_submittable = frappe.model.is_submittable(me.doctype);
var allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled);
me.page.add_menu_item(__('Print'), function () {
var items = me.get_checked_items();
var valid_docs = items.filter(function (doc) {
return !is_submittable || doc.docstatus === 1 || allow_print_for_cancelled && doc.docstatus == 2 || allow_print_for_draft && doc.docstatus == 0 || frappe.user_roles.includes('Administrator');
}).map(function (doc) {
return doc.name;
});
var invalid_docs = items.filter(function (doc) {
return !valid_docs.includes(doc.name);
});
if (invalid_docs.length >= 1) {
frappe.msgprint(__('You selected Draft or Cancelled documents'));
return;
}
if (valid_docs.length >= 1) {
var dialog = new frappe.ui.Dialog({
title: 'Print Documents',
fields: [{ 'fieldtype': 'Check', 'label': __('With Letterhead'), 'fieldname': 'with_letterhead' }, { 'fieldtype': 'Select', 'label': __('Print Format'), 'fieldname': 'print_sel' }]
});
dialog.set_primary_action(__('Print'), function () {
var args = dialog.get_values();
if (!args) return;
var default_print_format = locals.DocType[me.doctype].default_print_format;
var with_letterhead = args.with_letterhead ? 1 : 0;
var print_format = args.print_sel ? args.print_sel : default_print_format;
var json_string = JSON.stringify(valid_docs);
var w = window.open('/api/method/frappe.utils.print_format.download_multi_pdf?' + 'doctype=' + encodeURIComponent(me.doctype) + '&name=' + encodeURIComponent(json_string) + '&format=' + encodeURIComponent(print_format) + '&no_letterhead=' + (with_letterhead ? '0' : '1'));
if (!w) {
frappe.msgprint(__('Please enable pop-ups'));return;
}
});
var print_formats = frappe.meta.get_print_formats(me.doctype);
dialog.fields_dict.print_sel.$input.empty().add_options(print_formats);
dialog.show();
} else {
frappe.msgprint(__('Select atleast 1 record for printing'));
}
}, true);
},
setup_like: function setup_like() {
var me = this;
this.$page.find('.result-list').on('click', '.like-action', frappe.ui.click_toggle_like);
this.list_header.find('.list-liked-by-me').on('click', function () {
if (me.is_star_filtered()) {
me.remove_liked_by_me();
} else {
me.liked_by_me();
}
});
if (!frappe.dom.is_touchscreen()) {
frappe.ui.setup_like_popover(this.$page.find('.result-list'), '.liked-by');
}
},
setup_select_all: function setup_select_all() {
var me = this;
if (this.can_delete || this.list_renderer.settings.selectable) {
this.list_header.find('.list-select-all').on('click', function () {
me.$page.find('.list-row-checkbox').prop('checked', $(this).prop('checked'));
});
this.$page.on('click', '.list-row-checkbox', function (event) {
var $this = $(this);
if (event.shiftKey && $this.prop('checked')) {
var $end_row = $this.parents('.list-item-container');
var $start_row = $end_row.prevAll('.list-item-container').find('.list-row-checkbox:checked').last().parents('.list-item-container');
if ($start_row) {
$start_row.nextUntil($end_row).find('.list-row-checkbox').prop('checked', true);
}
}
});
}
},
setup_delete: function setup_delete() {
var me = this;
if (!(this.can_delete || this.list_renderer.settings.selectable)) {
return;
}
this.$page.on('change', '.list-row-checkbox, .list-select-all', function () {
me.toggle_delete();
});
this.wrapper.on('render-complete', function () {
me.toggle_delete();
});
},
toggle_delete: function toggle_delete() {
var me = this;
var checked_items = this.get_checked_items();
var checked_items_status = this.$page.find('.checked-items-status');
if (checked_items.length > 0) {
this.page.set_primary_action(__('Delete'), function () {
me.delete_items();
}, 'octicon octicon-trashcan').addClass('btn-danger');
checked_items_status.text(checked_items.length == 1 ? __('1 item selected') : __('{0} items selected', [checked_items.length]));
checked_items_status.removeClass('hide');
} else {
this.page.btn_primary.removeClass('btn-danger');
this.set_primary_action();
checked_items_status.addClass('hide');
}
},
toggle_tags: function toggle_tags() {
if (this.tags_shown) {
$('.tag-row').addClass('hide');
this.tags_shown = false;
} else {
$('.tag-row').removeClass('hide');
this.tags_shown = true;
}
},
get_checked_items: function get_checked_items() {
var names = this.$page.find('.list-row-checkbox:checked').map(function (i, item) {
return cstr($(item).data().name);
}).toArray();
return this.data.filter(function (doc) {
return names.includes(doc.name);
});
},
set_primary_action: function set_primary_action() {
if (this.list_renderer.settings.set_primary_action) {
this.list_renderer.settings.set_primary_action(this);
} else {
this._super();
}
},
delete_items: function delete_items() {
var me = this;
var to_delete = this.get_checked_items();
if (!to_delete.length) return;
var docnames = to_delete.map(function (doc) {
return doc.name;
});
frappe.confirm(__('Delete {0} items permanently?', [to_delete.length]), function () {
return frappe.call({
method: 'frappe.desk.reportview.delete_items',
freeze: true,
args: {
items: docnames,
doctype: me.doctype
},
callback: function callback() {
me.$page.find('.list-select-all').prop('checked', false);
frappe.utils.play_sound('delete');
me.refresh(true);
}
});
});
},
refresh_sidebar: function refresh_sidebar() {
this.list_sidebar = new frappe.views.ListSidebar({
doctype: this.doctype,
stats: this.list_renderer.stats,
parent: this.$page.find('.layout-side-section'),
set_filter: this.set_filter.bind(this),
default_filters: this.list_renderer.filters,
page: this.page,
list_view: this
});
}
});
frappe.provide('frappe.views');
frappe.views.ListSidebar = Class.extend({
init: function init(opts) {
$.extend(this, opts);
this.make();
this.get_stats();
this.cat_tags = [];
},
make: function make() {
var sidebar_content = frappe.render_template("list_sidebar", { doctype: this.list_view.doctype });
this.sidebar = $('<div class="list-sidebar overlay-sidebar hidden-xs hidden-sm"></div>').html(sidebar_content).appendTo(this.page.sidebar.empty());
this.setup_reports();
this.setup_assigned_to_me();
this.setup_views();
this.setup_kanban_boards();
this.setup_email_inbox();
},
setup_views: function setup_views() {
var show_list_link = false;
if (frappe.views.calendar[this.doctype]) {
this.sidebar.find('.list-link[data-view="Calendar"]').removeClass("hide");
this.sidebar.find('.list-link[data-view="Gantt"]').removeClass('hide');
show_list_link = true;
}
this.sidebar.find('.list-link[data-view="Kanban"]').removeClass('hide');
if (this.doctype === "Communication" && frappe.boot.email_accounts.length) {
this.sidebar.find('.list-link[data-view="Inbox"]').removeClass('hide');
show_list_link = true;
}
if (frappe.treeview_settings[this.doctype]) {
this.sidebar.find(".tree-link").removeClass("hide");
}
this.current_view = 'List';
var route = frappe.get_route();
if (route.length > 2 && frappe.views.view_modes.includes(route[2])) {
this.current_view = route[2];
if (this.current_view === 'Kanban') {
this.kanban_board = route[3];
} else if (this.current_view === 'Inbox') {
this.email_account = route[3];
}
}
this.sidebar.find('.list-link[data-view="' + this.current_view + '"] a').attr('disabled', 'disabled').addClass('disabled');
this.sidebar.find('.list-link[data-view="Kanban"] a, .list-link[data-view="Inbox"] a').attr('disabled', null).removeClass('disabled');
if (this.list_view.meta.image_field) {
this.sidebar.find('.list-link[data-view="Image"]').removeClass('hide');
show_list_link = true;
}
if (show_list_link) {
this.sidebar.find('.list-link[data-view="List"]').removeClass('hide');
}
},
setup_reports: function setup_reports() {
var me = this;
var added = [];
var dropdown = this.page.sidebar.find('.reports-dropdown');
var divider = false;
var add_reports = function add_reports(reports) {
$.each(reports, function (name, r) {
if (!r.ref_doctype || r.ref_doctype == me.doctype) {
var report_type = r.report_type === 'Report Builder' ? 'Report/' + r.ref_doctype : 'query-report';
var route = r.route || report_type + '/' + (r.title || r.name);
if (added.indexOf(route) === -1) {
added.push(route);
if (!divider) {
$('<li role="separator" class="divider"></li>').appendTo(dropdown);
divider = true;
}
$('<li><a href="#' + route + '">' + __(r.title || r.name) + '</a></li>').appendTo(dropdown);
}
}
});
};
if (this.list_view.list_renderer.settings.reports) {
add_reports(this.list_view.list_renderer.settings.reports);
}
add_reports(frappe.boot.user.all_reports || []);
},
setup_kanban_boards: function setup_kanban_boards() {
var me = this;
var $dropdown = this.page.sidebar.find('.kanban-dropdown');
var divider = false;
var meta = frappe.get_meta(this.doctype);
var boards = meta && meta.__kanban_boards;
if (!boards) return;
boards.forEach(function (board) {
var route = ["List", board.reference_doctype, "Kanban", board.name].join('/');
if (!divider) {
$('<li role="separator" class="divider"></li>').appendTo($dropdown);
divider = true;
}
$('<li><a href="#' + route + '">\n\t\t\t\t<span>' + __(board.name) + '</span>\n\t\t\t\t' + (board.private ? '<i class="fa fa-lock fa-fw text-warning"></i>' : '') + '\n\t\t\t</a></li>').appendTo($dropdown);
});
$dropdown.find('.new-kanban-board').click(function () {
var select_fields = frappe.get_meta(me.doctype).fields.filter(function (df) {
return df.fieldtype === 'Select' && df.fieldname !== 'kanban_column';
});
var fields = [{
fieldtype: 'Data',
fieldname: 'board_name',
label: __('Kanban Board Name'),
reqd: 1
}];
if (select_fields.length > 0) {
fields = fields.concat([{
fieldtype: 'Select',
fieldname: 'field_name',
label: __('Columns based on'),
options: select_fields.map(function (df) {
return df.label;
}).join('\n'),
default: select_fields[0]
}, {
fieldtype: 'Check',
fieldname: 'custom_column',
label: __('Custom Column'),
default: 0,
onchange: function onchange(e) {
var checked = d.get_value('custom_column');
if (checked) {
$(d.body).find('.frappe-control[data-fieldname="field_name"]').hide();
} else {
$(d.body).find('.frappe-control[data-fieldname="field_name"]').show();
}
}
}]);
}
if (me.doctype === 'Task') {
fields[0].description = __('A new Project with this name will be created');
}
if (['Note', 'ToDo'].includes(me.doctype)) {
fields[0].description = __('This Kanban Board will be private');
}
var d = new frappe.ui.Dialog({
title: __('New Kanban Board'),
fields: fields,
primary_action_label: __('Save'),
primary_action: function primary_action(values) {
var custom_column = values.custom_column !== undefined ? values.custom_column : 1;
if (custom_column) {
var field_name = 'kanban_column';
} else {
var field_name = select_fields.find(function (df) {
return df.label === values.field_name;
}).fieldname;
}
me.add_custom_column_field(custom_column).then(function (custom_column) {
return me.make_kanban_board(values.board_name, field_name);
}).then(function () {
d.hide();
}, function (err) {
frappe.msgprint(err);
});
}
});
d.show();
});
},
add_custom_column_field: function add_custom_column_field(flag) {
var me = this;
return new Promise(function (resolve, reject) {
if (!flag) resolve(false);
frappe.call({
method: 'frappe.custom.doctype.custom_field.custom_field.add_custom_field',
args: {
doctype: me.doctype,
df: {
label: 'Kanban Column',
fieldname: 'kanban_column',
fieldtype: 'Select',
hidden: 1
}
}
}).success(function () {
resolve(true);
}).error(function (err) {
reject(err);
});
});
},
make_kanban_board: function make_kanban_board(board_name, field_name) {
var me = this;
return frappe.call({
method: 'frappe.desk.doctype.kanban_board.kanban_board.quick_kanban_board',
args: {
doctype: me.doctype,
board_name: board_name,
field_name: field_name
},
callback: function callback(r) {
var kb = r.message;
if (kb.filters) {
frappe.provide('frappe.kanban_filters');
frappe.kanban_filters[kb.kanban_board_name] = kb.filters;
}
frappe.set_route('List', me.doctype, 'Kanban', kb.kanban_board_name);
}
});
},
setup_email_inbox: function setup_email_inbox() {
if (this.doctype != "Communication") return;
var $dropdown = this.page.sidebar.find('.email-account-dropdown');
var divider = false;
if (has_common(frappe.user_roles, ["System Manager", "Administrator"])) {
$('<li class="new-email-account"><a>' + __("New Email Account") + '</a></li>').appendTo($dropdown);
}
var accounts = frappe.boot.email_accounts;
accounts.forEach(function (account) {
var email_account = account.email_id == "All Accounts" ? "All Accounts" : account.email_account;
var route = ["List", "Communication", "Inbox", email_account].join('/');
if (!divider) {
$('<li role="separator" class="divider"></li>').appendTo($dropdown);
divider = true;
}
$('<li><a href="#' + route + '">' + account.email_id + '</a></li>').appendTo($dropdown);
if (account.email_id === "Sent Mail") divider = false;
});
$dropdown.find('.new-email-account').click(function () {
frappe.new_doc("Email Account");
});
},
setup_assigned_to_me: function setup_assigned_to_me() {
var me = this;
this.page.sidebar.find(".assigned-to-me a").on("click", function () {
me.list_view.assigned_to_me();
});
},
get_cat_tags: function get_cat_tags() {
return this.cat_tags;
},
get_stats: function get_stats() {
var me = this;
frappe.call({
method: 'frappe.desk.reportview.get_sidebar_stats',
args: {
stats: me.stats,
doctype: me.doctype,
filters: me.default_filters
},
callback: function callback(r) {
me.defined_category = r.message;
if (r.message.defined_cat) {
me.defined_category = r.message.defined_cat;
me.cats = {};
for (var i in me.defined_category) {
if (me.cats[me.defined_category[i].category] === undefined) {
me.cats[me.defined_category[i].category] = [me.defined_category[i].tag];
} else {
me.cats[me.defined_category[i].category].push(me.defined_category[i].tag);
}
me.cat_tags[i] = me.defined_category[i].tag;
}
me.tempstats = r.message.stats;
var len = me.cats.length;
$.each(me.cats, function (i, v) {
me.render_stat(i, (me.tempstats || {})["_user_tags"], v);
});
me.render_stat("_user_tags", (me.tempstats || {})["_user_tags"]);
} else {
me.render_stat("_user_tags", (r.message.stats || {})["_user_tags"]);
}
me.list_view.set_sidebar_height();
}
});
},
render_stat: function render_stat(field, stat, tags) {
var me = this;
var sum = 0;
var stats = [];
var label = frappe.meta.docfield_map[this.doctype][field] ? frappe.meta.docfield_map[this.doctype][field].label : field;
var show_tags = '<a class="list-tag-preview hidden-xs" title="' + __("Show tags") + '"><i class="octicon octicon-pencil"></i></a>';
stat = (stat || []).sort(function (a, b) {
return b[1] - a[1];
});
$.each(stat, function (i, v) {
sum = sum + v[1];
});
if (tags) {
for (var t in tags) {
var nfound = -1;
for (var i in stat) {
if (tags[t] === stat[i][0]) {
stats.push(stat[i]);
nfound = i;
break;
}
}
if (nfound < 0) {
stats.push([tags[t], 0]);
} else {
me.tempstats["_user_tags"].splice(nfound, 1);
}
}
field = "_user_tags";
} else {
stats = stat;
}
var context = {
field: field,
stat: stats,
sum: sum,
label: field === '_user_tags' ? tags ? __(label) + show_tags : __("UnCategorised Tags") + show_tags : __(label)
};
var sidebar_stat = $(frappe.render_template("list_sidebar_stat", context)).on("click", ".stat-link", function () {
var fieldname = $(this).attr('data-field');
var label = $(this).attr('data-label');
if (label == "No Tags") {
me.list_view.filter_list.add_filter(me.list_view.doctype, fieldname, 'not like', '%,%');
me.list_view.run();
} else {
me.set_filter(fieldname, label);
}
}).insertBefore(this.sidebar.find(".close-sidebar-button"));
},
set_fieldtype: function set_fieldtype(df, fieldtype) {
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 = [{ value: 0, label: 'No' }, { value: 1, label: 'Yes' }];
} 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' && this.$w.find('.condition').val() != "=") {
df.fieldtype = 'Data';
}
if (df.fieldtype === "Data" && (df.options || "").toLowerCase() === "email") {
df.options = null;
}
},
reload_stats: function reload_stats() {
this.sidebar.find(".sidebar-stat").remove();
this.get_stats();
}
});frappe.templates['list_sidebar'] = '<ul class="list-unstyled sidebar-menu user-actions hide"> <li class="divider"></li> </ul> <ul class="list-unstyled sidebar-menu standard-actions"> {% if frappe.model.can_get_report(doctype) %} <li class="divider"></li> <li> <div class="btn-group"> <a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {{ __("Reports") }} <span class="caret"></span> </a> <ul class="dropdown-menu reports-dropdown" style="max-height: 300px; overflow-y: auto;"> <li><a href="#Report/{{ doctype }}">{{ __("Report Builder") }}</a></li> </ul> </div> </li> {% endif %} <li class="divider"></li> <li class="list-link" data-view="List"> <a href="#List/{%= doctype %}/List">{%= __("List") %}</a></li> <li class="hide list-link" data-view="Image"> <a href="#List/{%= doctype %}/Image">{%= __("Images") %}</a></li> <li class="hide list-link" data-view="Gantt"> <a href="#List/{%= doctype %}/Gantt">{%= __("Gantt") %}</a></li> <li class="hide tree-link"> <a href="#Tree/{%= doctype %}">{%= __("Tree") %}</a></li> <li class="hide list-link" data-view="Calendar"> <a href="#List/{%= doctype %}/Calendar">{%= __("Calendar") %}</a></li> <li class="hide list-link" data-view="Kanban"> <div class="btn-group"> <a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {{ __("Kanban") }} <span class="caret"></span> </a> <ul class="dropdown-menu kanban-dropdown" style="max-height: 300px; overflow-y: auto;"> <li class="new-kanban-board"><a>{{ __("New Kanban Board") }}</a></li> </ul> </div> </li> <li class="hide list-link" data-view="Inbox"> <div class="btn-group"> <a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {{ __("Email Inbox") }} <span class="caret"></span> </a> <ul class="dropdown-menu email-account-dropdown" style="max-height: 300px; overflow-y: auto;"> </ul> </div> </li> <li class="assigned-to-me"> <a>{%= __("Assigned To Me") %}</a> </li> {% if(frappe.help.has_help(doctype)) { %} <li><a class="help-link" data-doctype="{{ doctype }}">{{ __("Help") }}</a></li> {% } %} </ul> <ul class="list-unstyled close-sidebar-button visible-xs visible-sm"> <li class="divider"></li> <li class="close-sidebar">Close</li> </ul> ';
frappe.templates['list_sidebar_stat'] = '<ul class="list-unstyled sidebar-menu sidebar-stat"> <li class="divider"></li> <li class="h6 stat-label">{%= label %}</li> {% if(!stat.length) { %} <li class="stat-no-records text-muted">{%= __("No records tagged.") %}</li> {% } else { for (var i=0, l=stat.length; i < l; i++) { var stat_label = stat[i][0]; var stat_count = stat[i][1]; %} <li> <a class="stat-link badge-hover" data-label="{%= stat_label %}" data-field="{%= field %}"> <span class="badge">{%= stat_count %}</span> <span>{%= __(stat_label) %}</span> </a> </li> {% } } %} </ul> ';
frappe.templates['list_item_main'] = '<div class="list-item__content ellipsis {% if(col.type==="Subject") { %} list-item__content--flex-2 {% } else { %} hidden-xs {% } %} {% if(col.df && ["Int", "Float", "Currency", "Percent"].indexOf(col.df.fieldtype)!==-1) { %}text-right{% } %}" {% if(col.type!=="Indicator" && col.title) { %} title="{%= col.title + ": " + value %}" {% } %} > {% if (col.type==="Subject") { %} {%= subject %} {% } else if (col.type==="Indicator") { %} {%= indicator %} {% } else if (col.render) { %} {%= col.render(data) %} {% } else if (col.fieldtype==="Image") { %} {% if(data[col.df.options]) { %} <img src="{%= data[col.df.options] %}" style="max-height: 30px; max-width: 100%;"> {% } else { %} <div class="missing-image small"><span class="octicon octicon-circle-slash"></span></div> {% } %} {% } else if(col.fieldtype==="Select") { %} <span class="filterable indicator {%= frappe.utils.guess_colour(value) %} ellipsis" data-filter="{%= col.fieldname %},=,{%= value %}">{%= __(value) %}</span> {% } else if(col.fieldtype==="Link") { %} <a class="filterable text-muted grey ellipsis" data-filter="{%= col.fieldname %},=,{%= value %}">{%= value %}</a> {% } else { %} <a class="filterable text-muted ellipsis" data-filter="{%= col.fieldname %},=,{%= value %}"> {% if(formatters && formatters[col.fieldname]) { %} {{ formatters[col.fieldname](value, col.df, data) }} {% } else { %} {{ frappe.format(value, col.df, null, data) }} {% } %} </a> {% } %} </div>';
frappe.templates['list_item_row'] = '<div class="list-item"> {%= main %} {% if (meta.title_field && !settings.hide_name_column) { var is_different = data.name !== data[meta.title_field]; %} <div class="list-item__content list-item__content--id hidden-xs hidden-sm ellipsis"> {% if (is_different) { %} <a class="text-muted ellipsis" href="#Form/{%= data._doctype_encoded %}/{%= data._name_encoded %}"> {%= data.name %}</a> {% } %} </div> {% } %} {% if (!data._hide_activity) { %} <div class="list-item__content list-item__content--activity hidden-xs"> {%= frappe.render_template("item_assigned_to_comment_count", { data: data }) %} </div> <div class="list-item__content list-item__content--indicator visible-xs text-right"> {%= indicator_dot %} </div> {% } %} </div> ';
frappe.templates['list_item_main_head'] = '<div class="list-item__content ellipsis text-muted {% if(col.type==="Subject") { %} list-item__content--flex-2 {% } else { %} hidden-xs {% } %} {% if(col.df && ["Int", "Float", "Currency", "Percent"].indexOf(col.df.fieldtype)!==-1) { %}text-right{% } %}" > {% if (col.type==="Subject") { %} {%= frappe.render_template("header_select_all_like_filter", { _checkbox: _checkbox }) %} {% } %} <span class="list-col-title ellipsis">{{ __(col.title) || __(col.label) || "" }}</span> </div>';
frappe.templates['list_item_row_head'] = '<div class="list-item list-item--head" data-list-renderer="{{list.name}}"> {%= main %} {% if(list.meta.title_field && !list.settings.hide_name_column) { %} <div class="list-item__content hidden-xs hidden-sm"></div> {% } %} <div class="list-item__content list-item__content--activity hidden-xs text-right list-row-right"></div> </div> ';
frappe.templates['list_item_subject'] = '{% if (_checkbox) { %} <input class="list-row-checkbox hidden-xs" type="checkbox" data-name="{{name}}"> {% } %} {% if (!_hide_activity) { %} <span class="liked-by" data-liked-by=\'{{ JSON.stringify(_liked_by) }}\'> <i class="octicon octicon-heart {% if (_liked_by.indexOf(_user)===-1) { %} text-extra-muted not-liked {% }%} fa-fw like-action" data-name="{{ _name }}" data-doctype="{{ doctype }}"> </i> <span class="likes-count">{{ (_liked_by.length > 99 ? "99+" : _liked_by.length) || "" }}</span> </span> {% } %} <a class="grey list-id {{ css_seen }} ellipsis" data-name="{{ _name }}" href="#Form/{{ _doctype_encoded }}/{{ _name_encoded }}" title="{{ _full_title }}">{{ strip_html(_title) }}</a> {% if (_workflow && !_without_workflow) { %} <span class="label label-{{ _workflow.style }} filterable" data-filter="{{ _workflow.fieldname }},=,{{ _workflow.value }}"> {%= _workflow.value %}</span> {% } %} ';
frappe.templates['list_permission_footer'] = '<div style="padding-left: 20px;"> <i class="octicon octicon-lock" style="float: left; margin-left: -20px;"></i> {% for(var i=0; i < condition_list.length; i++) { var conditions = condition_list[i]; %} <div style="margin-bottom: 5px;"> {% if (i > 0) { %}<span style="margin-right: 10px;">{{ __("Or") }}</span>{% } %} {% for(key in conditions) { %} <span class="label label-default" style="margin-right: 10px;"> {% if(conditions[key].length) { %} {{ key }} = {{ frappe.utils.comma_or(conditions[key]) }} {% } else { %} {{ __("{0} is not set", [key]) }} {% } %} </span> {% } %} </div> {% } %} </div> ';
frappe.provide('frappe.views');
frappe.views.ListRenderer = Class.extend({
name: 'List',
init: function init(opts) {
$.extend(this, opts);
this.meta = frappe.get_meta(this.doctype);
this.init_settings();
this.set_defaults();
this.set_fields();
this.set_columns();
this.setup_cache();
},
set_defaults: function set_defaults() {
var me = this;
this.page_title = __(this.doctype);
this.set_wrapper();
this.setup_filterable();
this.prepare_render_view();
this.no_realtime = false;
this.show_no_result = true;
this.hide_sort_selector = false;
this.order_by = this.order_by || 'modified desc';
this.filters = this.filters || [];
this.page_length = this.page_length || 20;
},
setup_cache: function setup_cache() {
frappe.provide('frappe.views.list_renderers.' + this.doctype);
frappe.views.list_renderers[this.doctype][this.list_view.current_view] = this;
},
init_settings: function init_settings() {
this.settings = frappe.listview_settings[this.doctype] || {};
this.init_user_settings();
this.order_by = this.user_settings.order_by || this.settings.order_by;
this.filters = this.user_settings.filters || this.settings.filters;
this.page_length = this.settings.page_length;
if (frappe.model.is_submittable(this.doctype) && (!this.filters || !this.filters.length)) {
this.filters = [[this.doctype, "docstatus", "!=", 2]];
}
},
init_user_settings: function init_user_settings() {
frappe.provide('frappe.model.user_settings.' + this.doctype + '.' + this.name);
this.user_settings = frappe.get_user_settings(this.doctype)[this.name];
},
after_refresh: function after_refresh() {},
before_refresh: function before_refresh() {},
should_refresh: function should_refresh() {
return this.list_view.current_view !== this.list_view.last_view;
},
set_wrapper: function set_wrapper() {
this.wrapper = this.list_view.wrapper && this.list_view.wrapper.find('.result-list');
},
set_fields: function set_fields() {
var me = this;
var tabDoctype = '`tab' + this.doctype + '`.';
this.fields = [];
this.stats = ['_user_tags'];
var add_field = function add_field(fieldname) {
if (!fieldname.includes('`tab')) {
fieldname = tabDoctype + '`' + fieldname + '`';
}
if (!me.fields.includes(fieldname)) me.fields.push(fieldname);
};
var defaults = ['name', 'owner', 'docstatus', '_user_tags', '_comments', 'modified', 'modified_by', '_assign', '_liked_by', '_seen'];
defaults.map(add_field);
if (this.meta.title_field) {
this.title_field = this.meta.title_field;
add_field(this.meta.title_field);
}
if (frappe.meta.has_field(this.doctype, 'enabled')) {
add_field('enabled');
}
if (frappe.meta.has_field(this.doctype, 'disabled')) {
add_field('disabled');
}
this.workflow_state_fieldname = frappe.workflow.get_state_fieldname(this.doctype);
if (this.workflow_state_fieldname) {
if (!frappe.workflow.workflows[this.doctype]['override_status']) {
add_field(this.workflow_state_fieldname);
}
this.stats.push(this.workflow_state_fieldname);
}
this.meta.fields.forEach(function (df, i) {
if (df.in_list_view && frappe.perm.has_perm(me.doctype, df.permlevel, 'read')) {
if (df.fieldtype == 'Image' && df.options) {
add_field(df.options);
} else {
add_field(df.fieldname);
}
if (df.fieldtype == 'Currency' && df.options) {
if (df.options.includes(':')) {
add_field(df.options.split(':')[1]);
} else {
add_field(df.options);
}
}
}
});
if (this.settings.add_fields) {
this.settings.add_fields.forEach(add_field);
}
if (me.meta.__kanban_column_fields) {
me.meta.__kanban_column_fields.map(add_field);
}
},
set_columns: function set_columns() {
var me = this;
this.columns = [];
var name_column = {
colspan: this.settings.colwidths && this.settings.colwidths.subject || 6,
type: 'Subject',
title: 'Name'
};
if (this.meta.title_field) {
name_column.title = frappe.meta.get_docfield(this.doctype, this.meta.title_field).label;
}
this.columns.push(name_column);
if (frappe.has_indicator(this.doctype)) {
this.columns.push({
colspan: this.settings.colwidths && this.settings.colwidths.indicator || 3,
type: 'Indicator',
title: 'Status'
});
}
this.total_colspans = this.columns.reduce(function (total, curr) {
return total + curr.colspan;
}, 0);
var overridden = (this.settings.add_columns || []).map(function (d) {
return d.content;
});
var docfields_in_list_view = frappe.get_children('DocType', this.doctype, 'fields', { 'in_list_view': 1 }).sort(function (a, b) {
return a.idx - b.idx;
});
docfields_in_list_view.forEach(function (d) {
if (overridden.includes(d.fieldname) || d.fieldname === me.title_field) {
return;
}
if (me.total_colspans < 12) {
me.add_column(d);
}
});
if (this.settings.add_columns) {
this.settings.add_columns.forEach(function (d) {
if (me.total_colspans < 12) {
if (typeof d === 'string') {
me.add_column(frappe.meta.get_docfield(me.doctype, d));
} else {
me.columns.push(d);
me.total_colspans += parseInt(d.colspan);
}
}
});
}
var empty_cols = flt(12 - this.total_colspans);
while (empty_cols > 0) {
this.columns = this.columns.map(function (col) {
if (empty_cols > 0) {
col.colspan = cint(col.colspan) + 1;
empty_cols = empty_cols - 1;
}
return col;
});
}
this.columns = this.columns.uniqBy(function (col) {
return col.title;
});
this.columns = this.columns.filter(function (col) {
return col.fieldtype !== 'Text Editor';
});
this.columns = this.columns.slice(0, 4);
},
add_column: function add_column(df) {
var colspan = 3;
if (in_list(['Int', 'Percent'], df.fieldtype)) {
colspan = 2;
} else if (in_list(['Check', 'Image'], df.fieldtype)) {
colspan = 1;
} else if (in_list(['name', 'subject', 'title'], df.fieldname)) {
colspan = 4;
} else if (df.fieldtype == 'Text Editor' || df.fieldtype == 'Text') {
colspan = 4;
}
if (df.columns && df.columns > 0) {
colspan = df.columns;
} else if (this.settings.column_colspan && this.settings.column_colspan[df.fieldname]) {
colspan = this.settings.column_colspan[df.fieldname];
} else {
colspan = 2;
}
this.total_colspans += parseInt(colspan);
var col = {
colspan: colspan,
content: df.fieldname,
type: df.fieldtype,
df: df,
fieldtype: df.fieldtype,
fieldname: df.fieldname,
title: __(df.label)
};
if (this.settings.column_render && this.settings.column_render[df.fieldname]) {
col.render = this.settings.column_render[df.fieldname];
}
this.columns.push(col);
},
setup_filterable: function setup_filterable() {
var me = this;
this.list_view.wrapper && this.list_view.wrapper.on('click', '.result-list .filterable', function (e) {
e.stopPropagation();
var filters = $(this).attr('data-filter').split('|');
var added = false;
filters.forEach(function (f) {
f = f.split(',');
if (f[2] === 'Today') {
f[2] = frappe.datetime.get_today();
} else if (f[2] == 'User') {
f[2] = frappe.session.user;
}
var new_filter = me.list_view.filter_list.add_filter(me.doctype, f[0], f[1], f.slice(2).join(','));
if (new_filter) {
added = true;
}
});
if (added) {
me.list_view.refresh(true);
}
});
this.list_view.wrapper && this.list_view.wrapper.on('click', '.list-item', function (e) {
if ($(e.target).hasClass('filterable') || $(e.target).hasClass('octicon-heart') || $(e.target).is(':checkbox')) {
return;
}
var link = $(this).parent().find('a.list-id').get(0);
window.location.href = link.href;
return false;
});
},
render_view: function render_view(values) {
var _this = this;
var me = this;
var $list_items = me.wrapper.find('.list-items');
if ($list_items.length === 0) {
$list_items = $('\n\t\t\t\t<div class="list-items">\n\t\t\t\t</div>\n\t\t\t');
me.wrapper.append($list_items);
}
values.map(function (value) {
var $item = $(_this.get_item_html(value));
var $item_container = $('<div class="list-item-container">').append($item);
$list_items.append($item_container);
if (_this.settings.post_render_item) {
_this.settings.post_render_item(_this, $item_container, value);
}
_this.render_tags($item_container, value);
});
},
get_item_html: function get_item_html(data) {
var _this2 = this;
var main = this.columns.map(function (column) {
return frappe.render_template('list_item_main', {
data: data,
col: column,
value: data[column.fieldname],
formatters: _this2.settings.formatters,
subject: _this2.get_subject_html(data, true),
indicator: _this2.get_indicator_html(data)
});
}).join("");
return frappe.render_template('list_item_row', {
data: data,
main: main,
settings: this.settings,
meta: this.meta,
indicator_dot: this.get_indicator_dot(data)
});
},
get_header_html: function get_header_html() {
var _this3 = this;
var main = this.columns.map(function (column) {
return frappe.render_template('list_item_main_head', {
col: column,
_checkbox: (frappe.model.can_delete(_this3.doctype) || _this3.settings.selectable) && !_this3.no_delete
});
}).join("");
return frappe.render_template('list_item_row_head', { main: main, list: this });
},
render_tags: function render_tags(element, data) {
var me = this;
var tag_row = $('<div class=\'tag-row\'>\n\t\t\t<div class=\'list-tag hidden-xs\'></div>\n\t\t\t<div class=\'clearfix\'></div>\n\t\t</div>').appendTo(element);
if (!me.list_view.tags_shown) {
tag_row.addClass('hide');
}
var tag_editor = new frappe.ui.TagEditor({
parent: tag_row.find('.list-tag'),
frm: {
doctype: this.doctype,
docname: data.name
},
list_sidebar: me.list_view.list_sidebar,
user_tags: data._user_tags,
on_change: function on_change(user_tags) {
data._user_tags = user_tags;
}
});
tag_editor.wrapper.on('click', '.tagit-label', function () {
me.list_view.set_filter('_user_tags', $(this).text());
});
},
get_subject_html: function get_subject_html(data, without_workflow) {
data._without_workflow = without_workflow;
return frappe.render_template('list_item_subject', data);
},
get_indicator_html: function get_indicator_html(doc) {
var indicator = this.get_indicator_from_doc(doc);
if (indicator) {
return '<span class=\'indicator ' + indicator[1] + ' filterable\'\n\t\t\t\tdata-filter=\'' + indicator[2] + '\'>\n\t\t\t\t' + __(indicator[0]) + '\n\t\t\t<span>';
}
return '';
},
get_indicator_dot: function get_indicator_dot(doc) {
var indicator = this.get_indicator_from_doc(doc);
if (!indicator) {
return '';
}
return '<span class=\'indicator ' + indicator[1] + '\' title=\'' + __(indicator[0]) + '\'></span>';
},
get_indicator_from_doc: function get_indicator_from_doc(doc) {
var workflow = frappe.workflow.workflows[this.doctype];
return frappe.get_indicator(doc, this.doctype, workflow && workflow['override_status'] || true);
},
prepare_data: function prepare_data(data) {
if (data.modified) this.prepare_when(data, data.modified);
for (var key in data) {
if (data[key] == null) {
data[key] = '';
}
}
data.doctype = this.doctype;
data._liked_by = JSON.parse(data._liked_by || '[]');
data._checkbox = (frappe.model.can_delete(this.doctype) || this.settings.selectable) && !this.no_delete;
data._doctype_encoded = encodeURIComponent(data.doctype);
data._name = data.name.replace(/'/g, '\'');
data._name_encoded = encodeURIComponent(data.name);
data._submittable = frappe.model.is_submittable(this.doctype);
var title_field = this.meta.title_field || 'name';
data._title = strip_html(data[title_field] || data.name);
data._full_title = data._title;
data._workflow = null;
if (this.workflow_state_fieldname) {
data._workflow = {
fieldname: this.workflow_state_fieldname,
value: data[this.workflow_state_fieldname],
style: frappe.utils.guess_style(data[this.workflow_state_fieldname])
};
}
data._user = frappe.session.user;
if (!data._user_tags) data._user_tags = "";
data._tags = data._user_tags.split(',').filter(function (v) {
return v;
});
data.css_seen = '';
if (data._seen) {
var seen = JSON.parse(data._seen);
if (seen && in_list(seen, data._user)) {
data.css_seen = 'seen';
}
}
data._hide_activity = 0;
data._assign_list = JSON.parse(data._assign || '[]');
if (this.settings.prepare_data) this.settings.prepare_data(data);
return data;
},
prepare_when: function prepare_when(data, date_str) {
if (!date_str) date_str = data.modified;
data.when = frappe.datetime.str_to_user(date_str).split(' ')[0];
var diff = frappe.datetime.get_diff(frappe.datetime.get_today(), date_str.split(' ')[0]);
if (diff === 0) {
data.when = comment_when(date_str);
}
if (diff === 1) {
data.when = __('Yesterday');
}
if (diff === 2) {
data.when = __('2 days ago');
}
},
required_libs: null,
prepare_render_view: function prepare_render_view() {
var me = this;
this._render_view = this.render_view;
var lib_exists = typeof this.required_libs === 'string' && this.required_libs || $.isArray(this.required_libs) && this.required_libs.length;
this.render_view = function (values) {
values = values.map(me.prepare_data.bind(this));
values = values.uniqBy(function (value) {
return value.name;
});
if (lib_exists) {
me.load_lib(function () {
me._render_view(values);
});
} else {
me._render_view(values);
}
}.bind(this);
},
load_lib: function load_lib(callback) {
frappe.require(this.required_libs, callback);
},
render_bar_graph: function render_bar_graph(parent, data, field, label) {
var args = {
percent: data[field],
label: __(label)
};
$(parent).append('<span class=\'progress\' style=\'width: 100 %; float: left; margin: 5px 0px;\'> \t\t\t<span class=\'progress- bar\' title=\'' + args.percent + '% ' + args.label + '\' \t\t\t\tstyle=\'width: ' + args.percent + '%;\'></span>\t\t</span>');
},
render_icon: function render_icon(parent, icon_class, label) {
var icon_html = '<i class=\'' + icon_class + '\' title=\'' + (__(label) || '') + '\'></i>';
$(parent).append(icon_html);
},
make_no_result: function make_no_result() {
var new_button = frappe.boot.user.can_create.includes(this.doctype) ? '<p><button class=\'btn btn-primary btn-sm\'\n\t\t\t\tlist_view_doc=\'' + this.doctype + '\'>\n\t\t\t\t\t' + __('Make a new {0}', [__(this.doctype)]) + '\n\t\t\t\t</button></p>' : '';
var no_result_message = '<div class=\'msg-box no-border\'>\n\t\t\t\t<p>' + __('No {0} found', [__(this.doctype)]) + '</p>\n\t\t\t\t' + new_button + '\n\t\t\t</div>';
return no_result_message;
}
});
frappe.provide('frappe.views');
frappe.views.GanttView = frappe.views.ListRenderer.extend({
name: 'Gantt',
prepare: function prepare(values) {
this.items = values;
this.prepare_tasks();
this.prepare_dom();
},
render_view: function render_view(values) {
var me = this;
this.prepare(values);
this.render_gantt();
},
set_defaults: function set_defaults() {
this._super();
this.no_realtime = true;
this.page_title = this.page_title + ' ' + __('Gantt');
},
init_settings: function init_settings() {
this._super();
this.field_map = frappe.views.calendar[this.doctype].field_map;
this.order_by = this.order_by || this.field_map.start + ' asc';
},
prepare_dom: function prepare_dom() {
this.wrapper.css('overflow', 'auto').append('<svg class="gantt-container" width="20" height="20"></svg>');
},
render_gantt: function render_gantt(tasks) {
var me = this;
this.gantt_view_mode = this.user_settings.gantt_view_mode || 'Day';
var field_map = frappe.views.calendar[this.doctype].field_map;
this.gantt = new Gantt(".gantt-container", this.tasks, {
view_mode: this.gantt_view_mode,
date_format: "YYYY-MM-DD",
on_click: function on_click(task) {
frappe.set_route('Form', task.doctype, task.id);
},
on_date_change: function on_date_change(task, start, end) {
if (!me.can_write()) return;
me.update_gantt_task(task, start, end);
},
on_progress_change: function on_progress_change(task, progress) {
if (!me.can_write()) return;
var progress_fieldname = 'progress';
if ($.isFunction(field_map.progress)) {
progress_fieldname = null;
} else if (field_map.progress) {
progress_fieldname = field_map.progress;
}
if (progress_fieldname) {
frappe.db.set_value(task.doctype, task.id, progress_fieldname, parseInt(progress));
}
},
on_view_change: function on_view_change(mode) {
frappe.model.user_settings.save(me.doctype, 'Gantt', {
gantt_view_mode: mode
});
},
custom_popup_html: function custom_popup_html(task) {
var item = me.get_item(task.id);
var html = '<h5>' + task.name + '</h5>\n\t\t\t\t\t<p>' + task._start.format('MMM D') + ' - ' + task._end.format('MMM D') + '</p>';
var custom = me.settings.gantt_custom_popup_html;
if (custom && $.isFunction(custom)) {
var ganttobj = task;
html = custom(ganttobj, item);
}
return '<div class="details-container">' + html + '</div>';
}
});
this.render_dropdown();
},
render_dropdown: function render_dropdown() {
var me = this;
var view_modes = this.gantt.config.view_modes || [];
var dropdown = "<div class='dropdown pull-right'>" + "<a class='text-muted dropdown-toggle' data-toggle='dropdown'>" + "<span class='dropdown-text'>" + __(this.gantt_view_mode) + "</span><i class='caret'></i></a>" + "<ul class='dropdown-menu'></ul>" + "</div>";
var dropdown_list = "";
view_modes.forEach(function (view_mode) {
dropdown_list += "<li>" + "<a class='option' data-value='" + view_mode + "'>" + __(view_mode) + "</a></li>";
});
var $dropdown = $(dropdown);
$dropdown.find(".dropdown-menu").append(dropdown_list);
me.list_view.$page.find('[data-list-renderer=\'Gantt\'] > .list-row-right').css("margin-right", "15px").html($dropdown);
$dropdown.on("click", ".option", function () {
var mode = $(this).data('value');
me.gantt.change_view_mode(mode);
$dropdown.find(".dropdown-text").text(mode);
});
},
prepare_tasks: function prepare_tasks() {
var me = this;
var meta = frappe.get_meta(this.doctype);
var field_map = frappe.views.calendar[this.doctype].field_map;
this.tasks = this.items.map(function (item) {
var progress = 0;
if (field_map.progress && $.isFunction(field_map.progress)) {
progress = field_map.progress(item);
} else if (field_map.progress) {
progress = item[field_map.progress];
}
if (meta.title_field) {
var label = $.format("{0} ({1})", [item[meta.title_field], item.name]);
} else {
var label = item[field_map.title];
}
var r = {
start: item[field_map.start],
end: item[field_map.end],
name: label,
id: item[field_map.id || 'name'],
doctype: me.doctype,
progress: progress,
dependencies: item.depends_on_tasks || ""
};
if (item.is_milestone) {
r['custom_class'] = 'bar-milestone';
};
return r;
});
},
get_item: function get_item(name) {
return this.items.find(function (item) {
return item.name === name;
});
},
update_gantt_task: function update_gantt_task(task, start, end) {
var me = this;
if (me.gantt.updating_task) {
setTimeout(me.update_gantt_task.bind(me, task, start, end), 200);
return;
}
me.gantt.updating_task = true;
var field_map = frappe.views.calendar[this.doctype].field_map;
frappe.call({
method: 'frappe.desk.gantt.update_task',
args: {
args: {
doctype: task.doctype,
name: task.id,
start: start.format('YYYY-MM-DD'),
end: end.format('YYYY-MM-DD')
},
field_map: field_map
},
callback: function callback() {
me.gantt.updating_task = false;
frappe.show_alert({ message: __("Saved"), indicator: 'green' }, 1);
}
});
},
get_header_html: function get_header_html() {
return frappe.render_template('list_item_row_head', { main: '', list: this });
},
refresh: function refresh(values) {
this.prepare(values);
this.render();
},
can_write: function can_write() {
if (frappe.model.can_write(this.doctype)) {
return true;
} else {
this.gantt.change_view_mode(this.gantt_view_mode);
frappe.show_alert({ message: __("Not permitted"), indicator: 'red' }, 1);
return false;
}
},
set_columns: function set_columns() {},
required_libs: ["assets/frappe/js/lib/snap.svg-min.js", "assets/frappe/js/lib/frappe-gantt/frappe-gantt.js"]
});
frappe.provide("frappe.views.calendar");
frappe.provide("frappe.views.calendars");
frappe.views.CalendarView = frappe.views.ListRenderer.extend({
name: 'Calendar',
render_view: function render_view() {
var me = this;
var options = {
doctype: this.doctype,
parent: this.wrapper,
page: this.list_view.page,
list_view: this.list_view
};
$.extend(options, frappe.views.calendar[this.doctype]);
this.calendar = new frappe.views.Calendar(options);
},
set_defaults: function set_defaults() {
this._super();
this.page_title = this.page_title + ' ' + __('Calendar');
this.no_realtime = true;
this.show_no_result = false;
this.hide_sort_selector = true;
},
get_header_html: function get_header_html() {
return null;
},
required_libs: ['assets/frappe/js/lib/fullcalendar/fullcalendar.min.css', 'assets/frappe/js/lib/fullcalendar/fullcalendar.min.js', 'assets/frappe/js/lib/fullcalendar/locale-all.js']
});
frappe.views.Calendar = Class.extend({
init: function init(options) {
$.extend(this, options);
this.make_page();
this.setup_options();
this.make();
},
make_page: function make_page() {
var me = this;
me.page.clear_user_actions();
$.each(frappe.boot.calendars, function (i, doctype) {
if (frappe.model.can_read(doctype)) {
me.page.add_menu_item(__(doctype), function () {
frappe.set_route("List", doctype, "Calendar");
});
}
});
$(this.parent).on("show", function () {
me.$cal.fullCalendar("refetchEvents");
});
},
make: function make() {
var me = this;
this.$wrapper = this.parent;
this.$cal = $("<div>").appendTo(this.$wrapper);
this.footnote_area = frappe.utils.set_footnote(this.footnote_area, this.$wrapper, __("Select or drag across time slots to create a new event."));
this.footnote_area.css({ "border-top": "0px" });
this.$cal.fullCalendar(this.cal_options);
this.set_css();
},
set_css: function set_css() {
this.$wrapper.find("button.fc-state-default").removeClass("fc-state-default").addClass("btn btn-default");
this.$wrapper.find(".fc-button-group").addClass("btn-group");
this.$wrapper.find('.fc-prev-button span').attr('class', '').addClass('fa fa-chevron-left');
this.$wrapper.find('.fc-next-button span').attr('class', '').addClass('fa fa-chevron-right');
var btn_group = this.$wrapper.find(".fc-button-group");
btn_group.find(".fc-state-active").addClass("active");
btn_group.find(".btn").on("click", function () {
btn_group.find(".btn").removeClass("active");
$(this).addClass("active");
});
},
field_map: {
"id": "name",
"start": "start",
"end": "end",
"allDay": "all_day"
},
color_map: {
"danger": "red",
"success": "green",
"warning": "orange"
},
get_system_datetime: function get_system_datetime(date) {
date._offset = moment.user_utc_offset;
return frappe.datetime.convert_to_system_tz(date);
},
setup_options: function setup_options() {
var me = this;
this.cal_options = {
locale: frappe.boot.user.language || "en",
header: {
left: 'title',
center: '',
right: 'prev,next month,agendaWeek,agendaDay'
},
editable: true,
selectable: true,
selectHelper: true,
forceEventDuration: true,
events: function events(start, end, timezone, _callback) {
return frappe.call({
method: me.get_events_method || "frappe.desk.calendar.get_events",
type: "GET",
args: me.get_args(start, end),
callback: function callback(r) {
var events = r.message;
events = me.prepare_events(events);
_callback(events);
}
});
},
eventRender: function eventRender(event, element) {
element.attr('title', event.tooltip);
},
eventClick: function eventClick(event, jsEvent, view) {
var doctype = event.doctype || me.doctype;
if (frappe.model.can_read(doctype)) {
frappe.set_route("Form", doctype, event.name);
}
},
eventDrop: function eventDrop(event, delta, revertFunc, jsEvent, ui, view) {
me.update_event(event, revertFunc);
},
eventResize: function eventResize(event, delta, revertFunc, jsEvent, ui, view) {
me.update_event(event, revertFunc);
},
select: function select(startDate, endDate, jsEvent, view) {
if (view.name === "month" && endDate - startDate === 86400000) {
return;
}
var event = frappe.model.get_new_doc(me.doctype);
event[me.field_map.start] = me.get_system_datetime(startDate);
if (me.field_map.end) event[me.field_map.end] = me.get_system_datetime(endDate);
if (me.field_map.allDay) {
var all_day = startDate._ambigTime && endDate._ambigTime ? 1 : 0;
event[me.field_map.allDay] = all_day;
if (all_day) event[me.field_map.end] = me.get_system_datetime(moment(endDate).subtract(1, "s"));
}
frappe.set_route("Form", me.doctype, event.name);
},
dayClick: function dayClick(date, jsEvent, view) {
if (view.name === 'month') {
var $date_cell = $('td[data-date=' + date.format('YYYY-MM-DD') + "]");
if ($date_cell.hasClass('date-clicked')) {
me.$cal.fullCalendar('changeView', 'agendaDay');
me.$cal.fullCalendar('gotoDate', date);
me.$wrapper.find('.date-clicked').removeClass('date-clicked');
me.$wrapper.find('.fc-month-button').removeClass('active');
me.$wrapper.find('.fc-agendaDay-button').addClass('active');
}
me.$wrapper.find('.date-clicked').removeClass('date-clicked');
$date_cell.addClass('date-clicked');
}
return false;
}
};
if (this.options) {
$.extend(this.cal_options, this.options);
}
},
get_args: function get_args(start, end) {
var args = {
doctype: this.doctype,
start: this.get_system_datetime(start),
end: this.get_system_datetime(end),
filters: this.list_view.filter_list.get_filters()
};
return args;
},
refresh: function refresh() {
this.$cal.fullCalendar('refetchEvents');
},
prepare_events: function prepare_events(events) {
var me = this;
return (events || []).map(function (d) {
d.id = d.name;
d.editable = frappe.model.can_write(d.doctype || me.doctype);
if (d.docstatus && d.docstatus > 0) {
d.editable = false;
}
$.each(me.field_map, function (target, source) {
d[target] = d[source];
});
if (!me.field_map.allDay) d.allDay = 1;
d.start = frappe.datetime.convert_to_user_tz(d.start);
d.end = frappe.datetime.convert_to_user_tz(d.end);
me.fix_end_date_for_event_render(d);
var color = void 0;
if (me.get_css_class) {
color = me.color_map[me.get_css_class(d)];
if (!Object.values(me.color_map).includes(color)) {
color = "blue";
}
} else {
color = d.color;
}
if (!color) color = "blue";
d.className = "fc-bg-" + color;
return d;
});
},
update_event: function update_event(event, revertFunc) {
var me = this;
frappe.model.remove_from_locals(me.doctype, event.name);
return frappe.call({
method: me.update_event_method || "frappe.desk.calendar.update_event",
args: me.get_update_args(event),
callback: function callback(r) {
if (r.exc) {
frappe.show_alert(__("Unable to update event"));
revertFunc();
}
},
error: function error() {
revertFunc();
}
});
},
get_update_args: function get_update_args(event) {
var me = this;
var args = {
name: event[this.field_map.id]
};
args[this.field_map.start] = me.get_system_datetime(event.start);
if (this.field_map.allDay) args[this.field_map.allDay] = event.start._ambigTime && event.end._ambigTime ? 1 : 0;
if (this.field_map.end) {
if (!event.end) {
event.end = event.start.add(1, "hour");
}
args[this.field_map.end] = me.get_system_datetime(event.end);
if (args[this.field_map.allDay]) {
args[this.field_map.end] = me.get_system_datetime(moment(event.end).subtract(1, "s"));
}
}
args.doctype = event.doctype || this.doctype;
return { args: args, field_map: this.field_map };
},
fix_end_date_for_event_render: function fix_end_date_for_event_render(event) {
if (event.allDay) {
event.start = event.start ? $.fullCalendar.moment(event.start).stripTime() : null;
event.end = event.end ? $.fullCalendar.moment(event.end).add(1, "day").stripTime() : null;
}
}
});
frappe.provide("frappe.views");
frappe.views.ImageView = frappe.views.ListRenderer.extend({
name: 'Image',
render_view: function render_view(values) {
this.items = values;
this.render_image_view();
this.setup_gallery();
},
set_defaults: function set_defaults() {
this._super();
this.page_title = this.page_title + ' ' + __('Images');
},
render_image_view: function render_image_view() {
var html = this.items.map(this.render_item.bind(this)).join("");
this.container = $('<div>').addClass('image-view-container').appendTo(this.wrapper);
this.container.append(html);
},
render_item: function render_item(item) {
var image_url = this.get_image_url(item);
var indicator = this.get_indicator_html(item);
return frappe.render_template("image_view_item_row", {
data: item,
indicator: indicator,
subject: this.get_subject_html(item, true),
additional_columns: this.additional_columns,
item_image: image_url,
color: frappe.get_palette(item.item_name)
});
},
get_image_url: function get_image_url(item) {
var url;
url = item.image ? item.image : item[this.meta.image_field];
if (window.cordova && !frappe.utils.is_url(url)) {
url = frappe.base_url + url;
}
if (url) {
return url;
}
return null;
},
get_header_html: function get_header_html() {
var main = frappe.render_template('list_item_main_head', {
col: { type: "Subject" },
_checkbox: (frappe.model.can_delete(this.doctype) || this.settings.selectable) && !this.no_delete
});
return frappe.render_template('list_item_row_head', { main: main, list: this });
},
setup_gallery: function setup_gallery() {
var me = this;
var gallery = new frappe.views.GalleryView({
doctype: this.doctype,
items: this.items,
wrapper: this.container
});
this.container.on('click', '.btn.zoom-view', function (e) {
e.preventDefault();
e.stopPropagation();
var name = $(this).data().name;
gallery.show(name);
return false;
});
}
});
frappe.views.GalleryView = Class.extend({
init: function init(opts) {
$.extend(this, opts);
var me = this;
this.ready = false;
this.load_lib(function () {
me.prepare();
me.ready = true;
});
},
prepare: function prepare() {
this.pswp_root = $('body > .pswp');
if (this.pswp_root.length === 0) {
var pswp = frappe.render_template('photoswipe_dom');
this.pswp_root = $(pswp).appendTo('body');
}
},
show: function show(docname) {
var me = this;
if (!this.ready) {
setTimeout(this.show.bind(this), 200);
return;
}
var items = this.items.map(function (i) {
var query = 'img[data-name="' + i.name + '"]';
var el = me.wrapper.find(query).get(0);
if (el) {
var width = el.naturalWidth;
var height = el.naturalHeight;
}
if (!el) {
el = me.wrapper.find('.image-field[data-name="' + i.name + '"]').get(0);
width = el.getBoundingClientRect().width;
height = el.getBoundingClientRect().height;
}
return {
src: i.image,
msrc: i.image,
name: i.name,
w: width,
h: height,
el: el
};
});
var index;
items.map(function (item, i) {
if (item.name === docname) index = i;
});
var options = {
index: index,
getThumbBoundsFn: function getThumbBoundsFn(index) {
var thumbnail = items[index].el,
pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
rect = thumbnail.getBoundingClientRect();
return { x: rect.left, y: rect.top + pageYScroll, w: rect.width };
},
history: false,
shareEl: false
};
var pswp = new PhotoSwipe(this.pswp_root.get(0), PhotoSwipeUI_Default, items, options);
pswp.init();
},
get_image_urls: function get_image_urls() {
return frappe.call({
method: "frappe.client.get_list",
args: {
doctype: "File",
order_by: "attached_to_name",
fields: ["'image/*' as type", "ifnull(thumbnail_url, file_url) as thumbnail", "concat(attached_to_name, ' - ', file_name) as title", "file_url as src", "attached_to_name as name"],
filters: [["File", "attached_to_doctype", "=", this.doctype], ["File", "attached_to_name", "in", this.docnames], ["File", "is_folder", "!=", 1]]
},
freeze: true,
freeze_message: __("Fetching Images..")
}).then(function (r) {
if (!r.message) {
frappe.msgprint(__("No Images found"));
} else {
var images = r.message.filter(function (image) {
return frappe.utils.is_image_file(image.title || image.href);
});
}
});
},
load_lib: function load_lib(callback) {
var asset_dir = 'assets/frappe/js/lib/photoswipe/';
frappe.require([asset_dir + 'photoswipe.css', asset_dir + 'default-skin.css', asset_dir + 'photoswipe.js', asset_dir + 'photoswipe-ui-default.js'], callback);
}
});
frappe.provide('frappe.views');
frappe.views.KanbanView = frappe.views.ListRenderer.extend({
name: 'Kanban',
render_view: function render_view(values) {
var board_name = this.get_board_name();
if (this.kanban && board_name === this.kanban.board_name) {
this.kanban.update(values);
return;
}
this.kanban = new frappe.views.KanbanBoard({
doctype: this.doctype,
board_name: board_name,
cards: values,
wrapper: this.wrapper,
cur_list: this.list_view,
user_settings: this.user_settings
});
},
after_refresh: function after_refresh() {
this.wrapper.find('.kanban').trigger('after-refresh');
frappe.kanban_filters[this.get_board_name()] = this.list_view.filter_list.get_filters();
},
should_refresh: function should_refresh() {
var to_refresh = this._super();
if (!to_refresh) {
this.last_kanban_board = this.current_kanban_board || '';
this.current_kanban_board = this.get_board_name();
this.page_title = __(this.get_board_name());
to_refresh = this.current_kanban_board !== this.last_kanban_board;
}
return to_refresh;
},
init_settings: function init_settings() {
this._super();
this.filters = this.get_kanban_filters();
},
get_kanban_filters: function get_kanban_filters() {
frappe.provide('frappe.kanban_filters');
var board_name = this.get_board_name();
if (!frappe.kanban_filters[board_name]) {
var kb = this.meta.__kanban_boards.find(function (board) {
return board.name === board_name;
});
frappe.kanban_filters[board_name] = JSON.parse(kb && kb.filters || '[]');
}
if (typeof frappe.kanban_filters[board_name] === 'string') {
frappe.kanban_filters[board_name] = JSON.parse(frappe.kanban_filters[board_name] || '[]');
}
var filters = frappe.kanban_filters[board_name];
return filters;
},
set_defaults: function set_defaults() {
this._super();
this.no_realtime = true;
this.show_no_result = false;
this.page_title = __(this.get_board_name());
},
get_board_name: function get_board_name() {
var route = frappe.get_route();
return route[3];
},
get_header_html: function get_header_html() {
return frappe.render_template('list_item_row_head', { main: '', list: this });
},
required_libs: ['assets/frappe/js/lib/fluxify.min.js', 'assets/frappe/js/frappe/views/kanban/kanban_board.js']
});
frappe.provide("frappe.views");
frappe.views.InboxView = frappe.views.ListRenderer.extend({
name: 'Inbox',
render_view: function render_view(values) {
var me = this;
this.emails = values;
frappe.model.user_settings.save("Communication", 'Inbox', {
last_email_account: this.current_email_account
});
this.render_inbox_view();
},
render_inbox_view: function render_inbox_view() {
var html = "";
var email_account = this.get_current_email_account();
if (email_account) html = this.emails.map(this.render_email_row.bind(this)).join("");else html = this.make_no_result();
this.container = $('<div>').addClass('inbox-container').appendTo(this.wrapper);
this.container.append(html);
},
render_email_row: function render_email_row(email) {
if (!email.css_seen && email.seen) email.css_seen = "seen";
return frappe.render_template("inbox_view_item_row", {
data: email,
is_sent_emails: this.is_sent_emails
});
},
set_defaults: function set_defaults() {
this._super();
this.page_title = __("Email Inbox");
},
init_settings: function init_settings() {
this._super();
this.filters = this.get_inbox_filters();
},
should_refresh: function should_refresh() {
var to_refresh = this._super();
if (!to_refresh) {
this.last_email_account = this.current_email_account || '';
this.current_email_account = this.get_current_email_account();
this.is_sent_emails = this.current_email_account === "Sent" ? true : false;
to_refresh = this.current_email_account !== this.last_email_account;
}
if (to_refresh) {
this.list_view.page.main.find(".list-headers").empty();
}
return to_refresh;
},
get_inbox_filters: function get_inbox_filters() {
var email_account = this.get_current_email_account();
var default_filters = [["Communication", "communication_type", "=", "Communication", true], ["Communication", "communication_medium", "=", "Email", true]];
var filters = [];
if (email_account === "Sent") {
filters = default_filters.concat([["Communication", "sent_or_received", "=", "Sent", true], ["Communication", "email_status", "not in", "Spam,Trash", true]]);
} else if (in_list(["Spam", "Trash"], email_account)) {
filters = default_filters.concat([["Communication", "email_status", "=", email_account, true], ["Communication", "email_account", "in", frappe.boot.all_accounts, true]]);
} else {
var op = "=";
if (email_account == "All Accounts") {
op = "in";
email_account = frappe.boot.all_accounts;
}
filters = default_filters.concat([["Communication", "sent_or_received", "=", "Received", true], ["Communication", "email_account", op, email_account, true], ["Communication", "email_status", "not in", "Spam,Trash", true]]);
}
return filters;
},
get_header_html: function get_header_html() {
var header = "";
if (this.current_email_account) {
header = frappe.render_template('inbox_view_item_main_head', {
_checkbox: (frappe.model.can_delete(this.doctype) || this.settings.selectable) && !this.no_delete,
is_sent_emails: this.is_sent_emails
});
}
return header;
},
get_current_email_account: function get_current_email_account() {
var route = frappe.get_route();
if (!route[3] && frappe.boot.email_accounts.length) {
var email_account;
if (frappe.boot.email_accounts[0].email_id == "All Accounts") {
email_account = "All Accounts";
} else {
email_account = frappe.boot.email_accounts[0].email_account;
}
frappe.set_route("List", "Communication", "Inbox", email_account);
} else if (route[3] && route[3] != "All Accounts" && !frappe.boot.email_accounts.find(function (b) {
return b.email_account === route[3];
})) {
return '';
}
return route[3];
},
make_no_result: function make_no_result() {
var no_result_message = "";
var email_account = this.get_current_email_account();
var args;
if (in_list(["Spam", "Trash"], email_account)) {
return __("No {0} mail", [email_account]);
} else if (!email_account && !frappe.boot.email_accounts.length) {
this.no_result_doctype = "Email Account";
args = {
doctype: "Email Account",
msg: __("No Email Account"),
label: __("New Email Account")
};
} else {
this.no_result_doctype = "Communication";
args = {
doctype: "Communication",
msg: __("No Emails"),
label: __("Compose Email")
};
}
var no_result_message = frappe.render_template("inbox_no_result", args);
return no_result_message;
},
make_new_doc: function make_new_doc() {
if (this.no_result_doctype == "Communication") {
new frappe.views.CommunicationComposer({
doc: {}
});
} else {
frappe.route_options = { 'email_id': frappe.session.user_email };
frappe.new_doc(this.no_result_doctype);
}
}
});frappe.templates['header_select_all_like_filter'] = '{% if (_checkbox) { %} <input class="list-select-all hidden-xs" type="checkbox" title="{%= __("Select All") %}"> {% } %} <span class="liked-by-filter-button"> <i class="fa-fw octicon octicon-heart text-extra-muted not-liked like-action list-liked-by-me" title="{%= __("Likes") %}"></i> </span>';
frappe.templates['item_assigned_to_comment_count'] = '<span class="list-row-modified text-muted"> {%= comment_when(data.modified, true) %} </span> {% if (data._assign_list.length) { %} <span class="filterable" data-filter="_assign,like,%{%= data._assign_list[data._assign_list.length - 1] %}%"> {%= frappe.avatar(data._assign_list[data._assign_list.length - 1]) %}</span> {% } else { %} <span class="avatar avatar-small avatar-empty"></span> {% } %} <span class="list-comment-count small {% if(!data._comment_count) { %} text-extra-muted {% } else { %} text-muted {% } %}"> <i class="octicon octicon-comment-discussion"></i> {%= (data._comment_count > 99 ? "99+" : data._comment_count) || 0 %} </span> ';
frappe.provide("frappe.treeview_settings");
frappe.provide('frappe.views.trees');
cur_tree = null;
frappe.views.TreeFactory = frappe.views.Factory.extend({
make: function make(route) {
frappe.model.with_doctype(route[1], function () {
var options = {
doctype: route[1],
meta: frappe.get_meta(route[1])
};
if (!frappe.treeview_settings[route[1]] && !frappe.meta.get_docfield(route[1], "is_group")) {
frappe.msgprint(__("Tree view not available for {0}", [route[1]]));
return false;
}
$.extend(options, frappe.treeview_settings[route[1]] || {});
frappe.views.trees[options.doctype] = new frappe.views.TreeView(options);
});
}
});
frappe.views.TreeView = Class.extend({
init: function init(opts) {
var me = this;
this.opts = {};
this.opts.get_tree_root = true;
$.extend(this.opts, opts);
this.doctype = opts.doctype;
this.args = { doctype: me.doctype };
this.page_name = frappe.get_route_str();
this.get_tree_nodes = me.opts.get_tree_nodes || "frappe.desk.treeview.get_children";
this.get_permissions();
this.make_page();
this.make_filters();
if (me.opts.get_tree_root) {
this.get_root();
}
this.set_menu_item();
this.set_primary_action();
},
get_permissions: function get_permissions() {
this.can_read = frappe.model.can_read(this.doctype);
this.can_create = frappe.boot.user.can_create.indexOf(this.doctype) !== -1 || frappe.boot.user.in_create.indexOf(this.doctype) !== -1;
this.can_write = frappe.model.can_write(this.doctype);
this.can_delete = frappe.model.can_delete(this.doctype);
},
make_page: function make_page() {
var me = this;
this.parent = frappe.container.add_page(this.page_name);
frappe.ui.make_app_page({ parent: this.parent, single_column: true });
this.page = this.parent.page;
frappe.container.change_to(this.page_name);
frappe.breadcrumbs.add(me.opts.breadcrumb || locals.DocType[me.doctype].module);
this.page.set_title(me.opts.title || __('{0} Tree', [__(this.doctype)]));
this.page.main.css({
"min-height": "300px",
"padding-bottom": "25px"
});
this.page.add_inner_button(__('Expand All'), function () {
me.tree.rootnode.load_all();
});
if (this.opts.view_template) {
var row = $('<div class="row"><div>').appendTo(this.page.main);
this.body = $('<div class="col-sm-6 col-xs-12"></div>').appendTo(row);
this.node_view = $('<div class="col-sm-6 hidden-xs"></div>').appendTo(row);
} else {
this.body = this.page.main;
}
},
make_filters: function make_filters() {
var me = this;
frappe.treeview_settings.filters = [];
$.each(this.opts.filters || [], function (i, filter) {
if (frappe.route_options && frappe.route_options[filter.fieldname]) {
filter.default = frappe.route_options[filter.fieldname];
}
me.page.add_field(filter).$input.on('change', function () {
var val = $(this).val();
if (val) {
me.args[$(this).attr("data-fieldname")] = val;
frappe.treeview_settings.filters = me.args;
me.make_tree();
me.page.set_title(val);
}
});
if (filter.default) {
$("[data-fieldname='" + filter.fieldname + "']").trigger("change");
}
});
},
get_root: function get_root() {
var me = this;
frappe.call({
method: me.get_tree_nodes,
args: me.args,
callback: function callback(r) {
if (r.message) {
me.root = r.message[0]["value"];
me.make_tree();
}
}
});
},
make_tree: function make_tree() {
var me = this;
$(me.parent).find(".tree").remove();
this.tree = new frappe.ui.Tree({
parent: me.body,
label: me.args[me.opts.root_label] || me.opts.root_label || me.root,
args: me.args,
method: me.get_tree_nodes,
toolbar: me.get_toolbar(),
get_label: me.opts.get_label,
onrender: me.opts.onrender,
onclick: function onclick(node) {
me.select_node(node);
}
});
cur_tree = this.tree;
},
select_node: function select_node(node) {
var me = this;
if (this.opts.click) {
this.opts.click(node);
}
if (this.opts.view_template) {
this.node_view.empty();
$(frappe.render_template(me.opts.view_template, { data: node.data, doctype: me.doctype })).appendTo(this.node_view);
}
},
get_toolbar: function get_toolbar() {
var me = this;
var toolbar = [{ toggle_btn: true }, {
label: __(me.can_write ? "Edit" : "Details"),
condition: function condition(node) {
return !node.root && me.can_read;
},
click: function click(node) {
frappe.set_route("Form", me.doctype, node.label);
}
}, {
label: __("Add Child"),
condition: function condition(node) {
return me.can_create && node.expandable;
},
click: function click(node) {
me.new_node();
},
btnClass: "hidden-xs"
}, {
label: __("Rename"),
condition: function condition(node) {
return !node.root && me.can_write;
},
click: function click(node) {
frappe.model.rename_doc(me.doctype, node.label, function (new_name) {
node.tree_link.find('a').text(new_name);
node.label = new_name;
});
},
btnClass: "hidden-xs"
}, {
label: __("Delete"),
condition: function condition(node) {
return !node.root && me.can_delete;
},
click: function click(node) {
frappe.model.delete_doc(me.doctype, node.label, function () {
node.parent.remove();
});
},
btnClass: "hidden-xs"
}];
if (this.opts.toolbar && this.opts.extend_toolbar) {
return toolbar.concat(this.opts.toolbar);
} else if (this.opts.toolbar && !this.opts.extend_toolbar) {
return this.opts.toolbar;
} else {
return toolbar;
}
},
new_node: function new_node() {
var me = this;
var node = me.tree.get_selected_node();
if (!(node && node.expandable)) {
frappe.msgprint(__("Select a group node first."));
return;
}
this.prepare_fields();
var d = new frappe.ui.Dialog({
title: __('New {0}', [__(me.doctype)]),
fields: me.fields
});
var args = $.extend({}, me.args);
args["parent_" + me.doctype.toLowerCase().replace(/ /g, '_')] = me.args["parent"];
d.set_value("is_group", 0);
d.set_values(args);
d.set_primary_action(__("Create New"), function () {
var btn = this;
var v = d.get_values();
if (!v) return;
var node = me.tree.get_selected_node();
v.parent = node.label;
v.doctype = me.doctype;
if (node.root) {
v.is_root = 1;
v.parent_account = null;
} else {
v.is_root = 0;
v.root_type = null;
}
$.extend(args, v);
return frappe.call({
method: me.opts.add_tree_node || "frappe.desk.treeview.add_node",
args: args,
callback: function callback(r) {
if (!r.exc) {
d.hide();
if (node.expanded) {
node.toggle_node();
}
node.load_all();
}
}
});
});
d.show();
},
prepare_fields: function prepare_fields() {
var me = this;
this.fields = [{ fieldtype: 'Check', fieldname: 'is_group', label: __('Group Node'),
description: __("Further nodes can be only created under 'Group' type nodes") }];
if (this.opts.fields) {
this.fields = this.opts.fields;
}
this.ignore_fields = this.opts.ignore_fields || [];
var mandatory_fields = $.map(me.opts.meta.fields, function (d) {
return d.reqd || d.bold && !d.read_only ? d : null;
});
var opts_field_names = this.fields.map(function (d) {
return d.fieldname;
});
mandatory_fields.map(function (d) {
if ($.inArray(d.fieldname, me.ignore_fields) === -1 && $.inArray(d.fieldname, opts_field_names) === -1) {
me.fields.push(d);
}
});
},
set_primary_action: function set_primary_action() {
var me = this;
if (!this.opts.disable_add_node && this.can_create) {
me.page.set_primary_action(__("New"), function () {
me.new_node();
}, "octicon octicon-plus");
}
},
set_menu_item: function set_menu_item() {
var me = this;
this.menu_items = [{
label: __('View List'),
action: function action() {
frappe.set_route('List', me.doctype);
}
}, {
label: __('Refresh'),
action: function action() {
me.make_tree();
}
}];
if (me.opts.menu_items) {
me.menu_items.push.apply(me.menu_items, me.opts.menu_items);
}
$.each(me.menu_items, function (i, menu_item) {
var has_perm = true;
if (menu_item["condition"]) {
has_perm = eval(menu_item["condition"]);
}
if (has_perm) {
me.page.add_menu_item(menu_item["label"], menu_item["action"]);
}
});
}
});frappe.templates['image_view_item_row'] = '<div class="image-view-item has-checkbox ellipsis"> <div class="image-view-header doclist-row"> <div class="list-value"> {{ subject }} </div> </div> <div class="image-view-body"> <a data-name="{{ data.name }}" title="{{ data.name }}" href="#Form/{{ data.doctype }}/{{ data.name }}" > <div class="image-field" data-name="{{ data.name }}" style=" {% if (!item_image) { %} background-color: {{ color }}; {% } %} border: 0px;" > {% if (!item_image) { %} <span class="placeholder-text"> {%= frappe.get_abbr(data._title) %} </span> {% } %} {% if (item_image) { %} <img data-name="{{ data.name }}" src="{{ item_image }}" alt="{{data.title}}"> {% } %} <button class="btn btn-default zoom-view" data-name="{{data.name}}"> <i class="fa fa-search-plus"></i> </button> </div> </a> </div> <div class="image-view-footer hide"> <div class="row"> <div class="col-xs-4">{%= indicator %}</div> <div class="col-xs-8 text-right"> {%= frappe.render_template("item_assigned_to_comment_count", { data: data }) %} </div> </div> </div> </div> ';
frappe.templates['photoswipe_dom'] = ' <div class="pswp" tabindex="-1" role="dialog" aria-hidden="true"> <div class="pswp__bg"></div> <div class="pswp__scroll-wrap"> <div class="pswp__container"> <div class="pswp__item"></div> <div class="pswp__item"></div> <div class="pswp__item"></div> </div> <div class="pswp__ui pswp__ui--hidden"> <div class="pswp__top-bar"> <div class="pswp__counter"></div> <button class="pswp__button pswp__button--close" title="Close (Esc)"></button> <button class="pswp__button pswp__button--share" title="Share"></button> <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button> <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button> <div class="pswp__preloader"> <div class="pswp__preloader__icn"> <div class="pswp__preloader__cut"> <div class="pswp__preloader__donut"></div> </div> </div> </div> </div> <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"> <div class="pswp__share-tooltip"></div> </div> <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)"> </button> <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)"> </button> <div class="pswp__caption"> <div class="pswp__caption__center"></div> </div> </div> </div> </div>';
frappe.templates['inbox_no_result'] = '<div class="msg-box no-border"> {% if(!frappe.model.can_create(doctype) && doctype == "Email Account") { %} <p>{{ __("No Email Accounts Assigned") }}</p> {% } else { %} <p>{{ msg }}</p> <p> <button class="btn btn-primary btn-sm btn-no-result" list_view_doc="{{ doctype }}"> {{ label }} </button> </p> {% } %} </div>';
frappe.templates['inbox_view_item_row'] = '<div class="list-row"> <div class="row doclist-row {% if (data._checkbox) { %} has-checkbox {% } %}"> <div class="col-sm-10 col-xs-10 list-row-left"> <div class="row"> <div class="col-sm-8 list-col ellipsis h6 text-muted"> <span class="list-value"> {% if (data._checkbox) { %} <input class="list-row-checkbox" type="checkbox" data-name="{{data.name}}"> {% } %} <a class="grey list-id {{ data.css_seen }} inbox-value" href="#Form/{%= data._doctype_encoded %}/{%= data._name_encoded %}"> {%= data.subject %} </a> </span> </div> <div class="col-sm-4 hidden-xs list-col ellipsis h6 text-muted"> <span class="filterable text-muted" data-filter="sender,=,{%= data.sender %} inbox-value"> {%= is_sent_emails? data.recipients: data.sender %} </span> </div> </div> </div> <div class="col-sm-2 col-xs-2 text-right list-row-right" style="padding-left:0px"> <div class="visible-xs"> <span class="text-muted inbox-attachment inbox-value"> {% if(data.has_attachment) { %} <i class="fa fa-paperclip fa-large"></i> {% } %} </span> </div> <div class="hidden-xs"> <span class="text-muted inbox-attachment inbox-value"> {% if(data.reference_doctype && data.reference_name) { %} <a class="text-muted grey" href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}"> <i class="fa fa-link fa-large"></i> </a> {% } %} </span> <span class="text-muted inbox-attachment inbox-value"> {% if(data.has_attachment) { %} <i class="fa fa-paperclip fa-large"></i> {% } %} </span> <span class="list-row-modified text-muted inbox-value"> {%= comment_when(data.modified, true) %} </span> </div> </div> </div> </div>';
frappe.templates['inbox_view_item_main_head'] = '<div class="list-row list-row-head" data-list-renderer="Inbox"> <div class="row doclist-row"> <div class="col-sm-10 list-row-left"> <div class="row"> <div class="col-sm-8 col-xs-12 list-col ellipsis h6 text-muted"> <div class="list-value"> {% if (_checkbox) { %} <input class="list-select-all" type="checkbox" title="{%= __("Select All") %}"> {% } %} <span class="list-col-title">{%= __("Subject") %}</span> </div> </div> <div class="col-sm-4 hidden-xs list-col ellipsis h6 text-muted"> <div class="list-value"> <span class="list-col-title">{%= __(is_sent_emails ? "To": "From") %}</span> </div> </div> </div> </div> <div class="col-sm-2 hidden-xs list-row-right"></div> </div> </div>';
frappe.templates['kanban_board'] = '<div class="kanban"> <div class="kanban-column add-new-column"> <div class="kanban-column-title compose-column"> <a class="text-muted"> {{ __("Add a column") }}</a> </div> <form class="compose-column-form kanban-column-title"> <input class="new-column-title" name="title" type="text" autocomplete="off"> </form> </div> <div class="kanban-empty-state text-muted text-center" style="display: none;"> {{ __("Loading...") }} </div> </div>';
frappe.templates['kanban_column'] = '<div class="kanban-column" data-column-value="{{title}}"> <div class="kanban-column-title indicator {{indicator}}"> <span>{{ __(title) }}</span> <div class="btn-group column-options dropdown pull-right"> <a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <button class="btn btn-default btn-xs"><span class="caret"></span></button> </a> <ul class="dropdown-menu" style="max-height: 300px; overflow-y: auto;"> <li><a data-action="archive">{{ __("Archive") }}</a></li> </ul> </div> </div> <div class="kanban-cards"> </div> <div class="kanban-card add-card"> <div class="kanban-card-title"> <i class="octicon octicon-plus"></i> {{ __("Add " + doctype) }} </div> </div> <div class="kanban-card new-card-area"> <textarea name="title"></textarea> </div> </div>';
frappe.templates['kanban_card'] = '<div class="kanban-card-wrapper" data-name="{{name}}"> <div class="kanban-card content"> <div class="kanban-card-title"> {{ title }} </div> <div class="kanban-card-meta"> </div> </div> </div>';