/
contentlisting.py
213 lines (183 loc) · 6.31 KB
/
contentlisting.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# -*- coding: utf-8 -*-
from operator import itemgetter
from plone.app.standardtiles import PloneMessageFactory as _
from plone.app.z3cform.widget import QueryStringFieldWidget
from plone.autoform.directives import widget
from plone.registry.interfaces import IRegistry
from plone.supermodel.model import Schema
from plone.tiles import Tile
from plone.tiles.interfaces import ITileType
from Products.CMFCore.interfaces import IFolderish
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from z3c.form.interfaces import IValue
from z3c.form.util import getSpecification
from zope import schema
from zope.component import adapter
from zope.component import getMultiAdapter
from zope.component import getUtility
from zope.component import queryUtility
from zope.interface import alsoProvides
from zope.interface import implementer
from zope.interface import Interface
from zope.interface import provider
from zope.schema import getFields
from zope.schema.interfaces import IVocabularyFactory
from zope.schema.vocabulary import SimpleVocabulary
class IContentListingTile(Schema):
"""A tile that displays a listing of content items"""
title = schema.TextLine(
title=_(u'label_title', default=u'Title'),
required=False
)
description = schema.Text(
title=_(u'label_description', default=u'Summary'),
description=_(
u'help_description',
default=u'Used in item listings and search results.'
),
required=False,
missing_value=u'',
)
widget(query=QueryStringFieldWidget)
query = schema.List(
title=_(u"Search terms"),
value_type=schema.Dict(
value_type=schema.Field(),
key_type=schema.TextLine()
),
description=_(u'Define the search terms for the items '
u'you want to list by choosing what to match on. The '
u'list of results will be dynamically updated'),
required=False
)
sort_on = schema.TextLine(
title=_(u'label_sort_on', default=u'Sort on'),
description=_(u'Sort the collection on this index'),
required=False,
)
sort_reversed = schema.Bool(
title=_(u'label_sort_reversed', default=u'Reversed order'),
description=_(u'Sort the results in reversed order'),
required=False,
)
limit = schema.Int(
title=_(u'Limit'),
description=_(u'Limit Search Results'),
required=False,
default=100,
min=1,
)
view_template = schema.Choice(
title=_(u'Display mode'),
source=_(u'Available Listing Views'),
required=True
)
class IContentListingTileLayer(Interface):
"""Layer (request marker interface) for content listing tile views"""
@implementer(IValue)
@adapter(
None,
None,
None,
getSpecification(IContentListingTile['query']),
None
)
class DefaultQuery(object):
def __init__(self, context, request, form, field, widget):
self.context = context
def get(self):
if IFolderish.providedBy(self.context):
value = '::1'
else:
value = '..::1'
return [{
'i': 'path',
'o': 'plone.app.querystring.operation.string.relativePath',
'v': value
}]
@implementer(IValue)
@adapter(
None,
None,
None,
getSpecification(IContentListingTile['sort_on']),
None
)
class DefaultSortOn(object):
def __init__(self, context, request, form, field, widget):
pass
def get(self):
return 'getObjPositionInParent'
class ContentListingTile(Tile):
"""A tile that displays a listing of content items"""
template = ViewPageTemplateFile('templates/contentlisting_view.pt')
def __call__(self):
self.update()
return self.template()
def update(self):
self.query = self.data.get('query')
self.sort_on = self.data.get('sort_on')
if self.query is None or self.sort_on is None:
# Get defaults
tileType = queryUtility(ITileType, name=self.__name__)
fields = getFields(tileType.schema)
if self.query is None:
self.query = getMultiAdapter((
self.context,
self.request,
None,
fields['query'],
None
), name='default').get()
if self.sort_on is None:
self.sort_on = getMultiAdapter((
self.context,
self.request,
None,
fields['sort_on'],
None
), name='default').get()
self.limit = self.data.get('limit')
if self.data.get('sort_reversed'):
self.sort_order = 'reverse'
else:
self.sort_order = 'ascending'
self.view_template = self.data.get('view_template')
@property
def title(self):
return self.data.get('title')
@property
def description(self):
return self.data.get('description')
def contents(self):
"""Search results"""
builder = getMultiAdapter(
(self.context, self.request),
name='querybuilderresults'
)
accessor = builder(
query=self.query,
sort_on=self.sort_on or 'getObjPositionInParent',
sort_order=self.sort_order,
limit=self.limit
)
view = self.view_template or 'listing_view'
view = view.encode('utf-8')
options = dict(original_context=self.context)
alsoProvides(self.request, IContentListingTileLayer)
return getMultiAdapter((accessor, self.request), name=view)(**options)
@provider(IVocabularyFactory)
def availableListingViewsVocabulary(context):
"""Get available views for listing content as vocabulary"""
registry = getUtility(IRegistry)
listing_views = registry.get('plone.app.standardtiles.listing_views', {})
if len(listing_views) == 0:
listing_views = {
'listing_view': u'Listing view',
'summary_view': u'Summary view',
'tabular_view': u'Tabular view'
}
voc = []
for key, label in sorted(listing_views.items(), key=itemgetter(1)):
voc.append(SimpleVocabulary.createTerm(key, key, label))
return SimpleVocabulary(voc)