diff --git a/.gitignore b/.gitignore index 7e71758..b64d96d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ nosetests.xml .project .pydevproject .settings +.idea/ +.env/ +/example/settings_custom.py diff --git a/example/app/tables.py b/example/app/tables.py index 1f7f339..8be9e2c 100644 --- a/example/app/tables.py +++ b/example/app/tables.py @@ -33,6 +33,10 @@ class AjaxTable(Table): id = Column(field='id', header=u'#') name = Column(field='name', header=u'NAME') organization = Column(field='organization.name', header=u'ORG') + organization1 = Column(field='organization.name', header=u'ORG1') + organization2 = Column(field='organization.name', header=u'ORG2') + organization3 = Column(field='organization.name', header=u'ORG3') + organization4 = Column(field='organization.name', header=u'ORG4') class Meta: model = Person diff --git a/example/requirements.txt b/example/requirements.txt new file mode 100644 index 0000000..50727c7 --- /dev/null +++ b/example/requirements.txt @@ -0,0 +1 @@ +Django>1.5 diff --git a/example/settings.py b/example/settings.py index 328b728..76e83a3 100644 --- a/example/settings.py +++ b/example/settings.py @@ -162,3 +162,11 @@ }, } } + +ALLOWED_HOSTS = ['127.0.0.1',] + + +try: + from example.settings_custom import * +except ImportError: + pass \ No newline at end of file diff --git a/setup.py b/setup.py index 4c4e6f0..d55a7f4 100644 --- a/setup.py +++ b/setup.py @@ -5,10 +5,10 @@ setup( name='django-datatable', - version='0.2.1', - author='shymonk', - author_email='hellojohn201@gmail.com', - url='https://github.com/shymonk/django-datatable', + version='0.2.10', + author='gpannullo', + author_email='giuseppe.pannullo@gmail.com', + url='https://github.com/gpannullo/django-datatable', description='A simple Django app to origanize data in tabular form.', long_description=open('README.rst').read(), packages=find_packages(exclude=['test*', 'example*']), @@ -17,7 +17,7 @@ install_requires=["django>=1.5"], license='MIT License', classifiers=[ - 'Development Status :: 3 - Alpha', + 'Development Status :: 3', 'Environment :: Web Environment', 'Framework :: Django', 'Intended Audience :: Developers', @@ -26,6 +26,8 @@ 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Software Development :: Libraries', ], diff --git a/table/columns/base.py b/table/columns/base.py index f471918..2c0d0fc 100644 --- a/table/columns/base.py +++ b/table/columns/base.py @@ -13,14 +13,17 @@ class Column(object): def __init__(self, field=None, header=None, attrs=None, header_attrs=None, header_row_order=0, sortable=True, searchable=True, safe=True, - visible=True, space=True): + visible=True, space=True, html=False, width='auto', model_function=''): self.field = field self.attrs = attrs or {} + self.width = width self.sortable = sortable self.searchable = searchable self.safe = safe self.visible = visible self.space = space + self.html = html + self.model_function = model_function self.header = ColumnHeader(header, header_attrs, header_row_order) self.instance_order = Column.instance_order @@ -30,7 +33,11 @@ def __str__(self): return self.header.text def render(self, obj): + if self.model_function: + self.field = self.model_function text = Accessor(self.field).resolve(obj) + if self.html: + return text return escape(text) diff --git a/table/columns/datetimecolumn.py b/table/columns/datetimecolumn.py index 0d5a647..071f644 100644 --- a/table/columns/datetimecolumn.py +++ b/table/columns/datetimecolumn.py @@ -2,13 +2,14 @@ # coding: utf-8 from django.utils.html import escape +from table.settings import TABLE_ATTR_DEFAULT_DATE_FORMAT from table.utils import Accessor from .base import Column class DatetimeColumn(Column): - DEFAULT_FORMAT = "%Y-%m-%d %H:%M:%S" + DEFAULT_FORMAT = TABLE_ATTR_DEFAULT_DATE_FORMAT def __init__(self, field, header=None, format=None, **kwargs): self.format = format or DatetimeColumn.DEFAULT_FORMAT diff --git a/table/columns/linkcolumn.py b/table/columns/linkcolumn.py index 76661ea..3d88af9 100644 --- a/table/columns/linkcolumn.py +++ b/table/columns/linkcolumn.py @@ -31,7 +31,7 @@ class Link(object): Represents a html tag. """ def __init__(self, text=None, viewname=None, args=None, kwargs=None, urlconf=None, - current_app=None, attrs=None): + current_app=None, attrs=None, html=None): self.basetext = text self.viewname = viewname self.args = args or [] @@ -39,6 +39,13 @@ def __init__(self, text=None, viewname=None, args=None, kwargs=None, urlconf=Non self.urlconf = urlconf self.current_app = current_app self.base_attrs = attrs or {} + self.basehtml = html + + @property + def html(self): + if self.basehtml: + return self.basehtml + return None @property def text(self): @@ -86,13 +93,16 @@ def render(self, obj): """ Render link as HTML output tag . """ self.obj = obj + text = escape(self.text) + if self.html: + text = self.html attrs = ' '.join([ '%s="%s"' % (attr_name, attr.resolve(obj)) if isinstance(attr, Accessor) else '%s="%s"' % (attr_name, attr) for attr_name, attr in self.attrs.items() ]) - return mark_safe(u'%s' % (attrs, self.text)) + return mark_safe(u'%s' % (attrs, text)) class ImageLink(Link): diff --git a/table/settings.py b/table/settings.py new file mode 100644 index 0000000..d78a597 --- /dev/null +++ b/table/settings.py @@ -0,0 +1,50 @@ +from django.conf import settings + +TABLE_ATTR_ATTRS = getattr(settings, 'TABLE_ATTR_ATTRS', {}) +# scrolling option +TABLE_ATTR_SCROLLABLE = getattr(settings, 'TABLE_ATTR_SCROLLABLE', False) +TABLE_ATTR_SCROLLINNER = getattr(settings, 'TABLE_ATTR_SCROLLINNER', "150%") +TABLE_ATTR_FIXED_COLUMNS = getattr(settings, 'TABLE_ATTR_FIXED_COLUMNS', None) +TABLE_ATTR_FIXED_COLUMNS_WIDTH = getattr(settings, 'TABLE_ATTR_FIXED_COLUMNS_WIDTH', None) +# sort +TABLE_ATTR_SEARCH = getattr(settings, 'TABLE_ATTR_SEARCH', True) +TABLE_ATTR_SEARCH_PLACEHOLDER = getattr(settings, 'TABLE_ATTR_SEARCH_PLACEHOLDER', None) + +TABLE_ATTR_INFO = getattr(settings, 'TABLE_ATTR_INFO', True) +TABLE_ATTR_INFO_FORMAT = getattr(settings, 'TABLE_ATTR_INFO_FORMAT', None) + +TABLE_ATTR_PAGINATION = getattr(settings, 'TABLE_ATTR_PAGINATION', True) +TABLE_ATTR_PAGE_LENGTH = getattr(settings, 'TABLE_ATTR_PAGE_LENGTH', 10) +TABLE_ATTR_PAGINATION_FIRST = getattr(settings, 'TABLE_ATTR_PAGINATION_FIRST', None) +TABLE_ATTR_PAGINATION_LAST = getattr(settings, 'TABLE_ATTR_PAGINATION_LAST', None) +TABLE_ATTR_PAGINATION_PREV = getattr(settings, 'TABLE_ATTR_PAGINATION_PREV', None) +TABLE_ATTR_PAGINATION_NEXT = getattr(settings, 'TABLE_ATTR_PAGINATION_NEXT', None) + +TABLE_ATTR_LENGTH_MENU = getattr(settings, 'TABLE_ATTR_LENGTH_MENU', True) + +TABLE_ATTR_EXT_BUTTON = getattr(settings, 'TABLE_ATTR_EXT_BUTTON', False) +TABLE_ATTR_EXT_BUTTON_TEMPLATE = getattr(settings, 'TABLE_ATTR_EXT_BUTTON_TEMPLATE', None) +TABLE_ATTR_EXT_BUTTON_TEMPLATE_NAME = getattr(settings, 'TABLE_ATTR_EXT_BUTTON_TEMPLATE_NAME', None) +TABLE_ATTR_EXT_BUTTON_CONTEXT = getattr(settings, 'TABLE_ATTR_EXT_BUTTON_CONTEXT', None) + +TABLE_ATTR_ZERO_RECORDS = getattr(settings, 'TABLE_ATTR_ZERO_RECORDS', 'No records') +TABLE_ATTR_THEME_CSS_FILE = getattr(settings, 'TABLE_ATTR_THEME_CSS_FILE', 'table/css/datatable.bootstrap.css') +TABLE_ATTR_THEME_JS_FILE = getattr(settings, 'TABLE_ATTR_THEME_JS_FILE', 'table/js/bootstrap.dataTables.js') + +TABLE_ATTR_MEDIA_JS = getattr(settings, 'TABLE_ATTR_MEDIA_JS', ('table/js/jquery.dataTables.min.js', + 'table/js/jquery.browser.min.js', + 'table/js/dataTables.fixedColumns.min.js' + )) # option cutomize list of static to load +# option stateSave +TABLE_ATTR_STATESAVE = getattr(settings, 'TABLE_ATTR_STATESAVE', False) +TABLE_ATTR_STATEDURATION = getattr(settings, 'TABLE_ATTR_STATEDURATION', 604800) + +# option responsive +TABLE_ATTR_RESPONSIVE = getattr(settings, 'TABLE_ATTR_RESPONSIVE', False) + +# option language json +TABLE_ATTR_LANGUAGE_STATIC_JSON = getattr(settings, 'TABLE_ATTR_LANGUAGE_STATIC_JSON', + 'datatables/i18n/datatables.english.json') + + +TABLE_ATTR_DEFAULT_DATE_FORMAT = getattr(settings, 'TABLE_ATTR_DEFAULT_DATE_FORMAT',"%Y-%m-%d %H:%M:%S") \ No newline at end of file diff --git a/table/static/datatables/i18n/datatables.english.json b/table/static/datatables/i18n/datatables.english.json new file mode 100644 index 0000000..e69de29 diff --git a/table/static/datatables/responsive/1.0.7/css/responsive.bootstrap.min.css b/table/static/datatables/responsive/1.0.7/css/responsive.bootstrap.min.css new file mode 100644 index 0000000..9f53806 --- /dev/null +++ b/table/static/datatables/responsive/1.0.7/css/responsive.bootstrap.min.css @@ -0,0 +1 @@ +table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:8px;left:4px;height:16px;width:16px;display:block;position:absolute;color:white;border:2px solid white;border-radius:16px;text-align:center;line-height:14px;box-shadow:0 0 3px #444;box-sizing:content-box;content:'+';background-color:#337ab7}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child.dataTables_empty:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child.dataTables_empty:before{display:none}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:12px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:16px;text-align:center;line-height:14px;box-shadow:0 0 3px #444;box-sizing:content-box;content:'+';background-color:#337ab7}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold} diff --git a/table/static/datatables/responsive/1.0.7/js/dataTables.responsive.min.js b/table/static/datatables/responsive/1.0.7/js/dataTables.responsive.min.js new file mode 100644 index 0000000..1d76889 --- /dev/null +++ b/table/static/datatables/responsive/1.0.7/js/dataTables.responsive.min.js @@ -0,0 +1,19 @@ +/*! + Responsive 1.0.7 + 2014-2015 SpryMedia Ltd - datatables.net/license +*/ +(function(n,p){var o=function(e,k){var h=function(d,a){if(!k.versionCheck||!k.versionCheck("1.10.1"))throw"DataTables Responsive requires DataTables 1.10.1 or newer";this.s={dt:new k.Api(d),columns:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details&&(a.details={type:a.details}),this.c=e.extend(!0,{},h.defaults,k.defaults.responsive,a),d.responsive=this,this._constructor())};h.prototype={_constructor:function(){var d=this,a=this.s.dt;a.settings()[0]._responsive=this;e(n).on("resize.dtr orientationchange.dtr", +a.settings()[0].oApi._fnThrottle(function(){d._resize()}));a.on("destroy.dtr",function(){e(n).off("resize.dtr orientationchange.dtr draw.dtr")});this.c.breakpoints.sort(function(a,c){return a.widthc.width?-1:0});this._classLogic();this._resizeAuto();var c=this.c.details;c.type&&(d._detailsInit(),this._detailsVis(),a.on("column-visibility.dtr",function(){d._detailsVis()}),a.on("draw.dtr",function(){a.rows({page:"current"}).iterator("row",function(b,c){var f=a.row(c);if(f.child.isShown()){var i= +d.c.details.renderer(a,c);f.child(i,"child").show()}})}),e(a.table().node()).addClass("dtr-"+c.type));this._resize()},_columnsVisiblity:function(d){var a=this.s.dt,c=this.s.columns,b,g,f=e.map(c,function(a){return a.auto&&null===a.minWidth?!1:!0===a.auto?"-":-1!==e.inArray(d,a.includeIn)}),i=0;b=0;for(g=f.length;ba-c[b].minWidth?(i=!0,f[b]=!1):f[b]=!0,a-=c[b].minWidth);a=!1;b=0;for(g=c.length;b=j&&b(f,a[g].name)}else{if("not-"===e){g=0;for(e=a.length;g").append(f).appendTo(b);"inline"===this.c.details.type&&e(c).addClass("dtr-inline collapsed");c=e("").css({width:1,height:1,overflow:"hidden"}).append(c);c.find("th.never, td.never").remove();c.insertBefore(d.table().node());d.columns().eq(0).each(function(b){a[b].minWidth=f[b].offsetWidth||0});c.remove()}}};h.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];h.defaults={breakpoints:h.breakpoints, +auto:!0,details:{renderer:function(d,a){var c=d.cells(a,":hidden").eq(0).map(function(a){var c=e(d.column(a.column).header()),a=d.cell(a).index();if(c.hasClass("control")||c.hasClass("never"))return"";var f=d.settings()[0],f=f.oApi._fnGetCellData(f,a.row,a.column,"display");(c=c.text())&&(c+=":");return''+c+' '+f+""}).toArray().join("");return c?e('').append(c):!1},target:0, +type:"inline"}};var m=e.fn.dataTable.Api;m.register("responsive()",function(){return this});m.register("responsive.index()",function(d){d=e(d);return{column:d.data("dtr-index"),row:d.parent().data("dtr-index")}});m.register("responsive.rebuild()",function(){return this.iterator("table",function(d){d._responsive&&d._responsive._classLogic()})});m.register("responsive.recalc()",function(){return this.iterator("table",function(d){d._responsive&&(d._responsive._resizeAuto(),d._responsive._resize())})}); +h.version="1.0.7";e.fn.dataTable.Responsive=h;e.fn.DataTable.Responsive=h;e(p).on("init.dt.dtr",function(d,a){if("dt"===d.namespace&&(e(a.nTable).hasClass("responsive")||e(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||k.defaults.responsive)){var c=a.oInit.responsive;!1!==c&&new h(a,e.isPlainObject(c)?c:{})}});return h};"function"===typeof define&&define.amd?define(["../../../datatables/1.10.9/js/jquery.dataTables.min","datatables"],o):"object"===typeof exports?o(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.Responsive&& +o(jQuery,jQuery.fn.dataTable)})(window,document); diff --git a/table/static/datatables/responsive/2.0.2/css/responsive.dataTables.min.css b/table/static/datatables/responsive/2.0.2/css/responsive.dataTables.min.css new file mode 100644 index 0000000..bdd7b92 --- /dev/null +++ b/table/static/datatables/responsive/2.0.2/css/responsive.dataTables.min.css @@ -0,0 +1 @@ +table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:8px;left:4px;height:16px;width:16px;display:block;position:absolute;color:white;border:2px solid white;border-radius:16px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:left;font-family:'Courier New', Courier, monospace;text-indent:4px;line-height:16px;content:'+';background-color:#31b131}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:16px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:left;font-family:'Courier New', Courier, monospace;text-indent:4px;line-height:16px;content:'+';background-color:#31b131}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}} \ No newline at end of file diff --git a/table/static/datatables/responsive/2.0.2/js/dataTables.responsive.min.js b/table/static/datatables/responsive/2.0.2/js/dataTables.responsive.min.js new file mode 100644 index 0000000..8fc97ef --- /dev/null +++ b/table/static/datatables/responsive/2.0.2/js/dataTables.responsive.min.js @@ -0,0 +1,25 @@ +/*! + Responsive 2.0.2 + 2014-2016 SpryMedia Ltd - datatables.net/license +*/ +(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(j){return c(j,window,document)}):"object"===typeof exports?module.exports=function(j,k){j||(j=window);if(!k||!k.fn.dataTable)k=require("datatables.net")(j,k).$;return c(k,j,j.document)}:c(jQuery,window,document)})(function(c,j,k,p){var n=c.fn.dataTable,l=function(a,b){if(!n.versionCheck||!n.versionCheck("1.10.3"))throw"DataTables Responsive requires DataTables 1.10.3 or newer";this.s={dt:new n.Api(a),columns:[], +current:[]};this.s.dt.settings()[0].responsive||(b&&"string"===typeof b.details?b.details={type:b.details}:b&&!1===b.details?b.details={type:!1}:b&&!0===b.details&&(b.details={type:"inline"}),this.c=c.extend(!0,{},l.defaults,n.defaults.responsive,b),a.responsive=this,this._constructor())};c.extend(l.prototype,{_constructor:function(){var a=this,b=this.s.dt,d=b.settings()[0],e=c(j).width();b.settings()[0]._responsive=this;c(j).on("resize.dtr orientationchange.dtr",n.util.throttle(function(){var b= +c(j).width();b!==e&&(a._resize(),e=b)}));d.oApi._fnCallbackReg(d,"aoRowCreatedCallback",function(e){-1!==c.inArray(!1,a.s.current)&&c("td, th",e).each(function(e){e=b.column.index("toData",e);!1===a.s.current[e]&&c(this).css("display","none")})});b.on("destroy.dtr",function(){b.off(".dtr");c(b.table().body()).off(".dtr");c(j).off("resize.dtr orientationchange.dtr");c.each(a.s.current,function(b,e){!1===e&&a._setColumnVis(b,!0)})});this.c.breakpoints.sort(function(a,b){return a.width +b.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!==d.type&&(a._detailsInit(),b.on("column-visibility.dtr",function(){a._classLogic();a._resizeAuto();a._resize()}),b.on("draw.dtr",function(){a._redrawChildren()}),c(b.table().node()).addClass("dtr-"+d.type));b.on("column-reorder.dtr",function(){a._classLogic();a._resizeAuto();a._resize()});b.on("column-sizing.dtr",function(){a._resize()});b.on("init.dtr",function(){a._resizeAuto();a._resize();c.inArray(false,a.s.current)&&b.columns.adjust()}); +this._resize()},_columnsVisiblity:function(a){var b=this.s.dt,d=this.s.columns,e,f,g=d.map(function(a,b){return{columnIdx:b,priority:a.priority}}).sort(function(a,b){return a.priority!==b.priority?a.priority-b.priority:a.columnIdx-b.columnIdx}),h=c.map(d,function(b){return b.auto&&null===b.minWidth?!1:!0===b.auto?"-":-1!==c.inArray(a,b.includeIn)}),m=0;e=0;for(f=h.length;eb-d[i].minWidth?(m=!0,h[i]=!1):h[i]=!0,b-=d[i].minWidth)}g=!1;e=0;for(f=d.length;e= +g&&f(c,b[d].name)}else{if("not-"===i){d=0;for(i=b.length;d").append(h).appendTo(f)}c("").append(g).appendTo(e);"inline"===this.c.details.type&&c(d).addClass("dtr-inline collapsed");d=c("").css({width:1,height:1,overflow:"hidden"}).append(d);d.insertBefore(a.table().node()); +g.each(function(c){c=a.column.index("fromVisible",c);b[c].minWidth=this.offsetWidth||0});d.remove()}},_setColumnVis:function(a,b){var d=this.s.dt,e=b?"":"none";c(d.column(a).header()).css("display",e);c(d.column(a).footer()).css("display",e);d.column(a).nodes().to$().css("display",e)},_tabIndexes:function(){var a=this.s.dt,b=a.cells({page:"current"}).nodes().to$(),d=a.settings()[0],e=this.c.details.target;b.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]");c("number"===typeof e?":eq("+ +e+")":e,a.rows({page:"current"}).nodes()).attr("tabIndex",d.iTabIndex).data("dtr-keyboard",1)}});l.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];l.display={childRow:function(a,b,d){if(b){if(c(a.node()).hasClass("parent"))return a.child(d(),"child").show(),!0}else{if(a.child.isShown())return a.child(!1),c(a.node()).removeClass("parent"),!1;a.child(d(),"child").show();c(a.node()).addClass("parent"); +return!0}},childRowImmediate:function(a,b,d){if(!b&&a.child.isShown()||!a.responsive.hasHidden())return a.child(!1),c(a.node()).removeClass("parent"),!1;a.child(d(),"child").show();c(a.node()).addClass("parent");return!0},modal:function(a){return function(b,d,e){if(d)c("div.dtr-modal-content").empty().append(e());else{var f=function(){g.remove();c(k).off("keypress.dtr")},g=c('').append(c('').append(c('').append(e())).append(c('×').click(function(){f()}))).append(c('').click(function(){f()})).appendTo("body"); +c(k).on("keyup.dtr",function(a){27===a.keyCode&&(a.stopPropagation(),f())})}a&&a.header&&c("div.dtr-modal-content").prepend(""+a.header(b)+"")}}};l.defaults={breakpoints:l.breakpoints,auto:!0,details:{display:l.display.childRow,renderer:function(a,b,d){return(a=c.map(d,function(a){return a.hidden?''+a.title+' '+a.data+"": +""}).join(""))?c('').append(a):!1},target:0,type:"inline"},orthogonal:"display"};var o=c.fn.dataTable.Api;o.register("responsive()",function(){return this});o.register("responsive.index()",function(a){a=c(a);return{column:a.data("dtr-index"),row:a.parent().data("dtr-index")}});o.register("responsive.rebuild()",function(){return this.iterator("table",function(a){a._responsive&&a._responsive._classLogic()})});o.register("responsive.recalc()",function(){return this.iterator("table", +function(a){a._responsive&&(a._responsive._resizeAuto(),a._responsive._resize())})});o.register("responsive.hasHidden()",function(){var a=this.context[0];return a._responsive?-1!==c.inArray(!1,a._responsive.s.current):!1});l.version="2.0.2";c.fn.dataTable.Responsive=l;c.fn.DataTable.Responsive=l;c(k).on("preInit.dt.dtr",function(a,b){if("dt"===a.namespace&&(c(b.nTable).hasClass("responsive")||c(b.nTable).hasClass("dt-responsive")||b.oInit.responsive||n.defaults.responsive)){var d=b.oInit.responsive; +!1!==d&&new l(b,c.isPlainObject(d)?d:{})}});return l}); diff --git a/table/tables.py b/table/tables.py index a931ff2..372c264 100644 --- a/table/tables.py +++ b/table/tables.py @@ -10,7 +10,7 @@ from table.columns import Column, BoundColumn, SequenceColumn from table.widgets import SearchBox, InfoLabel, Pagination, LengthMenu, ExtButton - +from table.settings import * class BaseTable(object): @@ -141,7 +141,7 @@ def __init__(self, options=None): # build attributes for tag, use bootstrap # css class "table table-boarded" as default style - attrs = getattr(options, 'attrs', {}) + attrs = getattr(options, 'attrs', TABLE_ATTR_ATTRS) attrs['class'] = 'table ' + attrs.get('class', '') self.attrs = mark_safe(' '.join(['%s="%s"' % (attr_name, attr) for attr_name, attr in attrs.items()])) @@ -154,10 +154,10 @@ def __init__(self, options=None): for attr_name, attr in tbody_attrs.items()])) # scrolling option - self.scrollable = getattr(options, 'scrollable', False) - self.scrollinner = getattr(options, 'scrollinner', "150%") - self.fixed_columns = getattr(options, 'fixed_columns', None) - self.fixed_columns_width = getattr(options, 'fixed_columns_width', None) + self.scrollable = getattr(options, 'scrollable', TABLE_ATTR_SCROLLABLE) + self.scrollinner = getattr(options, 'scrollinner', TABLE_ATTR_SCROLLINNER) + self.fixed_columns = getattr(options, 'fixed_columns', TABLE_ATTR_FIXED_COLUMNS) + self.fixed_columns_width = getattr(options, 'fixed_columns_width', TABLE_ATTR_FIXED_COLUMNS_WIDTH) # inspect sorting option self.sort = [] @@ -171,29 +171,48 @@ def __init__(self, options=None): self.sort.append((column, order)) # options for table add-on - self.search = getattr(options, 'search', True) - self.search_placeholder = getattr(options, 'search_placeholder', None) + self.search = getattr(options, 'search', TABLE_ATTR_SEARCH) + self.search_placeholder = getattr(options, 'search_placeholder', TABLE_ATTR_SEARCH_PLACEHOLDER) + + self.info = getattr(options, 'info', TABLE_ATTR_INFO) + self.info_format = getattr(options, 'info_format', TABLE_ATTR_INFO_FORMAT) + + self.pagination = getattr(options, 'pagination', TABLE_ATTR_PAGINATION) + self.page_length = getattr(options, 'page_length', TABLE_ATTR_PAGE_LENGTH) + self.pagination_first = getattr(options, 'pagination_first', TABLE_ATTR_PAGINATION_FIRST) + self.pagination_last = getattr(options, 'pagination_last', TABLE_ATTR_PAGINATION_LAST) + self.pagination_prev = getattr(options, 'pagination_prev', TABLE_ATTR_PAGINATION_PREV) + self.pagination_next = getattr(options, 'pagination_next', TABLE_ATTR_PAGINATION_NEXT) + + self.length_menu = getattr(options, 'length_menu', TABLE_ATTR_LENGTH_MENU) + + self.ext_button = getattr(options, 'ext_button', TABLE_ATTR_EXT_BUTTON) + self.ext_button_template = getattr(options, 'ext_button_template', TABLE_ATTR_EXT_BUTTON_TEMPLATE) + self.ext_button_template_name = getattr(options, 'ext_button_template_name', TABLE_ATTR_EXT_BUTTON_TEMPLATE_NAME) + self.ext_button_context = getattr(options, 'ext_button_context', TABLE_ATTR_EXT_BUTTON_CONTEXT) + + self.zero_records = getattr(options, 'zero_records', TABLE_ATTR_ZERO_RECORDS) + self.theme_css_file = getattr(options, 'theme_css_file', TABLE_ATTR_THEME_CSS_FILE) + self.theme_js_file = getattr(options, 'theme_js_file', TABLE_ATTR_THEME_JS_FILE) + + # option cutomize list of static to load + self.media_js = getattr(options, 'media_js',TABLE_ATTR_MEDIA_JS) - self.info = getattr(options, 'info', True) - self.info_format = getattr(options, 'info_format', None) + # option stateSave + self.stateSave = getattr(options, 'stateSave', TABLE_ATTR_STATESAVE) + self.stateDuration = getattr(options, 'stateDuration', TABLE_ATTR_STATEDURATION) - self.pagination = getattr(options, 'pagination', True) - self.page_length = getattr(options, 'page_length', 10) - self.pagination_first = getattr(options, 'pagination_first', None) - self.pagination_last = getattr(options, 'pagination_last', None) - self.pagination_prev = getattr(options, 'pagination_prev', None) - self.pagination_next = getattr(options, 'pagination_next', None) + # option language json + self.language_static_json = getattr(options, 'language_static_json', TABLE_ATTR_LANGUAGE_STATIC_JSON) - self.length_menu = getattr(options, 'length_menu', True) + # option responsive + self.responsive = getattr(options, 'responsive', TABLE_ATTR_RESPONSIVE) - self.ext_button = getattr(options, 'ext_button', False) - self.ext_button_template = getattr(options, 'ext_button_template', None) - self.ext_button_template_name = getattr(options, 'ext_button_template_name', None) - self.ext_button_context = getattr(options, 'ext_button_context', None) + # option tooltip + self.tooltip_name = getattr(options, 'tooltip_name', '') - self.zero_records = getattr(options, 'zero_records', u'No records') - self.theme_css_file = getattr(options, 'theme_css_file', 'table/css/datatable.bootstrap.css') - self.theme_js_file = getattr(options, 'theme_js_file', 'table/js/bootstrap.dataTables.js') + #Add custom function to InitComplete function + self.init_complete = getattr(options, 'init_complete', None) class TableMetaClass(type): diff --git a/table/templates/table/includes/media.html b/table/templates/table/includes/media.html new file mode 100644 index 0000000..0a3c1d2 --- /dev/null +++ b/table/templates/table/includes/media.html @@ -0,0 +1,16 @@ +{% spaceless %} + {% load static %} + {% if table.opts.theme_css_file %} + + {% endif %} + {% if table.opts.responsive %} + + {% endif %} + {% for m in table.opts.media_js %} + + {% endfor %} + + {% if table.opts.responsive %} + + {% endif %} +{% endspaceless %} \ No newline at end of file diff --git a/table/templates/table/includes/script.html b/table/templates/table/includes/script.html new file mode 100644 index 0000000..df69138 --- /dev/null +++ b/table/templates/table/includes/script.html @@ -0,0 +1,93 @@ +{% load static %} + + \ No newline at end of file diff --git a/table/templates/table/includes/table.html b/table/templates/table/includes/table.html new file mode 100644 index 0000000..7cce6d5 --- /dev/null +++ b/table/templates/table/includes/table.html @@ -0,0 +1,28 @@ +{% spaceless %} + + + + {% for row in table.header_rows %} + + {% for header in row %} + + {{ header.text }} + + {% endfor %} + + {% endfor %} + + {% if not table.opts.ajax %} + + {% for row in table.rows %} + + {% for column, td in row.items %} + {% if column.safe %}{{ td }}{% else %}{{ td|safe }}{% endif %} + {% endfor %} + + {% endfor %} + + {% endif %} + + +{% endspaceless %} diff --git a/table/templates/table/table.html b/table/templates/table/table.html index bc99cf7..c23eebc 100644 --- a/table/templates/table/table.html +++ b/table/templates/table/table.html @@ -1,106 +1,10 @@ {% spaceless %} {% load static %} - - - - - +{% include 'table/includes/media.html' %} - - - {% for row in table.header_rows %} - - {% for header in row %} - - {{ header.text }} - - {% endfor %} - - {% endfor %} - - {% if not table.opts.ajax %} - - {% for row in table.rows %} - - {% for column, td in row.items %} - {% if column.safe %}{{ td }}{% else %}{{ td|safe }}{% endif %} - {% endfor %} - - {% endfor %} - - {% endif %} - +{% include 'table/includes/table.html' %} - {% endspaceless %} diff --git a/table/templates/table/table_media.html b/table/templates/table/table_media.html new file mode 100644 index 0000000..9be4248 --- /dev/null +++ b/table/templates/table/table_media.html @@ -0,0 +1,5 @@ +{% spaceless %} + +{% include 'table/includes/media.html' %} + +{% endspaceless %} diff --git a/table/templates/table/table_script.html b/table/templates/table/table_script.html new file mode 100644 index 0000000..f2c2721 --- /dev/null +++ b/table/templates/table/table_script.html @@ -0,0 +1,5 @@ +{% spaceless %} + +{% include 'table/includes/script.html' %} + +{% endspaceless %} diff --git a/table/templates/table/table_table.html b/table/templates/table/table_table.html new file mode 100644 index 0000000..5f06ac4 --- /dev/null +++ b/table/templates/table/table_table.html @@ -0,0 +1,5 @@ +{% spaceless %} + +{% include 'table/includes/table.html' %} + +{% endspaceless %} \ No newline at end of file diff --git a/table/templatetags/table_tags.py b/table/templatetags/table_tags.py index aeade3d..9b477d9 100644 --- a/table/templatetags/table_tags.py +++ b/table/templatetags/table_tags.py @@ -15,7 +15,7 @@ def __init__(self, table): def render(self, context): table = self.table.resolve(context) - context = Context({'table': table}) + context = dict({'table': table}) t = template.loader.get_template(self.template_name) return t.render(context) @@ -24,6 +24,18 @@ class SimpleTableNode(TableNode): template_name = "table/simple_table.html" +class TableTableNode(TableNode): + template_name = "table/table_table.html" + + +class MediaTableNode(TableNode): + template_name = "table/table_media.html" + + +class ScriptTableNode(TableNode): + template_name = "table/table_script.html" + + @register.tag def render_table(parser, token): try: @@ -42,3 +54,33 @@ def render_simple_table(parser, token): msg = '%r tag requires a single arguments' % token.split_contents()[0] raise template.TemplateSyntaxError(msg) return SimpleTableNode(table) + + +@register.tag +def render_table_table(parser, token): + try: + tag, table = token.split_contents() + except ValueError: + msg = '%r tag requires a single arguments' % token.split_contents()[0] + raise template.TemplateSyntaxError(msg) + return TableTableNode(table) + + +@register.tag +def render_media_table(parser, token): + try: + tag, table = token.split_contents() + except ValueError: + msg = '%r tag requires a single arguments' % token.split_contents()[0] + raise template.TemplateSyntaxError(msg) + return MediaTableNode(table) + + +@register.tag +def render_script_table(parser, token): + try: + tag, table = token.split_contents() + except ValueError: + msg = '%r tag requires a single arguments' % token.split_contents()[0] + raise template.TemplateSyntaxError(msg) + return ScriptTableNode(table)