[fix] text editor in firefoxversion-14
@@ -602,7 +602,7 @@ def set_value(doctype, docname, fieldname, value=None): | |||
import frappe.client | |||
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. | |||
:param arg1: DocType name as string **or** document JSON. | |||
@@ -619,7 +619,7 @@ def get_doc(arg1, arg2=None): | |||
""" | |||
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): | |||
"""Get last created document of this type.""" | |||
@@ -25,7 +25,7 @@ class Communication(Document): | |||
"""create email flag queue""" | |||
if self.communication_type == "Communication" and self.communication_medium == "Email" \ | |||
and self.sent_or_received == "Received" and self.uid and self.uid != -1: | |||
email_flag_queue = frappe.db.get_value("Email Flag Queue", { | |||
"communication": self.name, | |||
"is_completed": 0}) | |||
@@ -69,7 +69,7 @@ class Communication(Document): | |||
def after_insert(self): | |||
if not (self.reference_doctype and self.reference_name): | |||
return | |||
if self.reference_doctype == "Communication" and self.sent_or_received == "Sent": | |||
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) \ | |||
or (doc.timeline_doctype == "Communication" and doc.timeline_name == doc.name): | |||
return | |||
if doc.reference_doctype and doc.reference_name: | |||
if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name): | |||
return True | |||
@@ -277,7 +277,9 @@ def get_permission_query_conditions_for_communication(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 | |||
else: | |||
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): | |||
"""Update status of parent document based on who is replying.""" | |||
if doc.communication_type != "Communication": | |||
return | |||
parent = doc.get_parent_doc() | |||
if not parent: | |||
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, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "color", | |||
"fieldtype": "Color", | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Color", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
@@ -142,18 +140,20 @@ | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break", | |||
"fieldname": "color", | |||
"fieldtype": "Color", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Color", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
@@ -544,7 +544,7 @@ | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2017-09-05 12:54:58.044162", | |||
"modified": "2017-09-30 13:57:29.398598", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "ToDo", | |||
@@ -273,7 +273,6 @@ class EmailAccount(Document): | |||
"uid_reindexed": uid_reindexed | |||
} | |||
communication = self.insert_communication(msg, args=args) | |||
#self.notify_update() | |||
except SentEmailInInbox: | |||
frappe.db.rollback() | |||
@@ -20,13 +20,13 @@ from frappe.integrations.doctype.webhook import run_webhooks | |||
# once_only validation | |||
# methods | |||
def get_doc(arg1, arg2=None): | |||
def get_doc(*args, **kwargs): | |||
"""returns a frappe.model.Document object. | |||
:param arg1: Document dict or DocType 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 | |||
user = get_doc("User", "test@example.com") | |||
@@ -39,23 +39,39 @@ def get_doc(arg1, arg2=None): | |||
{"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) | |||
if controller: | |||
return controller(arg1, arg2) | |||
return controller(*args, **kwargs) | |||
raise ImportError(arg1) | |||
raise ImportError(doctype) | |||
class Document(BaseDocument): | |||
"""All controllers inherit from `Document`.""" | |||
def __init__(self, arg1, arg2=None): | |||
def __init__(self, *args, **kwargs): | |||
"""Constructor. | |||
:param arg1: DocType name as string or document **dict** | |||
@@ -68,29 +84,37 @@ class Document(BaseDocument): | |||
self._default_new_docs = {} | |||
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 | |||
self.doctype = self.name = arg1 | |||
self.doctype = self.name = args[0] | |||
else: | |||
self.doctype = arg1 | |||
if isinstance(arg2, dict): | |||
self.doctype = args[0] | |||
if isinstance(args[1], dict): | |||
# 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: | |||
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: | |||
self.name = arg2 | |||
self.name = args[1] | |||
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() | |||
else: | |||
# incorrect arguments. let's not proceed. | |||
raise frappe.DataError("Document({0}, {1})".format(arg1, arg2)) | |||
raise ValueError('Illegal arguments') | |||
def reload(self): | |||
"""Reload document from database""" | |||
@@ -6,6 +6,11 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ | |||
this.setup_drag_drop(); | |||
this.setup_image_dialog(); | |||
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) => { | |||
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); | |||
}, | |||
onKeydown: function(e) { | |||
me._last_change_on = new Date(); | |||
me.last_keystroke_on = new Date(); | |||
var key = frappe.ui.keys.get_key(e); | |||
// prevent 'New DocType (Ctrl + B)' shortcut in editor | |||
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) { | |||
// 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; | |||
} | |||
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); | |||
this.editor.summernote('code', value || ''); | |||
this.last_keystroke_on = null; | |||
} 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(() => { | |||
if(time_since_last_keystroke > 3000) { | |||
// 3 seconds done! lets refresh | |||
// safe to update | |||
if(this.last_value !== this.get_input_value()) { | |||
// if not already in sync, reset | |||
this.editor.summernote('code', this.last_value || ''); | |||
@@ -226,6 +241,9 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ | |||
clearInterval(this._setting_value); | |||
this._setting_value = null; | |||
this.setting_count = 0; | |||
// clear timestamp of last keystroke | |||
this.last_keystroke_on = null; | |||
} | |||
}, 1000); | |||
} | |||
@@ -73,7 +73,7 @@ frappe.socketio = { | |||
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()) { | |||
return; | |||
} | |||
@@ -497,7 +497,7 @@ _f.Frm.prototype.render_form = function(is_a_different_doc) { | |||
// trigger global trigger | |||
// to use this | |||
$(document).trigger('form_refresh', [this]); | |||
$(document).trigger('form-refresh', [this]); | |||
// fields | |||
this.refresh_fields(); | |||