Skip to content

Commit

Permalink
Problem: customizing tabular view is hard
Browse files Browse the repository at this point in the history
Solution: use views for table cells such that they can be overridden
  • Loading branch information
Thibaut Born authored and gotcha committed Jun 22, 2021
1 parent 9744eae commit 5b2be74
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 51 deletions.
1 change: 1 addition & 0 deletions news/customize-tabular.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Enable customization of tabular_view via views for fields of contentlisting items.
24 changes: 24 additions & 0 deletions plone/app/contenttypes/browser/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,28 @@
<browser:page name="thumbnail_view" template="templates/listing_album.pt"/>
</browser:pages>

<browser:page
name="tabular-cell-Title"
for="plone.app.contentlisting.interfaces.IContentListingObject"
class=".tabular.TitleCell"
layer="plone.app.contenttypes.interfaces.IPloneAppContenttypesLayer"
permission="zope2.View"
/>

<browser:page
name="tabular-cell-Creator"
for="plone.app.contentlisting.interfaces.IContentListingObject"
class=".tabular.CreatorCell"
layer="plone.app.contenttypes.interfaces.IPloneAppContenttypesLayer"
permission="zope2.View"
/>

<browser:page
name="tabular-cell-icon"
for="plone.app.contentlisting.interfaces.IContentListingObject"
class=".tabular.IconCell"
layer="plone.app.contenttypes.interfaces.IPloneAppContenttypesLayer"
permission="zope2.View"
/>

</configure>
53 changes: 52 additions & 1 deletion plone/app/contenttypes/browser/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
from Products.CMFPlone.interfaces import ISiteSchema
from Products.CMFPlone.PloneBatch import Batch
from Products.CMFPlone.utils import safe_callable
from Products.CMFPlone import PloneMessageFactory
from Products.Five import BrowserView
from zope.component import getMultiAdapter
from zope.component import getUtility
from zope.contentprovider.interfaces import IContentProvider
from zope.component import queryMultiAdapter
from zope.i18n import translate
from zope.i18nmessageid import Message

import random

Expand All @@ -33,6 +37,7 @@ class FolderView(BrowserView):
_plone_view = None
_portal_state = None
_pas_member = None
_image_scale = None

@property
def plone_view(self):
Expand All @@ -52,6 +57,16 @@ def portal_state(self):
)
return self._portal_state

@property
def image_scale(self):
if not self._image_scale:
portal = self.portal_state.portal()
self._image_scale = getMultiAdapter(
(portal, self.request),
name=u'image_scale'
)
return self._image_scale

@property
def pas_member(self):
if not self._pas_member:
Expand Down Expand Up @@ -172,7 +187,10 @@ def tabular_field_label(self, field):
"""Return the internationalized label (Message object) corresponding
to the field.
"""
return get_field_label(field)
label = get_field_label(field)
if not isinstance(label, Message):
return PloneMessageFactory(label)
return label

def tabular_fielddata(self, item, fieldname):
value = getattr(item, fieldname, '')
Expand All @@ -198,6 +216,31 @@ def tabular_fielddata(self, item, fieldname):
'value': value
}

def render_cells(self, item):
result = []
icon_cell_view = queryMultiAdapter(
(item, self.request),
name=f"tabular-cell-icon"
)
if icon_cell_view is not None:
icon_cell_view.table_view = self
result.append(icon_cell_view())
for field in self.tabular_fields:
if field == 'getIcon':
continue
cell_view = queryMultiAdapter(
(item, self.request),
name=f"tabular-cell-{field}"
)
if cell_view is not None:
cell_view.table_view = self
result.append(cell_view())
else:
field_data = self.tabular_fielddata(item, field)
value = translate(field_data['value'], context=self.request)
result.append('<td>%s</td>' % value)
return ''.join(result)

def is_event(self, obj):
if getattr(obj, 'getObject', False):
obj = obj.getObject()
Expand Down Expand Up @@ -274,6 +317,10 @@ def get_thumb_scale_table(self):
return None
return settings.thumb_scale_table

@property
def img_class(self):
return 'thumb-%s pull-right' % self.get_thumb_scale_table()

@memoize
def get_thumb_scale_list(self):
if getattr(self.context, 'suppress_thumbs', False):
Expand Down Expand Up @@ -304,3 +351,7 @@ def get_thumb_scale_summary(self):

def show_icons(self):
return not getattr(self.context, 'suppress_icons', False)

@property
def iconresolver(self):
return self.context.restrictedTraverse("@@iconresolver")
73 changes: 73 additions & 0 deletions plone/app/contenttypes/browser/tabular.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from Products.Five import BrowserView

# BEWARE: the cell views are registered for ContentListingObject
# which are not acquisition aware.
# That precludes using Products.Five.ViewPageTemplateFile
# and imposes to use zope.browserpage.viewpagetemplatefile.
from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
# BEWARE

class TitleCell(BrowserView):
__call__ = ViewPageTemplateFile("templates/titlecell.pt")

@property
def title(self):
return self.context.Title() or self.context.getId()

@property
def link(self):
suffix = (
"/view"
if self.context.PortalType in self.table_view.use_view_action
else ""
)
return self.context.getURL() + suffix

