radiant-clipped-extension 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.md +230 -0
- data/Rakefile +109 -0
- data/app/controllers/admin/assets_controller.rb +60 -0
- data/app/controllers/admin/page_attachments_controller.rb +18 -0
- data/app/helpers/admin/assets_helper.rb +16 -0
- data/app/models/asset.rb +224 -0
- data/app/models/asset_tags.rb +384 -0
- data/app/models/asset_type.rb +170 -0
- data/app/models/old_page_attachment.rb +26 -0
- data/app/models/page_attachment.rb +21 -0
- data/app/views/admin/assets/_asset.html.haml +12 -0
- data/app/views/admin/assets/_asset_table.html.haml +30 -0
- data/app/views/admin/assets/_errors.html.haml +3 -0
- data/app/views/admin/assets/_form.html.haml +20 -0
- data/app/views/admin/assets/_page_assets.html.haml +12 -0
- data/app/views/admin/assets/_search.html.haml +17 -0
- data/app/views/admin/assets/_search_results.html.haml +17 -0
- data/app/views/admin/assets/edit.html.haml +40 -0
- data/app/views/admin/assets/index.html.haml +19 -0
- data/app/views/admin/assets/new.html.haml +24 -0
- data/app/views/admin/assets/refresh.html.haml +14 -0
- data/app/views/admin/assets/remove.html.haml +16 -0
- data/app/views/admin/configuration/_edit.html.haml +8 -0
- data/app/views/admin/configuration/_show.html.haml +12 -0
- data/app/views/admin/page_attachments/_attachment.html.haml +25 -0
- data/app/views/admin/page_parts/_page_part.html.haml +21 -0
- data/app/views/admin/pages/_asset_popups.html.haml +42 -0
- data/app/views/admin/pages/_assets.html.haml +11 -0
- data/app/views/admin/removed/_assets_bucket.html.haml +8 -0
- data/app/views/admin/removed/_assets_container.html.haml +58 -0
- data/app/views/admin/removed/_bucket.html.haml +11 -0
- data/app/views/admin/removed/_bucket_asset.html.haml +9 -0
- data/app/views/admin/removed/_show_bucket_link.html.haml +4 -0
- data/app/views/admin/removed/_upload_to_page.html.haml +12 -0
- data/app/views/admin/removed/bucket/_iframe.html.haml +1 -0
- data/artwork/icons.png +0 -0
- data/clipped_extension.rb +89 -0
- data/config/initializers/interpolation.rb +6 -0
- data/config/initializers/processors.rb +43 -0
- data/config/initializers/radiant_config.rb +34 -0
- data/config/locales/en.yml +108 -0
- data/config/locales/nl.yml +105 -0
- data/config/routes.rb +8 -0
- data/cucumber.yml +1 -0
- data/db/migrate/001_create_assets.rb +12 -0
- data/db/migrate/002_create_paperclip_attributes.rb +13 -0
- data/db/migrate/003_create_user_observer.rb +13 -0
- data/db/migrate/004_create_page_attachments.rb +19 -0
- data/db/migrate/005_rename_users.rb +13 -0
- data/db/migrate/20090316132151_disable_file_types.rb +20 -0
- data/db/migrate/20110513205050_asset_uuid.rb +11 -0
- data/db/migrate/20110606111250_update_configuration.rb +28 -0
- data/db/migrate/20110609101438_dimensions.rb +13 -0
- data/features/support/env.rb +11 -0
- data/features/support/paths.rb +22 -0
- data/lib/clipped_admin_ui.rb +32 -0
- data/lib/page_asset_associations.rb +13 -0
- data/lib/paperclip/frame_grab.rb +73 -0
- data/lib/paperclip/geometry_transformation.rb +79 -0
- data/lib/radiant-clipped-extension.rb +2 -0
- data/lib/radiant-clipped-extension/version.rb +3 -0
- data/lib/tasks/clipped_extension_tasks.rake +126 -0
- data/lib/tasks/paperclip_tasks.rake +79 -0
- data/public/flash/ZeroClipboard.swf +0 -0
- data/public/images/admin/assets/add.png +0 -0
- data/public/images/admin/assets/archive_icon.png +0 -0
- data/public/images/admin/assets/audio_icon.png +0 -0
- data/public/images/admin/assets/audio_thumbnail.png +0 -0
- data/public/images/admin/assets/c_icon.png +0 -0
- data/public/images/admin/assets/copy.png +0 -0
- data/public/images/admin/assets/css_icon.png +0 -0
- data/public/images/admin/assets/database_icon.png +0 -0
- data/public/images/admin/assets/delete.png +0 -0
- data/public/images/admin/assets/document_icon.png +0 -0
- data/public/images/admin/assets/document_thumbnail.png +0 -0
- data/public/images/admin/assets/flash_icon.png +0 -0
- data/public/images/admin/assets/flash_thumbnail.png +0 -0
- data/public/images/admin/assets/font_icon.png +0 -0
- data/public/images/admin/assets/gzip_icon.png +0 -0
- data/public/images/admin/assets/html_icon.png +0 -0
- data/public/images/admin/assets/image_icon.png +0 -0
- data/public/images/admin/assets/image_thumbnail.png +0 -0
- data/public/images/admin/assets/java_icon.png +0 -0
- data/public/images/admin/assets/page_edit.png +0 -0
- data/public/images/admin/assets/perl_icon.png +0 -0
- data/public/images/admin/assets/php_icon.png +0 -0
- data/public/images/admin/assets/presentation_icon.png +0 -0
- data/public/images/admin/assets/python_icon.png +0 -0
- data/public/images/admin/assets/reorder_assets.png +0 -0
- data/public/images/admin/assets/ruby_icon.png +0 -0
- data/public/images/admin/assets/script_icon.png +0 -0
- data/public/images/admin/assets/spreadsheet_icon.png +0 -0
- data/public/images/admin/assets/tar_icon.png +0 -0
- data/public/images/admin/assets/unknown_icon.png +0 -0
- data/public/images/admin/assets/unknown_thumbnail.png +0 -0
- data/public/images/admin/assets/video_icon.png +0 -0
- data/public/images/admin/assets/video_thumbnail.png +0 -0
- data/public/images/admin/assets/xml_icon.png +0 -0
- data/public/images/admin/assets/zip_icon.png +0 -0
- data/public/javascripts/admin/assets.js +296 -0
- data/public/stylesheets/sass/admin/assets.sass +209 -0
- data/radiant-clipped-extension.gemspec +33 -0
- data/spec/controllers/admin/assets_controller_spec.rb +50 -0
- data/spec/controllers/admin/page_attachments_controller_spec.rb +50 -0
- data/spec/datasets/assets_dataset.rb +35 -0
- data/spec/fixtures/test.flv +0 -0
- data/spec/lib/asset_tags_spec.rb +101 -0
- data/spec/lib/frame_grab_spec.rb +17 -0
- data/spec/lib/geometry_transformation_spec.rb +63 -0
- data/spec/models/asset_spec.rb +72 -0
- data/spec/models/asset_type_spec.rb +63 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +36 -0
- data/wireframes/edit-page-assets-2.bmml +453 -0
- data/wireframes/edit-page-assets-2.png +0 -0
- data/wireframes/edit-page-assets-3.bmml +454 -0
- data/wireframes/edit-page-assets-3.png +0 -0
- data/wireframes/edit-page-assets.bmml +433 -0
- data/wireframes/edit-page-assets.png +0 -0
- data/wireframes/edit-page.bmml +174 -0
- data/wireframes/edit-page.png +0 -0
- metadata +249 -0
data/app/models/asset.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
class Asset < ActiveRecord::Base
|
2
|
+
|
3
|
+
has_many :page_attachments, :dependent => :destroy
|
4
|
+
has_many :pages, :through => :page_attachments
|
5
|
+
has_site if respond_to? :has_site
|
6
|
+
|
7
|
+
belongs_to :created_by, :class_name => 'User'
|
8
|
+
belongs_to :updated_by, :class_name => 'User'
|
9
|
+
|
10
|
+
default_scope :order => "created_at DESC"
|
11
|
+
|
12
|
+
named_scope :latest, lambda { |limit|
|
13
|
+
{ :order => "created_at DESC", :limit => limit }
|
14
|
+
}
|
15
|
+
|
16
|
+
named_scope :of_types, lambda { |types|
|
17
|
+
mimes = AssetType.slice(*types).map(&:mime_types).flatten
|
18
|
+
{ :conditions => ["asset_content_type IN (#{mimes.map{'?'}.join(',')})", *mimes] }
|
19
|
+
}
|
20
|
+
|
21
|
+
named_scope :matching, lambda { |term|
|
22
|
+
{ :conditions => ["LOWER(assets.asset_file_name) LIKE (:term) OR LOWER(title) LIKE (:term) OR LOWER(caption) LIKE (:term)", {:term => "%#{term.downcase}%" }] }
|
23
|
+
}
|
24
|
+
|
25
|
+
named_scope :except, lambda { |assets|
|
26
|
+
if assets.any?
|
27
|
+
assets = assets.split(',') if assets.is_a?(String)
|
28
|
+
asset_ids = assets.first.is_a?(Asset) ? assets.map(&:id) : assets
|
29
|
+
{ :conditions => ["assets.id NOT IN(#{asset_ids.map{ '?' }.join(',')})", *asset_ids] }
|
30
|
+
else
|
31
|
+
{}
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
35
|
+
has_attached_file :asset,
|
36
|
+
:styles => lambda { |attachment|
|
37
|
+
AssetType.from(attachment.instance_read(:content_type)).paperclip_styles
|
38
|
+
},
|
39
|
+
:processors => lambda { |asset|
|
40
|
+
asset.paperclip_processors
|
41
|
+
},
|
42
|
+
:whiny => false,
|
43
|
+
:storage => Radiant.config["paperclip.storage"] == "s3" ? :s3 : :filesystem,
|
44
|
+
:s3_credentials => {
|
45
|
+
:access_key_id => Radiant.config["paperclip.s3.key"],
|
46
|
+
:secret_access_key => Radiant.config["paperclip.s3.secret"]
|
47
|
+
},
|
48
|
+
:s3_host_alias => Radiant.config["paperclip.s3.host_alias"] || Radiant.config["assets.s3.bucket"],
|
49
|
+
:bucket => Radiant.config["paperclip.s3.bucket"],
|
50
|
+
:url => Radiant.config["paperclip.url"],
|
51
|
+
:path => Radiant.config["paperclip.path"]
|
52
|
+
|
53
|
+
before_save :assign_title
|
54
|
+
before_save :assign_uuid
|
55
|
+
after_post_process :get_dimensions
|
56
|
+
|
57
|
+
validates_attachment_presence :asset, :message => "You must choose a file to upload!"
|
58
|
+
if Radiant.config["paperclip.skip_filetype_validation"] != "true" && Radiant.config['paperclip.content_types']
|
59
|
+
validates_attachment_content_type :asset, :content_type => Radiant.config["paperclip.content_types"].gsub(' ','').split(',')
|
60
|
+
end
|
61
|
+
validates_attachment_size :asset, :less_than => ( Radiant.config["assets.max_asset_size"] || 5 ).to_i.megabytes
|
62
|
+
|
63
|
+
def asset_type
|
64
|
+
AssetType.from(asset.content_type)
|
65
|
+
end
|
66
|
+
delegate :paperclip_processors, :paperclip_styles, :style_dimensions, :style_format, :to => :asset_type
|
67
|
+
|
68
|
+
def thumbnail(style_name='original')
|
69
|
+
return asset.url if style_name.to_sym == :original
|
70
|
+
return asset.url(style_name.to_sym) if has_style?(style_name)
|
71
|
+
return asset_type.icon(style_name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def has_style?(style_name)
|
75
|
+
paperclip_styles.keys.include?(style_name.to_sym)
|
76
|
+
end
|
77
|
+
|
78
|
+
def basename
|
79
|
+
File.basename(asset_file_name, ".*") if asset_file_name
|
80
|
+
end
|
81
|
+
|
82
|
+
def extension(style_name='original')
|
83
|
+
if style_name == 'original'
|
84
|
+
return original_extension
|
85
|
+
elsif style = asset.styles[style_name.to_sym]
|
86
|
+
return style.format
|
87
|
+
else
|
88
|
+
return original_extension
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def original_extension
|
93
|
+
return asset_file_name.split('.').last.downcase if asset_file_name
|
94
|
+
end
|
95
|
+
|
96
|
+
def attached_to?(page)
|
97
|
+
pages.include?(page)
|
98
|
+
end
|
99
|
+
|
100
|
+
def original_geometry
|
101
|
+
@original_geometry ||= Paperclip::Geometry.new(original_width, original_height)
|
102
|
+
end
|
103
|
+
|
104
|
+
def geometry(style_name='original')
|
105
|
+
if style_name == 'original'
|
106
|
+
original_geometry
|
107
|
+
elsif style = asset.styles[style_name.to_sym]
|
108
|
+
original_geometry * style.geometry
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def aspect(style_name='original')
|
113
|
+
image? && geometry(style_name).aspect
|
114
|
+
end
|
115
|
+
|
116
|
+
def orientation(style_name='original')
|
117
|
+
if image?
|
118
|
+
this_aspect = aspect(style_name)
|
119
|
+
case
|
120
|
+
when this_aspect < 1.0 then 'vertical'
|
121
|
+
when this_aspect > 1.0 then 'horizontal'
|
122
|
+
else 'square'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def width(style_name='original')
|
128
|
+
image? ? geometry(style_name).width.to_i : 0
|
129
|
+
end
|
130
|
+
|
131
|
+
def height(style_name='original')
|
132
|
+
image? ? geometry(style_name).height.to_i : 0
|
133
|
+
end
|
134
|
+
|
135
|
+
def square?(style_name='original')
|
136
|
+
image? && geometry(style_name).square?
|
137
|
+
end
|
138
|
+
|
139
|
+
def vertical?(style_name='original')
|
140
|
+
image? && geometry(style_name).vertical?
|
141
|
+
end
|
142
|
+
|
143
|
+
def horizontal?(style_name='original')
|
144
|
+
image? && geometry(style_name).horizontal?
|
145
|
+
end
|
146
|
+
|
147
|
+
def dimensions_known?
|
148
|
+
!original_width.blank? && !original_height.blank?
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def read_dimensions
|
154
|
+
if image? && !dimensions_known?
|
155
|
+
geometry = Paperclip::Geometry.from_file(asset.path)
|
156
|
+
self.update_attributes(
|
157
|
+
:original_width => geometry.width,
|
158
|
+
:original_height => geometry.height,
|
159
|
+
:original_extension => extension
|
160
|
+
)
|
161
|
+
geometry
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def assign_title
|
166
|
+
self.title = basename if title.blank?
|
167
|
+
end
|
168
|
+
|
169
|
+
def assign_uuid
|
170
|
+
self.uuid = UUIDTools::UUID.timestamp_create.to_s if uuid.blank?
|
171
|
+
end
|
172
|
+
|
173
|
+
class << self
|
174
|
+
def known_types
|
175
|
+
AssetType.known_types
|
176
|
+
end
|
177
|
+
|
178
|
+
# searching and pagination moved to the controller
|
179
|
+
|
180
|
+
def find_all_by_asset_types(asset_types, *args)
|
181
|
+
with_asset_types(asset_types) { find *args }
|
182
|
+
end
|
183
|
+
|
184
|
+
def count_with_asset_types(asset_types, *args)
|
185
|
+
with_asset_types(asset_types) { count *args }
|
186
|
+
end
|
187
|
+
|
188
|
+
def with_asset_types(asset_types, &block)
|
189
|
+
with_scope(:find => { :conditions => AssetType.conditions_for(asset_types) }, &block)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# called from AssetType to set type_condition? methods on Asset
|
194
|
+
def self.define_class_method(name, &block)
|
195
|
+
eigenclass.send :define_method, name, &block
|
196
|
+
end
|
197
|
+
|
198
|
+
# returns the return value of class << self block, which is self (as defined within that block)
|
199
|
+
def self.eigenclass
|
200
|
+
class << self; self; end
|
201
|
+
end
|
202
|
+
|
203
|
+
# for backwards compatibility
|
204
|
+
def self.thumbnail_sizes
|
205
|
+
AssetType.find(:image).paperclip_styles
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.thumbnail_names
|
209
|
+
thumbnail_sizes.keys
|
210
|
+
end
|
211
|
+
|
212
|
+
# this is a convenience for image-pickers
|
213
|
+
def self.thumbnail_options
|
214
|
+
asset_sizes = thumbnail_sizes.collect{|k,v|
|
215
|
+
size_id = k
|
216
|
+
size_description = "#{k}: "
|
217
|
+
size_description << (v.is_a?(Array) ? v.join(' as ') : v)
|
218
|
+
[size_description, size_id]
|
219
|
+
}.sort_by{|pair| pair.last.to_s}
|
220
|
+
asset_sizes.unshift ['Original (as uploaded)', 'original']
|
221
|
+
asset_sizes
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
@@ -0,0 +1,384 @@
|
|
1
|
+
module AssetTags
|
2
|
+
include Radiant::Taggable
|
3
|
+
|
4
|
+
class TagError < StandardError; end
|
5
|
+
|
6
|
+
%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|
|
7
|
+
deprecated_tag "assets:#{name}", :substitute => "asset:#{name}", :deadline => '2.0'
|
8
|
+
end
|
9
|
+
|
10
|
+
Asset.known_types.each do |known_type|
|
11
|
+
deprecated_tag "assets:if_#{known_type}", :substitute => "asset:if_#{known_type}", :deadline => '2.0'
|
12
|
+
deprecated_tag "assets:unless_#{known_type}", :substitute => "asset:unless_#{known_type}", :deadline => '2.0'
|
13
|
+
end
|
14
|
+
|
15
|
+
desc %{
|
16
|
+
The namespace for referencing images and assets.
|
17
|
+
|
18
|
+
*Usage:*
|
19
|
+
<pre><code><r:asset [name="asset name"]>...</r:asset></code></pre>
|
20
|
+
}
|
21
|
+
tag 'asset' do |tag|
|
22
|
+
tag.locals.asset = find_asset unless tag.attr.empty?
|
23
|
+
tag.expand
|
24
|
+
end
|
25
|
+
|
26
|
+
desc %{
|
27
|
+
Cycles through all assets attached to the current page.
|
28
|
+
This tag does not require the name atttribute, nor do any of its children.
|
29
|
+
Use the @limit@ and @offset@ attribute to render a specific number of assets.
|
30
|
+
Use @by@ and @order@ attributes to control the order of assets.
|
31
|
+
Use @extensions@ attribute to specify which assets to be rendered.
|
32
|
+
|
33
|
+
*Usage:*
|
34
|
+
<pre><code><r:assets:each [limit=0] [offset=0] [order="asc|desc"] [by="position|title|..."] [extensions="png|pdf|doc"]>...</r:assets:each></code></pre>
|
35
|
+
}
|
36
|
+
tag 'assets' do |tag|
|
37
|
+
tag.expand
|
38
|
+
end
|
39
|
+
tag 'assets:each' do |tag|
|
40
|
+
options = tag.attr.dup
|
41
|
+
result = []
|
42
|
+
tag.locals.assets = tag.locals.page.assets.scoped(assets_find_options(tag))
|
43
|
+
tag.render('asset_list', tag.attr.dup, &tag.block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# General purpose paginated asset lister. Very useful dryness.
|
47
|
+
# Tag.locals.assets must be defined but can be empty.
|
48
|
+
|
49
|
+
tag 'asset_list' do |tag|
|
50
|
+
raise TagError, "r:asset_list: no assets to list" unless tag.locals.assets
|
51
|
+
options = tag.attr.symbolize_keys
|
52
|
+
result = []
|
53
|
+
paging = pagination_find_options(tag)
|
54
|
+
assets = paging ? tag.locals.assets.paginate(paging) : tag.locals.assets.all
|
55
|
+
assets.each do |asset|
|
56
|
+
tag.locals.asset = asset
|
57
|
+
result << tag.expand
|
58
|
+
end
|
59
|
+
if paging && assets.total_pages > 1
|
60
|
+
tag.locals.paginated_list = assets
|
61
|
+
result << tag.render('pagination', tag.attr.dup)
|
62
|
+
end
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
66
|
+
desc %{
|
67
|
+
References the first asset attached to the current page.
|
68
|
+
|
69
|
+
*Usage:*
|
70
|
+
<pre><code><r:assets:first>...</r:assets:first></code></pre>
|
71
|
+
}
|
72
|
+
tag 'assets:first' do |tag|
|
73
|
+
if tag.locals.asset = tag.locals.page.assets.first
|
74
|
+
tag.expand
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
desc %{
|
79
|
+
References the last asset attached to the current page.
|
80
|
+
|
81
|
+
*Usage:*
|
82
|
+
<pre><code><r:assets:last>...</r:assets:last></code></pre>
|
83
|
+
}
|
84
|
+
tag 'assets:last' do |tag|
|
85
|
+
p "tag.locals.page.assets is #{tag.locals.page.assets.join(',')} and tag.locals.page.assets.last is #{tag.locals.page.assets.last}"
|
86
|
+
|
87
|
+
if tag.locals.asset = tag.locals.page.assets.last
|
88
|
+
tag.expand
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
desc %{
|
93
|
+
Renders the contained elements only if the current contextual page has one or
|
94
|
+
more assets. The @min_count@ attribute specifies the minimum number of required
|
95
|
+
assets. You can also filter by extensions with the @extensions@ attribute.
|
96
|
+
|
97
|
+
*Usage:*
|
98
|
+
<pre><code><r:if_assets [min_count="n"]>...</r:if_assets></code></pre>
|
99
|
+
}
|
100
|
+
tag 'if_assets' do |tag|
|
101
|
+
count = tag.attr['min_count'] && tag.attr['min_count'].to_i || 1
|
102
|
+
assets = tag.locals.page.assets.count(:conditions => assets_find_options(tag)[:conditions])
|
103
|
+
tag.expand if assets >= count
|
104
|
+
end
|
105
|
+
|
106
|
+
desc %{
|
107
|
+
The opposite of @<r:if_assets/>@.
|
108
|
+
}
|
109
|
+
tag 'unless_assets' do |tag|
|
110
|
+
count = tag.attr['min_count'] && tag.attr['min_count'].to_i || 1
|
111
|
+
assets = tag.locals.page.assets.count(:conditions => assets_find_options(tag)[:conditions])
|
112
|
+
tag.expand unless assets >= count
|
113
|
+
end
|
114
|
+
|
115
|
+
# Resets the page Url and title within the asset tag
|
116
|
+
[:title, :url].each do |method|
|
117
|
+
tag "asset:page:#{method.to_s}" do |tag|
|
118
|
+
tag.locals.page.send(method)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
desc %{
|
129
|
+
Renders the value for a top padding for the image. Put the image in a
|
130
|
+
container with specified height and using this tag you can vertically
|
131
|
+
align the image within it's container.
|
132
|
+
|
133
|
+
*Usage*:
|
134
|
+
<pre><code><r:asset:top_padding container = "140" [size="icon"]/></code></pre>
|
135
|
+
|
136
|
+
*Working Example*:
|
137
|
+
<pre><code>
|
138
|
+
<ul>
|
139
|
+
<r:asset:each>
|
140
|
+
<li style="height:140px">
|
141
|
+
<img style="padding-top:<r:top_padding size='category' container='140' />px"
|
142
|
+
src="<r:url />" alt="<r:title />" />
|
143
|
+
</li>
|
144
|
+
</r:asset:each>
|
145
|
+
</ul>
|
146
|
+
</code></pre>
|
147
|
+
}
|
148
|
+
tag 'asset:top_padding' do |tag|
|
149
|
+
asset, options = asset_and_options(tag)
|
150
|
+
raise TagError, 'Asset is not an image' unless asset.image?
|
151
|
+
raise TagError, "'container' attribute required" unless options['container']
|
152
|
+
size = options['size'] ? options.delete('size') : 'icon'
|
153
|
+
container = options.delete('container')
|
154
|
+
img_height = asset.height(size)
|
155
|
+
(container.to_i - img_height.to_i)/2
|
156
|
+
end
|
157
|
+
|
158
|
+
['height','width'].each do |dimension|
|
159
|
+
desc %{
|
160
|
+
Renders the #{dimension} of the asset.
|
161
|
+
}
|
162
|
+
tag "asset:#{dimension}" do |tag|
|
163
|
+
asset, options = asset_and_options(tag)
|
164
|
+
unless asset.dimensions_known?
|
165
|
+
raise TagError, "Can't determine #{dimension} for this Asset. It may not be a supported type."
|
166
|
+
end
|
167
|
+
size = options['size'] ? options.delete('size') : 'original'
|
168
|
+
asset.send(dimension, size)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
desc %{
|
173
|
+
Returns a string representing the orientation of the asset, which must be an image. Can be 'horizontal', 'vertical' or 'square'.
|
174
|
+
}
|
175
|
+
tag 'asset:orientation' do |tag|
|
176
|
+
asset, options = asset_and_options(tag)
|
177
|
+
raise TagError, 'Asset is not an image' unless asset.image?
|
178
|
+
size = options['size'] ? options.delete('size') : 'original'
|
179
|
+
asset.orientation(size)
|
180
|
+
end
|
181
|
+
|
182
|
+
desc %{
|
183
|
+
Returns the aspect ratio of the asset, which must be an image.
|
184
|
+
}
|
185
|
+
tag 'asset:aspect' do |tag|
|
186
|
+
asset, options = asset_and_options(tag)
|
187
|
+
raise TagError, 'Asset is not an image' unless asset.image?
|
188
|
+
size = options['size'] ? options.delete('size') : 'original'
|
189
|
+
asset.aspect(size)
|
190
|
+
end
|
191
|
+
|
192
|
+
desc %{
|
193
|
+
Renders the containing elements only if the asset's content type matches
|
194
|
+
the regular expression given in the @matches@ attribute. If the
|
195
|
+
@ignore_case@ attribute is set to false, the match is case sensitive. By
|
196
|
+
default, @ignore_case@ is set to true.
|
197
|
+
|
198
|
+
The @name@ or @id@ attribute is required on the parent tag unless this tag is used in @asset:each@.
|
199
|
+
|
200
|
+
*Usage:*
|
201
|
+
<pre><code><r:asset:each><r:if_content_type matches="regexp" [ignore_case=true|false"]>...</r:if_content_type></r:asset:each></code></pre>
|
202
|
+
}
|
203
|
+
tag 'asset:if_content_type' do |tag|
|
204
|
+
options = tag.attr.dup
|
205
|
+
# XXX build_regexp_for comes from StandardTags
|
206
|
+
regexp = build_regexp_for(tag,options)
|
207
|
+
asset_content_type = tag.locals.asset.asset_content_type
|
208
|
+
tag.expand unless asset_content_type.match(regexp).nil?
|
209
|
+
end
|
210
|
+
|
211
|
+
#TODO: could use better docs for Asset#other? case explaining what types it covers
|
212
|
+
Asset.known_types.each do |known_type|
|
213
|
+
desc %{
|
214
|
+
Renders the contents only of the asset is of the type #{known_type}
|
215
|
+
}
|
216
|
+
tag "asset:if_#{known_type}" do |tag|
|
217
|
+
tag.expand if find_asset(tag, tag.attr.dup).send("#{known_type}?".to_sym)
|
218
|
+
end
|
219
|
+
|
220
|
+
desc %{
|
221
|
+
Renders the contents only of the asset is not of the type #{known_type}
|
222
|
+
}
|
223
|
+
tag "asset:unless_#{known_type}" do |tag|
|
224
|
+
tag.expand unless find_asset(tag, tag.attr.dup).send("#{known_type}?".to_sym)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
[:title, :caption, :asset_file_name, :extension, :asset_content_type, :asset_file_size, :id].each do |method|
|
229
|
+
desc %{
|
230
|
+
Renders the @#{method.to_s}@ attribute of the asset
|
231
|
+
}
|
232
|
+
tag "asset:#{method.to_s}" do |tag|
|
233
|
+
asset, options = asset_and_options(tag)
|
234
|
+
asset.send(method) rescue nil
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
tag 'asset:name' do |tag|
|
239
|
+
tag.render('asset:title', tag.attr.dup)
|
240
|
+
end
|
241
|
+
|
242
|
+
tag 'asset:filename' do |tag|
|
243
|
+
asset, options = asset_and_options(tag)
|
244
|
+
asset.asset_file_name rescue nil
|
245
|
+
end
|
246
|
+
|
247
|
+
desc %{
|
248
|
+
Renders an image tag for the asset.
|
249
|
+
|
250
|
+
Using the optional @size@ attribute, different sizes can be display.
|
251
|
+
"thumbnail" and "icon" sizes are built in, but custom ones can be set
|
252
|
+
using by changing assets.addition_thumbnails in the Radiant::Config
|
253
|
+
settings.
|
254
|
+
|
255
|
+
*Usage:*
|
256
|
+
<pre><code><r:asset:image [name="asset name" or id="asset id"] [size="icon|thumbnail|whatever"]></code></pre>
|
257
|
+
}
|
258
|
+
tag 'asset:image' do |tag|
|
259
|
+
tag.locals.asset, options = asset_and_options(tag)
|
260
|
+
if tag.locals.asset.image?
|
261
|
+
size = options['size'] ? options.delete('size') : 'original'
|
262
|
+
alt = "alt='#{tag.locals.asset.title}'" unless tag.attr['alt']
|
263
|
+
attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
|
264
|
+
attributes << alt unless alt.nil?
|
265
|
+
url = tag.locals.asset.thumbnail(size)
|
266
|
+
%{<img src="#{url}" #{attributes unless attributes.empty?} />} rescue nil
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
desc %{
|
271
|
+
Embeds a flash-movie in a cross-browser-compatible fashion using only HTML
|
272
|
+
If no width and height attributes are given it will use the intrinsic
|
273
|
+
dimensions of the swf file
|
274
|
+
|
275
|
+
*Usage:*
|
276
|
+
<pre><code><r:asset:flash [name="asset name" or id="asset id"] [width="100"] [height="100"]>Fallback content</flash></code></pre>
|
277
|
+
|
278
|
+
*Example with text fallback:*
|
279
|
+
<pre><code><r:asset:flash name="flash_movie">
|
280
|
+
Sorry, you need to have flash installed, <a href="http://adobe.com/flash">get it here</a>
|
281
|
+
</flash></code></pre>
|
282
|
+
|
283
|
+
*Example with image fallback and explicit dimensions:*
|
284
|
+
<pre><code><r:asset:flash name="flash_movie" width="300" height="200">
|
285
|
+
<r:asset:image name="flash_screenshot" />
|
286
|
+
</flash></code></pre>
|
287
|
+
}
|
288
|
+
tag 'asset:flash' do |tag|
|
289
|
+
asset, options = asset_and_options(tag)
|
290
|
+
if tag.locals.asset.flash?
|
291
|
+
url = asset.thumbnail('original')
|
292
|
+
dimensions = [(tag.attr['width'] || asset.width),(tag.attr['height'] || asset.height)]
|
293
|
+
swf_embed_markup url, dimensions, tag.expand
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
desc %{
|
298
|
+
Renders the url for the asset. If the asset is an image, the <code>size</code> attribute can be used to
|
299
|
+
generate the url for that size.
|
300
|
+
|
301
|
+
*Usage:*
|
302
|
+
<pre><code><r:url [name="asset name" or id="asset id"] [size="icon|thumbnail"]></code></pre>
|
303
|
+
}
|
304
|
+
tag 'asset:url' do |tag|
|
305
|
+
asset, options = asset_and_options(tag)
|
306
|
+
size = options['size'] ? options.delete('size') : 'original'
|
307
|
+
asset.thumbnail(size) rescue nil
|
308
|
+
end
|
309
|
+
|
310
|
+
desc %{
|
311
|
+
Renders a link to the asset. If the asset is an image, the <code>size</code> attribute can be used to
|
312
|
+
generate a link to that size.
|
313
|
+
|
314
|
+
*Usage:*
|
315
|
+
<pre><code><r:asset:link [name="asset name" or id="asset id"] [size="icon|thumbnail"] /></code></pre>
|
316
|
+
}
|
317
|
+
tag 'asset:link' do |tag|
|
318
|
+
asset, options = asset_and_options(tag)
|
319
|
+
size = options['size'] ? options.delete('size') : 'original'
|
320
|
+
text = options['text'] || asset.title
|
321
|
+
anchor = options['anchor'] ? "##{options.delete('anchor')}" : ''
|
322
|
+
attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
|
323
|
+
attributes = " #{attributes}" unless attributes.empty?
|
324
|
+
text = tag.double? ? tag.expand : text
|
325
|
+
url = asset.thumbnail(size)
|
326
|
+
%{<a href="#{url }#{anchor}"#{attributes}>#{text}</a>} rescue nil
|
327
|
+
end
|
328
|
+
|
329
|
+
private
|
330
|
+
def asset_and_options(tag)
|
331
|
+
options = tag.attr.dup
|
332
|
+
[find_asset(tag, options), options]
|
333
|
+
end
|
334
|
+
|
335
|
+
def find_asset(tag, options)
|
336
|
+
return tag.locals.asset if tag.locals.asset
|
337
|
+
if title = options.delete('name') || options.delete('title')
|
338
|
+
Asset.find_by_title(title)
|
339
|
+
elsif id = options.delete('id')
|
340
|
+
Asset.find_by_id(id)
|
341
|
+
else
|
342
|
+
raise TagError, "'name' or 'id' attribute required for unenclosed r:asset tag" unless tag.locals.asset
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def assets_find_options(tag)
|
347
|
+
attr = tag.attr.symbolize_keys
|
348
|
+
extensions = attr[:extensions] && attr[:extensions].split('|') || []
|
349
|
+
conditions = unless extensions.blank?
|
350
|
+
# this is soon to be removed in favour of asset types
|
351
|
+
[ extensions.map { |ext| "assets.asset_file_name LIKE ?"}.join(' OR '),
|
352
|
+
*extensions.map { |ext| "%.#{ext}" } ]
|
353
|
+
else
|
354
|
+
nil
|
355
|
+
end
|
356
|
+
|
357
|
+
by = attr[:by] || 'page_attachments.position'
|
358
|
+
order = attr[:order] || 'asc'
|
359
|
+
|
360
|
+
options = {
|
361
|
+
:order => "#{by} #{order}",
|
362
|
+
:limit => attr[:limit] || nil,
|
363
|
+
:offset => attr[:offset] || nil,
|
364
|
+
:conditions => conditions
|
365
|
+
}
|
366
|
+
end
|
367
|
+
|
368
|
+
def swf_embed_markup(url, dimensions, fallback_content)
|
369
|
+
width, height = dimensions
|
370
|
+
%{<!--[if !IE]> -->
|
371
|
+
<object type="application/x-shockwave-flash" data="#{url}" width="#{width}" height="#{height}">
|
372
|
+
<!-- <![endif]-->
|
373
|
+
<!--[if IE]>
|
374
|
+
<object width="#{width}" height="#{height}"
|
375
|
+
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
|
376
|
+
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0">
|
377
|
+
<param name="movie" value="#{url}" />
|
378
|
+
<!-->
|
379
|
+
#{fallback_content}
|
380
|
+
</object>
|
381
|
+
<!-- <![endif]-->}
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|