[fix] text editor in firefoxversion-14
@@ -602,7 +602,7 @@ def set_value(doctype, docname, fieldname, value=None): | |||||
import frappe.client | import frappe.client | ||||
return frappe.client.set_value(doctype, docname, fieldname, value) | return frappe.client.set_value(doctype, docname, fieldname, value) | ||||
def get_doc(arg1, arg2=None): | |||||
def get_doc(*args, **kwargs): | |||||
"""Return a `frappe.model.document.Document` object of the given type and name. | """Return a `frappe.model.document.Document` object of the given type and name. | ||||
:param arg1: DocType name as string **or** document JSON. | :param arg1: DocType name as string **or** document JSON. | ||||
@@ -619,7 +619,7 @@ def get_doc(arg1, arg2=None): | |||||
""" | """ | ||||
import frappe.model.document | import frappe.model.document | ||||
return frappe.model.document.get_doc(arg1, arg2) | |||||
return frappe.model.document.get_doc(*args, **kwargs) | |||||
def get_last_doc(doctype): | def get_last_doc(doctype): | ||||
"""Get last created document of this type.""" | """Get last created document of this type.""" | ||||
@@ -25,7 +25,7 @@ class Communication(Document): | |||||
"""create email flag queue""" | """create email flag queue""" | ||||
if self.communication_type == "Communication" and self.communication_medium == "Email" \ | if self.communication_type == "Communication" and self.communication_medium == "Email" \ | ||||
and self.sent_or_received == "Received" and self.uid and self.uid != -1: | and self.sent_or_received == "Received" and self.uid and self.uid != -1: | ||||
email_flag_queue = frappe.db.get_value("Email Flag Queue", { | email_flag_queue = frappe.db.get_value("Email Flag Queue", { | ||||
"communication": self.name, | "communication": self.name, | ||||
"is_completed": 0}) | "is_completed": 0}) | ||||
@@ -69,7 +69,7 @@ class Communication(Document): | |||||
def after_insert(self): | def after_insert(self): | ||||
if not (self.reference_doctype and self.reference_name): | if not (self.reference_doctype and self.reference_name): | ||||
return | return | ||||
if self.reference_doctype == "Communication" and self.sent_or_received == "Sent": | if self.reference_doctype == "Communication" and self.sent_or_received == "Sent": | ||||
frappe.db.set_value("Communication", self.reference_name, "status", "Replied") | frappe.db.set_value("Communication", self.reference_name, "status", "Replied") | ||||
@@ -264,7 +264,7 @@ def has_permission(doc, ptype, user): | |||||
if (doc.reference_doctype == "Communication" and doc.reference_name == doc.name) \ | if (doc.reference_doctype == "Communication" and doc.reference_name == doc.name) \ | ||||
or (doc.timeline_doctype == "Communication" and doc.timeline_name == doc.name): | or (doc.timeline_doctype == "Communication" and doc.timeline_name == doc.name): | ||||
return | return | ||||
if doc.reference_doctype and doc.reference_name: | if doc.reference_doctype and doc.reference_name: | ||||
if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name): | if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name): | ||||
return True | return True | ||||
@@ -277,7 +277,9 @@ def get_permission_query_conditions_for_communication(user): | |||||
if not user: user = frappe.session.user | if not user: user = frappe.session.user | ||||
if "Super Email User" in frappe.get_roles(user): | |||||
roles = frappe.get_roles(user) | |||||
if "Super Email User" in roles or "System Manager" in roles: | |||||
return None | return None | ||||
else: | else: | ||||
accounts = frappe.get_all("User Email", filters={ "parent": user }, | accounts = frappe.get_all("User Email", filters={ "parent": user }, | ||||
@@ -166,9 +166,6 @@ def _notify(doc, print_html=None, print_format=None, attachments=None, | |||||
def update_parent_status(doc): | def update_parent_status(doc): | ||||
"""Update status of parent document based on who is replying.""" | """Update status of parent document based on who is replying.""" | ||||
if doc.communication_type != "Communication": | |||||
return | |||||
parent = doc.get_parent_doc() | parent = doc.get_parent_doc() | ||||
if not parent: | if not parent: | ||||
return | return | ||||
@@ -0,0 +1,23 @@ | |||||
/* eslint-disable */ | |||||
// rename this file from _test_[name] to test_[name] to activate | |||||
// and remove above this line | |||||
QUnit.test("test: ToDo", function (assert) { | |||||
let done = assert.async(); | |||||
// number of asserts | |||||
assert.expect(1); | |||||
frappe.run_serially([ | |||||
// insert a new ToDo | |||||
() => frappe.tests.make('ToDo', [ | |||||
// values to be set | |||||
{key: 'value'} | |||||
]), | |||||
() => { | |||||
assert.equal(cur_frm.doc.key, 'value'); | |||||
}, | |||||
() => done() | |||||
]); | |||||
}); |
@@ -112,20 +112,18 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"fieldname": "color", | |||||
"fieldtype": "Color", | |||||
"fieldname": "column_break_2", | |||||
"fieldtype": "Column Break", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
"in_filter": 0, | "in_filter": 0, | ||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 1, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Color", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"permlevel": 0, | "permlevel": 0, | ||||
"precision": "", | |||||
"print_hide": 0, | "print_hide": 0, | ||||
"print_hide_if_no_value": 0, | "print_hide_if_no_value": 0, | ||||
"read_only": 0, | "read_only": 0, | ||||
@@ -142,18 +140,20 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"fieldname": "column_break_2", | |||||
"fieldtype": "Column Break", | |||||
"fieldname": "color", | |||||
"fieldtype": "Color", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
"in_filter": 0, | "in_filter": 0, | ||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | |||||
"in_list_view": 1, | |||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Color", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"permlevel": 0, | "permlevel": 0, | ||||
"precision": "", | |||||
"print_hide": 0, | "print_hide": 0, | ||||
"print_hide_if_no_value": 0, | "print_hide_if_no_value": 0, | ||||
"read_only": 0, | "read_only": 0, | ||||
@@ -544,7 +544,7 @@ | |||||
"issingle": 0, | "issingle": 0, | ||||
"istable": 0, | "istable": 0, | ||||
"max_attachments": 0, | "max_attachments": 0, | ||||
"modified": "2017-09-05 12:54:58.044162", | |||||
"modified": "2017-09-30 13:57:29.398598", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Desk", | "module": "Desk", | ||||
"name": "ToDo", | "name": "ToDo", | ||||
@@ -273,7 +273,6 @@ class EmailAccount(Document): | |||||
"uid_reindexed": uid_reindexed | "uid_reindexed": uid_reindexed | ||||
} | } | ||||
communication = self.insert_communication(msg, args=args) | communication = self.insert_communication(msg, args=args) | ||||
#self.notify_update() | |||||
except SentEmailInInbox: | except SentEmailInInbox: | ||||
frappe.db.rollback() | frappe.db.rollback() | ||||
@@ -20,13 +20,13 @@ from frappe.integrations.doctype.webhook import run_webhooks | |||||
# once_only validation | # once_only validation | ||||
# methods | # methods | ||||
def get_doc(arg1, arg2=None): | |||||
def get_doc(*args, **kwargs): | |||||
"""returns a frappe.model.Document object. | """returns a frappe.model.Document object. | ||||
:param arg1: Document dict or DocType name. | :param arg1: Document dict or DocType name. | ||||
:param arg2: [optional] document name. | :param arg2: [optional] document name. | ||||
There are two ways to call `get_doc` | |||||
There are multiple ways to call `get_doc` | |||||
# will fetch the latest user object (with child table) from the database | # will fetch the latest user object (with child table) from the database | ||||
user = get_doc("User", "test@example.com") | user = get_doc("User", "test@example.com") | ||||
@@ -39,23 +39,39 @@ def get_doc(arg1, arg2=None): | |||||
{"role": "System Manager"} | {"role": "System Manager"} | ||||
] | ] | ||||
}) | }) | ||||
# create new object with keyword arguments | |||||
user = get_doc(doctype='User', email_id='test@example.com') | |||||
""" | """ | ||||
if isinstance(arg1, BaseDocument): | |||||
return arg1 | |||||
elif isinstance(arg1, string_types): | |||||
doctype = arg1 | |||||
else: | |||||
doctype = arg1.get("doctype") | |||||
if args: | |||||
if isinstance(args[0], BaseDocument): | |||||
# already a document | |||||
return args[0] | |||||
elif isinstance(args[0], string_types): | |||||
doctype = args[0] | |||||
elif isinstance(args[0], dict): | |||||
# passed a dict | |||||
kwargs = args[0] | |||||
else: | |||||
raise ValueError('First non keyword argument must be a string or dict') | |||||
if kwargs: | |||||
if 'doctype' in kwargs: | |||||
doctype = kwargs['doctype'] | |||||
else: | |||||
raise ValueError('"doctype" is a required key') | |||||
controller = get_controller(doctype) | controller = get_controller(doctype) | ||||
if controller: | if controller: | ||||
return controller(arg1, arg2) | |||||
return controller(*args, **kwargs) | |||||
raise ImportError(arg1) | |||||
raise ImportError(doctype) | |||||
class Document(BaseDocument): | class Document(BaseDocument): | ||||
"""All controllers inherit from `Document`.""" | """All controllers inherit from `Document`.""" | ||||
def __init__(self, arg1, arg2=None): | |||||
def __init__(self, *args, **kwargs): | |||||
"""Constructor. | """Constructor. | ||||
:param arg1: DocType name as string or document **dict** | :param arg1: DocType name as string or document **dict** | ||||
@@ -68,29 +84,37 @@ class Document(BaseDocument): | |||||
self._default_new_docs = {} | self._default_new_docs = {} | ||||
self.flags = frappe._dict() | self.flags = frappe._dict() | ||||
if arg1 and isinstance(arg1, string_types): | |||||
if not arg2: | |||||
if args and args[0] and isinstance(args[0], string_types): | |||||
# first arugment is doctype | |||||
if len(args)==1: | |||||
# single | # single | ||||
self.doctype = self.name = arg1 | |||||
self.doctype = self.name = args[0] | |||||
else: | else: | ||||
self.doctype = arg1 | |||||
if isinstance(arg2, dict): | |||||
self.doctype = args[0] | |||||
if isinstance(args[1], dict): | |||||
# filter | # filter | ||||
self.name = frappe.db.get_value(arg1, arg2, "name") | |||||
self.name = frappe.db.get_value(args[0], args[1], "name") | |||||
if self.name is None: | if self.name is None: | ||||
frappe.throw(_("{0} {1} not found").format(_(arg1), arg2), frappe.DoesNotExistError) | |||||
frappe.throw(_("{0} {1} not found").format(_(args[0]), args[1]), | |||||
frappe.DoesNotExistError) | |||||
else: | else: | ||||
self.name = arg2 | |||||
self.name = args[1] | |||||
self.load_from_db() | self.load_from_db() | ||||
return | |||||
if args and args[0] and isinstance(args[0], dict): | |||||
# first argument is a dict | |||||
kwargs = args[0] | |||||
elif isinstance(arg1, dict): | |||||
super(Document, self).__init__(arg1) | |||||
if kwargs: | |||||
# init base document | |||||
super(Document, self).__init__(kwargs) | |||||
self.init_valid_columns() | self.init_valid_columns() | ||||
else: | else: | ||||
# incorrect arguments. let's not proceed. | # incorrect arguments. let's not proceed. | ||||
raise frappe.DataError("Document({0}, {1})".format(arg1, arg2)) | |||||
raise ValueError('Illegal arguments') | |||||
def reload(self): | def reload(self): | ||||
"""Reload document from database""" | """Reload document from database""" | ||||
@@ -6,6 +6,11 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ | |||||
this.setup_drag_drop(); | this.setup_drag_drop(); | ||||
this.setup_image_dialog(); | this.setup_image_dialog(); | ||||
this.setting_count = 0; | this.setting_count = 0; | ||||
$(document).on('form-refresh', () => { | |||||
// reset last keystroke when a new form is loaded | |||||
this.last_keystroke_on = null; | |||||
}) | |||||
}, | }, | ||||
render_camera_button: (context) => { | render_camera_button: (context) => { | ||||
var ui = $.summernote.ui; | var ui = $.summernote.ui; | ||||
@@ -74,7 +79,7 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ | |||||
me.parse_validate_and_set_in_model(value); | me.parse_validate_and_set_in_model(value); | ||||
}, | }, | ||||
onKeydown: function(e) { | onKeydown: function(e) { | ||||
me._last_change_on = new Date(); | |||||
me.last_keystroke_on = new Date(); | |||||
var key = frappe.ui.keys.get_key(e); | var key = frappe.ui.keys.get_key(e); | ||||
// prevent 'New DocType (Ctrl + B)' shortcut in editor | // prevent 'New DocType (Ctrl + B)' shortcut in editor | ||||
if(['ctrl+b', 'meta+b'].indexOf(key) !== -1) { | if(['ctrl+b', 'meta+b'].indexOf(key) !== -1) { | ||||
@@ -205,20 +210,30 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ | |||||
if(this.setting_count > 2) { | if(this.setting_count > 2) { | ||||
// we don't understand how the internal triggers work, | // we don't understand how the internal triggers work, | ||||
// so if someone is setting the value third time, then quit | |||||
// so if someone is setting the value third time in 500ms, | |||||
// then quit | |||||
return; | return; | ||||
} | } | ||||
this.setting_count += 1; | this.setting_count += 1; | ||||
let time_since_last_keystroke = moment() - moment(this._last_change_on); | |||||
let time_since_last_keystroke = moment() - moment(this.last_keystroke_on); | |||||
if(!this._last_change_on || (time_since_last_keystroke > 3000)) { | |||||
if(!this.last_keystroke_on || (time_since_last_keystroke > 3000)) { | |||||
// if 3 seconds have passed since the last keystroke and | |||||
// we have not set any value in the last 1 second, do this | |||||
setTimeout(() => this.setting_count = 0, 500); | setTimeout(() => this.setting_count = 0, 500); | ||||
this.editor.summernote('code', value || ''); | this.editor.summernote('code', value || ''); | ||||
this.last_keystroke_on = null; | |||||
} else { | } else { | ||||
// user is probably still in the middle of typing | |||||
// so lets not mess up the html by re-updating it | |||||
// keep checking every second if our 3 second barrier | |||||
// has been completed, so that we can refresh the html | |||||
this._setting_value = setInterval(() => { | this._setting_value = setInterval(() => { | ||||
if(time_since_last_keystroke > 3000) { | if(time_since_last_keystroke > 3000) { | ||||
// 3 seconds done! lets refresh | |||||
// safe to update | |||||
if(this.last_value !== this.get_input_value()) { | if(this.last_value !== this.get_input_value()) { | ||||
// if not already in sync, reset | // if not already in sync, reset | ||||
this.editor.summernote('code', this.last_value || ''); | this.editor.summernote('code', this.last_value || ''); | ||||
@@ -226,6 +241,9 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ | |||||
clearInterval(this._setting_value); | clearInterval(this._setting_value); | ||||
this._setting_value = null; | this._setting_value = null; | ||||
this.setting_count = 0; | this.setting_count = 0; | ||||
// clear timestamp of last keystroke | |||||
this.last_keystroke_on = null; | |||||
} | } | ||||
}, 1000); | }, 1000); | ||||
} | } | ||||
@@ -73,7 +73,7 @@ frappe.socketio = { | |||||
frappe.socketio.doc_subscribe(frm.doctype, frm.docname); | frappe.socketio.doc_subscribe(frm.doctype, frm.docname); | ||||
}); | }); | ||||
$(document).on("form_refresh", function(e, frm) { | |||||
$(document).on("form-refresh", function(e, frm) { | |||||
if (frm.is_new()) { | if (frm.is_new()) { | ||||
return; | return; | ||||
} | } | ||||
@@ -497,7 +497,7 @@ _f.Frm.prototype.render_form = function(is_a_different_doc) { | |||||
// trigger global trigger | // trigger global trigger | ||||
// to use this | // to use this | ||||
$(document).trigger('form_refresh', [this]); | |||||
$(document).trigger('form-refresh', [this]); | |||||
// fields | // fields | ||||
this.refresh_fields(); | this.refresh_fields(); | ||||