@@ -460,7 +460,7 @@ def has_website_permission(doctype, ptype="read", doc=None, user=None, verbose=F | |||
doc = get_doc(doctype, doc) | |||
for method in hooks: | |||
result = call(get_attr(method), doc=doc, ptype=ptype, user=user, verbose=verbose) | |||
result = call(method, doc=doc, ptype=ptype, user=user, verbose=verbose) | |||
# if even a single permission check is Falsy | |||
if not result: | |||
return False | |||
@@ -789,6 +789,9 @@ def get_attr(method_string): | |||
def call(fn, *args, **kwargs): | |||
"""Call a function and match arguments.""" | |||
if isinstance(fn, basestring): | |||
fn = get_attr(fn) | |||
if hasattr(fn, 'fnargs'): | |||
fnargs = fn.fnargs | |||
else: | |||
@@ -7,6 +7,7 @@ | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Setup", | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
@@ -19,7 +20,7 @@ | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Description and Status", | |||
"label": "", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
@@ -36,29 +37,55 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "description", | |||
"fieldtype": "Text", | |||
"default": "Open", | |||
"fieldname": "status", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Status", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Open\nClosed", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"default": "Medium", | |||
"fieldname": "priority", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Description", | |||
"label": "Priority", | |||
"length": 0, | |||
"no_copy": 0, | |||
"oldfieldname": "description", | |||
"oldfieldtype": "Text", | |||
"oldfieldname": "priority", | |||
"oldfieldtype": "Data", | |||
"options": "High\nMedium\nLow", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"print_width": "300px", | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0, | |||
"width": "300px" | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
@@ -87,18 +114,18 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"default": "Open", | |||
"fieldname": "status", | |||
"fieldtype": "Select", | |||
"fieldname": "date", | |||
"fieldtype": "Date", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Status", | |||
"in_list_view": 0, | |||
"label": "Due Date", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Open\nClosed", | |||
"oldfieldname": "date", | |||
"oldfieldtype": "Date", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
@@ -113,20 +140,17 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"default": "Medium", | |||
"fieldname": "priority", | |||
"fieldtype": "Select", | |||
"fieldname": "owner", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_user_permissions": 1, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Priority", | |||
"label": "Allocated To", | |||
"length": 0, | |||
"no_copy": 0, | |||
"oldfieldname": "priority", | |||
"oldfieldtype": "Data", | |||
"options": "High\nMedium\nLow", | |||
"options": "User", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
@@ -141,19 +165,18 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "date", | |||
"fieldtype": "Date", | |||
"fieldname": "description_section", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Due Date", | |||
"label": "", | |||
"length": 0, | |||
"no_copy": 0, | |||
"oldfieldname": "date", | |||
"oldfieldtype": "Date", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
@@ -167,26 +190,29 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "owner", | |||
"fieldtype": "Link", | |||
"fieldname": "description", | |||
"fieldtype": "Text Editor", | |||
"hidden": 0, | |||
"ignore_user_permissions": 1, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Allocated To", | |||
"label": "Description", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "User", | |||
"oldfieldname": "description", | |||
"oldfieldtype": "Text", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"print_width": "300px", | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
"unique": 0, | |||
"width": "300px" | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
@@ -370,14 +396,14 @@ | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"icon": "icon-check", | |||
"idx": 0, | |||
"idx": 2, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-04-01 06:08:48.898505", | |||
"modified": "2016-04-07 01:35:53.935024", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "ToDo", | |||
@@ -17,7 +17,7 @@ def search_link(doctype, txt, query=None, filters=None, page_len=20, searchfield | |||
# this is called by the search box | |||
@frappe.whitelist() | |||
def search_widget(doctype, txt, query=None, searchfield=None, start=0, | |||
page_len=10, filters=None): | |||
page_len=10, filters=None, as_dict=False): | |||
if isinstance(filters, basestring): | |||
import json | |||
filters = json.loads(filters) | |||
@@ -31,8 +31,8 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0, | |||
if query and query.split()[0].lower()!="select": | |||
# by method | |||
frappe.response["values"] = frappe.get_attr(query)(doctype, txt, | |||
searchfield, start, page_len, filters) | |||
frappe.response["values"] = frappe.call(query, doctype, txt, | |||
searchfield, start, page_len, filters, as_dict=as_dict) | |||
elif not query and doctype in standard_queries: | |||
# from standard queries | |||
search_widget(doctype, txt, standard_queries[doctype][0], | |||
@@ -89,7 +89,8 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0, | |||
limit_page_length=page_len, | |||
order_by="if(_relevance, _relevance, 99999), idx desc, modified desc".format(doctype), | |||
ignore_permissions = True if doctype == "DocType" else False, # for dynamic links | |||
as_list=True) | |||
as_dict=as_dict, | |||
as_list=not as_dict) | |||
# remove _relevance from results | |||
frappe.response["values"] = [r[:-1] for r in values] | |||
@@ -31,11 +31,14 @@ frappe.ui.form.Grid = Class.extend({ | |||
.appendTo(this.parent) | |||
.attr("data-fieldname", this.df.fieldname); | |||
$(this.wrapper).find(".grid-add-row").click(function() { | |||
this.wrapper.find(".grid-add-row").click(function() { | |||
me.add_new_row(null, null, true); | |||
return false; | |||
}); | |||
this.custom_buttons = {}; | |||
this.grid_buttons = this.wrapper.find('.grid-buttons'); | |||
this.setup_allow_bulk_edit(); | |||
}, | |||
@@ -344,7 +347,23 @@ frappe.ui.form.Grid = Class.extend({ | |||
frappe.tools.downloadify(data, null, me.df.label); | |||
return false; | |||
}); | |||
}, | |||
add_custom_button: function(label, click) { | |||
// add / unhide a custom button | |||
var btn = this.custom_buttons[label]; | |||
if(!btn) { | |||
btn = $('<button class="btn btn-default btn-xs btn-custom">' + label + '</button>') | |||
.css('margin-right', '10px') | |||
.prependTo(this.grid_buttons) | |||
.on('click', click); | |||
this.custom_buttons[label] = btn; | |||
} else { | |||
btn.removeClass('hidden'); | |||
} | |||
}, | |||
clear_custom_buttons: function() { | |||
// hide all custom buttons | |||
this.grid_buttons.find('.btn-custom').addClass('hidden'); | |||
} | |||
}); | |||
@@ -6,7 +6,7 @@ | |||
<div class="grid-empty text-center hide">{%= __("No Data") %}</div> | |||
<div class="small form-clickable-section grid-footer"> | |||
<div class="row"> | |||
<div class="col-sm-6"> | |||
<div class="col-sm-6 grid-buttons"> | |||
<a href="#" class="grid-add-multiple-rows btn btn-xs btn-default hide" | |||
style="margin-right: 10px;"> | |||
{%= __("Add multiple rows") %}</a> | |||
@@ -498,7 +498,7 @@ frappe.ui.form.Section = Class.extend({ | |||
var missing_mandatory = false; | |||
for (var j=0, l=this.fields_list.length; j < l; j++) { | |||
var section_df = this.fields_list[j].df; | |||
if (section_df.reqd && this.layout.frm.doc[section_df.fieldname]==null) { | |||
if (section_df.reqd && this.layout.doc[section_df.fieldname]==null) { | |||
missing_mandatory = true; | |||
break; | |||
} | |||
@@ -2,7 +2,6 @@ | |||
// MIT License. See license.txt | |||
frappe.ui.form.LinkSelector = Class.extend({ | |||
_help: __("Dialog box to select a Link Value"), | |||
init: function(opts) { | |||
/* help: Options: doctype, get_query, target */ | |||
$.extend(this, opts); | |||
@@ -49,7 +48,6 @@ frappe.ui.form.LinkSelector = Class.extend({ | |||
search: function() { | |||
var args = { | |||
txt: this.dialog.fields_dict.txt.get_value(), | |||
doctype: this.doctype, | |||
searchfield: "name" | |||
}, | |||
me = this; | |||
@@ -65,55 +63,50 @@ frappe.ui.form.LinkSelector = Class.extend({ | |||
this.target.fieldinfo[this.fieldname].get_query(cur_frm.doc)); | |||
} | |||
return frappe.call({ | |||
method: "frappe.desk.search.search_widget", | |||
type: "GET", | |||
args: args, | |||
callback: function(r) { | |||
var parent = me.dialog.fields_dict.results.$wrapper; | |||
parent.empty(); | |||
if(r.values.length) { | |||
$.each(r.values, function(i, v) { | |||
var row = $(repl('<div class="row link-select-row">\ | |||
<div class="col-xs-4">\ | |||
<b><a href="#" data-value="%(name)s">%(name)s</a></b></div>\ | |||
<div class="col-xs-8">\ | |||
<span class="text-muted">%(values)s</span></div>\ | |||
</div>', { | |||
name: v[0], | |||
values: v.splice(1).join(", ") | |||
})).appendTo(parent); | |||
frappe.link_search(this.doctype, args, function(r) { | |||
var parent = me.dialog.fields_dict.results.$wrapper; | |||
parent.empty(); | |||
if(r.values.length) { | |||
$.each(r.values, function(i, v) { | |||
var row = $(repl('<div class="row link-select-row">\ | |||
<div class="col-xs-4">\ | |||
<b><a href="#" data-value="%(name)s">%(name)s</a></b></div>\ | |||
<div class="col-xs-8">\ | |||
<span class="text-muted">%(values)s</span></div>\ | |||
</div>', { | |||
name: v[0], | |||
values: v.splice(1).join(", ") | |||
})).appendTo(parent); | |||
row.find("a").click(function() { | |||
var value = $(this).attr("data-value"); | |||
var $link = this; | |||
if(me.target.is_grid) { | |||
// set in grid | |||
me.set_in_grid(value); | |||
} else { | |||
if(me.target.doctype) | |||
me.target.parse_validate_and_set_in_model(value); | |||
else { | |||
me.target.set_input(value); | |||
me.target.$input.trigger("change"); | |||
} | |||
me.dialog.hide(); | |||
row.find("a").click(function() { | |||
var value = $(this).attr("data-value"); | |||
var $link = this; | |||
if(me.target.is_grid) { | |||
// set in grid | |||
me.set_in_grid(value); | |||
} else { | |||
if(me.target.doctype) | |||
me.target.parse_validate_and_set_in_model(value); | |||
else { | |||
me.target.set_input(value); | |||
me.target.$input.trigger("change"); | |||
} | |||
return false; | |||
}) | |||
me.dialog.hide(); | |||
} | |||
return false; | |||
}) | |||
} else { | |||
$('<div class="alert alert-info">' + __("No Results") | |||
+ (frappe.model.can_read(me.doctype) ? | |||
('. <a class="new-doc">' | |||
+ __("Make a new") + " " + __(me.doctype) + "</a>") : '') | |||
+ '</div>').appendTo(parent).find(".new-doc").click(function() { | |||
me.target.new_doc(); | |||
}); | |||
} | |||
}, | |||
btn: this.dialog.get_primary_btn() | |||
}); | |||
}) | |||
} else { | |||
$('<div class="alert alert-info">' + __("No Results") | |||
+ (frappe.model.can_read(me.doctype) ? | |||
('. <a class="new-doc">' | |||
+ __("Make a new") + " " + __(me.doctype) + "</a>") : '') | |||
+ '</div>').appendTo(parent).find(".new-doc").click(function() { | |||
me.target.new_doc(); | |||
}); | |||
} | |||
}, this.dialog.get_primary_btn()); | |||
}, | |||
set_in_grid: function(value) { | |||
var me = this, updated = false; | |||
@@ -145,4 +138,27 @@ frappe.ui.form.LinkSelector = Class.extend({ | |||
show_alert(__("{0} added", [value])); | |||
} | |||
} | |||
}) | |||
}); | |||
frappe.link_search = function(doctype, args, callback, btn) { | |||
if(!args) { | |||
args: { | |||
txt: '' | |||
} | |||
} | |||
args.doctype = doctype; | |||
if(!args.searchfield) { | |||
args.searchfield = 'name'; | |||
} | |||
frappe.call({ | |||
method: "frappe.desk.search.search_widget", | |||
type: "GET", | |||
args: args, | |||
callback: function(r) { | |||
callback && callback(r); | |||
}, | |||
btn: btn | |||
}); | |||
} | |||
@@ -288,9 +288,11 @@ frappe.ui.Page = Class.extend({ | |||
set_title: function(txt, icon) { | |||
if(!txt) txt = ""; | |||
// strip icon | |||
// strip html | |||
txt = txt.replace(/<[^>]*>/g, ""); | |||
this.title = txt; | |||
frappe.utils.set_title(txt.replace(/<[^>]*>/g, "")); | |||
frappe.utils.set_title(txt); | |||
if(icon) { | |||
txt = '<span class="'+ icon +' text-muted" style="font-size: inherit;"></span> ' + txt; | |||
} | |||
@@ -427,7 +427,7 @@ _f.Frm.prototype.refresh = function(docname) { | |||
this.print_preview.preview(); | |||
} | |||
if(is_a_different_doc && this.doc.docstatus===1) { | |||
if(this.show_print_first && is_a_different_doc && this.doc.docstatus===1) { | |||
// show print view | |||
this.print_doc(); | |||
} | |||