src/pyams_skin/table.py
changeset 0 bb4aabe07487
child 2 a0a4774f0ce9
equal deleted inserted replaced
-1:000000000000 0:bb4aabe07487
       
     1 #
       
     2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
       
     3 # All Rights Reserved.
       
     4 #
       
     5 # This software is subject to the provisions of the Zope Public License,
       
     6 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
       
     7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
       
     8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
     9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
       
    10 # FOR A PARTICULAR PURPOSE.
       
    11 #
       
    12 
       
    13 __docformat__ = 'restructuredtext'
       
    14 
       
    15 # import standard library
       
    16 
       
    17 # import interfaces
       
    18 from pyams_skin.interfaces.container import ITable, ITableElementEditor
       
    19 from pyams_skin.layer import IPyAMSLayer
       
    20 from z3c.table.interfaces import IColumn
       
    21 from zope.container.interfaces import IContained
       
    22 
       
    23 # import packages
       
    24 from pyams_template.template import get_view_template, template_config
       
    25 from pyams_utils.adapter import ContextRequestViewAdapter, adapter_config
       
    26 from pyams_utils.url import absolute_url
       
    27 from pyramid.url import resource_url
       
    28 from z3c.table.column import Column, GetAttrColumn
       
    29 from z3c.table.table import Table
       
    30 from zope.interface import implementer, Interface
       
    31 
       
    32 from pyams_skin import _
       
    33 
       
    34 
       
    35 @adapter_config(context=(IContained, IPyAMSLayer, ITable), provides=ITableElementEditor)
       
    36 class DefaultElementEditorAdapter(ContextRequestViewAdapter):
       
    37     """Default contained element editor"""
       
    38 
       
    39     view_name = 'properties.html'
       
    40 
       
    41     @property
       
    42     def url(self):
       
    43         return resource_url(self.context, self.request, self.view_name)
       
    44 
       
    45     modal_target = True
       
    46 
       
    47 
       
    48 def get_element_editor(table, element):
       
    49     """Get editor for selected element"""
       
    50     registry = table.request.registry
       
    51     return registry.queryMultiAdapter((element, table.request, table), ITableElementEditor)
       
    52 
       
    53 
       
    54 @template_config(template='templates/table.pt', layer=IPyAMSLayer)
       
    55 @implementer(ITable)
       
    56 class BaseTable(Table):
       
    57     """Custom table"""
       
    58 
       
    59     id = _("TableID")
       
    60     title = _("Container elements")
       
    61 
       
    62     cssClasses = {'table': 'table table-bordered table-striped table-hover table-tight datatable'}
       
    63 
       
    64     @property
       
    65     def data_attributes(self):
       
    66         return {'tr': {'id': lambda x: '{0}::{1}'.format(self.id, x.__name__),
       
    67                        'data-ams-element-name': lambda x: x.__name__,
       
    68                        'data-ams-url': lambda x: getattr(get_element_editor(self, x), 'url', ''),
       
    69                        'data-toggle': lambda x: 'modal' if getattr(get_element_editor(self, x), 'modal_target', None) else None}}
       
    70 
       
    71     batchSize = 10000
       
    72     startBatchingAt = 10000
       
    73 
       
    74     def getBatchSize(self):
       
    75         return int(self.request.params.get(self.prefix + '-batchSize', self.batchSize))
       
    76 
       
    77     def getBatchStart(self):
       
    78         return int(self.request.params.get(self.prefix + '-batchStart', self.batchStart))
       
    79 
       
    80     def getSortOn(self):
       
    81         return self.request.params.get(self.prefix + '-sortOn', self.sortOn)
       
    82 
       
    83     def getSortOrder(self):
       
    84         return self.request.params.get(self.prefix + '-sortOrder', self.sortOrder)
       
    85 
       
    86     @staticmethod
       
    87     def check_data_attribute(attribute, source):
       
    88         if isinstance(attribute, str):
       
    89             return attribute
       
    90         elif callable(attribute):
       
    91             return attribute(source)
       
    92         else:
       
    93             return str(attribute)
       
    94 
       
    95     def get_data_attributes(self, element, source, column=None):
       
    96         attrs = self.data_attributes.get(element)
       
    97         if attrs:
       
    98             result = ''
       
    99             for key, value in attrs.items():
       
   100                 checked_value = self.check_data_attribute(value, source)
       
   101                 if checked_value is not None:
       
   102                     result += "{0}='{1}'".format(key, checked_value)
       
   103             return result
       
   104         else:
       
   105             return ''
       
   106 
       
   107     render = get_view_template()
       
   108 
       
   109     def renderTable(self):
       
   110         return super(BaseTable, self).renderTable() \
       
   111                                      .replace('<table', '<table %s' % self.get_data_attributes('table', self))
       
   112 
       
   113     def renderRow(self, row, cssClass=None):
       
   114         return super(BaseTable, self).renderRow(row, cssClass) \
       
   115                                      .replace('<tr', '<tr %s' % self.get_data_attributes('tr', row[0][0]))
       
   116 
       
   117     def renderCell(self, item, column, colspan=0):
       
   118         return super(BaseTable, self).renderCell(item, column, colspan) \
       
   119                                      .replace('<td', '<td %s' % self.get_data_attributes('td', item, column))
       
   120 
       
   121 
       
   122 @adapter_config(name='name', context=(Interface, IPyAMSLayer, BaseTable), provides=IColumn)
       
   123 class NameColumn(GetAttrColumn):
       
   124     """Container column"""
       
   125 
       
   126     header = _("Name")
       
   127     attrName = '__name__'
       
   128 
       
   129 
       
   130 class ActionColumn(Column):
       
   131     """Base action icon column"""
       
   132 
       
   133     header = ''
       
   134     icon_class = 'fa fa-fw fa-search'
       
   135     icon_hint = _("Search")
       
   136     cssClasses = {'th': 'action',
       
   137                   'td': 'action'}
       
   138     url = "#"
       
   139     target = '#content'
       
   140     modal_target = False
       
   141 
       
   142     def renderCell(self, item):
       
   143         translate = self.request.localizer.translate
       
   144         return '''<a class="hint" title="{title}" href="{url}"
       
   145                      data-ams-target="{target}" {modal} data-ams-hint-gravity="se">
       
   146             <i class="{icon_class}"></i>
       
   147         </a>'''.format(title=translate(self.icon_hint),
       
   148                        url=self.get_url(item),
       
   149                        target=self.target,
       
   150                        modal='data-toggle="modal"' if self.modal_target else '',
       
   151                        icon_class=self.icon_class)
       
   152 
       
   153     def get_url(self, item):
       
   154         return absolute_url(item, self.request, self.url)