trusty-cms 3.1.11 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -14
  3. data/Gemfile.lock +84 -70
  4. data/README.md +4 -0
  5. data/app/assets/images/admin/add.png +0 -0
  6. data/app/assets/images/admin/archive_icon.png +0 -0
  7. data/app/assets/images/admin/audio_icon.png +0 -0
  8. data/app/assets/images/admin/audio_thumbnail.png +0 -0
  9. data/app/assets/images/admin/c_icon.png +0 -0
  10. data/app/assets/images/admin/copy.png +0 -0
  11. data/app/assets/images/admin/css_icon.png +0 -0
  12. data/app/assets/images/admin/database_icon.png +0 -0
  13. data/app/assets/images/admin/delete.png +0 -0
  14. data/app/assets/images/admin/document_icon.png +0 -0
  15. data/app/assets/images/admin/document_thumbnail.png +0 -0
  16. data/app/assets/images/admin/flash_icon.png +0 -0
  17. data/app/assets/images/admin/flash_thumbnail.png +0 -0
  18. data/app/assets/images/admin/font_icon.png +0 -0
  19. data/app/assets/images/admin/gzip_icon.png +0 -0
  20. data/app/assets/images/admin/html_icon.png +0 -0
  21. data/app/assets/images/admin/image_icon.png +0 -0
  22. data/app/assets/images/admin/image_thumbnail.png +0 -0
  23. data/app/assets/images/admin/java_icon.png +0 -0
  24. data/app/assets/images/admin/page_edit.png +0 -0
  25. data/app/assets/images/admin/pdf_icon.png +0 -0
  26. data/app/assets/images/admin/pdf_thumbnail.png +0 -0
  27. data/app/assets/images/admin/perl_icon.png +0 -0
  28. data/app/assets/images/admin/php_icon.png +0 -0
  29. data/app/assets/images/admin/presentation_icon.png +0 -0
  30. data/app/assets/images/admin/python_icon.png +0 -0
  31. data/app/assets/images/admin/reorder_assets.png +0 -0
  32. data/app/assets/images/admin/ruby_icon.png +0 -0
  33. data/app/assets/images/admin/script_icon.png +0 -0
  34. data/app/assets/images/admin/spinner.gif +0 -0
  35. data/app/assets/images/admin/spreadsheet_icon.png +0 -0
  36. data/app/assets/images/admin/tar_icon.png +0 -0
  37. data/app/assets/images/admin/unknown_icon.png +0 -0
  38. data/app/assets/images/admin/unknown_thumbnail.png +0 -0
  39. data/app/assets/images/admin/video_icon.png +0 -0
  40. data/app/assets/images/admin/video_thumbnail.png +0 -0
  41. data/app/assets/images/admin/xml_icon.png +0 -0
  42. data/app/assets/images/admin/zip_icon.png +0 -0
  43. data/app/assets/javascripts/admin/assets.js +268 -0
  44. data/app/assets/javascripts/admin/assets_admin.js +16 -0
  45. data/app/assets/javascripts/admin/jquery.fileupload.js +1457 -0
  46. data/app/assets/javascripts/admin/jquery.iframe-transport.js +214 -0
  47. data/app/assets/javascripts/admin/jquery.ui.widget.js +558 -0
  48. data/app/assets/stylesheets/admin/assets.scss +283 -0
  49. data/app/controllers/admin/assets_controller.rb +88 -0
  50. data/app/controllers/admin/page_attachments_controller.rb +23 -0
  51. data/app/helpers/admin/assets_helper.rb +16 -0
  52. data/app/helpers/admin/page_attachments_helper.rb +2 -0
  53. data/app/models/asset.rb +251 -0
  54. data/app/models/asset_type.rb +239 -0
  55. data/app/models/old_page_attachment.rb +26 -0
  56. data/app/models/page_attachment.rb +20 -0
  57. data/app/views/admin/assets/_asset.html.haml +12 -0
  58. data/app/views/admin/assets/_asset_table.html.haml +30 -0
  59. data/app/views/admin/assets/_errors.html.haml +3 -0
  60. data/app/views/admin/assets/_form.html.haml +18 -0
  61. data/app/views/admin/assets/_page_assets.html.haml +12 -0
  62. data/app/views/admin/assets/_search.html.haml +17 -0
  63. data/app/views/admin/assets/_search_results.html.haml +17 -0
  64. data/app/views/admin/assets/edit.html.haml +40 -0
  65. data/app/views/admin/assets/index.html.haml +15 -0
  66. data/app/views/admin/assets/new.html.haml +24 -0
  67. data/app/views/admin/assets/refresh.html.haml +14 -0
  68. data/app/views/admin/assets/remove.html.haml +16 -0
  69. data/app/views/admin/configuration/_clipped_edit.html.haml +8 -0
  70. data/app/views/admin/configuration/_clipped_show.html.haml +12 -0
  71. data/app/views/admin/page_attachments/_attachment.html.haml +25 -0
  72. data/app/views/admin/pages/_asset_popups.html.haml +37 -0
  73. data/app/views/admin/pages/_assets.html.haml +13 -0
  74. data/app/views/admin/removed/_assets_bucket.html.haml +8 -0
  75. data/app/views/admin/removed/_assets_container.html.haml +54 -0
  76. data/app/views/admin/removed/_bucket.html.haml +11 -0
  77. data/app/views/admin/removed/_bucket_asset.html.haml +9 -0
  78. data/app/views/admin/removed/_show_bucket_link.html.haml +4 -0
  79. data/app/views/admin/removed/_upload_to_page.html.haml +12 -0
  80. data/app/views/admin/removed/bucket/_iframe.html.haml +1 -0
  81. data/config/application.rb +0 -37
  82. data/config/initializers/assets.rb +1 -0
  83. data/config/initializers/interpolation.rb +6 -0
  84. data/config/initializers/kraken.rb +7 -0
  85. data/config/initializers/trusty_cms_config.rb +67 -0
  86. data/config/locales/en.yml +101 -0
  87. data/config/routes.rb +14 -3
  88. data/coverage/index.html +26 -26
  89. data/db/migrate/028_create_assets.rb +12 -0
  90. data/db/migrate/029_create_paperclip_attributes.rb +13 -0
  91. data/db/migrate/030_create_user_observer.rb +13 -0
  92. data/db/migrate/031_create_page_attachments.rb +19 -0
  93. data/db/migrate/032_rename_users.rb +13 -0
  94. data/db/migrate/20110513205050_asset_uuid.rb +11 -0
  95. data/db/migrate/20110606111250_update_configuration.rb +34 -0
  96. data/db/migrate/20110609101438_dimensions.rb +13 -0
  97. data/lib/trusty_cms.rb +1 -1
  98. data/spec/dummy/db/schema.rb +22 -0
  99. data/spec/dummy/log/test.log +95620 -0
  100. data/spec/dummy/tmp/cache/747/A70/TrustyCms%3A%3AConfig +0 -0
  101. data/spec/dummy/tmp/cache/85C/FA0/TrustyCms.cache_mtime +0 -0
  102. data/spec/dummy/tmp/capybara/capybara-20180312152412265881245.html +262 -0
  103. data/spec/dummy/tmp/capybara/capybara-201803121526139973682798.html +149 -0
  104. data/spec/factories/layout.rb +1 -1
  105. data/spec/factories/page.rb +3 -3
  106. data/spec/factories/page_part.rb +1 -1
  107. data/spec/factories/user.rb +1 -1
  108. data/spec/models/layout_spec.rb +6 -6
  109. data/spec/spec_helper.rb +4 -4
  110. data/trusty_cms.gemspec +27 -22
  111. data/vendor/extensions/clipped-extension/clipped_extension.rb +40 -0
  112. data/vendor/extensions/clipped-extension/lib/asset_tags.rb +346 -0
  113. data/vendor/extensions/clipped-extension/lib/clipped/engine.rb +11 -0
  114. data/vendor/extensions/clipped-extension/lib/clipped_admin_ui.rb +28 -0
  115. data/vendor/extensions/clipped-extension/lib/generators/templates/clipped_config.rb +53 -0
  116. data/vendor/extensions/clipped-extension/lib/page_asset_associations.rb +13 -0
  117. data/vendor/extensions/clipped-extension/lib/paperclip/frame_grab.rb +73 -0
  118. data/vendor/extensions/clipped-extension/lib/paperclip/geometry_transformation.rb +80 -0
  119. data/vendor/extensions/clipped-extension/lib/tasks/clipped_extension_tasks.rake +124 -0
  120. data/vendor/extensions/clipped-extension/lib/tasks/paperclip_tasks.rake +79 -0
  121. data/vendor/extensions/clipped-extension/lib/trusty-clipped-extension.rb +2 -0
  122. data/vendor/extensions/clipped-extension/lib/trusty_cms_clipped_extension/cloud.rb +41 -0
  123. metadata +219 -67
  124. data/config/initializers/ckeditor.rb +0 -3
  125. data/config/initializers/haml.rb +0 -2
  126. data/config/initializers/rails_patch.rb +0 -2
  127. data/config/initializers/string_extensions.rb +0 -1
  128. data/config/initializers/symbol_extensions.rb +0 -1
