radiant-library-extension 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,276 @@
1
+ module Library
2
+ module LibraryTags
3
+ include Radiant::Taggable
4
+
5
+ class TagError < StandardError; end
6
+
7
+ ############### tags for use on library pages
8
+ # usually to build a faceted browser
9
+
10
+ tag "library" do |tag|
11
+ raise TagError, "library:* tags can only be used on a LibraryPage" unless tag.locals.page && tag.locals.page.is_a?(LibraryPage)
12
+ tag.expand
13
+ end
14
+
15
+ desc %{
16
+ Displays a list of the tags that can be used to narrow the set of results displayed. This begins as a list of
17
+ all available tags, and as they are chosen it shrinks to show only the coincident tags that will further reduce the set.
18
+
19
+ This is normally used to display a list or cloud of facets that can be added to a search. The default is to show a cloud.
20
+
21
+ <pre><code>
22
+ <r:library:tags:each><li><r:tag:link /></li></r:library:tags:each>
23
+ <r:library:tags:list />
24
+ <r:library:tags:cloud />
25
+ <r:library:tags />
26
+ </code></pre>
27
+
28
+ To show only those tags attached to a particular kind of object, supply a 'for' parameter.
29
+ The parameter can be 'pages', 'assets' or the plural of any asset type. If you're displaying an image gallery,
30
+ you may want to start with a cloud of all the tags that have been applied to images:
31
+
32
+ <pre><code>
33
+ <r:library:tags for="images" />
34
+ </code></pre>
35
+
36
+ You can still display pages associated with those tags, but the list will not include tags that only have pages.
37
+ }
38
+ tag "library:tags" do |tag|
39
+ tag.locals.tags = _get_coincident_tags(tag)
40
+ if tag.double?
41
+ tag.expand
42
+ else
43
+ tag.render('tags:cloud', tag.attr.dup)
44
+ end
45
+ end
46
+ tag "library:tags:each" do |tag|
47
+ tag.render('tags:each', tag.attr.dup, &tag.block)
48
+ end
49
+ tag "library:tags:list" do |tag|
50
+ tag.render('tags:list', tag.attr.dup)
51
+ end
52
+ tag "library:tags:cloud" do |tag|
53
+ tag.render('tags:cloud', tag.attr.dup)
54
+ end
55
+
56
+
57
+ desc %{
58
+ Expands if there are is more than one tag to show.
59
+ (If there is only one tag coincident with the present set then it offers no reduction).
60
+
61
+ *Usage:*
62
+ <pre><code>
63
+ <r:library:if_tags>
64
+ Displaying items tagged with all of <r:requested_tags />
65
+ <r:library:if_requested_tags>
66
+ </code></pre>
67
+ }
68
+ tag "library:unless_tags" do |tag|
69
+ tag.locals.tags = _get_coincident_tags(tag)
70
+ tag.expand if tag.locals.tags.length > 1
71
+ end
72
+ desc %{
73
+ Expands if there are is more than one tag to show.
74
+ (If there is only one tag coincident with the present set then it offers no reduction, so we don't show it).
75
+
76
+ *Usage:*
77
+ <pre><code>
78
+ <r:library:if_tags><r:library:tags /></r:library:if_tags>
79
+ </code></pre>
80
+ }
81
+ tag "library:if_tags" do |tag|
82
+ tag.locals.tags = _get_coincident_tags(tag)
83
+ tag.expand if tag.locals.tags.length > 1
84
+ end
85
+
86
+ desc %{
87
+ Expands if there are is one or no coincident tags to show.
88
+ }
89
+ tag "library:unless_tags" do |tag|
90
+ tag.expand unless _get_coincident_tags(tag).length > 1
91
+ end
92
+
93
+ desc %{
94
+ Displays a list of the tags requested by the user.
95
+ To offer links that remove the tag from the current set, these will both work:
96
+
97
+ *Usage:*
98
+ <pre><code>
99
+ <r:library:requested_tags:each><li><r:tag:unlink /></li></r:library:requested_tags:each>
100
+ <r:library:requested_tags />
101
+ </code></pre>
102
+ }
103
+ tag "library:requested_tags" do |tag|
104
+ tag.locals.tags = _get_requested_tags(tag)
105
+ if tag.double?
106
+ tag.expand
107
+ else
108
+ tag.render('tags:unlink_list', tag.attr.dup)
109
+ end
110
+ end
111
+ tag "library:requested_tags:each" do |tag|
112
+ tag.render('tags:each', tag.attr.dup, &tag.block)
113
+ end
114
+
115
+ desc %{
116
+ Expands if any tags have been specified:
117
+
118
+ *Usage:*
119
+ <pre><code>
120
+ <r:library:if_requested_tags>
121
+ Displaying items tagged with all of <r:requested_tags />
122
+ <r:library:if_requested_tags>
123
+ </code></pre>
124
+ }
125
+ tag "library:if_requested_tags" do |tag|
126
+ tag.locals.tags = _get_requested_tags(tag)
127
+ tag.expand if tag.locals.tags.any?
128
+ end
129
+
130
+ desc %{
131
+ Expands if no tags have been specified:
132
+
133
+ *Usage:*
134
+ <pre><code>
135
+ <r:library:unless_requested_tags>
136
+ Showing everything. Choose a tag to start narrowing down the list.
137
+ <r:library:unless_requested_tags>
138
+ </code></pre>
139
+ }
140
+ tag "library:unless_requested_tags" do |tag|
141
+ tag.expand unless _get_requested_tags(tag).any?
142
+ end
143
+
144
+ desc %{
145
+ Displays a list of the pages associated with the current tag set. If no tags are specified, this will show all pages.
146
+ You can use all the usual r:page tags within the list.
147
+
148
+ *Usage:*
149
+ <pre><code>
150
+ <r:library:pages:each><li><r:link /><br /><r:content part="description" /></li></r:library:pages:each>
151
+ </code></pre>
152
+ }
153
+ tag "library:pages" do |tag|
154
+ tag.locals.pages = _get_pages(tag)
155
+ tag.expand
156
+ end
157
+ tag "library:pages:each" do |tag|
158
+ tag.render('page_list', tag.attr.dup, &tag.block) # r:page_list is defined in taggable
159
+ end
160
+
161
+ desc %{
162
+ Expands if there are any pages associated with all of the current tag set.
163
+
164
+ *Usage:*
165
+ <pre><code>
166
+ <r:library:if_pages><h2>Pages</h2>...</r:library:if_pages>
167
+ </code></pre>
168
+ }
169
+ tag "library:if_pages" do |tag|
170
+ tag.expand if _get_pages(tag).any?
171
+ end
172
+
173
+ desc %{
174
+ Displays a list of the assets associated with the current tag set. If no tags are specified, this will show all assets.
175
+ You can use all the usual r:assets tags within the list.
176
+
177
+ *Usage:*
178
+ <pre><code>
179
+ <r:library:assets:each><li><r:assets:thumbnail /></li></r:library:assets:each>
180
+ </code></pre>
181
+ }
182
+ tag "library:assets" do |tag|
183
+ tag.locals.assets = _get_assets(tag)
184
+ tag.expand
185
+ end
186
+ tag "library:assets:each" do |tag|
187
+ tag.render('asset_list', tag.attr.dup, &tag.block)
188
+ end
189
+
190
+ desc %{
191
+ Expands if there are any assets associated with all of the current tag set.
192
+
193
+ *Usage:*
194
+ <pre><code>
195
+ <r:library:if_assets><h2>Assets</h2>...</r:library:if_assets>
196
+ </code></pre>
197
+ }
198
+ tag "library:if_assets" do |tag|
199
+ tag.expand if _get_assets(tag).any?
200
+ end
201
+
202
+ Asset.known_types.each do |type|
203
+ these = type.to_s.pluralize
204
+
205
+ desc %{
206
+ Displays a list of the all the #{these} associated with the current tag set. If no tags are specified, this will show all such assets.
207
+ You can use all the usual r:assets tags within the list.
208
+
209
+ *Usage:*
210
+ <pre><code>
211
+ <r:library:#{these}:each><li><r:assets:link /></li></r:library:#{these}:each>
212
+ </code></pre>
213
+ }
214
+ tag "library:#{these}" do |tag|
215
+ tag.locals.assets = _get_assets(tag).send(these.intern)
216
+ tag.expand
217
+ end
218
+ tag "library:#{these}:each" do |tag|
219
+ tag.render('asset_list', tag.attr.dup, &tag.block)
220
+ end
221
+
222
+ desc %{
223
+ Expands if there are any #{these} associated with all of the current tag set.
224
+
225
+ *Usage:*
226
+ <pre><code>
227
+ <r:library:if_#{these}><h2>#{these.titlecase}</h2>...</r:library:if_#{these}>
228
+ </code></pre>
229
+ }
230
+ tag "library:if_#{these}" do |tag|
231
+ tag.locals.assets = _get_assets(tag).send(these.intern)
232
+ tag.expand if tag.locals.assets.any?
233
+ end
234
+
235
+ private
236
+
237
+ def _get_requested_tags(tag)
238
+ tag.locals.page.requested_tags
239
+ end
240
+
241
+ def _get_coincident_tags(tag)
242
+ requested = _get_requested_tags(tag)
243
+ limit = tag.attr['limit'] || 50
244
+ if requested.any?
245
+ Tag.coincident_with(requested)
246
+ else
247
+ Tag.most_popular(limit)
248
+ end
249
+ end
250
+ end
251
+
252
+ # in the absence of any requested tags we default to all, not none
253
+
254
+ def _get_pages(tag)
255
+ requested = _get_requested_tags(tag)
256
+ if requested.any?
257
+ Page.tagged_with(requested)
258
+ else
259
+ Page.scoped({}) # there must be a better way to return a new scope
260
+ end
261
+ end
262
+
263
+ def _get_assets(tag)
264
+ requested = _get_requested_tags(tag)
265
+ if requested.any?
266
+ Asset.tagged_with(requested)
267
+ else
268
+ Asset.scoped({})
269
+ end
270
+ end
271
+
272
+ end
273
+
274
+ end
275
+
276
+
@@ -0,0 +1,22 @@
1
+ # This handy simplification is adapted from SphinxSearch (thanks)
2
+ # and originally came from Ultrasphinx
3
+ # it saves us a lot of including and bodging to make will_paginate's template calls work in the Page model
4
+
5
+ module Library
6
+ class LinkRenderer < WillPaginate::LinkRenderer
7
+ def initialize(tag)
8
+ @tag = tag
9
+ end
10
+
11
+ def page_link(page, text, attributes = {})
12
+ linkclass = %{ class="#{attributes[:class]}"} if attributes[:class]
13
+ linkrel = %{ rel="#{attributes[:rel]}"} if attributes[:rel]
14
+ %Q{<a href="#{@tag.locals.page.url}?page=#{page}"#{linkrel}#{linkclass}>#{text}</a>}
15
+ end
16
+
17
+ def page_span(page, text, attributes = {})
18
+ spanclass = attributes[:class]
19
+ %{<span class="#{attributes[:class]}">#{text}</span>}
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,151 @@
1
+ module Library
2
+ module MoreAssetTags
3
+ include Radiant::Taggable
4
+
5
+ class TagError < StandardError; end
6
+
7
+ ############### assets: tags for displaying tags and relatives when we have an asset
8
+ # similar tags already exist for pages
9
+
10
+ desc %{
11
+ Cycles through all tags attached to present asset.
12
+
13
+ *Usage:*
14
+ <pre><code><r:assets:tags><r:tag:title /></r:assets:tags></code></pre>
15
+ }
16
+ tag 'assets:tags' do |tag|
17
+ raise TagError, "asset must be defined for asset:tags tag" unless tag.locals.asset
18
+ tag.locals.tags = tag.locals.asset.tags
19
+ tag.expand
20
+ end
21
+ tag 'assets:tags:each' do |tag|
22
+ tag.render('tags:each', tag.attr.dup, &tag.block)
23
+ end
24
+
25
+ desc %{
26
+ Lists all the assets similar to this asset (based on its tagging), in descending order of relatedness.
27
+
28
+ *Usage:*
29
+ <pre><code><r:related_assets:each>...</r:related_assets:each></code></pre>
30
+ }
31
+ tag 'related_assets' do |tag|
32
+ raise TagError, "asset must be defined for related_assets tag" unless tag.locals.asset
33
+ tag.locals.assets = tag.locals.asset.related_assets
34
+ tag.expand
35
+ end
36
+ tag 'related_assets:each' do |tag|
37
+ tag.render('assets:each', tag.attr.dup, &tag.block)
38
+ end
39
+
40
+ ############### extra asset fields
41
+
42
+ [:copyright].each do |method|
43
+ desc %{
44
+ Expands if the asset has a #{method} notice.
45
+ The 'title' attribute is required on this tag or the parent tag.
46
+ }
47
+ tag "assets:if_#{method.to_s}" do |tag|
48
+ options = tag.attr.dup
49
+ asset = find_asset(tag, options)
50
+ tag.expand if asset.respond_to?(method) && asset.send(method)
51
+ end
52
+
53
+ desc %{
54
+ Expands unless the asset has a #{method} notice.
55
+ The 'title' attribute is required on this tag or the parent tag.
56
+ }
57
+ tag "assets:unless_#{method.to_s}" do |tag|
58
+ options = tag.attr.dup
59
+ asset = find_asset(tag, options)
60
+ tag.expand unless asset.respond_to?(method) && asset.send(method)
61
+ end
62
+
63
+ desc %{
64
+ Renders the `#{method.to_s}' attribute of the asset.
65
+ The 'title' attribute is required on this tag or the parent tag.
66
+ }
67
+ tag "assets:#{method.to_s}" do |tag|
68
+ options = tag.attr.dup
69
+ asset = find_asset(tag, options)
70
+ asset.send(method) rescue nil
71
+ end
72
+ end
73
+
74
+ ############### useful shorthands
75
+
76
+ desc %{
77
+ Renders an illustration block for the asset, with image and caption.
78
+
79
+ *Usage:*
80
+ <pre><code><r:assets:image [title="asset_title"] [size="icon|thumbnail"]></code></pre>
81
+ }
82
+ tag "assets:illustration" do |tag|
83
+ options = tag.attr.dup
84
+ options['size'] ||= 'illustration'
85
+ tag.locals.asset = find_asset(tag, options)
86
+ if tag.locals.asset.image?
87
+ result = %{<div class="illustration">}
88
+ result << tag.render('assets:image', options)
89
+ result << %{<p class="caption">#{tag.render('assets:caption', options)}</p>}
90
+ result << "</div>"
91
+ result
92
+ end
93
+ end
94
+
95
+ desc %{
96
+ Presents a standard marginal gallery block suitable for turning unobtrusively into a rollover or lightbox gallery.
97
+ We need to be able to work out a collection of assets: that can be defined already (eg by assets:all) or come from the current page.
98
+ Default preview size is 'large' and thumbnail size 'thumbnail' but you can specify any of your asset sizes.
99
+
100
+ *Usage:*
101
+ <pre><code>
102
+ <r:assets:images>
103
+ <r:assets:minigallery [size="..."] [thumbnail_size="..."] [tags="one,or,more,tags"] />
104
+ </r:assets:images>
105
+ </code></pre>
106
+
107
+ }
108
+ tag 'assets:minigallery' do |tag|
109
+ options = tag.attr.dup.symbolize_keys
110
+ raise TagError, "asset collection must be available for assets:minigallery tag" unless tag.locals.assets or tag.locals.page or tag.attr[:tags]
111
+ if options[:tags] && tags = Tag.from_list(options[:tags])
112
+ tag.locals.assets = Asset.images.from_all_tags(tags)
113
+ else
114
+ tag.locals.assets = tag.locals.page.assets
115
+ end
116
+ tag.locals.assets.images.to_a # because we can't let empty? trigger a call to count
117
+
118
+ unless tag.locals.assets.empty?
119
+ size = tag.attr['size'] || 'illustration'
120
+ thumbsize = tag.attr['thumbnail_size'] || 'icon'
121
+ result = ""
122
+ result << %{
123
+ <div class="minigallery">}
124
+ tag.locals.asset = tag.locals.assets.first
125
+ result << tag.render('assets:image', {'size' => size})
126
+ result << %{
127
+ <p class="caption">#{tag.render('assets:caption')}</p>
128
+ <ul class="thumbnails">}
129
+ if tag.locals.assets.size > 1
130
+ tag.locals.assets.each do |asset|
131
+ tag.locals.asset = asset
132
+ result << %{
133
+ <li class="thumbnail">
134
+ <a href="#{tag.render('assets:url', 'size' => 'illustration')}" title="#{asset.caption}" id="thumbnail_#{asset.id}">
135
+ }
136
+ result << tag.render('assets:image', {'size' => thumbsize, 'alt' => asset.title})
137
+ result << %{
138
+ </a>
139
+ </li>}
140
+ end
141
+ end
142
+ result << %{
143
+ </ul>
144
+ </div>}
145
+ result
146
+ end
147
+ end
148
+
149
+ end
150
+ end
151
+