mirror of
https://github.com/frappe/frappe_docker.git
synced 2026-06-22 15:55:09 +00:00
4183 lines
139 KiB
JavaScript
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>';
|