src/pyams_skin/table.py
changeset 0 bb4aabe07487
child 2 a0a4774f0ce9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_skin/table.py	Thu Feb 19 10:59:00 2015 +0100
@@ -0,0 +1,154 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+# import standard library
+
+# import interfaces
+from pyams_skin.interfaces.container import ITable, ITableElementEditor
+from pyams_skin.layer import IPyAMSLayer
+from z3c.table.interfaces import IColumn
+from zope.container.interfaces import IContained
+
+# import packages
+from pyams_template.template import get_view_template, template_config
+from pyams_utils.adapter import ContextRequestViewAdapter, adapter_config
+from pyams_utils.url import absolute_url
+from pyramid.url import resource_url
+from z3c.table.column import Column, GetAttrColumn
+from z3c.table.table import Table
+from zope.interface import implementer, Interface
+
+from pyams_skin import _
+
+
+@adapter_config(context=(IContained, IPyAMSLayer, ITable), provides=ITableElementEditor)
+class DefaultElementEditorAdapter(ContextRequestViewAdapter):
+    """Default contained element editor"""
+
+    view_name = 'properties.html'
+
+    @property
+    def url(self):
+        return resource_url(self.context, self.request, self.view_name)
+
+    modal_target = True
+
+
+def get_element_editor(table, element):
+    """Get editor for selected element"""
+    registry = table.request.registry
+    return registry.queryMultiAdapter((element, table.request, table), ITableElementEditor)
+
+
+@template_config(template='templates/table.pt', layer=IPyAMSLayer)
+@implementer(ITable)
+class BaseTable(Table):
+    """Custom table"""
+
+    id = _("TableID")
+    title = _("Container elements")
+
+    cssClasses = {'table': 'table table-bordered table-striped table-hover table-tight datatable'}
+
+    @property
+    def data_attributes(self):
+        return {'tr': {'id': lambda x: '{0}::{1}'.format(self.id, x.__name__),
+                       'data-ams-element-name': lambda x: x.__name__,
+                       'data-ams-url': lambda x: getattr(get_element_editor(self, x), 'url', ''),
+                       'data-toggle': lambda x: 'modal' if getattr(get_element_editor(self, x), 'modal_target', None) else None}}
+
+    batchSize = 10000
+    startBatchingAt = 10000
+
+    def getBatchSize(self):
+        return int(self.request.params.get(self.prefix + '-batchSize', self.batchSize))
+
+    def getBatchStart(self):
+        return int(self.request.params.get(self.prefix + '-batchStart', self.batchStart))
+
+    def getSortOn(self):
+        return self.request.params.get(self.prefix + '-sortOn', self.sortOn)
+
+    def getSortOrder(self):
+        return self.request.params.get(self.prefix + '-sortOrder', self.sortOrder)
+
+    @staticmethod
+    def check_data_attribute(attribute, source):
+        if isinstance(attribute, str):
+            return attribute
+        elif callable(attribute):
+            return attribute(source)
+        else:
+            return str(attribute)
+
+    def get_data_attributes(self, element, source, column=None):
+        attrs = self.data_attributes.get(element)
+        if attrs:
+            result = ''
+            for key, value in attrs.items():
+                checked_value = self.check_data_attribute(value, source)
+                if checked_value is not None:
+                    result += "{0}='{1}'".format(key, checked_value)
+            return result
+        else:
+            return ''
+
+    render = get_view_template()
+
+    def renderTable(self):
+        return super(BaseTable, self).renderTable() \
+                                     .replace('<table', '<table %s' % self.get_data_attributes('table', self))
+
+    def renderRow(self, row, cssClass=None):
+        return super(BaseTable, self).renderRow(row, cssClass) \
+                                     .replace('<tr', '<tr %s' % self.get_data_attributes('tr', row[0][0]))
+
+    def renderCell(self, item, column, colspan=0):
+        return super(BaseTable, self).renderCell(item, column, colspan) \
+                                     .replace('<td', '<td %s' % self.get_data_attributes('td', item, column))
+
+
+@adapter_config(name='name', context=(Interface, IPyAMSLayer, BaseTable), provides=IColumn)
+class NameColumn(GetAttrColumn):
+    """Container column"""
+
+    header = _("Name")
+    attrName = '__name__'
+
+
+class ActionColumn(Column):
+    """Base action icon column"""
+
+    header = ''
+    icon_class = 'fa fa-fw fa-search'
+    icon_hint = _("Search")
+    cssClasses = {'th': 'action',
+                  'td': 'action'}
+    url = "#"
+    target = '#content'
+    modal_target = False
+
+    def renderCell(self, item):
+        translate = self.request.localizer.translate
+        return '''<a class="hint" title="{title}" href="{url}"
+                     data-ams-target="{target}" {modal} data-ams-hint-gravity="se">
+            <i class="{icon_class}"></i>
+        </a>'''.format(title=translate(self.icon_hint),
+                       url=self.get_url(item),
+                       target=self.target,
+                       modal='data-toggle="modal"' if self.modal_target else '',
+                       icon_class=self.icon_class)
+
+    def get_url(self, item):
+        return absolute_url(item, self.request, self.url)