Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve table view customizability (fix dependency) #676

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ global-exclude *.pyc

recursive-exclude news *
exclude news
include flake.nix
26 changes: 26 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
description = "A very basic flake";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/release-23.05";
flake-utils.url = "github:numtide/flake-utils";
};

outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem
(system:
let
pkgs = nixpkgs.legacyPackages.${system};

my-python-packages = python-packages: with python-packages; [
virtualenv
tox
];
python = pkgs.python311.withPackages my-python-packages;
in
{
devShells.default = pkgs.mkShell {
buildInputs = [ python pkgs.geckodriver pkgs.chromedriver];
};
}
);
}
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.
32 changes: 32 additions & 0 deletions plone/app/contenttypes/browser/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -223,4 +223,36 @@
name="plone.app.contenttypes.migration.changed_base_classes"
/>

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

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

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

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

</configure>
60 changes: 58 additions & 2 deletions plone/app/contenttypes/browser/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
from plone.event.interfaces import IEvent
from plone.memoize.view import memoize
from plone.registry.interfaces import IRegistry
from Products.CMFPlone import PloneMessageFactory
from Products.Five import BrowserView
from zope.component import getMultiAdapter
from zope.component import getUtility
from zope.component import queryMultiAdapter
from zope.contentprovider.interfaces import IContentProvider
from zope.i18n import translate
from zope.i18nmessageid import Message

import random

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

@property
def plone_view(self):
Expand All @@ -42,6 +47,15 @@ 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="image_scale"
)
return self._image_scale

@property
def pas_member(self):
if not self._pas_member:
Expand Down Expand Up @@ -142,7 +156,6 @@ def text(self):
)
return text

@property
def tabular_fields(self):
ret = []
ret.append("Title")
Expand All @@ -157,7 +170,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 @@ -179,11 +195,43 @@ def tabular_fielddata(self, item, fieldname):
]:
value = self.toLocalizedTime(value, long_format=1)

if isinstance(value, (list, tuple)):
value = ", ".join([entry for entry in value])

return {
# 'title': _(fieldname, default=fieldname),
"value": value
}

def render_cells(self, item):
result = []
icon_cell_view = queryMultiAdapter(
(item, self.request), name="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 class="text-nowrap">%s</td>' % value)
image_cell_view = queryMultiAdapter(
(item, self.request), name="tabular-cell-image"
)
if image_cell_view is not None:
image_cell_view.table_view = self
result.append(image_cell_view())
return "".join(result)

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

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

@memoize
def get_thumb_scale_list(self):
if getattr(self.context, "suppress_thumbs", False):
Expand Down Expand Up @@ -276,3 +328,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")
81 changes: 81 additions & 0 deletions plone/app/contenttypes/browser/tabular.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
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.portal_type 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.portal_type)
if self.table_view.show_icons
else ""
)

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


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.portal_type
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>"


class ImageCell(BrowserView):
def render_image(self):
thumb_scale_table = self.table_view.get_thumb_scale_table()
if thumb_scale_table and self.context.getIcon:
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
)
else:
return ""

def __call__(self):
image = self.render_image()
return "<td>" + image + "</td>"
8 changes: 8 additions & 0 deletions plone/app/contenttypes/browser/templates/creatorcell.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<td class="text-nowrap">
<a tal:condition="view/author"
tal:content="view/author_name"
tal:attributes="
href string:${view/table_view/navigation_root_url}/author/${context/Creator};
"
>Jos Henken</a>
</td>
89 changes: 5 additions & 84 deletions plone/app/contenttypes/browser/templates/listing_tabular.pt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
tal:define="
tabular_fields view/tabular_fields;
thumb_scale_table python:view.get_thumb_scale_table();
img_class python:'thumb-%s float-end' % thumb_scale_table;
showicons python:view.show_icons();
"
i18n:attributes="summary summary_content_listing;"
Expand All @@ -62,93 +61,15 @@
>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:define="
field_data python:view.tabular_fielddata(item, field);
"
tal:condition="python:field not in ['Title', 'Creator', 'getIcon']"
>
<tal:block tal:replace="python: field_data.get('value')" />
</td>

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

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

</tal:block>

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

</tr>

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