Преглед изворни кода

[fix] text editor in firefox

version-14
Rushabh Mehta пре 7 година
родитељ
комит
78995ceb3e
10 измењених фајлова са 110 додато и 47 уклоњено
  1. +2
    -2
      frappe/__init__.py
  2. +6
    -4
      frappe/core/doctype/communication/communication.py
  3. +0
    -3
      frappe/core/doctype/communication/email.py
  4. +23
    -0
      frappe/desk/doctype/todo/test_todo.js
  5. +9
    -9
      frappe/desk/doctype/todo/todo.json
  6. +0
    -1
      frappe/email/doctype/email_account/email_account.py
  7. +46
    -22
      frappe/model/document.py
  8. +22
    -4
      frappe/public/js/frappe/form/controls/text_editor.js
  9. +1
    -1
      frappe/public/js/frappe/socketio_client.js
  10. +1
    -1
      frappe/public/js/legacy/form.js

+ 2
- 2
frappe/__init__.py Прегледај датотеку

@@ -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."""


+ 6
- 4
frappe/core/doctype/communication/communication.py Прегледај датотеку

@@ -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 },


+ 0
- 3
frappe/core/doctype/communication/email.py Прегледај датотеку

@@ -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


+ 23
- 0
frappe/desk/doctype/todo/test_todo.js Прегледај датотеку

@@ -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()
]);

});

+ 9
- 9
frappe/desk/doctype/todo/todo.json Прегледај датотеку

@@ -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",


+ 0
- 1
frappe/email/doctype/email_account/email_account.py Прегледај датотеку

@@ -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()


+ 46
- 22
frappe/model/document.py Прегледај датотеку

@@ -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"""


+ 22
- 4
frappe/public/js/frappe/form/controls/text_editor.js Прегледај датотеку

@@ -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);
} }


+ 1
- 1
frappe/public/js/frappe/socketio_client.js Прегледај датотеку

@@ -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;
} }


+ 1
- 1
frappe/public/js/legacy/form.js Прегледај датотеку

@@ -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();


Loading…
Откажи
Сачувај