@@ -0,0 +1,346 @@
1
+ module AssetTags
2
+ include TrustyCms::Taggable
3
+ include ActionView::Helpers::TagHelper
4
+ include ActionView::Helpers::AssetTagHelper
5
+
6
+ class TagError < StandardError; end
7
+
8
+ %w{top_padding width height caption asset_file_name asset_content_type asset_file_size id filename image flash thumbnail url link extension if_content_type page:title page:url}.each do |name|
9
+ deprecated_tag "assets:#{name}", :substitute => "asset:#{name}", :deadline => '2.0'
10
+ end
11
+
12
+ desc %{
13
+ The namespace for referencing images and assets.
14
+
15
+ *Usage:*
16
+ <pre><code><r:asset [name="asset name"]>...</r:asset></code></pre>
17
+ }
18
+ tag 'asset' do |tag|
19
+ tag.locals.asset = find_asset(tag, tag.attr) unless tag.attr.empty?
20
+ tag.expand
21
+ end
22
+
23
+ desc %{
24
+ Cycles through all assets attached to the current page.
25
+ This tag does not require the name atttribute, nor do any of its children.
26
+ Use the @limit@ and @offset@ attribute to render a specific number of assets.
27
+ Use @by@ and @order@ attributes to control the order of assets.
28
+ Use @extensions@ attribute to specify which assets to be rendered.
29
+
30
+ *Usage:*
31
+ <pre><code><r:assets:each [limit=0] [offset=0] [order="asc|desc"] [by="position|title|..."] [extensions="png|pdf|doc"]>...</r:assets:each></code></pre>
32
+ }
33
+ tag 'assets' do |tag|
34
+ tag.expand
35
+ end
36
+ tag 'assets:each' do |tag|
37
+ options = tag.attr.dup
38
+ tag.locals.assets = tag.locals.page.assets.scoped(assets_find_options(tag))
39
+ tag.render('asset_list', tag.attr.dup, &tag.block)
40
+ end
41
+
42
+ # General purpose paginated asset lister. Very useful dryness.
43
+ # Tag.locals.assets must be defined but can be empty.
44
+
45
+ tag 'asset_list' do |tag|
46
+ raise TagError, "r:asset_list: no assets to list" unless tag.locals.assets
47
+ options = tag.attr.symbolize_keys
48
+ result = ""
49
+ paging = pagination_find_options(tag)
50
+ assets = paging ? tag.locals.assets.paginate(paging) : tag.locals.assets.all
51
+ assets.each do |asset|
52
+ tag.locals.asset = asset
53
+ result << tag.expand
54
+ end
55
+ if paging && assets.total_pages > 1
56
+ tag.locals.paginated_list = assets
57
+ result << tag.render('pagination', tag.attr.dup)
58
+ end
59
+ result
60
+ end
61
+
62
+ desc %{
63
+ References the first asset attached to the current page.
64
+
65
+ *Usage:*
66
+ <pre><code><r:assets:first>...</r:assets:first></code></pre>
67
+ }
68
+ tag 'assets:first' do |tag|
69
+ if tag.locals.asset = tag.locals.page.assets.first
70
+ tag.expand
71
+ end
72
+ end
73
+
74
+ desc %{
75
+ Renders the contained elements only if the current contextual page has one or
76
+ more assets. The @min_count@ attribute specifies the minimum number of required
77
+ assets. You can also filter by extensions with the @extensions@ attribute.
78
+
79
+ *Usage:*
80
+ <pre><code><r:if_assets [min_count="n"]>...</r:if_assets></code></pre>
81
+ }
82
+ tag 'if_assets' do |tag|
83
+ count = tag.attr['min_count'] && tag.attr['min_count'].to_i || 1
84
+ assets = tag.locals.page.assets.count(:conditions => assets_find_options(tag)[:conditions])
85
+ tag.expand if assets >= count
86
+ end
87
+
88
+ desc %{
89
+ The opposite of @<r:if_assets/>@.
90
+ }
91
+ tag 'unless_assets' do |tag|
92
+ count = tag.attr['min_count'] && tag.attr['min_count'].to_i || 1
93
+ assets = tag.locals.page.assets.count(:conditions => assets_find_options(tag)[:conditions])
94
+ tag.expand unless assets >= count
95
+ end
96
+
97
+ # Resets the page Url and title within the asset tag
98
+ [:title, :url].each do |method|
99
+ tag "asset:page:#{method.to_s}" do |tag|
100
+ tag.locals.page.send(method)
101
+ end
102
+ end
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+ desc %{
111
+ Renders the value for a top padding for a thumbnail. Put the thumbnail in a
112
+ container with specified height and using this tag you can vertically
113
+ align the image within its container.
114
+
115
+ *Usage*:
116
+ <pre><code><r:asset:top_padding container = "140" [size="icon"]/></code></pre>
117
+
118
+ *Working Example*:
119
+ <pre><code>
120
+ <ul>
121
+ <r:asset:each>
122
+ <li style="height:140px">
123
+ <img style="padding-top:<r:top_padding size='category' container='140' />px"
124
+ src="<r:url />" alt="<r:title />" />
125
+ </li>
126
+ </r:asset:each>
127
+ </ul>
128
+ </code></pre>
129
+ }
130
+ tag 'asset:top_padding' do |tag|
131
+ asset, options = asset_and_options(tag)
132
+ raise TagError, "'container' attribute required" unless options['container']
133
+ size = options['size'] ? options.delete('size') : 'icon'
134
+ raise TagError, "asset #{tag.locals.asset.title} has no '#{size}' thumbnail" unless tag.locals.asset.has_style?(size)
135
+ container = options.delete('container')
136
+ ((container.to_i - asset.height(size).to_i)/2).to_s
137
+ end
138
+
139
+ ['height','width'].each do |dimension|
140
+ desc %{
141
+ Renders the #{dimension} of the asset.
142
+ }
143
+ tag "asset:#{dimension}" do |tag|
144
+ asset, options = asset_and_options(tag)
145
+ unless asset.dimensions_known?
146
+ raise TagError, "Can't determine #{dimension} for this Asset. It may not be a supported type."
147
+ end
148
+ size = options['size'] ? options.delete('size') : 'original'
149
+ asset.send(dimension, size)
150
+ end
151
+ end
152
+
153
+ desc %{
154
+ Returns a string representing the orientation of the asset, which must be imageable.
155
+ (ie, it is an image or it has been processed to produce an image).
156
+ Can be 'horizontal', 'vertical' or 'square'.
157
+ }
158
+ tag 'asset:orientation' do |tag|
159
+ asset, options = asset_and_options(tag)
160
+ size = options['size'] ? options.delete('size') : 'original'
161
+ raise TagError, "asset #{tag.locals.asset.title} has no '#{size}' thumbnail" unless tag.locals.asset.has_style?(size)
162
+ asset.orientation(size)
163
+ end
164
+
165
+ desc %{
166
+ Returns the aspect ratio of the asset, which must be an image.
167
+ }
168
+ tag 'asset:aspect' do |tag|
169
+ asset, options = asset_and_options(tag)
170
+ size = options['size'] ? options.delete('size') : 'original'
171
+ raise TagError, "asset #{tag.locals.asset.title} has no '#{size}' thumbnail" unless tag.locals.asset.has_style?(size)
172
+ asset.aspect(size)
173
+ end
174
+
175
+ desc %{
176
+ Renders the containing elements only if the asset's content type matches
177
+ the regular expression given in the @matches@ attribute. If the
178
+ @ignore_case@ attribute is set to false, the match is case sensitive. By
179
+ default, @ignore_case@ is set to true.
180
+
181
+ The @name@ or @id@ attribute is required on the parent tag unless this tag is used in @asset:each@.
182
+
183
+ *Usage:*
184
+ <pre><code><r:asset:each><r:if_content_type matches="regexp" [ignore_case=true|false"]>...</r:if_content_type></r:asset:each></code></pre>
185
+ }
186
+ tag 'asset:if_content_type' do |tag|
187
+ options = tag.attr.dup
188
+ # XXX build_regexp_for comes from StandardTags
189
+ regexp = build_regexp_for(tag,options)
190
+ asset_content_type = tag.locals.asset.asset_content_type
191
+ tag.expand unless asset_content_type.match(regexp).nil?
192
+ end
193
+
194
+ #TODO: could use better docs for Asset#other? case explaining what types it covers
195
+
196
+ [:title, :caption, :asset_file_name, :extension, :asset_content_type, :asset_file_size, :id].each do |method|
197
+ desc %{
198
+ Renders the @#{method.to_s}@ attribute of the asset
199
+ }
200
+ tag "asset:#{method.to_s}" do |tag|
201
+ asset, options = asset_and_options(tag)
202
+ asset.send(method) rescue nil
203
+ end
204
+ end
205
+
206
+ tag 'asset:name' do |tag|
207
+ tag.render('asset:title', tag.attr.dup)
208
+ end
209
+
210
+ tag 'asset:filename' do |tag|
211
+ asset, options = asset_and_options(tag)
212
+ asset.asset_file_name rescue nil
213
+ end
214
+
215
+ desc %{
216
+ Renders an image tag for the asset.
217
+
218
+ Using the optional @size@ attribute, different sizes can be display.
219
+ "thumbnail" and "icon" sizes are built in, but custom ones can be set
220
+ by changing `assets.thumbnails.[type]` in the TrustyCms::Config settings.
221
+
222
+ *Usage:*
223
+ <pre><code><r:asset:image [name="asset name" or id="asset id"] [size="icon|thumbnail|whatever"]></code></pre>
224
+ }
225
+ tag 'asset:image' do |tag|
226
+ tag.locals.asset, options = asset_and_options(tag)
227
+ size = options.delete('size') || 'original'
228
+ raise TagError, "asset #{tag.locals.asset.title} has no '#{size}' thumbnail" unless tag.locals.asset.has_style?(size)
229
+ options['alt'] ||= tag.locals.asset.title
230
+ url = tag.locals.asset.thumbnail(size)
231
+ ActionController::Base.helpers.image_tag(url, options)
232
+ end
233
+
234
+ desc %{
235
+ Embeds a flash-movie in a cross-browser-compatible fashion using only HTML
236
+ If no width and height attributes are given it will use the intrinsic
237
+ dimensions of the swf file
238
+
239
+ *Usage:*
240
+ <pre><code><r:asset:flash [name="asset name" or id="asset id"] [width="100"] [height="100"]>Fallback content</flash></code></pre>
241
+
242
+ *Example with text fallback:*
243
+ <pre><code><r:asset:flash name="flash_movie">
244
+ Sorry, you need to have flash installed, <a href="http://adobe.com/flash">get it here</a>
245
+ </flash></code></pre>
246
+
247
+ *Example with image fallback and explicit dimensions:*
248
+ <pre><code><r:asset:flash name="flash_movie" width="300" height="200">
249
+ <r:asset:image name="flash_screenshot" />
250
+ </flash></code></pre>
251
+ }
252
+ tag 'asset:flash' do |tag|
253
+ asset, options = asset_and_options(tag)
254
+ if tag.locals.asset.flash?
255
+ url = asset.thumbnail('original')
256
+ dimensions = [(tag.attr['width'] || asset.width),(tag.attr['height'] || asset.height)]
257
+ swf_embed_markup url, dimensions, tag.expand
258
+ end
259
+ end
260
+
261
+ desc %{
262
+ Renders the url for the asset. If the asset is an image, the <code>size</code> attribute can be used to
263
+ generate the url for that size.
264
+
265
+ *Usage:*
266
+ <pre><code><r:url [name="asset name" or id="asset id"] [size="icon|thumbnail"]></code></pre>
267
+ }
268
+ tag 'asset:url' do |tag|
269
+ asset, options = asset_and_options(tag)
270
+ size = options['size'] ? options.delete('size') : 'original'
271
+ asset.thumbnail(size) rescue nil
272
+ end
273
+
274
+ desc %{
275
+ Renders a link to the asset. If the asset is an image, the <code>size</code> attribute can be used to
276
+ generate a link to that size.
277
+
278
+ *Usage:*
279
+ <pre><code><r:asset:link [name="asset name" or id="asset id"] [size="icon|thumbnail"] /></code></pre>
280
+ }
281
+ tag 'asset:link' do |tag|
282
+ asset, options = asset_and_options(tag)
283
+ size = options['size'] ? options.delete('size') : 'original'
284
+ text = options['text'] || asset.title
285
+ anchor = options['anchor'] ? "##{options.delete('anchor')}" : ''
286
+ attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
287
+ attributes = " #{attributes}" unless attributes.empty?
288
+ text = tag.double? ? tag.expand : text
289
+ url = asset.thumbnail(size)
290
+ %{<a href="#{url }#{anchor}"#{attributes}>#{text}</a>} rescue nil
291
+ end
292
+
293
+ private
294
+ def asset_and_options(tag)
295
+ options = tag.attr.dup
296
+ [find_asset(tag, options), options]
297
+ end
298
+
299
+ def find_asset(tag, options)
300
+ tag.locals.asset ||= if title = (options.delete('name') || options.delete('title'))
301
+ Asset.find_by_title(title)
302
+ elsif id = options.delete('id')
303
+ Asset.find_by_id(id)
304
+ end
305
+ tag.locals.asset || raise(TagError, "Asset not found.")
306
+ end
307
+
308
+ def assets_find_options(tag)
309
+ attr = tag.attr.symbolize_keys
310
+ extensions = attr[:extensions] && attr[:extensions].split('|') || []
311
+ conditions = unless extensions.blank?
312
+ # this is soon to be removed in favour of asset types
313
+ [ extensions.map { |ext| "assets.asset_file_name LIKE ?"}.join(' OR '),
314
+ *extensions.map { |ext| "%.#{ext}" } ]
315
+ else
316
+ nil
317
+ end
318
+
319
+ by = attr[:by] || 'page_attachments.position'
320
+ order = attr[:order] || 'asc'
321
+
322
+ options = {
323
+ :order => "#{by} #{order}",
324
+ :limit => attr[:limit] || nil,
325
+ :offset => attr[:offset] || nil,
326
+ :conditions => conditions
327
+ }
328
+ end
329
+
330
+ def swf_embed_markup(url, dimensions, fallback_content)
331
+ width, height = dimensions
332
+ %{<!--[if !IE]> -->
333
+ <object type="application/x-shockwave-flash" data="#{url}" width="#{width}" height="#{height}">
334
+ <!-- <![endif]-->
335
+ <!--[if IE]>
336
+ <object width="#{width}" height="#{height}"
337
+ classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
338
+ codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0">
339
+ <param name="movie" value="#{url}" />
340
+ <!-->
341
+ #{fallback_content}
342
+ </object>
343
+ <!-- <![endif]-->}
344
+ end
345
+ end
346
+
@@ -0,0 +1,11 @@
1
+ require 'acts_as_list'
2
+ require 'uuidtools'
3
+ require 'trusty_cms_clipped_extension/cloud'
4
+ require 'paperclip'
5
+ require 'will_paginate/array'
6
+ module Clipped
7
+ class Engine < Rails::Engine
8
+ paths["app/helpers"] = []
9
+
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ module ClippedAdminUI
2
+
3
+ def self.included(base)
4
+ base.class_eval {
5
+ attr_accessor :asset
6
+ alias_method :assets, :asset
7
+
8
+ def load_default_asset_regions
9
+ OpenStruct.new.tap do |asset|
10
+ asset.edit = TrustyCms::AdminUI::RegionSet.new do |edit|
11
+ edit.main.concat %w{edit_header edit_form edit_regenerate}
12
+ edit.form.concat %w{edit_title edit_metadata}
13
+ end
14
+ asset.new = asset.edit
15
+ asset.index = TrustyCms::AdminUI::RegionSet.new do |index|
16
+ index.top.concat %w{filters}
17
+ index.bottom.concat %w{}
18
+ index.thead.concat %w{thumbnail_header content_type_header actions_header}
19
+ index.tbody.concat %w{thumbnail_cell title_cell content_type_cell actions_cell}
20
+ index.paginate
21
+ end
22
+ asset.remove = asset.index
23
+ end
24
+ end
25
+ }
26
+ end
27
+ end
28
+
@@ -0,0 +1,53 @@
1
+ TrustyCms.config do |config|
2
+
3
+ # Uncomment and change the settings below to customize the Clipped extension
4
+
5
+ # The default settings
6
+ # config["paperclip.url"] = "/system/:attachment/:id/:style/:basename:no_original_style.:extension"
7
+ # config["paperclip.path"] = ":rails_root/public/system/:attachment/:id/:style/:basename:no_original_style.:extension"
8
+ # config["paperclip.storage"] = "filesystem"
9
+ # config["paperclip.skip_filetype_validation"] = true
10
+ # config["assets.max_asset_size"] = 5 # megabytes
11
+ # config["assets.display_size"] = "normal"
12
+ # config["assets.insertion_size"] = "normal"
13
+ # config["assets.create_image_thumbnails?"] = true
14
+ # config["assets.create_video_thumbnails?"] = true
15
+ # config["assets.create_pdf_thumbnails?"] = true
16
+ # Check http://www.imagemagick.org/script/command-line-processing.php#geometry
17
+ # for more details on ImageMagick settings for thumbnail generation
18
+ # config["assets.thumbnails.image"] = "normal:size=640x640>|small:size=320x320>"
19
+ # config["assets.thumbnails.video"] = "normal:size=640x640>,format=jpg|small:size=320x320>,format=jpg"
20
+ # config["assets.thumbnails.pdf"] = "normal:size=640x640>,format=jpg|small:size=320x320>,format=jpg"
21
+
22
+ # An example of using Amazon S3
23
+ # add `gem "fog", "~> 1.0"` to your Gemfile and run `bundle install`
24
+ # config["paperclip.storage"] = "fog"
25
+ # config["paperclip.path"] = ":attachment/:id/:style/:basename:no_original_style.:extension"
26
+ # config["paperclip.fog.provider"] = "AWS"
27
+ # config["paperclip.fog.directory"] = "bucket-name"
28
+ # config["paperclip.s3.key"] = "S3_KEY"
29
+ # config["paperclip.s3.secret"] = "S3_SECRET"
30
+ # optionally use a custom domain name; requires a CNAME DNS record
31
+ # config["paperclip.fog.host"] = "http://assets.example.com"
32
+ # optionally set the S3 region of your bucket; defaults to US East
33
+ # Asia North East => ap-northeast-1
34
+ # Asia South East => ap-southeast-1
35
+ # EU West => eu-west-1
36
+ # US East => us-east-1
37
+ # US West => us-west-1
38
+ # config["paperclip.s3.region"] = "us-east-1"
39
+
40
+ # An example of using Rackspace Cloud Files
41
+ # add `gem "fog", "~> 1.0"` to your Gemfile and run `bundle install`
42
+ # config["paperclip.storage"] = "fog"
43
+ # config["paperclip.path"] = ":attachment/:id/:style/:basename:no_original_style.:extension"
44
+ # config["paperclip.fog.provider"] = "Rackspace"
45
+ # config["paperclip.fog.directory"] = "container-name"
46
+ # config["paperclip.rackspace.username"] = "RACKSPACE_USERNAME"
47
+ # config["paperclip.rackspace.api_key"] = "RACKSPACE_API_KEY"
48
+ # paperclip.fog.host is your Cloud Files CDN URL
49
+ # config["paperclip.fog.host"] = "http://a.b.c.rackcdn.com"
50
+ # optionally use a custom domain name; requires a CNAME DNS record
51
+ # config["paperclip.fog.host"] = "http://assets.example.com"
52
+
53
+ end
@@ -0,0 +1,13 @@
1
+ module PageAssetAssociations
2
+
3
+ #TODO: Turn page_attachments into a generic, polymorphic asset-attachment mechanism
4
+
5
+ def self.included(base)
6
+ base.class_eval {
7
+ has_many :page_attachments, -> { order 'position desc' }
8
+ has_many :assets,{ :through => :page_attachments}, -> { order 'page_attachments.position ASC' }
9
+ accepts_nested_attributes_for :page_attachments, :allow_destroy => true
10
+ }
11
+ end
12
+
13
+ end
@@ -0,0 +1,73 @@
1
+ module Paperclip
2
+ class FrameGrab < Processor
3
+
4
+ attr_accessor :time_offset, :current_geometry, :target_geometry, :whiny, :current_format, :target_format
5
+
6
+ def initialize(file, options = {}, attachment = nil)
7
+ super
8
+ @file = file
9
+ @time_offset = options[:time_offset] || '-4'
10
+ geometry = options[:geometry]
11
+ unless geometry.blank?
12
+ @crop = geometry[-1,1] == '#'
13
+ @target_geometry = Geometry.parse(geometry)
14
+ @current_geometry = Geometry.parse(video_dimensions(file))
15
+ end
16
+ @current_format = File.extname(@file.path)
17
+ @target_format = options[:format] || 'jpg'
18
+ @basename = File.basename(@file.path, @current_format)
19
+ @whiny = options[:whiny].nil? ? true : options[:whiny]
20
+ end
21
+
22
+ def crop?
23
+ !!@crop
24
+ end
25
+
26
+ def make
27
+ src = @file
28
+ dst = Tempfile.new([ @basename, @target_format ].compact.join("."))
29
+ dst.binmode
30
+
31
+ begin
32
+ # grab frame at offset
33
+ cmd = %Q[-itsoffset #{time_offset} -i :source -y -vcodec mjpeg -vframes 1 -an -f rawvideo ]
34
+
35
+ # if scale-and-crop parameters can be calculated, we pipe to convert for resizing
36
+ if scale_and_crop = transformation_options
37
+ cmd << %{pipe: | convert #{scale_and_crop} - #{target_format}:- }
38
+
39
+ # otherwise we let ffmpeg resize the to the right size without preserving aspect ratio
40
+ else
41
+ cmd << %{-s #{target_geometry} pipe: }
42
+ end
43
+
44
+ # then pipe to composite to overlay video icon
45
+ cmd << %{| composite -gravity center :icon - :dest }
46
+
47
+ Paperclip.run('ffmpeg', cmd, :source => File.expand_path(src.path), :dest => File.expand_path(dst.path), :icon => AssetType.find(:video).icon_path, :swallow_stderr => false)
48
+ rescue PaperclipCommandLineError => e
49
+ raise PaperclipError, "There was an error processing the thumbnail for #{@basename}: #{e}" if whiny
50
+ end
51
+
52
+ dst
53
+ end
54
+
55
+ # get video dimensions in nasty hacky way
56
+ def video_dimensions(file)
57
+ dim = Paperclip.run('ffmpeg', '-i :source 2>&1', :source => File.expand_path(file.path), :expected_outcodes => [0,1], :swallow_stderr => false)
58
+ $1 if dim =~ /(\d+x\d+)/
59
+ end
60
+
61
+ # Duplicated from Thumbnail. We can't just subclass because of assumed compatibility with Geometry.from_file
62
+ def transformation_options
63
+ if current_geometry
64
+ scale, crop = current_geometry.transformation_to(target_geometry, crop?)
65
+ trans = []
66
+ trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
67
+ trans << "-crop" << %["#{crop}"] << "+repage" if crop
68
+ trans.join(" ")
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,80 @@
1
+ module Paperclip
2
+
3
+ class TransformationError < PaperclipError; end
4
+ class StyleError < PaperclipError; end
5
+
6
+ class Geometry
7
+
8
+ # Returns a new Geometry object with the the same dimensions as this but with no modifier.
9
+ def without_modifier
10
+ Geometry.new(self.width, self.height)
11
+ end
12
+
13
+ # Returns the dimensions that would result if a thumbnail was created by transforming this geometry into that geometry.
14
+ # Its purpose is to mimic imagemagick conversions. Used like so:
15
+ # file_geometry.transformed_by(style_geometry)
16
+ # it returns the size of the thumbnail image you would get by applying that rule.
17
+ # This saves us having to go back to the file, which is expensive with S3.
18
+ # We understand all the Imagemagick geometry arguments described at http://www.imagemagick.org/script/command-line-processing.php#geometry
19
+ # including both '^' and paperclip's own '#' modifier.
20
+ #
21
+ def transformed_by (other)
22
+ other = Geometry.parse(other) unless other.is_a? Geometry
23
+ # if the two geometries are similar, or the destination geometry is a fixed size, the resulting dimensions are fixed
24
+ return other.without_modifier if self =~ other || ['#', '!', '^'].include?(other.modifier)
25
+ # otherwise, we apply the transformation
26
+ raise TransformationError, "geometry is not transformable without both width and height" if self.height == 0 or self.width == 0
27
+ case other.modifier
28
+ when '>'
29
+ (other.width < self.width || other.height < self.height) ? scaled_to_fit(other) : self
30
+ when '<'
31
+ (other.width > self.width && other.height > self.height) ? scaled_to_fit(other) : self
32
+ when '%'
33
+ scaled_by(other)
34
+ when '@'
35
+ scaled_by(other.width * 100 / (self.width * self.height))
36
+ else
37
+ scaled_to_fit(other)
38
+ end
39
+ end
40
+ alias :* :transformed_by
41
+
42
+ # Tests whether two geometries are identical in dimensions and modifier.
43
+ def == (other)
44
+ self.to_s == other.to_s
45
+ end
46
+
47
+ # Tests whether two geometries have the same dimensions, ignoring modifier.
48
+ def =~ (other)
49
+ self.height.to_i == other.height.to_i && self.width.to_i == other.width.to_i
50
+ end
51
+
52
+ # Scales this geometry to fit within that geometry.
53
+ def scaled_to_fit(other)
54
+ if (other.width > 0 && other.height == 0)
55
+ Geometry.new(other.width, self.height * other.width / self.width)
56
+ elsif (other.width == 0 && other.height > 0)
57
+ Geometry.new(self.width * other.height / self.height, other.height)
58
+ else
59
+ ratio = Geometry.new( other.width / self.width, other.height / self.height )
60
+ if ratio.square?
61
+ other.without_modifier
62
+ elsif ratio.horizontal?
63
+ Geometry.new(ratio.height * self.width, other.height)
64
+ else
65
+ Geometry.new(other.width, ratio.width * self.height)
66
+ end
67
+ end
68
+ end
69
+
70
+ # Scales this geometry by the percentage(s) specified in that geometry.
71
+ def scaled_by(other)
72
+ other = Geometry.new("#{other}%") unless other.is_a? Geometry
73
+ if other.height > 0
74
+ Geometry.new(self.width * other.width / 100, self.height * other.height / 100)
75
+ else
76
+ Geometry.new(self.width * other.width / 100, self.height * other.width / 100)
77
+ end
78
+ end
79
+ end
80
+ end