tangsel apps

1 parent c459ab6b
...@@ -22,9 +22,9 @@ pyramid.includes = ...@@ -22,9 +22,9 @@ pyramid.includes =
pyramid_chameleon pyramid_chameleon
pyramid_rpc.jsonrpc pyramid_rpc.jsonrpc
pyramid_debugtoolbar pyramid_debugtoolbar
tangsel.pbb.models ; tangsel.pbb.models
tangsel.pbb.esppt ; tangsel.pbb.esppt
tangsel.pbb.monitoring ; tangsel.pbb.monitoring
session.type = ext:database session.type = ext:database
......
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
...@@ -36,7 +36,7 @@ renderer = deform.ZPTRendererFactory(search_path) ...@@ -36,7 +36,7 @@ renderer = deform.ZPTRendererFactory(search_path)
deform.Form.set_zpt_renderer(search_path) deform.Form.set_zpt_renderer(search_path)
main_title = 'openSIPKD' main_title = 'tangSEL Apps'
titles = {} titles = {}
static_route = [] static_route = []
...@@ -94,7 +94,7 @@ def add_cors_headers_response_callback(event): ...@@ -94,7 +94,7 @@ def add_cors_headers_response_callback(event):
event.request.add_response_callback(cors_headers) event.request.add_response_callback(cors_headers)
def get_app_name(request): def get_app_name(request):
return get_params('app_name', 'openSIPKD Application') return get_params('app_name', 'tangSEL Apps')
def get_menus(request): def get_menus(request):
""" """
...@@ -149,7 +149,7 @@ def get_title(request): ...@@ -149,7 +149,7 @@ def get_title(request):
return titles[route_name] return titles[route_name]
def get_company(request): def get_company(request):
return get_params('company', 'openSIPKD').upper() return get_params('company', 'tangSEL').upper()
def format_datetime(v): def format_datetime(v):
if v.time() != datetime.time(0, 0): if v.time() != datetime.time(0, 0):
...@@ -195,7 +195,7 @@ def google_signin_client_id(request): ...@@ -195,7 +195,7 @@ def google_signin_client_id(request):
def get_config(settings): def get_config(settings):
session_factory = session_factory_from_settings(settings) session_factory = session_factory_from_settings(settings)
config = Configurator(settings=settings, config = Configurator(settings=settings,
root_factory='opensipkd.base.models.users.RootFactory', root_factory='tangsel.base.models.users.RootFactory',
session_factory=session_factory) session_factory=session_factory)
config.set_default_csrf_options(require_csrf=False) config.set_default_csrf_options(require_csrf=False)
config.set_security_policy(MySecurityPolicy(settings["session.secret"])) config.set_security_policy(MySecurityPolicy(settings["session.secret"]))
...@@ -213,7 +213,7 @@ def get_config(settings): ...@@ -213,7 +213,7 @@ def get_config(settings):
'google_signin_client_ids', reify=True) 'google_signin_client_ids', reify=True)
config.add_request_method(allow_register, 'allow_register', reify=True) config.add_request_method(allow_register, 'allow_register', reify=True)
config.add_static_view('static', 'opensipkd.base:static', config.add_static_view('static', 'tangsel.base:static',
cache_max_age=3600) cache_max_age=3600)
config.add_static_view('deform_static', 'deform:static', config.add_static_view('deform_static', 'deform:static',
cache_max_age=3600) cache_max_age=3600)
...@@ -398,8 +398,7 @@ class BaseApp(): ...@@ -398,8 +398,7 @@ class BaseApp():
'docs/partner', self.partner_doc, cache_max_age=0) 'docs/partner', self.partner_doc, cache_max_age=0)
config.add_static_view('captcha', self.captcha_files, cache_max_age=0) config.add_static_view('captcha', self.captcha_files, cache_max_age=0)
def add_menu(self, config, route_menus, parent=None, paket="tangsel.base.views"):
def add_menu(self, config, route_menus, parent=None, paket="opensipkd.base.views"):
route_names = [] route_names = []
for route in route_menus: for route in route_menus:
# if not int(route.get("status", 0)): # if not int(route.get("status", 0)):
...@@ -463,7 +462,7 @@ class BaseApp(): ...@@ -463,7 +462,7 @@ class BaseApp():
if p["children"]: if p["children"]:
self.route_children(p["children"], row) self.route_children(p["children"], row)
def route_from_csv(self, config, paket="opensipkd.base.views", filename="routes.csv"): def route_from_csv(self, config, paket="tangsel.base.views", filename="routes.csv"):
with self.get_route_file(filename) as f: with self.get_route_file(filename) as f:
rows = csv.DictReader(f) rows = csv.DictReader(f)
new_routes = [] new_routes = []
...@@ -482,7 +481,7 @@ class BaseApp(): ...@@ -482,7 +481,7 @@ class BaseApp():
self.add_menu(config, new_routes, None, paket) self.add_menu(config, new_routes, None, paket)
def route_from_list(self, config, routs=[], paket="opensipkd.base.views"): def route_from_list(self, config, routs=[], paket="tangsel.base.views"):
new_routes = [] new_routes = []
for route in routs: for route in routs:
d = {"kode": route[0], d = {"kode": route[0],
......
from .meta import * from .meta import *
from .base import * from .base import *
from .users import * from .users import *
from .wilayah import *
from .partner import *
# from .common import * # from .common import *
# from .wilayah import *
# from .partner import *
# from .targets import * # from .targets import *
# from .user_area import * # from .user_area import *
from sqlalchemy import (Column, Integer, String, DateTime, func, ) from sqlalchemy import (Column, Integer, String, DateTime, func, )
from sqlalchemy.orm import (scoped_session, sessionmaker, ) from sqlalchemy.orm import (scoped_session, sessionmaker, )
from .base import CommonModel from . import Base, CommonModel
from .meta import Base
factory = sessionmaker(autoflush=True, autocommit=True) factory = sessionmaker(autoflush=True, autocommit=True)
LogDBSession = scoped_session(factory) LogDBSession = scoped_session(factory)
......
from sqlalchemy import (
Column,
Integer,
BigInteger,
func,
)
from . import NamaModel, Base, DBSession
class Targets(Base, NamaModel):
__tablename__ = 'targets'
__table_args__ = {'extend_existing': True}
tahun = Column(Integer, nullable=False)
jenis = Column(Integer, nullable=False)
m01 = Column(BigInteger, nullable=False)
m02 = Column(BigInteger, nullable=False)
m03 = Column(BigInteger, nullable=False)
m04 = Column(BigInteger, nullable=False)
m05 = Column(BigInteger, nullable=False)
m06 = Column(BigInteger, nullable=False)
m07 = Column(BigInteger, nullable=False)
m08 = Column(BigInteger, nullable=False)
m09 = Column(BigInteger, nullable=False)
m10 = Column(BigInteger, nullable=False)
m11 = Column(BigInteger, nullable=False)
m12 = Column(BigInteger, nullable=False)
@classmethod
def query_jenis_sum(cls, tahun, jenis):
return DBSession.query(cls.tahun, cls.jenis,
func.sum(cls.m01).label('m01'), func.sum(cls.m02).label('m02'),
func.sum(cls.m03).label('m03'), func.sum(cls.m04).label('m04'),
func.sum(cls.m05).label('m05'), func.sum(cls.m06).label('m06'),
func.sum(cls.m06).label('m07'), func.sum(cls.m08).label('m08'),
func.sum(cls.m09).label('m09'), func.sum(cls.m10).label('m10'),
func.sum(cls.m11).label('m11'), func.sum(cls.m12).label('m12'),
). \
group_by(cls.tahun, cls.jenis, ). \
filter(cls.tahun == tahun, cls.jenis == jenis)
class TargetJenis(Base, NamaModel):
__tablename__ = 'target_jenis'
__table_args__ = {'extend_existing': True}
from sqlalchemy import (
Column,
ForeignKey,
String,
SmallInteger,
)
from sqlalchemy.orm import relationship, backref
from . import Base, TABLE_ARGS, NamaModel
kategori_provinsi = (
("provinsi", "Provinsi"),
("provinsi administratif", "Provinsi Administratif"),
)
class ResProvinsi(Base, NamaModel):
__tablename__ = 'res_provinsi'
__table_args__ = (TABLE_ARGS,)
kategori = Column(String(32))
ibu_kota = Column(String(64))
kategori_dati2 = (
("kota", "Kota"),
("kabupaten", "Kabupaten"),
("kota administratif", "Kota Administratif"),
("kabupaten administratif", "Kabupaten Administratif"),
)
class ResDati2(Base, NamaModel):
__tablename__ = 'res_dati2'
__table_args__ = (TABLE_ARGS,)
kategori = Column(String(32))
ibu_kota = Column(String(64))
provinsi_id = Column(SmallInteger, ForeignKey(ResProvinsi.id))
provinsi = relationship(ResProvinsi, backref=backref("dati2"))
@classmethod
def get_list(cls, provinsi_id):
qry = cls.query_list()
if provinsi_id:
qry = qry.filter(cls.provinsi_id == provinsi_id)
return qry.all()
class ResKecamatan(Base, NamaModel):
__tablename__ = 'res_kecamatan'
__table_args__ = (TABLE_ARGS,)
ibu_kota = Column(String(64))
dati2_id = Column(SmallInteger, ForeignKey(ResDati2.id))
dati2 = relationship(ResDati2, backref=backref("kecamatan"))
@classmethod
def get_list(cls, dati2_id=None):
qry = cls.query_list()
if dati2_id:
qry = qry.filter(cls.dati2_id == dati2_id)
return qry.all()
kategori_desa = (
("desa", "Desa"),
("kelurahan", "Kelurahan")
)
class ResDesa(Base, NamaModel):
__tablename__ = 'res_desa'
__table_args__ = (TABLE_ARGS,)
kategori = Column(String(32))
kecamatan_id = Column(SmallInteger, ForeignKey(ResKecamatan.id))
kecamatan = relationship(ResKecamatan, backref=backref("desa"))
@classmethod
def get_list(cls, kecamatan_id=None):
qry = cls.query_list()
if kecamatan_id:
qry = qry.filter(cls.kecamatan_id == kecamatan_id)
return qry.all()
.navbar-default .navbar-nav>.open>a,
.navbar-default .navbar-nav>.open>a:hover {
color: #555!important
}
#loading {
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
display: block;
opacity: 0.7;
background-color: #fff;
z-index: 1000;
text-align: center;
}
#loading-image {
display:block;
margin-top: auto;
margin-bottom: auto;
margin-left: auto;
margin-right: auto;
/*width: 10%;*/
z-index: 1000;
}
body {
background: 0 0;
background-image: url(/static/img/background.png);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
background-attachment: fixed
}
.navbar-default .navbar-nav>li>a {
color: #fff
}
.navbar-default .navbar-nav>li>a:hover {
color: #fff
}
.project-context .title-page {
font-size: 16px;
line-height: 40px;
color: #474544
}
.dataTable td {
transition: opacity 1s ease 0s
}
body,
html {
overflow-x: hidden
}
.well {
background-color: #fff
}
#header {
background-image: none!important;
background-color: #57889c!important;
box-shadow: none!important;
border: 0!important;
height:auto !important;
}
.container {
height: 100%
}
.fixed-navigation nav>ul {
height: auto
}
#header #logo-group {
padding: 2px 5px
}
#header #logo-group #logo {
margin: 0
}
#header #logo-group #logo img {
height: 44px;
width: auto;
margin: 0
}
.project-context .title-page {
font-weight: 400;
color: #fff
}
#header .header-dropdown-list a.dropdown-toggle,
.project-context .label,
.project-context .project-selector {
color: #fff
}
.project-context .label {
text-shadow: none
}
#header #fullscreen a,
#header #hide-menu a {
background-image: none;
background-color: #fff;
border: 0;
color:#222;
}
.alert {
border-left-width: 0
}
.btn-primary {
background-color: #57889c!important;
color: #fff!important;
border: 0
}
.btn-default {
background-color: #e6e6e6!important;
color: #676767!important;
border: 0
}
.alert-info,
.btn-info {
background-color: #1956af!important;
color: #fff!important
}
.alert-success,
.btn-success {
background-color: #00a65a!important;
color: #fff!important
}
.alert-warning,
.btn-warning {
background-color: #f39c12!important;
color: #fff!important
}
.alert-danger,
.btn-danger {
background-color: #dd4b39!important;
color: #fff!important
}
.btn {
border: 0!important
}
.help-block {
color: #f30303!important
}
nav ul li a i {
width: 24px!important
}
@media only screen and (max-width:768px) {
#header #fullscreen a,
#header #hide-menu a {
background-image: none;
background-color: rgba(255, 255, 255, 0);
border: 0
}
#hide-menu i {
color: #fff!important
}
}
.btn,
a:link,
button {
-webkit-tap-highlight-color: rgba(87, 136, 156, .5)
}
.panel {
border: 1px solid #ddd!important
}
.panel-danger {
border-color: #dd4b39
}
.panel-success {
border-color: #00a65a
}
.panel-info {
/*border-color: #1956af*/
border-color: #57889c
}
.panel-warning {
border-color: #f39c12
}
.panel-danger>.panel-heading {
color: #fff;
background-color: #dd4b39;
border-color: #dd4b39
}
.panel-success>.panel-heading {
color: #fff;
background-color: #00a65a;
border-color: #00a65a
}
.panel-info>.panel-heading {
color: #fff;
/*background-color: #1956af;*/
background-color: #57889c;
border-color: #57889c
/*border-color: #1956af*/
}
.panel-warning>.panel-heading {
color: #fff;
background-color: #f39c12;
border-color: #f39c12
}
table.dataTable tr.selected td {
background-color: #9fafd1
}
:fullscreen #fullscreen>:first-child>a {
color: #6d6a69
}
.select2-selection__rendered {
padding-left: 0
}
.select2-selection--single {
height: 32px!important;
border-radius: 0!important;
border: 1px solid #ccc!important
}
div.toolbar::after {
content: "\0020";
width:100vw;
display:block;
clear:both;
}
div.dataTables_length select,
div.dataTables_filter input {
display:inline;
}
div.dataTables_filter label {
margin-bottom:0px;
}
div.dataTables_length label {
margin-bottom:0px;
}
.dataTables_wrapper {
overflow-x:scroll !important;
}
.col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 {
padding-left:7px;
padding-right:7px;
}
.dataTables_length {
margin-left:6px;
}
.ui-autocomplete-loading {
padding-right:10px;
background: url("../img/loading.gif") right 10px center no-repeat !important;
}
.ui-autocomplete {
max-height: 200px;
overflow-y: auto;
overflow-x: hidden;
}
.panel-body {
margin: 0 auto !important;
}
.col-md-5 {
padding: 0px 15px !important;
}
form.form-horizontal {
padding: 0 !important;
}
div.col-md-6 {
padding-right: 12px !important;
padding-left: 15px !important;
}
.twitter-typeahead .tt-query,
.twitter-typeahead .tt-hint {
padding: .25rem .5rem !important;
line-height: normal;
font-size: 12px;
border-radius: 0 !important;
}
.form-control{
font-size:10px !important;
height: 26px;
padding: 3px 6px;
margin-bottom: 1px !important;
}
.form-control-static {
border: 1px solid #ccc;
padding: 6px 6px;
height: 26px;
background-color: #ccc;
font-size: 10px;
margin-bottom: 1px;
}
.control-label{
font-size:10px !important;
padding: 3px 6px!important;
margin-top: 1px !important;
margin-bottom: 1px !important;
}
.help-block{
font-size:10px !important;
padding: 1px 1px !important;
}
.input-group-addon {
padding: 3px 3px !important;
font-size: 10px !important;
}
.input-group-addon:first-child {
padding: 3px 3px !important;
font-size: 10px !important;
}
.input-group {
padding: 3px 3px 7px !important;
font-size: 10px !important;
}
.form-group {
text-align: left;
margin-top:5px !important;
margin-bottom:5px !important;
}
.dataTables_filter .input-group-addon{
width: 32px !important;
margin-top: 0 !important;
float: left !important;
height: 26px !important;
padding-top: 4px !important;
}
.fc-border-separate thead tr, .table thead tr {
font-size:10px !important;
}
.twitter-typeahead{
font-size: 10px !important;
margin-bottom: 0;
width: 100%;
height: 26px;
position: absolute;
top: 0;
left: 0;
z-index:2;
}
.twitter-typeahead .tt-query, .twitter-typeahead .tt-hint {
font-size: 10px !important;
margin-bottom: 0;
width: 100%;
height: 26px;
position: absolute;
top: 0;
left: 0;
z-index:2;
}
.table-responsive {
overflow-x: hidden !important;
}
.dataTables_wrapper {
overflow-x: hidden !important;
}
.dataTables_filter{
margin-left: -8px !important;
}
.table tbody tr td {
font-size: 10px;
}
.span-new {
border-left: 0;
margin: -5px;
border: -12px;
padding: 7px !important;
}
.form-horizontal .checkbox, .form-horizontal .radio {
padding: 0px;
}
.checkbox, .radio {
position: relative;
display: block;
margin-top: 3px;
margin-bottom: 3px;
}
.form-tutup {
margin-left: 5px;
}
.footer-me {
padding-top: -16px;
margin-top: 4px;
}
.alert-success {
margin-bottom: 5px;
margin-left: 8px;
margin-right: 8px;
}
.alert-danger {
margin-bottom: 5px;
margin-left: 8px;
margin-right: 8px;
}
.twitter-typeahead .tt-query, .twitter-typeahead .tt-hint {
font-size: 10px !important;
}
.disabled {
color:
#000;
}
.checkbox label, .radio label {
font-size: 10px !important;
}
input[type="checkbox"], input[type="radio"] {
margin-top: 1px !important;
}
.list-group, .list-group-item {
font-size: 10px !important;
padding: 6px 15px !important;
}
.content-image {
display: block;
}
.img-float {
float: left;
width: 150px;
height: 150px;
margin: 0 20px 10px 0;
padding: 10px;
border: 1px solid white;
display: inline-block;
-webkit-box-shadow: inset 0 0 20px #ADADAD;
box-shadow: inset 0 0 20px #ADADAD;
}
}
...@@ -5,13 +5,13 @@ from pyramid.httpexceptions import ( ...@@ -5,13 +5,13 @@ from pyramid.httpexceptions import (
HTTPSeeOther) HTTPSeeOther)
from pyramid.interfaces import IRoutesMapper from pyramid.interfaces import IRoutesMapper
from pyramid.view import view_config from pyramid.view import view_config
from opensipkd.base import get_params, get_home from tangsel.base import get_params, get_home
from pyramid.renderers import render_to_response from pyramid.renderers import render_to_response
#, get_urls #, get_urls
from .base_views import BaseView from .base_views import BaseView
#, DataTables #, DataTables
from datetime import timedelta from datetime import timedelta
from opensipkd.detable import * from tangsel.detable import *
from .common import ColumnDT, DataTables from .common import ColumnDT, DataTables
from opensipkd.tools import mem_tmp_store from opensipkd.tools import mem_tmp_store
from deform import ( from deform import (
......
...@@ -5,7 +5,6 @@ from datetime import datetime ...@@ -5,7 +5,6 @@ from datetime import datetime
# from email.utils import parseaddr # from email.utils import parseaddr
import colander import colander
from opensipkd.base import BASE_CLASS
from pyramid.csrf import new_csrf_token, get_csrf_token from pyramid.csrf import new_csrf_token, get_csrf_token
from datatables import ColumnDT from datatables import ColumnDT
# from dateutil.relativedelta import relativedelta # from dateutil.relativedelta import relativedelta
...@@ -22,6 +21,7 @@ from opensipkd.tools.buttons import ( ...@@ -22,6 +21,7 @@ from opensipkd.tools.buttons import (
btn_pdf, btn_unpost, btn_post, btn_upload) btn_pdf, btn_unpost, btn_post, btn_upload)
# 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 .. import BASE_CLASS
from .common import DataTables from .common import DataTables
from ..models import DBSession, Partner from ..models import DBSession, Partner
# , get_params, get_urls # , get_params, get_urls
......
...@@ -4,7 +4,7 @@ from pyramid.i18n import TranslationStringFactory ...@@ -4,7 +4,7 @@ from pyramid.i18n import TranslationStringFactory
from pyramid.view import view_config from pyramid.view import view_config
from . import BaseView from . import BaseView
from opensipkd.models import ( from ..models import (
DBSession, DBSession,
Group, Group,
Permission, Permission,
......
...@@ -2,7 +2,7 @@ import colander ...@@ -2,7 +2,7 @@ import colander
from deform import (widget, ) from deform import (widget, )
from pyramid.view import (view_config, ) from pyramid.view import (view_config, )
from opensipkd.models import Permission from ..models import Permission
from ..views import BaseView from ..views import BaseView
SESS_ADD_FAILED = 'Tambah permission gagal' SESS_ADD_FAILED = 'Tambah permission gagal'
......
...@@ -31,23 +31,18 @@ from datetime import datetime ...@@ -31,23 +31,18 @@ from datetime import datetime
import colander import colander
from deform import (widget, FileData, ValidationFailure, Button) from deform import (widget, FileData, ValidationFailure, Button)
from opensipkd.base import BASE_CLASS
from opensipkd.tools import Upload, mem_tmp_store, image_validator, date_from_str from opensipkd.tools import Upload, mem_tmp_store, image_validator, date_from_str
from opensipkd.tools.buttons import btn_cancel, btn_save from opensipkd.tools.buttons import btn_cancel, btn_save
from pyramid.httpexceptions import HTTPFound, HTTPNotFound from pyramid.httpexceptions import HTTPFound, HTTPNotFound
from pyramid.i18n import TranslationStringFactory from pyramid.i18n import TranslationStringFactory
# from pyramid.security import forget
# from pyramid.view import view_config
from ziggurat_foundations.models.services.user import UserService from ziggurat_foundations.models.services.user import UserService
# from opensipkd.base import get_params, get_id_card_folder from .user import email_validator, add_member_count
from opensipkd.base.views.user import email_validator, add_member_count from .user_login import regenerate_security_code, send_email_security_code
from .. import BASE_CLASS
from ..models import User, DBSession, Partner, Group, UserGroup from ..models import User, DBSession, Partner, Group, UserGroup
from ..widgets import widget_os from ..widgets import widget_os
# from .base_views import need_captcha, get_url_captcha
from .user_login import regenerate_security_code, send_email_security_code
from ..views import BaseView from ..views import BaseView
# from .. import get_urls
_ = TranslationStringFactory('user') _ = TranslationStringFactory('user')
......
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" tal:define="home request.home;"> <html lang="en" tal:define="home request.home;">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
...@@ -10,27 +11,27 @@ ...@@ -10,27 +11,27 @@
<title tal:content="request.title" /> <title tal:content="request.title" />
<!-- SmartAdmin Styles : Caution! DO NOT change the order --> <!-- SmartAdmin Styles : Caution! DO NOT change the order -->
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-production-plugins.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/smartadmin-production-plugins.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-production.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/smartadmin-production.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-skins.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/smartadmin-skins.min.css">
<!-- Bootstrap core CSS --> <!-- Bootstrap core CSS -->
<link href="${home}/static/v3/css/bootstrap.min.css" rel="stylesheet"> <link href="${home}/static/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome --> <!-- Font Awesome -->
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/font-awesome.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/font-awesome.min.css">
<!-- Jquery CSS --> <!-- Jquery CSS -->
<link href="${home}/static/v3/plugin/jqueryui/themes/base/jquery-ui.min.css" rel="stylesheet"> <link href="${home}/static/plugin/jqueryui/themes/base/jquery-ui.min.css" rel="stylesheet">
<!-- DataTables --> <!-- DataTables -->
<!-- <link href="${home}/static/v3/plugin/datatables/1.10/media/css/dataTables.bootstrap.css" rel="stylesheet"> --> <!-- <link href="${home}/static/plugin/datatables/1.10/media/css/dataTables.bootstrap.css" rel="stylesheet"> -->
<!-- <link href="${home}/deform_static/css/typeahead.css" rel="stylesheet"> --> <!-- <link href="${home}/deform_static/css/typeahead.css" rel="stylesheet"> -->
<link href="${home}/deform_static/css/form.css" rel="stylesheet"> <link href="${home}/deform_static/css/form.css" rel="stylesheet">
<link href="${home}/static/css/theme.css" rel="stylesheet"> <link href="${home}/static/css/theme.css" rel="stylesheet">
<link href="${home}/static/css/navbar-fixed-top.css" rel="stylesheet"> <link href="${home}/static/css/navbar-fixed-top.css" rel="stylesheet">
<!-- Home CSS -->
<link href="${home}/static/css/custom.css" rel="stylesheet" type="text/css"> <link href="${home}/static/css/custom.css" rel="stylesheet" type="text/css">
<!-- Home CSS -->
<metal:css define-slot="css_files"></metal:css> <metal:css define-slot="css_files"></metal:css>
<style> <style>
#content { #content {
...@@ -74,9 +75,7 @@ ...@@ -74,9 +75,7 @@
<!-- End Tombol Navigator --> <!-- End Tombol Navigator -->
<ul class="nav navbar-nav navbar-right" style="margin-right:0px;"> <ul class="nav navbar-nav navbar-right" style="margin-right:0px;">
<!-- Admin Menu --> <!-- Admin Menu -->
<li <li class="dropdown" tal:condition="has_permission(request, ['user-view', 'user-edit'])"
class="dropdown"
tal:condition="has_permission(request, ['user-view', 'user-edit'])"
tal:attributes="class request.matched_route.name in ['user', 'user-add', 'user-edit', 'user-delete', 'group', 'group-add', 'group-edit', 'group-delete'] and 'active'"> tal:attributes="class request.matched_route.name in ['user', 'user-add', 'user-edit', 'user-delete', 'group', 'group-add', 'group-edit', 'group-delete'] and 'active'">
<a href="#" class="dropdown-toggle txt-color-white" data-toggle="dropdown">Admin <b class="caret"></b></a> <a href="#" class="dropdown-toggle txt-color-white" data-toggle="dropdown">Admin <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
...@@ -87,24 +86,31 @@ ...@@ -87,24 +86,31 @@
<a href="${home}/group">Group</a> <a href="${home}/group">Group</a>
</li> </li>
<li tal:condition="has_permission(request, 'routes')"><a href="${home}/routes">Routes</a></li> <li tal:condition="has_permission(request, 'routes')"><a href="${home}/routes">Routes</a></li>
<li tal:condition="has_permission(request, 'upload-logo')"><a href="${home}/upload/logo">Upload Logo</a></li> <li tal:condition="has_permission(request, 'upload-logo')"><a href="${home}/upload/logo">Upload Logo</a>
</li>
<li tal:condition="has_permission(request, 'parameter')"> <li tal:condition="has_permission(request, 'parameter')">
<a href="${home}/parameter">Parameter</a></li> <a href="${home}/parameter">Parameter</a>
</li>
<li tal:condition="has_permission(request, 'departemen')"> <li tal:condition="has_permission(request, 'departemen')">
<a href="${home}/departemen">Departemen</a></li> <a href="${home}/departemen">Departemen</a>
</li>
<li tal:condition="has_permission(request, 'partner')"> <li tal:condition="has_permission(request, 'partner')">
<a href="${home}/partner">Partner</a></li> <a href="${home}/partner">Partner</a>
</li>
<li tal:condition="has_permission(request, 'parameter')"> <li tal:condition="has_permission(request, 'parameter')">
<a href="${home}/parameter">Parameter</a></li> <a href="${home}/parameter">Parameter</a>
</li>
</ul> </ul>
</li> </li>
<!-- User Login Menu--> <!-- User Login Menu-->
<li class="dropdown" tal:attributes="class request.path in <li class="dropdown" tal:attributes="class request.path in
['/password', '/recreate-api-key'] and 'active'"> ['/password', '/recreate-api-key'] and 'active'">
<a href="#" class="dropdown-toggle txt-color-white" data-toggle="dropdown">My Account <b class="caret"></b></a> <a href="#" class="dropdown-toggle txt-color-white" data-toggle="dropdown">My Account <b
class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a style="text-transform:capitalize" href="${home}/logout">${request.user.nice_username()} Logout</a></li> <li><a style="text-transform:capitalize" href="${home}/logout">${request.user.nice_username()} Logout</a>
</li>
<li><a style="text-transform:capitalize" href="${home}/profile">Profile</a></li> <li><a style="text-transform:capitalize" href="${home}/profile">Profile</a></li>
<li><a style="text-transform:capitalize" href="${home}/password">Ubah password</a></li> <li><a style="text-transform:capitalize" href="${home}/password">Ubah password</a></li>
<li tal:condition="request.user.api_key"> <li tal:condition="request.user.api_key">
...@@ -122,10 +128,12 @@ ...@@ -122,10 +128,12 @@
<div class="container-fluid"> <div class="container-fluid">
<!-- Error session flash --> <!-- Error session flash -->
<div tal:condition="request.session.peek_flash()"> <div tal:condition="request.session.peek_flash()">
<div class="alert alert-success" tal:repeat="message request.session.pop_flash()"><i class="fa fa-fw fa-lg fa-check-circle"></i>&nbsp;${message}</div> <div class="alert alert-success" tal:repeat="message request.session.pop_flash()"><i
class="fa fa-fw fa-lg fa-check-circle"></i>&nbsp;${message}</div>
</div> </div>
<div tal:condition="request.session.peek_flash('error')"> <div tal:condition="request.session.peek_flash('error')">
<div class="alert alert-danger" tal:repeat="message request.session.pop_flash('error')"><i class="fa fa-fw fa-lg fa-times-circle"></i>&nbsp;${message}</div> <div class="alert alert-danger" tal:repeat="message request.session.pop_flash('error')"><i
class="fa fa-fw fa-lg fa-times-circle"></i>&nbsp;${message}</div>
</div> </div>
<!-- Error session flash --> <!-- Error session flash -->
...@@ -140,17 +148,17 @@ ...@@ -140,17 +148,17 @@
<!-- Bootstrap core JavaScript <!-- Bootstrap core JavaScript
================================================== --> ================================================== -->
<!-- Placed at the end of the document so the pages load faster --> <!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="${home}/static/v3/js/jquery-2.1.1.min.js"></script> <script type="text/javascript" src="${home}/static/js/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="${home}/static/v3/js/jquery-ui-1.10.3.min.js"></script> <script type="text/javascript" src="${home}/static/js/jquery-ui-1.10.3.min.js"></script>
<script type="text/javascript"> <script type="text/javascript">
// Change JQueryUI plugin names to fix name collision with Bootstrap. // Change JQueryUI plugin names to fix name collision with Bootstrap.
$.widget.bridge('uitooltip', $.ui.tooltip); $.widget.bridge('uitooltip', $.ui.tooltip);
$.widget.bridge('uibutton', $.ui.button); $.widget.bridge('uibutton', $.ui.button);
</script> </script>
<script type="text/javascript" src="${home}/static/v3/js/bootstrap/bootstrap.min.js"></script> <script type="text/javascript" src="${home}/static/js/bootstrap/bootstrap.min.js"></script>
<!-- <script type="text/javascript" src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.min.js"></script> --> <!-- <script type="text/javascript" src="${home}/static/plugin/datatables/1.10/media/js/jquery.dataTables.min.js"></script> -->
<!-- <script type="text/javascript" src="${home}/static/v3/plugin/datatables/1.10/media/js/dataTables.bootstrap.js"></script> --> <!-- <script type="text/javascript" src="${home}/static/plugin/datatables/1.10/media/js/dataTables.bootstrap.js"></script> -->
<!-- <script type="text/javascript" src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.ext.js"></script> --> <!-- <script type="text/javascript" src="${home}/static/plugin/datatables/1.10/media/js/jquery.dataTables.ext.js"></script> -->
<!-- <script type="text/javascript" src="${home}/deform_static/scripts/deform.js"></script> --> <!-- <script type="text/javascript" src="${home}/deform_static/scripts/deform.js"></script> -->
<!-- <script type="text/javascript" src="${home}/deform_static/scripts/typeahead.min.js"></script> --> <!-- <script type="text/javascript" src="${home}/deform_static/scripts/typeahead.min.js"></script> -->
<!-- <script type="text/javascript" src="${home}/static/js/tools.js"></script> --> <!-- <script type="text/javascript" src="${home}/static/js/tools.js"></script> -->
...@@ -158,4 +166,5 @@ ...@@ -158,4 +166,5 @@
<script metal:define-slot="scripts"></script> <script metal:define-slot="scripts"></script>
</body> </body>
</html> </html>
\ No newline at end of file \ No newline at end of file
...@@ -33,23 +33,23 @@ ...@@ -33,23 +33,23 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- FAVICONS --> <!-- FAVICONS -->
<link rel="shortcut icon" href="${home}/static/v3/img/favicon.png" type="image/x-icon"> <link rel="shortcut icon" href="${home}/static/img/favicon.png" type="image/x-icon">
<link rel="icon" href="${home}/static/v3/img/favicon.png" type="image/x-icon"> <link rel="icon" href="${home}/static/img/favicon.png" type="image/x-icon">
<!-- GOOGLE FONT --> <!-- GOOGLE FONT -->
<link rel="stylesheet" href="${home}/static/v3/css/gf_open_sans-400italic_700italic_300_400_700.css"> <link rel="stylesheet" href="${home}/static/css/gf_open_sans-400italic_700italic_300_400_700.css">
<!-- Basic Styles --> <!-- Basic Styles -->
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/bootstrap.min.css">
<!--? <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/font-awesome.min.css">--> <!--? <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/font-awesome.min.css">-->
<link rel="stylesheet" type="text/css" media="screen" <link rel="stylesheet" type="text/css" media="screen"
href="${home}/static/v3/fonts/fontawesome-free-6.1.2-web/css/all.min.css"> href="${home}/static/fonts/fontawesome-free-6.1.2-web/css/all.min.css">
<!-- SmartAdmin Styles : Caution! DO NOT change the order --> <!-- SmartAdmin Styles : Caution! DO NOT change the order -->
<link rel="stylesheet" type="text/css" media="screen" <link rel="stylesheet" type="text/css" media="screen"
href="${home}/static/v3/css/smartadmin-production-plugins.min.css"> href="${home}/static/css/smartadmin-production-plugins.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-production.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/smartadmin-production.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-skins.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/smartadmin-skins.min.css">
<!-- We recommend you use "your_style.css" to override SmartAdmin <!-- We recommend you use "your_style.css" to override SmartAdmin
specific styles this will also ensure you retrain your customization with each SmartAdmin update. --> specific styles this will also ensure you retrain your customization with each SmartAdmin update. -->
...@@ -60,16 +60,16 @@ ...@@ -60,16 +60,16 @@
tal:condition="css_resource[:4]!='http'"> tal:condition="css_resource[:4]!='http'">
<link rel="stylesheet" href="${css_resource}" type="text/css" tal:condition="css_resource[:4]=='http'"> <link rel="stylesheet" href="${css_resource}" type="text/css" tal:condition="css_resource[:4]=='http'">
</tal:loop> </tal:loop>
<!--? <link href="${home}/static/v3/js/plugin/bootstrap-datepicker/css/bootstrap-datepicker.min.css"--> <!--? <link href="${home}/static/js/plugin/bootstrap-datepicker/css/bootstrap-datepicker.min.css"-->
<!--? rel="stylesheet">--> <!--? rel="stylesheet">-->
<link href="${home}/deform_static/css/form.css" rel="stylesheet"> <link href="${home}/deform_static/css/form.css" rel="stylesheet">
<!--? <link href="${home}/static/v3/css/select2.min.css" rel="stylesheet" type="text/css">--> <!--? <link href="${home}/static/css/select2.min.css" rel="stylesheet" type="text/css">-->
<metal:css define-slot="css_files"></metal:css> <metal:css define-slot="css_files"></metal:css>
</head> </head>
<body class="fixed-header"> <body class="fixed-header">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/osipkd.css"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/css/osipkd.css">
<div id="loading" style="display:none;"> <div id="loading" style="display:none;">
<img id="loading-image" src="${home}/static/img/ajax-loader.gif" alt="Loading..." /> <img id="loading-image" src="${home}/static/img/ajax-loader.gif" alt="Loading..." />
</div> </div>
...@@ -217,27 +217,27 @@ ...@@ -217,27 +217,27 @@
<!-- JS --> <!-- JS -->
<script src="${home}/static/v3/js/jquery-2.1.1.min.js"></script> <script src="${home}/static/js/jquery-2.1.1.min.js"></script>
<script> <script>
if (!window.jQuery) { if (!window.jQuery) {
document.write('<script src="${home}/static/v3/js/libs/jquery-2.1.1.min.js"><\/script>'); document.write('<script src="${home}/static/js/libs/jquery-2.1.1.min.js"><\/script>');
} }
</script> </script>
<!--?<script src="${home}/static/v3/js/jquery-ui-1.10.3.min.js"></script>--> <!--?<script src="${home}/static/js/jquery-ui-1.10.3.min.js"></script>-->
<script> <script>
// if (!window.jQuery.ui) { // if (!window.jQuery.ui) {
<!--? document.write('<script src="${home}/static/v3/js/libs/jquery-ui-1.10.3.min.js"><\/script>');--> <!--? document.write('<script src="${home}/static/js/libs/jquery-ui-1.10.3.min.js"><\/script>');-->
// } // }
</script> </script>
<!-- IMPORTANT: APP CONFIG --> <!-- IMPORTANT: APP CONFIG -->
<script src="${home}/static/v3/js/app.config.js"></script> <script src="${home}/static/js/app.config.js"></script>
<!-- BOOTSTRAP JS --> <!-- BOOTSTRAP JS -->
<script src="${home}/static/v3/js/bootstrap/bootstrap.min.js"></script> <script src="${home}/static/js/bootstrap/bootstrap.min.js"></script>
<!-- FastClick: For mobile devices --> <!-- FastClick: For mobile devices -->
<script src="${home}/static/v3/js/plugin/fastclick/fastclick.min.js"></script> <script src="${home}/static/js/plugin/fastclick/fastclick.min.js"></script>
<!--[if IE 8]> <!--[if IE 8]>
...@@ -246,27 +246,27 @@ ...@@ -246,27 +246,27 @@
<![endif]--> <![endif]-->
<!-- MAIN APP JS FILE --> <!-- MAIN APP JS FILE -->
<script src="${home}/static/v3/js/app.min.js"></script> <script src="${home}/static/js/app.min.js"></script>
<!-- PAGE RELATED PLUGIN(S) --> <!-- PAGE RELATED PLUGIN(S) -->
<!--?<script src="${home}/static/v3/js/plugin/datatables/jquery.dataTables.min.js"></script>--> <!--?<script src="${home}/static/js/plugin/datatables/jquery.dataTables.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/plugin/datatables/dataTables.colVis.min.js"></script>--> <!--?<script src="${home}/static/js/plugin/datatables/dataTables.colVis.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/plugin/datatables/dataTables.tableTools.min.js"></script>--> <!--?<script src="${home}/static/js/plugin/datatables/dataTables.tableTools.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/plugin/datatables/dataTables.bootstrap.min.js"></script>--> <!--?<script src="${home}/static/js/plugin/datatables/dataTables.bootstrap.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/plugin/datatable-responsive/datatables.responsive.min.js"></script>--> <!--?<script src="${home}/static/js/plugin/datatable-responsive/datatables.responsive.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/plugin/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script>--> <!--?<script src="${home}/static/js/plugin/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/plugin/bootstrap-timepicker/bootstrap-timepicker.min.js"></script>--> <!--?<script src="${home}/static/js/plugin/bootstrap-timepicker/bootstrap-timepicker.min.js"></script>-->
<!--?<script src="${home}/deform_static/scripts/deform.js"></script>--> <!--?<script src="${home}/deform_static/scripts/deform.js"></script>-->
<!--?<script src="${home}/deform_static/scripts/typeahead.min.js"></script>--> <!--?<script src="${home}/deform_static/scripts/typeahead.min.js"></script>-->
<!--?<script src="${home}/deform_static/scripts/jquery.maskMoney-3.1.1.min.js"></script>--> <!--?<script src="${home}/deform_static/scripts/jquery.maskMoney-3.1.1.min.js"></script>-->
<!--?<script src="${home}/deform_static/tinymce/tinymce.min.js"></script>--> <!--?<script src="${home}/deform_static/tinymce/tinymce.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/tools.js"></script>--> <!--?<script src="${home}/static/js/tools.js"></script>-->
<!--?<script src="${home}/static/v3/js/notification/SmartNotification.min.js"></script>--> <!--?<script src="${home}/static/js/notification/SmartNotification.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/plugin/masked-input/jquery.maskedinput.min.js"></script>--> <!--?<script src="${home}/static/js/plugin/masked-input/jquery.maskedinput.min.js"></script>-->
<!--?<script src="${home}/static/v3/js/select2.full.min.js"></script>--> <!--?<script src="${home}/static/js/select2.full.min.js"></script>-->
<!--?<script src="${home}/deform_static/scripts/file_upload.js"></script>--> <!--?<script src="${home}/deform_static/scripts/file_upload.js"></script>-->
<script src="${home}/static/v3/js/osipkd.js"></script> <script src="${home}/static/js/osipkd.js"></script>
<!-- LOOP ON JS RESOURCE --> <!-- LOOP ON JS RESOURCE -->
<tal:loop tal:repeat="js_resource js"> <tal:loop tal:repeat="js_resource js">
<script src="${home}${request.static_path(js_resource)}" tal:condition="js_resource[:4]!='http'"></script> <script src="${home}${request.static_path(js_resource)}" tal:condition="js_resource[:4]!='http'"></script>
......
import colander
from deform import widget
from pyramid.view import view_config
from . import BaseView
from ..models import ResDesa, User, UserArea
class ListSchema(colander.Schema):
id = colander.SchemaNode(
colander.Integer(),
title="Action"
)
user_name = colander.SchemaNode(
colander.String(),
field=User.user_name,
title="User"
)
desa_kd = colander.SchemaNode(
colander.String(),
field=ResDesa.kode)
desa_name = colander.SchemaNode(
colander.String(),
field=ResDesa.nama)
class AddSchema(colander.Schema):
user_id = colander.SchemaNode(
colander.Integer(),
widget=widget.SelectWidget(values=User.get_list()),
oid="user_id",
title="User",
)
desa_id = colander.SchemaNode(
colander.Integer(),
widget=widget.SelectWidget(values=ResDesa.get_list()),
oid="desa_id",
title="Kelurahan/Desa", )
class EditSchema(AddSchema):
id = colander.SchemaNode(colander.String(),
missing=colander.drop,
widget=widget.HiddenWidget(readonly=True))
class Views(BaseView):
def __init__(self, request):
super().__init__(request)
self.list_schema = ListSchema
self.add_schema = AddSchema
self.edit_schema = EditSchema
self.list_route = 'user-area'
self.table = UserArea
def list_join(self, query, **kwargs):
return query.outerjoin(ResDesa, ResDesa.id == self.table.desa_id) \
.outerjoin(User, User.id == self.table.user_id)
# @view_config(route_name='user-area', renderer='templates/table.pt',
# permission='user-view')
# def view_list(self, **kwargs):
# return super().view_list(**kwargs)
# @view_config(route_name='user-area-act', renderer='json',
# permission='user-view')
# def view_act(self):
# return super().view_act()
# @view_config(route_name='user-area-add', renderer='templates/form.pt',
# permission='user-edit')
# def view_add(self):
# return super().view_add()
# @view_config(route_name='user-area-view', renderer='templates/form.pt',
# permission='user-view')
# def view_view(self):
# return super().view_view()
# @view_config(route_name='user-area-delete', renderer='templates/form.pt',
# permission='user-edit')
# def view_delete(self):
# return super().view_delete()
# @view_config(route_name='user-area-edit', renderer='templates/form.pt',
# permission='user-edit')
# def view_edit(self):
# return super().view_edit()
...@@ -37,7 +37,8 @@ from ziggurat_foundations.models.services.external_identity import \ ...@@ -37,7 +37,8 @@ from ziggurat_foundations.models.services.external_identity import \
ExternalIdentityService ExternalIdentityService
from ziggurat_foundations.models.services.user import UserService from ziggurat_foundations.models.services.user import UserService
from opensipkd.base import BASE_CLASS, DBSession, get_params, scripts from .. import BASE_CLASS, get_params, scripts
from ..models import DBSession
from . import one_hour, two_minutes from . import one_hour, two_minutes
from ..models.users import User, ExternalIdentity from ..models.users import User, ExternalIdentity
# , Partner # , Partner
......
TODO
- docs
- column formating (left, right, center)
- numeric formating
- date formating
"""Detable."""
import os
from pkg_resources import resource_filename
from . import detable # API
from deform.field import Field # API
from .detable import Button # API
from .detable import DeTable # API
from deform import ZPTRendererFactory # API
from deform import default_renderer # API
deform_templates = resource_filename('deform', 'templates')
path = os.path.dirname(__file__)
path = os.path.join(path, 'templates')
search_path = (path, deform_templates) #,
# renderer = ZPTRendererFactory(search_path)
DeTable.set_zpt_renderer(search_path)
"""Form."""
# Standard Library
import json
import logging
import re
import colander
# import deform
from deform import compat, widget as deform_widget, field
from . import widget
log = logging.getLogger(__name__)
class DeTable(field.Field):
"""
Field representing an entire form.
Arguments:
schema
A :class:`colander.SchemaNode` object representing a
schema to be rendered. Required.
action
The table action (inserted into the ``ajax_url`` attribute of
the datatable's scripts tag when rendered). Required.
# method
# The form method (inserted into the ``method`` attribute of
# the form's form tag when rendered). Default: ``POST``.
buttons
A sequence of strings or :class:`deform.form.Button`
objects representing submit buttons that will be placed at
the bottom of the form. If any string is passed in the
sequence, it is converted to
:class:`deform.form.Button` objects.
tableid
The identifier for this table. This value will be used as the
HTML ``id`` attribute of the rendered HTML table. You should
pass a string value for ``tableid`` when more than one Detable
table is placed into a single page and both share the same action.
When one of the tables on the page is posted, your code will to
be able to decide which of those tables was posted based on the
differing values of ``__tableid__``. By default,
``tableid`` is ``detable``.
use_ajax
If this option is ``True``, the form will use AJAX (actually
AJAH); when any submit button is clicked, the DOM node related
to this form will be replaced with the result of the form post
caused by the submission. The page will not be reloaded. This
feature uses the ``jquery.form`` library ``ajaxForm`` feature
as per `http://jquery.malsup.com/form/
<http://jquery.malsup.com/form/>`_. Default: ``False``. If
this option is ``True``, the ``jquery.form.js`` library must be
loaded in the HTML page which embeds the form. A copy of it
exists in the ``static`` directory of the ``deform`` package.
ajax_options
A *string* which must represent a JavaScript object
(dictionary) of extra AJAX options as per
`http://jquery.malsup.com/form/#tab3
<http://jquery.malsup.com/form/#tab3>`_. For
example:
.. code-block:: python
'{"success": function (rText, sText, xhr, form) {alert(sText)};}'
Default options exist even if ``ajax_options`` is not provided.
By default, ``target`` points at the DOM node representing the
form and and ``replaceTarget`` is ``true``.
A success handler calls the ``deform.processCallbacks`` method
that will ajaxify the newly written form again. If you pass
these values in ``ajax_options``, the defaults will be
overridden. If you want to override the success handler, don't
forget to call ``deform.processCallbacks``, otherwise
subsequent form submissions won't be submitted via AJAX.
This option has no effect when ``use_ajax`` is False.
The default value of ``ajax_options`` is a string
representation of the empty object.
The :class:`deform.Form` constructor also accepts all the keyword
arguments accepted by the :class:`deform.Field` class. These
keywords mean the same thing in the context of a Form as they do
in the context of a Field (a Form is just another kind of Field).
"""
css_class = "deform" # bw compat only; pass a widget to override
def __init__(
self,
schema,
action,
action_suffix='/grid/act',
buttons=(),
tableid="detable",
sorts='true',
filters='true',
paginates='true',
params="",
server_side=True,
state_save=True,
data=[],
allow_edit=True,
allow_delete=True,
allow_view=True,
allow_post=False,
allow_unpost=False,
allow_check=False,
check_field=False,
filter_columns=False,
scroll_x=False,
scroll_y=False,
**kw
):
super().__init__(schema, **kw)
self.request = kw.get("request")
self.rows = kw.get("rows")
self.action = action
self.tableid = tableid
self.data = data
self.allow_edit = json.dumps(allow_edit)
self.allow_delete = json.dumps(allow_delete)
self.allow_view = json.dumps(allow_view)
self.allow_post = json.dumps(allow_post)
self.allow_unpost = json.dumps(allow_unpost)
self.allow_check = json.dumps(allow_check)
self.check_field = json.dumps(check_field)
self.filter_columns = filter_columns
self.scroll_x = json.dumps(scroll_x)
self.scroll_y = json.dumps(scroll_y)
# self.widget = None
# Button yang dikirim sebagai tambahan
html_buttons = kw.get("html_buttons", None)
new_buttons = kw.get("new_buttons") or {}
action_suffix = f"{action_suffix}{params}"
close_url = self.action
if close_url[:4] != "http":
close_url = self.action.split("/")
close_url = "/".join(close_url[:-1])
close_url.replace(":/", "://")
params = params and f"?{params}" or ""
dict_buttons = {
"close": "{window.location = '" + close_url + "'; return false;}",
"add": "{window.location = o%sUri+'/add%s';}" % (tableid, params),
"edit": """{
if (m%sID) window.location = o%sUri+'/'+m%sID+'/edit%s';
else alert('Pilih Baris');
}""" % (tableid, tableid, tableid, params),
"view": "{window.location = o%sUri+'/'+m%sID+'/view%s';}" % (
tableid, tableid, params),
"delete": "{window.location = o%sUri+'/'+m%sID+'/delete%s';}" % (
tableid, tableid, params),
"csv": "{window.location = o%sUri+'/csv/act%s';}" % (
tableid, params),
"pdf": "{window.open(o%sUri+'/pdf/act%s');}" % (tableid, params),
"upload": "{window.location = o%sUri+'/upload%s';}" % (
tableid, params),
}
for k in new_buttons:
buttons += (new_buttons[k]["obj"],)
dict_buttons[k] = '{' + new_buttons[k]["js"].format(tableid=tableid,
params=params) + '}'
obj_buttons = [] # Adalah Header Buttone
_scripts = []
# buttons = Params Buttons
for button in buttons:
if isinstance(button, compat.string_types):
button = Button(button)
obj_buttons.append(button)
header_buttons = []
for button in obj_buttons:
header_buttons.append(
f"""<button
id="{tableid}{button.name}"
name="{button.name}"
type="{button.type}"
class="btn {button.css_class}">
{button.title} </button>\n
""")
_scripts.append(f'$("#{tableid + button.name}").click(function ()' +
dict_buttons[button.name] + ');')
if html_buttons:
for html in html_buttons:
header_buttons.append(html["obj"])
_scripts.append(html["js"])
if filter_columns:
button = f"""
<a href="#{tableid}-form-filter"
data-toggle="collapse"
class= "btn btn-warning dropdown">Filters</a>
"""
header_buttons.insert(0, button)
edit_buttons = []
if allow_check:
button = f"""
<input type="checkbox" class="{tableid}checkAll form-control"> All</input>
"""
edit_buttons.append(button)
self.buttons = "','".join(header_buttons).replace('\n', ""). \
replace(';', ';\n')
self.edit_buttons = "','".join(edit_buttons).replace('\n', ""). \
replace(';', ';\n')
self.tableid = tableid
self.scripts = ''.join(_scripts).replace(';', ";\n")
table_widget = getattr(schema, "widget", None)
if table_widget is None:
table_widget = widget.TableWidget()
self.widget = table_widget
self.server_side = json.dumps(server_side)
self.data = data
columns = []
headers = []
cols2 = []
filter_form = ""
field_index = 0
filter_scripts = ""
for f in schema:
field_index += 1
d = {'data': f.name, 'title': f.title}
data = []
if hasattr(f, 'width'):
d["width"] = f.width
data.append(f"width: '{f.width}'")
if hasattr(f, 'aligned'):
d["className"] = f.aligned
data.append(f"className: '{f.aligned}'")
if hasattr(f, 'searchable'):
d["searchable"] = f.searchable
data.append(f"searchable: {f.searchable}")
if hasattr(f, 'visible'):
d["visible"] = f.visible
data.append(f"visible: {f.visible}")
if hasattr(f, 'orderable'):
d["orderable"] = f.orderable
data.append(f"orderable: {f.orderable}")
if hasattr(f, "url"):
d["url"] = f.url
# # request = kw.get("request")
# # if request:
# # d["url"] = request.static_url(f.url)
# # log.debug(d["url"])
if hasattr(f, "action"):
d["action"] = f.action
else:
d["action"] = True
if hasattr(f, "search_method"):
d["search_method"] = f.search_method
if isinstance(f.widget, deform_widget.HiddenWidget):
d["visible"] = False
elif isinstance(f.widget, deform_widget.CheckboxWidget):
d.update(self.widget_checkbox(f))
elif isinstance(f.widget, deform_widget.SelectWidget):
d.update(self.widget_select(f))
else:
d["wg_checkbox"] = False
d["wg_select"] = False
if hasattr(f, "url"):
url = f.url
d["render"] = """
function(data){
let result = "No Data"
if (data != null)
result = '<a href="' + url + data + '" target="_blank">Link</a>&nbsp;';
return result;
}"""
if f.name == "id" and self.action:
if not d.get("orderable"):
d["orderable"] = True
d["width"] = "30pt"
d["className"] = "text-center"
d["visible"] = True
d["render"] = """
function (id) {
return %s;
}
""" % self.action_url(f)
if filter_columns and hasattr(f, "searchable") and getattr(f, "searchable"):
filter_form += self.get_filter_form(f, field_index)
# if type(f.typ) == colander.Integer:
# d["field_typ"] = f"int"
# elif type(f.typ) == colander.Boolean:
# d["field_typ"] = f"bool"
# elif type(f.typ) in (colander.Float, colander.Money):
# d["field_typ"] = f"float"
# else:
# d["field_typ"] = f"str"
thousand = hasattr(f, 'thousand') and f.thousand or None
separator = thousand and "separator" in thousand \
and thousand["separator"] or ','
decimal = thousand and "decimal" in thousand and thousand[
"decimal"] or '.'
point = thousand and thousand.get("point", 0) or 0
point = thousand and thousand.get("precision", point) or point
currency = thousand and "currency" in thousand and \
thousand["currency"] or ""
if thousand or isinstance(f.typ, colander.Float) or \
isinstance(f.typ, colander.Integer):
d["render"] = \
f"<script>$.fn.dataTable.render.number( '{separator}', " \
f"'{decimal}', {point}, '{currency}' )</script>"
if 'className' not in d:
d["className"] = "text-right"
columns.append(d)
headers.append(f.title)
# cols2.append(data)
filter_scripts = self.get_filter_scripts(f)
self.filter_scripts = filter_scripts
self.filter_form = filter_form
self.headers = headers
self.head = headers
self.columns = json.dumps(columns)
self.columns = self.columns.replace('"<script>', "").replace(
'</script>"', "").replace("\n", "")
self.url = action
self.url_suffix = action_suffix
self.sorts = sorts
self.paginates = paginates
self.filters = filters
self.state_save = json.dumps(state_save)
def widget_checkbox(self, column):
d = {}
d["wg_checkbox"] = True
d["wg_checkbox_val"] = [column.widget.true_val, column.widget.false_val]
d["className"] = "text-center"
d["width"] = "30pt"
# d["render"] = """
# function(value){
# if (typeof value == = "string" & & value.length > 0)
# return render_checkbox(value)
# if (["", false, 0, null].indexOf(value) === -1)
# return render_checkbox(true);
#
# return render_checkbox(false);
# }"""
return d
def widget_select(self, column):
d = {}
d["wg_select"] = True
d["wg_select_val"] = column.widget.values
if column.widget.values:
for val in column.widget.values:
if hasattr(column, f"color_{val}"):
d[f"color_{val}"] = getattr(column, f"color_{val}")
return d
def action_url(self, f):
act = ""
if self.allow_view:
act = f"""
'<a href="{self.action}/' + id + '/view">'+
'<i class="fas fa-eye" aria-hidden="true" title="View"></i></a>';\n
"""
if self.allow_edit:
act += f"""
'<a href="{self.action}/' + id + '/edit">'+
'<i class="fas fa-edit" aria-hidden="true" title="Edit"></i></a>';\n
"""
if self.allow_delete:
act += f"""
'<a href="{self.action}/' + id + '/delete">'+
'<i class="fas fa-trash" aria-hidden="true" title="Delete"></i></a>';\n
"""
if self.allow_post:
act += f"""
'<a href="{self.action}/' + id + '/post">'+
'<i class="fas fa-signs-post" aria-hidden="true" title="Post"></i></a>';\n
"""
if self.allow_unpost:
act += f"""
'<a href="{self.action}/' + id + '/unpost">'+
'<i class="fas fa-delete-left" aria-hidden="true" title="Unpost"></i></a>';\n
"""
return act
def get_filter_form(self, f, field_index):
field_index -= 1
html = ""
col_id = f"{self.tableid}-{f.name}"
txt = f'id="{col_id}" data-index={field_index} '
html += '<div class="form-group">'
if isinstance(f.widget, deform_widget.CheckboxWidget):
wg_check_val = [f.widget.true_val, f.widget.false_val]
radio_val = [["", 'Semua'], [wg_check_val[0],
'Aktif'], [wg_check_val[1], 'Pasif']]
html += '<label class="" for="' + col_id + '">' + f.title + '</label>'
html += '<div class="input-group" id="' + col_id + '">'
for rdo in range(len(radio_val)):
# selected = (col_val == = radioVal[rdo][0]) ? "checked": "";
log.debug(f"{rdo}, {radio_val[rdo]}")
txt = f'id="{col_id}-{radio_val[rdo][0]}" value="{radio_val[rdo][0]}" '
txt += f'class="{self.tableid}-control-filter" data-index="{field_index}" '
txt += f'name="{col_id}" '
html += '<label class="radio-inline">'
html += f'<input type="radio" {txt}/>'
html += f'<label for="{col_id}-{radio_val[rdo][0]}">'
html += f'{radio_val[rdo][1]}</label>'
html += '</label>'
html += '</div>'
elif isinstance(f.widget, deform_widget.SelectWidget):
wg_select_val = f.widget.values
html += f'<select class="form-control {self.tableid}-control-filter"'
html += f'placeholder="{f.title}" {txt}/>'
html += '<option value="">Semua</option>'
if type(wg_select_val) == list:
wg_select_val = dict(wg_select_val)
for key in wg_select_val:
html += f'<option value="{key}">{wg_select_val[key]}</option>'
html += '</select>'
elif isinstance(f.typ, colander.Date):
search_method = getattr(f, "search_method", None)
if search_method == "date":
# html += f'<div class="tooltip">'
html += f'<label class="form-label" style="font-size:12px">{f.title}</label>'
html += f'<input type="date" class="form-control {self.tableid}-control-filter"'
html += f'{txt}/>'
# html += f'<span class="tooltiptext">{f.title}</span>'
# html += f'</div>'
else:
html += f'<div class="form-group" {txt}>'
html += f'<label class="form-label" style="font-size:12px">{f.title}</label>'
html += f'<div class="input-group input-daterange" style="padding: 3px 0px 7px !important;">'
html += f'<input type="date" class="form-control {self.tableid}-control-filter hasDatePicker"'
html += f'data-index={field_index} placeholder="{f.title} Awal"'
html += f'name="{col_id}" id="{col_id}-min"/>'
html += f'<div class="input-group-addon">-</div>'
html += f'<input type="date" class="form-control {self.tableid}-control-filter hasDatePicker"'
html += f'data-index={field_index} placeholder="{f.title} Akhir" '
html += f'name="{col_id}" id="{col_id}-max" /></span>'
html += f'</div>'
html += f'</div>'
"""
awal
html += f'<div class="form-group" {txt}>'
html += f'<div class="input-group">'
html += f'<span class="input-group-addon">{f.title}</span>'
html += f'<span class="input-group-addon"><input type="date" class="form-control {self.tableid}-control-filter hasDatePicker"'
html += f'data-index={field_index} placeholder="{f.title} Awal" '
html += f'name="{col_id}" id="{col_id}-min"/></span>'
html += f'<span class="input-group-addon"><input type="date" class="form-control {self.tableid}-control-filter hasDatePicker"'
html += f'data-index={field_index} placeholder="{f.title} Akhir" '
html += f'name="{col_id}" id="{col_id}-max" /></span>'
html += f'</div>'
html += f'</div>'
"""
# html += """
# <script type="text/javascript">
# deform.addCallback(
# '%s',
# function deform_cb(oid) {
# $('#'+oid).datepicker();
# }
# );
# </script>
# """ % self.tableid
# requirements = f.widget.requirements
# for requirement in requirements:
# if type(requirement) == dict and "js" in requirement:
# for req in requirement:
#
else:
html += f'<input type="text" class="form-control {self.tableid}-control-filter"'
html += f'placeholder="{f.title}" {txt}/>'
html += '</div>'
return html
def get_filter_scripts(self, f):
return ""
"""
for (let co in ${tableid}Columns) {
if (${tableid}Columns[co].checkbox === true) {
} else if (${tableid}Columns[co].hasOwnProperty("url")) {
} else
${tableid}Columns[co].width = "30pt";
${tableid}Columns[co].orderable = false;
${tableid}Columns[co].className = "text-center";
${tableid}Columns[co].visible = true;
//columns[1].order = "order_asc";
}
"""
class Button(object):
"""
A class representing a form submit button. A sequence of
:class:`deform.widget.Button` objects may be passed to the
constructor of a :class:`deform.form.Form` class when it is
created to represent the buttons renderered at the bottom of the
form.
Arguments:
name
The string or unicode value used as the ``name`` of the button
when rendered (the ``name`` attribute of the button or input
tag resulting from a form rendering). Default: ``submit``.
title
The value used as the title of the button when rendered (shows
up in the button inner text). Default: capitalization of
whatever is passed as ``name``. E.g. if ``name`` is passed as
``submit``, ``title`` will be ``Submit``.
type
The value used as the type of button. The HTML spec supports
``submit``, ``reset`` and ``button``. A special value of
``link`` will create a regular HTML link that's styled to look
like a button. Default: ``submit``.
value
The value used as the value of the button when rendered (the
``value`` attribute of the button or input tag resulting from
a form rendering). If the button ``type`` is ``link`` then
this setting is used as the URL for the link button.
Default: same as ``name`` passed.
icon
glyph icon name to include as part of button. (Ex. If you
wanted to add the glyphicon-plus to this button then you'd pass
in a value of ``plus``) Default: ``None`` (no icon is added)
disabled
Render the button as disabled if True.
css_class
The name of a CSS class to attach to the button. In the default
form rendering, this string will replace the default button type
(either ``btn-primary`` or ``btn-default``) on the the ``class``
attribute of the button. For example, if ``css_class`` was
``btn-danger`` then the resulting default class becomes
``btn btn-danger``. Default: ``None`` (use default class).
attributes
HTML5 attributes passed in as a dictionary. This is especially
useful for a Cancel button where you do not want the client to
validate the form inputs, for example
``attributes={"formnovalidate": "formnovalidate"}``.
"""
def __init__(
self,
name="view",
oid=None,
title=None,
type="button", # noQA
css_class=None,
icon=None,
attributes=None,
disabled=None
):
if attributes is None:
attributes = {}
if title is None:
title = name.capitalize()
name = re.sub(r"\s", "_", name)
if oid is None:
self.oid = f"detable_btn_{name}"
self.name = name
self.title = title
self.type = type # noQA
self.disabled = disabled
self.css_class = css_class
self.icon = icon
self.attributes = attributes
"""I18n."""
from translationstring import TranslationStringFactory
_ = TranslationStringFactory("detable")
2024-08-05
Penambahan fungsi Tombol
kwargs = new_buttons
value = {"btn_name":
{"obj": objBtn or btn name,
"js": "jsScript{tableid} {params}"
}
}
contoh pada file partner
def view_list(self):
ktp = Button("ktp", "KTP", )
new_buttons = {"kta":
{"obj": "kta",
"js": """if (m{tableid}ID!=null)
window.location=o{tableid}Uri+'/'+m{tableid}ID+'/kta?{params}';
else displayEmptyID();
"""
},
"ktp":
{"obj": Button("ktp", title=_('KTP'), css_class="btn-danger"),
"js": """if (m{tableid}ID!=null)
window.location=o{tableid}Uri+'/'+m{tableid}ID+'/ktp?{params}';
else displayEmptyID();
"""
}
}
return super().view_list(new_buttons=new_buttons)
new_buttons ini bisa di pasang pada init ataua saat memanggil view_list(new_buttons=new_buttons)
kalau pada init gunakan self.new_buttons
\ No newline at end of file \ No newline at end of file
<div tal:define="style style|field.widget.style;
css_class css_class|string:${field.widget.css_class or field.css_class or 'jarviswidget jarviswidget-color-blueLight'};
item_template item_template|field.widget.item_template;
title title|field.title;
errormsg errormsg|field.errormsg;
description description|field.description;
buttons buttons|field.buttons;
tableid tableid|field.tableid;
columns columns|field.columns;
btnscripts scripts|field.scripts;
url url|field.url;
url_suffix url_suffix|field.url_suffix;
sorts sorts|field.sorts;
filters filters|field.filters;
paginates paginates|field.paginates;
server_side server_side|field.server_side;
data data|field.data;
allow_edit allow_edit|field.allow_edit;
allow_delete allow_delete|field.allow_delete;
allow_view allow_view|field.allow_view;
allow_post allow_post|field.allow_post;
allow_unpost allow_unpost|field.allow_unpost;
allow_check allow_check|field.allow_check;
check_field check_field|field.check_field;
state_save state_save|field.state_save;
filter_columns filter_columns|field.filter_columns;
filter_scripts filter_scripts|field.filter_scripts;
filter_form filter_form|field.filter_form;
edit_buttons edit_buttons|field.edit_buttons;
" tal:attributes="style style; class css_class; attributes|field.widget.attributes|{};" i18n:domain="detable">
<header role="heading" class="txt-color-grayDark">
<h2 tal:condition="title"><i class="fa fa-fw fa-table"></i>${title}</h2>
<div class="alert alert-danger " role="alert" id="emptyID" style="opacity:0.7;display: none;">
<strong>Pilih data terlebih dahulu!!</strong>
<!--? <button type="button" class="close" data-dismiss="alert" aria-label="Close">-->
<!--? <span aria-hidden="true">&times;</span>-->
<!--? </button>-->
</div>
<div role="content">
<div class="widget-body">
<div class="row" tal:condition="filter_columns">
<div id="${tableid}-form-filter-container" class="col-md-3">
<div id="${tableid}-form-filter" class="collapse">
${structure:filter_form}
</div>
</div>
</div>
<div tal:condition="allow_check=='true'">
<!-- <div class="row">
<div class="input-group col-md-2">
<span class="input-group-addon">
<input type="checkbox" class="${tableid}checkAll"/>
</span>
<label for="${tableid}checkAll">Pilih Semua</label>
</div>
</div> -->
<script>
$(document).ready(function () {
$(document).on("click", '.${tableid}checkAll', function () {
if (this.checked) {
$(".${tableid}_check").prop("checked", true);
} else {
$(".${tableid}_check").prop("checked", false);
}
});
});
</script>
</div>
<table id="${tableid}" class="table table-bordered table-hover table-condensed dataTable no-footer">
<thead>
<tr>
<tr>
<tal:block tal:repeat="child field">
<tal:block tal:condition="python:not hasattr(child, 'visible') or getattr(child, 'visible')==True">
<th
tal:condition="python:hasattr(child, 'action') and not getattr(child.condition)==False and False or True">
${child.title} </th>
</tal:block>
</tal:block>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<!-- widget-body -->
</div>
</header>
<style>
.fa-minus-square {
color: red;
}
.fa-check-square {
color: forestgreen;
}
</style>
<script type="text/javascript">
var m${tableid}ID;
var o${tableid};
var o${tableid}Uri = "${url}";
var o${tableid}Url = o${tableid}Uri + "${url_suffix}";
var m${tableid}ID;
var m${tableid}CheckList = [];
var check_field = ${ check_field };
deform.addCallback('${tableid}', function (oid) {
function displayEmptyID() {
$("#emptyID").show();
$('#emptyID').animate({ opacity: 0.8 }, 2000);
setTimeout(function () {
$("#emptyID").fadeTo(500, 0).slideUp(500, function () {
$("#emptyID").hide();
});
}, 4000);
}
let tb_array = [
'<div class="btn-group pull-left">',
'${structure:buttons}',
' &nbsp;',
'</div>',
]
let ${tableid}Language = {
"search": "Cari: ",
"paginate": {
"first": '<span class="glyphicon glyphicon-step-backward"></span> ',
"last": '<span class="glyphicon glyphicon glyphicon-step-forward"></span> ',
"previous": '<span class="glyphicon glyphicon-backward"></span> ',
"next": '<span class="glyphicon glyphicon-forward"></span> ',
},
"infoEmpty": "Menampilkan 0 sampai 0 dari 0",
"info": "Menampilkan _START_ sampai _END_ dari _TOTAL_",
"infoFiltered": "(disaring dari _MAX_ total keseluruhan)",
"lengthMenu": " _MENU_ baris ",
"loadingRecords": "Sedang memuat...",
"processing": "Sedang memproses...",
"emptyTable": "Tidak ada data yang tersedia pada tabel ini",
"zeroRecords": "Tidak ditemukan data yang sesuai",
};
let ${tableid}Columns = ${ structure: columns };
function render_checkbox(value) {
if (value === true)
return '<i class="fas fa-check-square" aria-hidden="true">';
if (value === false)
return '<i class="fas fa-minus-square" aria-hidden="true">';
return value;
}
function render_checklist(value) {
return '<input type="checkbox" class="${tableid}_check" checked="' + { value } + '"></input>';
}
for (let co in ${tableid}Columns) {
if (${tableid}Columns[co].wg_checkbox === true) {
${tableid}Columns[co].render = function (value) {
if (typeof value === "string" && value.length > 0) {
return render_checkbox(value)
}
if (["", false, 0, null].indexOf(value) === -1) {
return render_checkbox(true);
}
return render_checkbox(false);
}
//}
//else if (${tableid}Columns[co].wg_select === true) {
// ${tableid}Columns[co].render = function (value) {
// if (value != null)
// return ${tableid}Columns[co].wg_select_val[value];
// return "";
// }
}else if (${tableid}Columns[co].hasOwnProperty("url")) {
let url = ${tableid}Columns[co].url;
${tableid}Columns[co].render = function (data) {
let result = "No Data";
if (data != null) {
result = '<a href="' + url + data + '" target="_blank">Link</a>&nbsp;';
}
return result;
}
}else if (${tableid}Columns[co].data === "id") {
${tableid}Columns[co].render = function (id, typ, data, setting) {
if (${tableid}Columns[co].action === false) return ""
let result = "";
if (${ allow_check }) {
var checked = "";
if (check_field !== "") {
checked = data[check_field] !== null ? "checked" : "";
m${tableid}CheckList.push(id);
}
var mtableId = "${tableid}";
result = '<input type="checkbox" class="' + mtableId + '_check" value="' + id + '" ' + checked + ' name="' + mtableId + '_check"/>&nbsp;';
}
if (${ allow_view })
result += '<a href="${url}/' + id + '/view"><i class="fas fa-eye" aria-hidden="true" title="View"></i></a>&nbsp;';
if (${ allow_edit })
result += '<a href="${url}/' + id + '/edit"><i class="fas fa-edit" aria-hidden="true" title="Edit"></i></a>&nbsp;'
if (${ allow_delete })
result += '<a href="${url}/' + id + '/delete"><i class="fas fa-trash" aria-hidden="true" title="Delete"></i></a>';
if (${ allow_post })
result += '<a href="${url}/' + id + '/post"><i class="fas fa-signs-post" aria-hidden="true" title="Post"></i></a>';
if (${ allow_unpost })
result += '<a href="${url}/' + id + '/unpost"><i class="fas fa-delete-left" aria-hidden="true" title="Unpost"></i></a>';
return result;
}
}
}
let ${tableid}Params = {};
var param_ajax = "";
var param_data = [];
if (!${ server_side }) param_data = ${ data };
else param_ajax = o${tableid}Url;
o${tableid} = $('#${tableid}').DataTable({
scrollX: ${ field.scroll_x },
//scrollY: ${field.scroll_y},
//dom: '<"row"<"col-md-8"<"toolbar">Bl><"col-md-4"fr>>tip',
dom: '<"row"<"col-md-8"<"toolbar">>><"row"<"col-md-8"Bl><"col-md-4"fr>>t<"row dt-footer"<"col-md-8" i><"col-md-4"p>>',
processing: true,
serverSide: ${ server_side },
data: param_data,
ajax: param_ajax,
stateSave: ${ state_save },
scrollCollapse: true,
sort: ${ sorts },
info: true,
filter: ${ filters },
autoWidth: false,
paginate: ${ paginates },
paginationType: "full_numbers",
order: [],
lengthMenu: [
[10, 25, 50, 100],
[10, 25, 50, 100]
],
pageLength: 25,
columns: ${tableid}Columns,
language: ${tableid}Language,
initComplete: function () {
$('.dataTables_filter input').unbind()
.bind('keyup', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
o${tableid}.search(this.value).draw();
}
});
}
});
let tb = tb_array.join(' ');
$("div.toolbar").html(tb);
$("div.toolbar").attr('style', 'display:block; float: left; margin-bottom:6px; line-height:16px;');
$("div.dt-footer").attr('style', 'margin-left: -7px;');
$(".dataTables_scrollBody").attr('style', 'margin-top: -10px;');
$('#${tableid} tbody').on('click', ':checkbox', function () {
if (this.checked) m${tableid}CheckList.push($(this).val());
else m${tableid}CheckList.splice(m${tableid}CheckList.indexOf($(this).val()), 1);
});
$('#${tableid} tbody').on('click', 'tr', function () {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
m${tableid}ID = null;
} else {
let aData = o${tableid}.row(this).data();
o${tableid}.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
m${tableid}ID = aData.id;
o${tableid}.$('tr.row_selected').removeClass('row_selected');
$(this).addClass('row_selected');
}
});
<tal:block tal:condition="filter_columns">
$(".${tableid}-control-filter").on('keyup', function (e) {
var code = e.keyCode || e.which;
if (code === 13) filter_table();
});
$("#${tableid}_length").append('<label>&emsp;${structure:edit_buttons}</label>');
function filter_table() {
$(".${tableid}-control-filter").each(function (e) {
var col_id = $(this).attr("id");
var value;
if ($(this).attr("type") === 'radio') {
col_id = $(this).attr('id').split("-");
col_id.length = 2;
col_id = col_id.join("-");
value = this.value;
if (this.checked) {
//console.log(col_id, $(this).attr('id'), value, this.checked);
localStorage.setItem(col_id, value);
o${tableid}.column($(this).data('index')).search(this.value)
}
}
else if ($(this).attr("type") === 'date') {
value = this.value;
localStorage.setItem(col_id, value);
var splitted = col_id.split('-');
if (splitted[splitted.length - 1] !== "min" && splitted[splitted.length - 1] !== "max"){
o${tableid}.column($(this).data('index')).search(value)
}
else{
var min_val = undefined;
var max_val = undefined;
if (splitted[splitted.length - 1] === "min") {
min_val = this.value;
splitted.length = splitted.length - 1;
col_id = splitted.join("-");
max_val = $("#" + col_id + '-max').val()
}
else {
max_val = this.value;
splitted.length = splitted.length - 1;
col_id = splitted.join("-");
min_val = $("#" + col_id + '-min').val();
}
if (min_val === undefined && max_val !== undefined) min_val = max_val;
if (max_val === undefined && min_val !== undefined) max_val = min_val;
if (max_val !== undefined && min_val !== undefined && min_val !== null && max_val !== null)
o${tableid}
.column($(this).data('index'))
.search(min_val + '-yadcf_delim-' + max_val, true);
//&& min_val !== "" && max_val !== ""
}
}
else {
col_id = this.id;
value = this.value;
if (value === undefined || value === null) value = "";
console.log(col_id, $(this).attr('id'), value, $(this).data('index'));
localStorage.setItem(col_id, value);
o${tableid}
.column($(this).data('index'))
.search(value);
}
});
o${tableid}.draw();
}
$(".${tableid}-control-filter").on('click', function (e) {
//console.log("Write Data Click");
var typ = $(this).attr("type");
if (typ === 'radio') {
filter_table();
}
});
$(".${tableid}-control-filter").on('change', function (e) {
var typ = $(this).prop("nodeName").toLowerCase();
if (typ === "select") filter_table();
var typ = $(this).attr("type").toLowerCase();
if (typ === "date") filter_table();
});
console.log("Read Data");
$(".${tableid}-control-filter").each(function (e) {
var col_id = $(this).attr("id")
var value;
if ($(this).attr("type") === 'radio') {
col_id = $(this).attr('id').split("-");
col_id.length = 2;
col_id = col_id.join("-");
value = localStorage.getItem(col_id);
if (value !== undefined && value != null)
if ($(this).val() === value) $(this).attr("checked", true);
else $(this).attr("checked", false);
}
else {
value = localStorage.getItem(col_id);
if (value !== undefined && value !== null)
$(this).val(value);
}
});
filter_table();
</tal:block>
${structure:btnscripts}
${structure:filter_scripts}
});
</script>
</div>
\ No newline at end of file \ No newline at end of file
"""Widget."""
# Standard Library
import csv
import json
import random
# Pyramid
from colander import Invalid
from colander import Mapping
from colander import SchemaNode
from colander import SchemaType
from colander import Sequence
from colander import String
from colander import null
from iso8601.iso8601 import ISO8601_REGEX
from translationstring import TranslationString
from deform.widget import MappingWidget
from deform.compat import text_
from .i18n import _
_BLANK = text_("")
class TableWidget(MappingWidget):
"""
The top-level widget; represents an entire table.
**Attributes/Arguments**
template
The template name used to render the widget. Default:
``detable``.
"""
template = "detable"
readonly_template = "readonly/detable"
requirements = (("deform", None),
{"js": "opensipkd.base:static/v3/js/plugin/datatables/jquery.dataTables.min.js"})
from opensipkd.base.models import *
\ No newline at end of file \ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!