Enhance form handling and response structure in BaseView and user login flow

1 parent c69c7bef
...@@ -20,6 +20,7 @@ from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close, btn_delete, ...@@ -20,6 +20,7 @@ from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close, btn_delete,
btn_pdf, btn_unpost, btn_post btn_pdf, btn_unpost, btn_post
from opensipkd.tools.captcha import get_captcha from opensipkd.tools.captcha import get_captcha
from opensipkd.tools.report import csv_response, file_response from opensipkd.tools.report import csv_response, file_response
from pyramid.request import Response
from .common import DataTables from .common import DataTables
from .. import DBSession, get_params, get_urls from .. import DBSession, get_params, get_urls
from ..scripts.initializedb import append_csv from ..scripts.initializedb import append_csv
...@@ -199,7 +200,19 @@ class BaseView(object): ...@@ -199,7 +200,19 @@ class BaseView(object):
'jenis'] or self.jenis 'jenis'] or self.jenis
self.ses['jenis'] = self.jenis self.ses['jenis'] = self.jenis
def form2dict(self, field):
children = []
for c in field.children:
children.append(self.form2dict(c))
d = {
"id": field.oid,
"name": field.name,
"error" : {"msg": field.error and field.error.msg or ""},
"children":children
}
return d
def query_register(self, **kwargs): def query_register(self, **kwargs):
pass pass
...@@ -546,6 +559,10 @@ class BaseView(object): ...@@ -546,6 +559,10 @@ class BaseView(object):
return self.route_list(**kwargs) return self.route_list(**kwargs)
def returned_form(self, form, table=None, **kwargs): def returned_form(self, form, table=None, **kwargs):
if self.req.is_xhr:
d = self.form2dict(form.field)
return Response(json=d)
resources = form.get_widget_resources() resources = form.get_widget_resources()
readonly = "readonly" in kwargs and kwargs["readonly"] or False readonly = "readonly" in kwargs and kwargs["readonly"] or False
kwargs["readonly"] = readonly kwargs["readonly"] = readonly
...@@ -556,18 +573,21 @@ class BaseView(object): ...@@ -556,18 +573,21 @@ class BaseView(object):
table = table["form"] table = table["form"]
# resources["js"] = list(resources["js"]) # resources["js"] = list(resources["js"])
# resources["css"] = list(resources["css"]) # resources["css"] = list(resources["css"])
if is_object: if not is_object:
return dict(form=form, form = form.render(readonly=readonly)
table=table and table.render() or None,
scripts=self.form_scripts, # return dict(form=form,
css=resources["css"], # table=table and table.render() or None,
js=resources["js"], # scripts=self.form_scripts,
**kwargs # css=resources["css"],
) # js=resources["js"],
# **kwargs
return dict(form=form.render(readonly=readonly), # )
return dict(form=form,
table=table and table.render() or None, table=table and table.render() or None,
scripts=self.form_scripts, css=resources["css"], scripts=self.form_scripts,
css=resources["css"],
js=resources["js"], js=resources["js"],
**kwargs **kwargs
) )
......
...@@ -312,7 +312,7 @@ class Registrasi(BaseView): ...@@ -312,7 +312,7 @@ class Registrasi(BaseView):
forget(self.req) forget(self.req)
self.ses.delete() self.ses.delete()
@view_config(route_name='register', renderer='templates/form.pt') # @view_config(route_name='register', renderer='templates/form.pt')
def view_register(self): def view_register(self):
self.bindings = dict(user=None) self.bindings = dict(user=None)
request = self.req request = self.req
......
<html metal:use-macro="load: ./base3.1.pt" tal:define="
scripts scripts|scripts;
readonly readonly|readonly;">
<div metal:fill-slot="content">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-fw fa-plus"></i>&nbsp;${request.title}</h3>
</div>
<div class="panel-body">
<div tal:content="structure form.render(readonly=readonly)"></div>
</div>
</div>
</div>
<div metal:fill-slot="scripts">
<script>
$(document).ready(function () {
// $(".read-only").attr("readonly", true);
$(".readonly").attr("readonly", true);
$(".date").attr("readonly", true);
// $(".date").datepicker({
// format: 'dd-mm-yyyy'
// });
${ structure: scripts }
});
</script>
<div metal:define-slot="scripts"></div>
</div>
</html>
\ No newline at end of file \ No newline at end of file
...@@ -23,7 +23,7 @@ import os ...@@ -23,7 +23,7 @@ import os
import re import re
from datetime import timedelta, datetime from datetime import timedelta, datetime
from importlib import import_module from importlib import import_module
from pyramid.request import Response
import colander import colander
from deform import widget, Form, ValidationFailure, Button from deform import widget, Form, ValidationFailure, Button
from pyramid.csrf import new_csrf_token from pyramid.csrf import new_csrf_token
...@@ -196,7 +196,12 @@ class ViewLogin(BaseView): ...@@ -196,7 +196,12 @@ class ViewLogin(BaseView):
except ValidationFailure as e: except ValidationFailure as e:
msg = 'Login gagal' msg = 'Login gagal'
set_user_log(msg, request, log, identity) set_user_log(msg, request, log, identity)
if self.req.is_xhr:
d = self.form2dict(form.field)
return Response(json=d)
request.session.flash(msg, 'error') request.session.flash(msg, 'error')
return HTTPFound(location=get_urls(request.route_url('login'))) return HTTPFound(location=get_urls(request.route_url('login')))
values = dict(c) values = dict(c)
......
<form <form tal:define="style style|field.widget.style;
tal:define="style style|field.widget.style;
css_class css_class|string:${field.widget.css_class or field.css_class or ''}; css_class css_class|string:${field.widget.css_class or field.css_class or ''};
item_template item_template|field.widget.item_template; item_template item_template|field.widget.item_template;
autocomplete autocomplete|field.autocomplete; autocomplete autocomplete|field.autocomplete;
...@@ -11,62 +10,45 @@ ...@@ -11,62 +10,45 @@
ajax_options ajax_options|field.ajax_options; ajax_options ajax_options|field.ajax_options;
formid formid|field.formid; formid formid|field.formid;
action action|field.action or None; action action|field.action or None;
method method|field.method;" method method|field.method;" tal:attributes="autocomplete autocomplete;
tal:attributes="autocomplete autocomplete;
style style; style style;
class css_class; class css_class;
action action; action action;
attributes|field.widget.attributes|{};" attributes|field.widget.attributes|{};" id="${formid}" method="${method}" enctype="multipart/form-data"
id="${formid}" accept-charset="utf-8" class="deform ${field.bootstrap_form_style | 'form-horizontal'}" i18n:domain="deform">
method="${method}"
enctype="multipart/form-data"
accept-charset="utf-8"
class="deform ${field.bootstrap_form_style | 'form-horizontal'}"
i18n:domain="deform"
>
<fieldset class="deform-form-fieldset"> <fieldset class="deform-form-fieldset">
<div class="row"> <div class="row">
<legend tal:condition="title">${title}</legend> <legend tal:condition="title">${title}</legend>
<input type="hidden" name="_charset_"/> <input type="hidden" name="_charset_" />
<input type="hidden" name="__formid__" value="${formid}"/> <input type="hidden" name="__formid__" value="${formid}" />
<div class="alert alert-danger" tal:condition="field.error"> <div class="alert alert-danger" tal:condition="field.error">
<div class="error-msg-lbl" i18n:translate="">There was a problem with your submission</div> <div class="error-msg-lbl" i18n:translate="">There was a problem with your submission</div>
<div class="error-msg-detail" i18n:translate="">Errors have been highlighted below</div> <div class="error-msg-detail" i18n:translate="">Errors have been highlighted below</div>
<p class="error-msg">${field.errormsg}</p> <p class="error-msg">${field.errormsg}</p>
</div> </div>
<p class="section first" tal:condition="description"> <p class="section first" tal:condition="description">
${description} ${description}
</p> </p>
<div tal:repeat="child field" <div tal:repeat="child field" tal:replace="structure child.render_template(item_template)" />
tal:replace="structure child.render_template(item_template)"/>
</div> </div>
<div class="row"> <div class="row">
<div class="form-group deform-form-buttons"> <div class="form-group deform-form-buttons">
<tal:loop tal:repeat="button buttons"> <tal:loop tal:repeat="button buttons">
<button <button tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-default';"
tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-default';" tal:attributes="disabled button.disabled if button.disabled else None;
tal:attributes="disabled button.disabled if button.disabled else None; attributes|button.attributes|{};" id="${formid+button.name}" name="${button.name}"
attributes|button.attributes|{};" type="${button.type}" class="btn ${button.css_class or btn_disposition}" value="${button.value}"
id="${formid+button.name}" tal:condition="button.type != 'link'">
name="${button.name}"
type="${button.type}"
class="btn ${button.css_class or btn_disposition}"
value="${button.value}"
tal:condition="button.type != 'link'">
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span> <span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span>
${button.title} ${button.title}
</button> </button>
<a <a tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-default';
tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-default'; btn_href button.value|''" class="btn ${button.css_class or btn_disposition}"
btn_href button.value|''" id="${field.formid + button.name}" href="${btn_href}" tal:condition="button.type == 'link'">
class="btn ${button.css_class or btn_disposition}"
id="${field.formid + button.name}"
href="${btn_href}"
tal:condition="button.type == 'link'">
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span> <span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span>
${button.title} ${button.title}
</a> </a>
</tal:loop> </tal:loop>
</div> </div>
...@@ -75,34 +57,38 @@ ...@@ -75,34 +57,38 @@
<script type="text/javascript" tal:condition="use_ajax"> <script type="text/javascript" tal:condition="use_ajax">
deform.addCallback( deform.addCallback(
'${formid}', '${formid}',
function (oid) { function (oid) {
var target = '#' + oid; var target = '#' + oid;
var options = { var options = {
target: target, // target: target,
replaceTarget: true, // replaceTarget: true,
success: function () { replaceTarget: false,
deform.processCallbacks(); success: function () {
deform.focusFirstInput(target); deform.processCallbacks();
}, deform.focusFirstInput(target);
beforeSerialize: function () { },
// See http://bit.ly/1agBs9Z (hack to fix tinymce-related ajax bug) beforeSerialize: function () {
if ('tinymce' in window) { // See http://bit.ly/1agBs9Z (hack to fix tinymce-related ajax bug)
$(tinymce.get()).each( if ('tinymce' in window) {
function (i, el) { $(tinymce.get()).each(
var content = el.getContent(); function (i, el) {
var editor_input = document.getElementById(el.id); var content = el.getContent();
editor_input.value = content; var editor_input = document.getElementById(el.id);
}); editor_input.value = content;
} });
} }
};
var extra_options = ${ajax_options} ||
{
} }
; };
$('#' + oid).ajaxForm($.extend(options, extra_options)); var extra_options = ${ ajax_options }|| {};
} $('#' + oid).ajaxForm($.extend(options, extra_options));
// $('#' + oid).ajaxForm(
// function () {
// alert("test");
// }
// );
}
); );
</script> </script>
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!