Commit cd59b89c by Owo Sugiana

Kali pertama

0 parents
*egg-info
*pyc
*~
test*
dist
__pycache__
0.1 2022-04-14
--------------
- Kali pertama
Yaform
======
Ini untuk menata form HTML yang lebih ringkas dengan berbekal file YAML. Pola
yang sudah ditetapkan adalah::
+-------------------------------------+
| Judul Panel 1 |
+-------------------------------------+
| Label-1 Widget-1 Label-2 Widget-2 |
| Label-3 Widget-3 Label-4 Widget-4 |
+-------------------------------------+
+--------------------------------------------------------+
| Judul Panel 2 |
+--------------------------------------------------------+
| Label-1 Widget-1 Label-2 Widget-2 Label-3 Widget-3 |
| Label-4 Widget-4 Label-5 Widget-5 |
+--------------------------------------------------------+
Buatlah file ``views/templates/user/edit.yml`` yang berisi::
%YAML 1.2
---
No Title:
- user_name
- email
- groups
Bio Data:
- tempat_lahir
- tgl_lahir
Alamat:
- alamat
- rt col-md-2
- rw col-md-2
- kelurahan
- kecamatan
- kabupaten
- provinsi
``col-md-2`` adalah contoh class. Bila tidak disebutkan maka digunakan
``col-md-6``. Lalu beritahu lokasinya, misalnya di ``views/user.py``::
import os
from yaform import Form
here = os.path.abspath(os.path.dirname(__file__))
my_templates = os.path.join(here, 'templates', 'user')
Form.default_renderer.loader.search_path.insert(0, my_templates)
@view_config(route_name='user-add', template='templates/user/add.pt')
def my_view(request):
...
form = Form(schema, buttons=buttons)
html = form.render(yml_template='edit')
return dict(form=html)
Kata ``edit`` berarti akan dicari file bernama ``edit.yml`` di direktori yang
disebutkan oleh ``my_templates``. Contoh lengkapnya bisa lihat di `Web Starter
<https://git.opensipkd.com/sugiana/web-starter>`_
%YAML 1.2
---
No Title:
- user_name
- email
- groups
Bio Data:
- tempat_lahir
- tgl_lahir
Alamat:
- alamat
- rt col-md-2
- rw col-md-2
- kelurahan
- kecamatan
- kabupaten
- provinsi
import os
import sys
import subprocess
from setuptools import (
setup,
find_packages,
)
here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, 'README.rst')) as f:
README = f.read()
with open(os.path.join(here, 'CHANGES.txt')) as f:
CHANGES = f.read()
line = CHANGES.splitlines()[0]
version = line.split()[0]
requires = [
'deform',
'PyYAML']
setup(
name='yaform',
version=version,
description='HTML form yang ringkas',
long_description=README + '\n\n' + CHANGES,
classifiers=[
'Programming Language :: Python',
'Framework :: Pyramid',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
],
author='Owo Sugiana',
author_email='sugiana@gmail.com',
keywords='web pyramid pylons',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=requires,
)
from .form import Form
import os
import yaml
import colander
import deform
from .template import default_dir
from .panel import Panel
schema = colander.Schema()
def read_yml(name, search_path):
yml_file = name + '.yml'
full_path = None
for path in search_path:
full_path = os.path.join(path, yml_file)
if os.path.exists(full_path):
break
if not full_path:
raise Exception(f'File {yml_file} tidak ditemukan')
with open(full_path) as f:
return yaml.safe_load(f)
class Form(deform.Form):
def render_children(self, fields):
r = []
for field_id in fields:
t = field_id.split()
field_id = t[0]
if t[1:]:
self[field_id].my_class = t[1]
else:
self[field_id].my_class = None
# templates/mapping_item.pt
field = self[field_id].render_template('mapping_item')
r.append(field)
return r
def render(self, *args, **kwargs):
yml_template = kwargs.pop('yml_template', None)
if yml_template:
layout = read_yml(yml_template, self.renderer.loader.search_path)
else:
layout = kwargs.pop('layout_struct')
panels = []
for title in layout:
panel = Panel(schema)
panel.title = title
fields = layout[title]
panel.my_widgets = self.render_children(fields)
panels.append(panel.render())
self.my_widgets = '\n'.join(panels)
return super().render(*args, **kwargs)
search_path = [default_dir, deform.template.default_dir]
Form.set_zpt_renderer(search_path)
from deform import field
from deform.widget import MappingWidget
from .template import default_dir
class PanelWidget(MappingWidget):
# templates/panel.pt
template = 'panel'
class Panel(field.Field):
widget = PanelWidget()
Panel.set_zpt_renderer((default_dir,))
from pkg_resources import resource_filename
default_dir = resource_filename('yaform', 'templates/')
<form
tal:define="style style|field.widget.style;
css_class css_class|string:${field.widget.css_class or field.css_class or ''};
item_template item_template|field.widget.item_template;
autocomplete autocomplete|field.autocomplete;
title title|field.title;
errormsg errormsg|field.errormsg;
description description|field.description;
buttons buttons|field.buttons;
use_ajax use_ajax|field.use_ajax;
ajax_options ajax_options|field.ajax_options;
formid formid|field.formid;
action action|field.action or None;
method method|field.method;"
tal:attributes="autocomplete autocomplete;
style style;
class css_class;
action action;
attributes|field.widget.attributes|{};"
id="${formid}"
method="${method}"
enctype="multipart/form-data"
accept-charset="utf-8"
i18n:domain="deform">
<!-- fieldset class="deform-form-fieldset" -->
<legend tal:condition="title">${title}</legend>
<input type="hidden" name="_charset_"/>
<input type="hidden" name="__formid__" value="${formid}"/>
<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-detail" i18n:translate="">
Errors have been highlighted below
</div>
<p class="error-msg">${field.errormsg}</p>
</div>
<p class="section first" tal:condition="description">
${description}
</p>
<div tal:replace="structure field.my_widgets"/>
<div class="form-group deform-form-buttons">
<tal:loop tal:repeat="button buttons">
<button
tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-default';"
tal:attributes="disabled button.disabled if button.disabled else None;
attributes|button.attributes|{};"
id="${formid+button.name}"
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>
${button.title}
</button>
<a
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}"
id="${field.formid + button.name}"
href="${btn_href}"
tal:condition="button.type == 'link'">
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span>
${button.title}
</a>
</tal:loop>
</div>
<!-- /fieldset -->
<script type="text/javascript" tal:condition="use_ajax">
deform.addCallback(
'${formid}',
function(oid) {
var target = '#' + oid;
var options = {
target: target,
replaceTarget: true,
success: function() {
deform.processCallbacks();
deform.focusFirstInput(target);
},
beforeSerialize: function() {
// See http://bit.ly/1agBs9Z (hack to fix tinymce-related ajax bug)
if ('tinymce' in window) {
$(tinymce.get()).each(
function(i, el) {
var content = el.getContent();
var editor_input = document.getElementById(el.id);
editor_input.value = content;
});
}
}
};
var extra_options = ${ajax_options} || {};
$('#' + oid).ajaxForm($.extend(options, extra_options));
}
);
</script>
</form>
<div class="${field.my_class or 'col-md-6'}">
<div tal:define="error_class error_class|field.widget.error_class;
description description|field.description;
title title|field.title;
oid oid|field.oid;
hidden hidden|field.widget.hidden;
category category|field.widget.category;
structural hidden or category == 'structural';
required required|field.required;"
class="form-group ${field.error and 'has-error' or ''} ${field.widget.item_css_class or ''} ${field.default_item_css_class()}"
title="${description}"
id="item-${oid}"
tal:omit-tag="structural"
i18n:domain="user">
<label for="${oid}"
class="col-md-3 control-label ${required and 'required' or ''}"
tal:condition="not structural"
id="req-${oid}">
${title}
</label>
<div tal:define="input_prepend field.widget.input_prepend | None;
input_append field.widget.input_append | None"
tal:omit-tag="not (input_prepend or input_append)">
<span class="input-group-addon" tal:condition="input_prepend">
${input_prepend}
</span>
<div class="col-md-9">
<span tal:replace="structure field.serialize(cstruct).strip()"/>
<span class="input-group-addon" tal:condition="input_append">
${input_append}
</span>
</div>
</div>
<p class="help-block"
tal:define="errstr 'error-%s' % field.oid"
tal:repeat="msg field.error.messages()"
i18n:translate=""
tal:attributes="id repeat.msg.index==0 and errstr or
('%s-%s' % (errstr, repeat.msg.index))"
tal:condition="field.error and not field.widget.hidden and not field.typ.__class__.__name__=='Mapping'">
${msg}
</p>
<p tal:condition="field.description and not field.widget.hidden" class="help-block">
${field.description}
</p>
</div>
</div>
<div class="panel">
<div tal:condition="field.title != 'No Title'" class="panel-heading bg-info">
<h2 class="panel-title text-center">${field.title}</h2>
</div>
<div class="panel-body">
<div tal:repeat="widget field.my_widgets" tal:replace="structure widget"/>
</div>
</div>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!