@property
def type_class(self):
return ("contenttype-" +
self.table_view.normalizeString(self.context.PortalType())
if self.table_view.show_icons else '')

@property
def wf_state_class(self):
return ("state-" +
self.table_view.normalizeString(self.context.review_state()))

def render_image(self):
thumb_scale_table = self.table_view.get_thumb_scale_table()
img_class = self.table_view.img_class
return self.table_view.image_scale.tag(
self.context, "image",
scale=thumb_scale_table, css_class=img_class
)


class CreatorCell(BrowserView):
__call__ = ViewPageTemplateFile("templates/creatorcell.pt")

@property
def author(self):
return self.table_view.pas_member.info(self.context.Creator)

@property
def author_name(self):
return self.author["fullname"] or self.author["username"]


class IconCell(BrowserView):
def __call__(self):
item = self.context
item_type = item.PortalType()
if item_type == "File":
icon_type = "mimetype-" + item.mime_type
elif self.table_view.show_icons:
icon_type = ("contenttype/"
+ self.table_view.normalizeString(item_type))
else:
icon_type = ""
icon = self.table_view.iconresolver.tag(icon_type).decode("utf8")
return "<td>" + icon + "</td>"

def normalizeString(self, string):
return self.table_view.normalizeString(string)
5 changes: 5 additions & 0 deletions plone/app/contenttypes/browser/templates/creatorcell.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<td>
<a tal:condition="view/author"
tal:attributes="href string:${view/table_view/navigation_root_url}/author/${context/Creator}"
tal:content="view/author_name">Jos Henken</a>
</td>
53 changes: 3 additions & 50 deletions plone/app/contenttypes/browser/templates/listing_tabular.pt
Original file line number Diff line number Diff line change
Expand Up @@ -31,58 +31,11 @@
<th class="text-nowrap" i18n:translate="image" tal:condition="python:thumb_scale_table">Image</th>
</tr>
</thead>

<tbody tal:define="portal python:portal_state.portal(); image_scale portal/@@image_scale">
<tal:entries tal:repeat="item python:batch">
<tal:block tal:define="item_url python:item.getURL();
item_id python:item.getId();
item_title python:item.Title();
item_title python:item_title or item_id;
item_type python:item.PortalType();
item_type_class python:'contenttype/' + view.normalizeString(item_type) if showicons else '';
item_wf_state python:item.review_state();
item_wf_state_class python:'state-' + view.normalizeString(item_wf_state);
item_creator python:item.Creator();
item_has_image python:item.getIcon;
item_link python:item_type in view.use_view_action and item_url+'/view' or item_url;
item_mime_type python:item.mime_type;
item_mime_type_icon python: 'mimetype-' + item_mime_type;
">

<tr metal:define-macro="listitem">

<td>
<tal:icon tal:condition="python: item_type == 'File'" tal:replace="structure python:icons.tag(item_mime_type_icon)" />
<tal:icon tal:condition="python: item_type != 'File'" tal:replace="structure python:icons.tag(item_type_class)" />
</td>

<tal:block tal:repeat="field python:tabular_fields">

<td class="text-nowrap" tal:condition="python:field not in ['Title', 'Creator', 'getIcon']" tal:define="field_data python:view.tabular_fielddata(item, field)">
<tal:block tal:replace="python: field_data.get('value')" />
</td>

<td class="text-nowrap" tal:condition="python:field == 'Title'">
<a tal:attributes="href python:item_link; class string:$item_type_class $item_wf_state_class url; title python:item_type" tal:content="python: item_title">
Item Title
</a>
</td>

<td class="text-nowrap" tal:condition="python:field == 'Creator'" tal:define="author python:view.pas_member.info(item_creator); name python:author['fullname'] or author['username']">
<a tal:condition="python: author" tal:attributes="href string:${view.navigation_root_url}/author/${item_creator}" tal:content="python: name">Jos Henken</a>
</td>

</tal:block>

<td>
<a tal:condition="python:item_has_image and thumb_scale_table">
<img tal:attributes="href python: item_link" tal:replace="structure python:image_scale.tag(item, 'image', scale=thumb_scale_table, css_class=img_class)" />
</a>
</td>

<tal:entries tal:repeat="item batch">
<tr metal:define-macro="listitem"
tal:content="structure python:view.render_cells(item)">
</tr>

</tal:block>
</tal:entries>
</tbody>
</table>
Expand Down
19 changes: 19 additions & 0 deletions plone/app/contenttypes/browser/templates/titlecell.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<td tal:define="table_view nocall:view/table_view;
thumb_scale_table view/table_view/get_thumb_scale_table;">
<a tal:condition="python:context.PortalType == 'File' and table_view.show_icons()"
tal:attributes="href view/link;
class string:${view/type_class} ${view/wf_state_class} url;
title context/PortalType">
<img class="mime-icon"
tal:attributes="src context/MimeTypeIcon">
</a>
<a tal:attributes="href view/link;
class string:${view/type_class} ${view/wf_state_class} url;
title context/PortalType"
tal:content="view/title">Item Title
</a>
<a tal:condition="python:context.getIcon and thumb_scale_table">
<img tal:attributes="href view/link"
tal:replace="structure view/render_image" />
</a>
</td>

0 comments on commit 5b2be74

Please sign in to comment.