1. perabaikan fungsi allow_check untuk menampilkan checkbox pada sisi kiri datatabale

2. Pnambahan paramater list_view_field menampilkan url view pada kolom/field yang diperlukan
3. Penambahan default sort menajdi column[0] desc
4.Penambahan defalt tombol edit dan delete pada saat view data
1 parent 93a1f9f9
...@@ -17,7 +17,7 @@ from sqlalchemy import Table ...@@ -17,7 +17,7 @@ from sqlalchemy import Table
from opensipkd.tools import dmy, get_settings, get_ext, \ from opensipkd.tools import dmy, get_settings, get_ext, \
date_from_str, get_random_string, Upload, InvalidExtension, mem_tmp_store date_from_str, get_random_string, Upload, InvalidExtension, mem_tmp_store
from opensipkd.tools.buttons import ( from opensipkd.tools.buttons import (
btn_save, btn_cancel, btn_close, btn_delete, btn_add, btn_csv, btn_save, btn_cancel, btn_close, btn_delete, btn_add, btn_csv, btn_edit,
btn_pdf, btn_upload) btn_pdf, 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
...@@ -48,6 +48,8 @@ class CSRFSchema(colander.Schema): ...@@ -48,6 +48,8 @@ class CSRFSchema(colander.Schema):
widget=widget_os.CSRFWidget(), widget=widget_os.CSRFWidget(),
) )
from pyramid.interfaces import IRoutesMapper
from pyramid.threadlocal import get_current_registry
class BaseView(object): class BaseView(object):
def __init__(self, request): def __init__(self, request):
...@@ -76,6 +78,7 @@ class BaseView(object): ...@@ -76,6 +78,7 @@ class BaseView(object):
self.list_report = (btn_csv, btn_pdf) self.list_report = (btn_csv, btn_pdf)
self.list_buttons = (btn_add,) self.list_buttons = (btn_add,)
self.list_upload = (btn_upload,) self.list_upload = (btn_upload,)
self.list_view_field = None
self.columns = None self.columns = None
# self.form_params = dict(scripts="") # self.form_params = dict(scripts="")
self.list_url = "" self.list_url = ""
...@@ -106,9 +109,21 @@ class BaseView(object): ...@@ -106,9 +109,21 @@ class BaseView(object):
});""" });"""
self.form_widget = None self.form_widget = None
# self.list_schema = colander.Schema() self.list_schema = colander.Schema(
self.add_schema = colander.Schema() error=colander.SchemaNode(
# self.edit_schema = colander.Schema() colander.String, title="Override",
missing=colander.drop,
default="Silahkan buat list schema"))
self.add_schema = colander.Schema(
error=colander.SchemaNode(
colander.String, title="Override",
missing=colander.drop,
default="Silahkan buat add schema"))
self.edit_schema = colander.Schema(
error=colander.SchemaNode(
colander.String, title="Override",
missing=colander.drop,
default="Silahkan buat schema edit"))
self.upload_schema = UploadSchema self.upload_schema = UploadSchema
self.upload_exts = (".csv", ".tsv") self.upload_exts = (".csv", ".tsv")
...@@ -244,6 +259,11 @@ class BaseView(object): ...@@ -244,6 +259,11 @@ class BaseView(object):
pass pass
""" """
def route_found(self, route_name):
reg = get_current_registry() # b/c
mapper = reg.getUtility(IRoutesMapper)
return mapper.get_route(route_name)
def get_routes(self): def get_routes(self):
""" """
Digunakan untuk mendapatkan default url apabila list_url tidak ada Digunakan untuk mendapatkan default url apabila list_url tidak ada
...@@ -542,10 +562,17 @@ class BaseView(object): ...@@ -542,10 +562,17 @@ class BaseView(object):
# log.debug(str(columns)) # log.debug(str(columns))
# qry = query.add_columns(*[c.sqla_expr for c in columns]) # qry = query.add_columns(*[c.sqla_expr for c in columns])
# log.debug(str(qry)) # log.debug(str(qry))
if self.req.params.get("order[0][column]", None):
self.req.params["order[0][column]"]='0'
self.req.params["order[0][dir]"]='desc'
row_table = DataTables(self.req.GET, query, columns) row_table = DataTables(self.req.GET, query, columns)
result = row_table.output_result() result = row_table.output_result()
data = result and result.get("data") or {} data = result and result.get("data") or {}
for res in data: for res in data:
if self.list_view_field:
list_url = self.req.route_url(self.list_route)
res[self.list_view_field] = f"<a href='{list_url}/{res['id']}/view'>{res[self.list_view_field]}</a>"
for k in res: for k in res:
if k in select_list.keys(): if k in select_list.keys():
vals = select_list[k] vals = select_list[k]
...@@ -639,8 +666,13 @@ class BaseView(object): ...@@ -639,8 +666,13 @@ class BaseView(object):
) )
def view_buttons(self, row): def view_buttons(self, row):
result = (btn_close,) result =[]
return result if self.route_found(self.list_route+"-edit"):
result.append(btn_edit)
if self.route_found(self.list_route+"-delete"):
result.append(btn_delete)
result.append(btn_close)
return tuple(result)
def before_view(self, **kw): def before_view(self, **kw):
return False return False
...@@ -665,6 +697,19 @@ class BaseView(object): ...@@ -665,6 +697,19 @@ class BaseView(object):
form = self.get_form(self.edit_schema, buttons=buttons, form = self.get_form(self.edit_schema, buttons=buttons,
bindings=bindings) bindings=bindings)
if request.POST: if request.POST:
if 'edit' in request.POST:
return HTTPFound(
location=self.req.route_url(
self.list_route+"-edit",
id=row.id,
act='edit'))
elif 'delete' in request.POST:
return HTTPFound(
location=self.req.route_url(
self.list_route+"-delete",
id=row.id,
act='delete'))
result = self.next_view(form=form, row=row) result = self.next_view(form=form, row=row)
if result: if result:
return result return result
...@@ -1065,7 +1110,22 @@ class BaseView(object): ...@@ -1065,7 +1110,22 @@ class BaseView(object):
def view_delete(self, **kwargs): def view_delete(self, **kwargs):
request = self.req request = self.req
q = self.query_id() q = self.query_id()
if self.allow_check:
rcount = q.count()
if rcount > 1:
try:
q.delete(synchronize_session='fetch')
self.db_session.flush()
request.session.flash(f"{rcount} Data berhasil dihapus.")
except Exception as e:
request.session.flash(
f"Gagal menghapus data. "
f"Pastikan data tidak berelasi dengan data lain. "
f"Error: {str(e)}", "error")
return self.route_list()
self.ses["readonly"] = True self.ses["readonly"] = True
row = q.first() row = q.first()
is_object = kwargs.get("is_object", self.is_object) is_object = kwargs.get("is_object", self.is_object)
...@@ -1099,6 +1159,9 @@ class BaseView(object): ...@@ -1099,6 +1159,9 @@ class BaseView(object):
def query_id(self, id_=None): def query_id(self, id_=None):
id_ = id_ or self.req.matchdict['id'] id_ = id_ or self.req.matchdict['id']
if id_=='all':
ids_ = [int(i) for i in self.req.params.get("ids").split(",")]
return self.table.query().filter(self.table.id.in_(ids_))
return self.table.query_id(id_) return self.table.query_id(id_)
# if self.req.user: # if self.req.user:
......
...@@ -160,8 +160,16 @@ class DeTable(field.Field): ...@@ -160,8 +160,16 @@ class DeTable(field.Field):
}""" % (tableid, tableid, tableid, params), }""" % (tableid, tableid, tableid, params),
"view": "{window.location = o%sUri+'/'+m%sID+'/view%s';}" % ( "view": "{window.location = o%sUri+'/'+m%sID+'/view%s';}" % (
tableid, tableid, params), tableid, tableid, params),
"delete": "{window.location = o%sUri+'/'+m%sID+'/delete%s';}" % ( "delete": not self.allow_check and "{window.location = o%sUri+'/'+m%sID+'/delete%s';}" % (
tableid, tableid, params), tableid, tableid, params) or \
"""{
var cnt = m%sCheckList.length;
if (confirm('Menghapus '+cnt+' data, pastikan data yang dipilih sudah benar!')){
ids = m%sCheckList.join(',');
window.location = o%sUri+'/all/delete?ids='+ids;
};
event.stopPropagation();
}""" % (tableid, tableid, tableid),
"csv": "{window.location = o%sUri+'/csv/act%s';}" % ( "csv": "{window.location = o%sUri+'/csv/act%s';}" % (
tableid, params), tableid, params),
"pdf": "{window.open(o%sUri+'/pdf/act%s');}" % (tableid, params), "pdf": "{window.open(o%sUri+'/pdf/act%s');}" % (tableid, params),
...@@ -191,7 +199,8 @@ class DeTable(field.Field): ...@@ -191,7 +199,8 @@ class DeTable(field.Field):
class="btn {button.css_class}"> class="btn {button.css_class}">
{button.title} </button>\n {button.title} </button>\n
""") """)
_scripts.append(f'$("#{tableid + button.name}").click(function ()' + if dict_buttons[button.name]:
_scripts.append(f'$("#{tableid + button.name}").click(function ()' +
dict_buttons[button.name] + ');') dict_buttons[button.name] + ');')
if html_buttons: if html_buttons:
...@@ -236,7 +245,7 @@ class DeTable(field.Field): ...@@ -236,7 +245,7 @@ class DeTable(field.Field):
filter_scripts = "" filter_scripts = ""
for f in schema: for f in schema:
field_index += 1 field_index += 1
d = {'data': f.name, 'title': f.title} d = {'data': f.name}
data = [] data = []
if hasattr(f, 'width'): if hasattr(f, 'width'):
d["width"] = f.width d["width"] = f.width
......
...@@ -46,41 +46,31 @@ ...@@ -46,41 +46,31 @@
</div> </div>
</div> </div>
<div tal:condition="allow_check=='true'"> <div tal:condition="allow_check=='true'">
<!-- <div class="row"> <div class="row">
<!--
<div class="input-group col-md-2"> <div class="input-group col-md-2">
<span class="input-group-addon"> <span class="input-group-addon">
<input type="checkbox" class="${tableid}checkAll"/> <input type="checkbox" class="${tableid}checkAll"/>
</span> </span>
<label for="${tableid}checkAll">Pilih Semua</label> <label for="${tableid}checkAll">Pilih Semua</label>
</div> </div>
</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> </div>
<table id="${tableid}" class="table table-bordered table-hover table-condensed dataTable no-footer"> <table id="${tableid}" class="table table-bordered table-hover table-condensed dataTable no-footer">
<thead> <thead>
<tr> <tr>
<tr> <tal:block tal:repeat="child field">
<tal:block tal:repeat="child field"> <th class="no-sort" tal:condition="child.name=='id'">
<input type="checkbox" class="${tableid}checkAll" id="${tableid}checkAll"/>
<tal:block tal:condition="python:not hasattr(child, 'visible') or getattr(child, 'visible')==True"> </th>
<th <th tal:condition="child.name!='id'">
tal:condition="python:hasattr(child, 'action') and not getattr(child.condition)==False and False or True"> ${child.title}
${child.title} </th> </th>
</tal:block>
</tr>
</tal:block>
</tal:block>
</tr>
</thead> </thead>
<tbody></tbody> <tbody></tbody>
...@@ -157,7 +147,7 @@ ...@@ -157,7 +147,7 @@
return '<input type="checkbox" class="${tableid}_check" checked="' + { value } + '"></input>'; return '<input type="checkbox" class="${tableid}_check" checked="' + { value } + '"></input>';
} }
var mtableId = "${tableid}";
for (let co in ${tableid}Columns) { for (let co in ${tableid}Columns) {
if (${tableid}Columns[co].wg_checkbox === true) { if (${tableid}Columns[co].wg_checkbox === true) {
${tableid}Columns[co].render = function (value) { ${tableid}Columns[co].render = function (value) {
...@@ -189,37 +179,39 @@ ...@@ -189,37 +179,39 @@
${tableid}Columns[co].render = function (id, typ, data, setting) { ${tableid}Columns[co].render = function (id, typ, data, setting) {
if (${tableid}Columns[co].action === false) return "" if (${tableid}Columns[co].action === false) return ""
let result = ""; let result = "";
if (${ allow_check }) { <tal:block tal:condition="allow_check=='true'">
var checked = ""; var checked = "";
if (check_field !== "") { if (check_field !== "") {
checked = data[check_field] !== null ? "checked" : ""; checked = data[check_field] !== null ? "checked" : "";
m${tableid}CheckList.push(id); m${tableid}CheckList.push(id);
} }
var mtableId = "${tableid}"; result = '<input type="checkbox" class="' + mtableId + '_check" id="' + mtableId + '_check_' + id +'" value="' + id + '" ' + checked + ' name="' + mtableId + '_check"/>&nbsp;';
result = '<input type="checkbox" class="' + mtableId + '_check" value="' + id + '" ' + checked + ' name="' + mtableId + '_check"/>&nbsp;'; </tal:block>
} <tal:block tal:condition="allow_check=='false'">
if (${ allow_view }) <tal:block tal:condition="allow_view=='true'">
result += '<a href="${url}/' + id + '/view"><i class="fas fa-eye" aria-hidden="true" title="View"></i></a>&nbsp;'; result += '<a href="${url}/' + id + '/view"><i class="fas fa-eye" aria-hidden="true" title="View"></i></a>&nbsp;';
</tal:block>
if (${ allow_edit }) <tal:block tal:condition="allow_edit=='true'">
result += '<a href="${url}/' + id + '/edit"><i class="fas fa-edit" aria-hidden="true" title="Edit"></i></a>&nbsp;' result += '<a href="${url}/' + id + '/edit"><i class="fas fa-edit" aria-hidden="true" title="Edit"></i></a>&nbsp;'
</tal:block>
if (${ allow_delete }) <tal:block tal:condition="allow_delete=='true'">
result += '<a href="${url}/' + id + '/delete"><i class="fas fa-trash" aria-hidden="true" title="Delete"></i></a>'; result += '<a href="${url}/' + id + '/delete"><i class="fas fa-trash" aria-hidden="true" title="Delete"></i></a>';
</tal:block>
if (${ allow_post }) <tal:block tal:condition="allow_post=='true'">
result += '<a href="${url}/' + id + '/post"><i class="fas fa-signs-post" aria-hidden="true" title="Post"></i></a>'; result += '<a href="${url}/' + id + '/post"><i class="fas fa-signs-post" aria-hidden="true" title="Post"></i></a>';
</tal:block>
if (${ allow_unpost }) <tal:block tal:condition="allow_post=='true'">
result += '<a href="${url}/' + id + '/unpost"><i class="fas fa-delete-left" aria-hidden="true" title="Unpost"></i></a>'; result += '<a href="${url}/' + id + '/unpost"><i class="fas fa-delete-left" aria-hidden="true" title="Unpost"></i></a>';
</tal:block>
</tal:block>
return result; return result;
} }
} }
} }
//end column definition loop
let ${tableid}Params = {}; let ${tableid}Params = {};
var param_ajax = ""; var param_ajax = "";
var param_data = []; var param_data = [];
...@@ -268,10 +260,97 @@ ...@@ -268,10 +260,97 @@
$("div.dt-footer").attr('style', 'margin-left: -7px;'); $("div.dt-footer").attr('style', 'margin-left: -7px;');
$("div.sub-foot").attr('style', 'position:unset;'); $("div.sub-foot").attr('style', 'position:unset;');
$(".dataTables_scrollBody").attr('style', 'margin-top: -10px;'); $(".dataTables_scrollBody").attr('style', 'margin-top: -10px;');
$('#${tableid} tbody').on('click', ':checkbox', function () { <tal:block tal:condition="allow_check=='true'">
if (this.checked) m${tableid}CheckList.push($(this).val());
else m${tableid}CheckList.splice(m${tableid}CheckList.indexOf($(this).val()), 1); //Begin Allow Check
$('#${tableid} tbody').on('click', ':checkbox', function () {
var checkboxValue = $(this).val();
if (this.checked) {
// Add to list if not already present
if (m${tableid}CheckList.indexOf(checkboxValue) === -1) {
m${tableid}CheckList.push(checkboxValue);
}
}else {
// Remove from list
var index = m${tableid}CheckList.indexOf(checkboxValue);
if (index > -1) {
m${tableid}CheckList.splice(index, 1);
}
}
console.log("Checkbox Clicked", m${tableid}CheckList);
updateCheckAllStatus();
});
$('#${tableid} tbody').on('change', ':checkbox', function () {
var checkboxValue = $(this).val();
if (this.checked) {
// Add to list if not already present
if (m${tableid}CheckList.indexOf(checkboxValue) === -1) {
m${tableid}CheckList.push(checkboxValue);
}
}else {
// Remove from list
var index = m${tableid}CheckList.indexOf(checkboxValue);
if (index > -1) {
m${tableid}CheckList.splice(index, 1);
}
}
console.log("Checkbox Changed", m${tableid}CheckList);
updateCheckAllStatus();
});
$("#${tableid}checkAll").on("click", '', function (e) {
e.stopPropagation();
if (this.checked) {
// Check all checkboxes and add all to list
$(".${tableid}_check").each(function () {
$(this).prop("checked", true);
var checkboxValue = $(this).val();
if (m${tableid}CheckList.indexOf(checkboxValue) === -1) {
m${tableid}CheckList.push(checkboxValue);
}
}); });
}else {
// Uncheck all checkboxes and clear list
$(".${tableid}_check").prop("checked", false);
m${tableid}CheckList = [];
}
console.log("Check All Clicked", m${tableid}CheckList);
});
// Function to update check all status based on individual checkboxes
function updateCheckAllStatus() {
var totalCheckboxes = $(".${tableid}_check").length;
var checkedCheckboxes = $(".${tableid}_check:checked").length;
if (checkedCheckboxes === 0) {
$("#${tableid}checkAll").prop("checked", false);
$("#${tableid}checkAll").prop("indeterminate", false);
}else if (checkedCheckboxes === totalCheckboxes) {
$("#${tableid}checkAll").prop("checked", true);
$("#${tableid}checkAll").prop("indeterminate", false);
}else {
$("#${tableid}checkAll").prop("checked", false);
$("#${tableid}checkAll").prop("indeterminate", true);
}
};
// Function to get selected data from checked rows
function get${tableid}SelectedData() {
var selectedData = [];
$(".${tableid}_check:checked").each(function() {
var rowData = o${tableid}.row($(this).closest('tr')).data();
if (rowData) {
selectedData.push(rowData);
}
});
return selectedData;
};
// Function to get selected IDs
function get${tableid}SelectedIds() {
return m${tableid}CheckList.slice(); // Return copy of the array
};
//End Allow Check
</tal:block>
$('#${tableid} tbody').on('click', 'tr', function () { $('#${tableid} tbody').on('click', 'tr', function () {
if ($(this).hasClass('selected')) { if ($(this).hasClass('selected')) {
$(this).removeClass('selected'); $(this).removeClass('selected');
...@@ -285,7 +364,10 @@ ...@@ -285,7 +364,10 @@
$(this).addClass('row_selected'); $(this).addClass('row_selected');
} }
}); });
<tal:block tal:condition="filter_columns"> <tal:block tal:condition="filter_columns">
//Begin Filter Columns
$(".${tableid}-control-filter").on('keyup', function (e) { $(".${tableid}-control-filter").on('keyup', function (e) {
var code = e.keyCode || e.which; var code = e.keyCode || e.which;
if (code === 13) filter_table(); if (code === 13) filter_table();
...@@ -389,9 +471,12 @@ ...@@ -389,9 +471,12 @@
}); });
filter_table(); filter_table();
//End Filter Columns
</tal:block> </tal:block>
${structure:btnscripts} ${structure:btnscripts}
${structure:filter_scripts} ${structure:filter_scripts}
});
}); // deform callback
</script> </script>
</div> </div>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!