From 4027a3cda392a85db74ae5efab3771a303fd3f08 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sun, 23 Sep 2012 19:24:05 -0500 Subject: [PATCH] SQLFORM().accepts(onvalidation=dict(onchange=lambda....)), thanks Alan --- VERSION | 2 +- gluon/html.py | 26 ++++++++++++++++++++++++-- gluon/sqlhtml.py | 24 +++++++++++++++++++----- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index dcbbf3cd..02c893ea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-23 19:16:20) stable +Version 2.0.9 (2012-09-23 19:24:01) stable diff --git a/gluon/html.py b/gluon/html.py index 471756f3..77fb0bd4 100644 --- a/gluon/html.py +++ b/gluon/html.py @@ -1938,6 +1938,7 @@ class FORM(DIV): # check formname and formkey status = True + changed = False request_vars = self.request_vars if session: formkey = session.get('_formkey[%s]' % formname, None) @@ -1950,18 +1951,23 @@ class FORM(DIV): # check if editing a record that has been modified by the server if hasattr(self,'record_hash') and self.record_hash != formkey: status = False - self.record_changed = True + self.record_changed = changed = True status = self._traverse(status,hideerror) status = self.assert_status(status, request_vars) if onvalidation: if isinstance(onvalidation, dict): onsuccess = onvalidation.get('onsuccess', None) onfailure = onvalidation.get('onfailure', None) + onchange = onvalidation.get('onchange', None) if onsuccess and status: onsuccess(self) if onfailure and request_vars and not status: onfailure(self) status = len(self.errors) == 0 + if changed: + if onchange and self.record_changed and \ + self.detect_record_change: + onchange(self) elif status: if isinstance(onvalidation, (list, tuple)): [f(self) for f in onvalidation] @@ -2030,8 +2036,13 @@ class FORM(DIV): onfailure = 'flash' - will show message_onfailure in response.flash None - will do nothing can be a function (lambda form: pass) + onchange = 'flash' - will show message_onchange in response.flash + None - will do nothing + can be a function (lambda form: pass) + message_onsuccess message_onfailure + message_onchange next = where to redirect in case of success any other kwargs will be passed for form.accepts(...) """ @@ -2042,13 +2053,17 @@ class FORM(DIV): onsuccess = kwargs.get('onsuccess','flash') onfailure = kwargs.get('onfailure','flash') + onchange = kwargs.get('onchange', 'flash') message_onsuccess = kwargs.get('message_onsuccess', current.T("Success!")) message_onfailure = kwargs.get('message_onfailure', current.T("Errors in form, please check it out.")) + message_onchange = kwargs.get('message_onchange', + current.T("Form consecutive submissions not allowed. " + + "Try re-submitting or refreshing the form page.")) next = kwargs.get('next',None) for key in ('message_onsuccess','message_onfailure','onsuccess', - 'onfailure','next'): + 'onfailure','next', 'message_onchange', 'onchange'): if key in kwargs: del kwargs[key] @@ -2075,6 +2090,13 @@ class FORM(DIV): elif callable(onfailure): onfailure(self) return False + elif hasattr(self, "record_changed"): + if self.record_changed and self.detect_record_change: + if onchange == 'flash': + current.response.flash = message_onchange + elif callable(onchange): + onchange(self) + return False def process(self, **kwargs): """ diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 26cc90b8..bd36d6cd 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -888,6 +888,8 @@ class SQLFORM(FORM): self.ignore_rw = ignore_rw self.formstyle = formstyle self.readonly = readonly + # Default dbio setting + self.detect_record_change = None nbsp = XML(' ') # Firefox2 does not display fields with blanks FORM.__init__(self, *[], **attributes) @@ -1165,6 +1167,7 @@ class SQLFORM(FORM): dbio=True, hideerror=False, detect_record_change=False, + **kwargs ): """ @@ -1189,7 +1192,8 @@ class SQLFORM(FORM): # implement logic to detect whether record exist but has been modified # server side self.record_changed = None - if detect_record_change: + self.detect_record_change = detect_record_change + if self.detect_record_change: if self.record: self.record_changed = False serialized = '|'.join(str(self.record[k]) for k in self.table.fields()) @@ -1245,6 +1249,7 @@ class SQLFORM(FORM): keepvalues, onvalidation, hideerror=hideerror, + **kwargs ) self.deleted = \ @@ -1254,10 +1259,19 @@ class SQLFORM(FORM): auch = record_id and self.errors and self.deleted - # auch is true when user tries to delete a record - # that does not pass validation, yet it should be deleted - - if not ret and not auch: + if self.record_changed and self.detect_record_change: + message_onchange = \ + kwargs.setdefault("message_onchange", + current.T("A record change was detected. " + + "Consecutive update self-submissions " + + "are not allowed. Try re-submitting or " + + "refreshing the form page.")) + if message_onchange is not None: + current.response.flash = message_onchange + return ret + elif (not ret) and (not auch): + # auch is true when user tries to delete a record + # that does not pass validation, yet it should be deleted for fieldname in self.fields: field = self.table[fieldname] ### this is a workaround! widgets should always have default not None!