radiant-page_attachments-extension 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/.gitignore +5 -0
  2. data/LICENSE +20 -0
  3. data/README.md +129 -0
  4. data/Rakefile +57 -0
  5. data/VERSION +1 -0
  6. data/app/models/observe_page_attachments.rb +5 -0
  7. data/app/models/page_attachment.rb +28 -0
  8. data/app/models/page_attachment_associations.rb +20 -0
  9. data/app/models/page_attachment_tags.rb +261 -0
  10. data/app/models/page_attachments_interface.rb +19 -0
  11. data/app/views/admin/pages/_attachment.html.haml +12 -0
  12. data/app/views/admin/pages/_attachments_box.html.haml +12 -0
  13. data/db/migrate/001_create_page_attachments_extension_schema.rb +22 -0
  14. data/db/migrate/002_add_page_attachments_fields.rb +23 -0
  15. data/features/attachments.feature +42 -0
  16. data/features/step_definitions/attachment_steps.rb +61 -0
  17. data/features/support/env.rb +57 -0
  18. data/features/support/paths.rb +14 -0
  19. data/lib/difference_test_helper.rb +20 -0
  20. data/lib/radiant-page_attachments-extension.rb +0 -0
  21. data/lib/tasks/page_attachments_extension_tasks.rake +28 -0
  22. data/page_attachments_extension.rb +27 -0
  23. data/public/images/admin/drag_order.png +0 -0
  24. data/public/javascripts/admin/page_attachments.js +30 -0
  25. data/public/stylesheets/admin/page_attachments.css +133 -0
  26. data/radiant-page_attachments-extension.gemspec +139 -0
  27. data/spec/controllers/pages_controller_spec.rb +10 -0
  28. data/spec/datasets/page_attachments_dataset.rb +31 -0
  29. data/spec/fixtures/foo.txt +1 -0
  30. data/spec/fixtures/rails.png +0 -0
  31. data/spec/models/observe_page_attachments_spec.rb +14 -0
  32. data/spec/models/page_attachment_spec.rb +18 -0
  33. data/spec/models/page_attachment_tags_spec.rb +172 -0
  34. data/spec/models/page_spec.rb +32 -0
  35. data/spec/spec.opts +6 -0
  36. data/spec/spec_helper.rb +39 -0
  37. data/vendor/plugins/acts_as_list/README +23 -0
  38. data/vendor/plugins/acts_as_list/init.rb +3 -0
  39. data/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +256 -0
  40. data/vendor/plugins/acts_as_list/test/list_test.rb +332 -0
  41. data/vendor/plugins/attachment_fu/CHANGELOG +35 -0
  42. data/vendor/plugins/attachment_fu/LICENSE +20 -0
  43. data/vendor/plugins/attachment_fu/README +193 -0
  44. data/vendor/plugins/attachment_fu/Rakefile +22 -0
  45. data/vendor/plugins/attachment_fu/amazon_s3.yml.tpl +17 -0
  46. data/vendor/plugins/attachment_fu/init.rb +16 -0
  47. data/vendor/plugins/attachment_fu/install.rb +7 -0
  48. data/vendor/plugins/attachment_fu/lib/geometry.rb +93 -0
  49. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb +211 -0
  50. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +39 -0
  51. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +126 -0
  52. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/s3_backend.rb +394 -0
  53. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +59 -0
  54. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +54 -0
  55. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +61 -0
  56. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +132 -0
  57. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +57 -0
  58. data/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb +514 -0
  59. data/vendor/plugins/attachment_fu/rackspace_cloudfiles.yml.tpl +14 -0
  60. data/vendor/plugins/attachment_fu/test/backends/db_file_test.rb +16 -0
  61. data/vendor/plugins/attachment_fu/test/backends/file_system_test.rb +143 -0
  62. data/vendor/plugins/attachment_fu/test/backends/remote/cloudfiles_test.rb +102 -0
  63. data/vendor/plugins/attachment_fu/test/backends/remote/s3_test.rb +119 -0
  64. data/vendor/plugins/attachment_fu/test/base_attachment_tests.rb +77 -0
  65. data/vendor/plugins/attachment_fu/test/basic_test.rb +70 -0
  66. data/vendor/plugins/attachment_fu/test/database.yml +18 -0
  67. data/vendor/plugins/attachment_fu/test/extra_attachment_test.rb +67 -0
  68. data/vendor/plugins/attachment_fu/test/fixtures/attachment.rb +226 -0
  69. data/vendor/plugins/attachment_fu/test/fixtures/files/fake/rails.png +0 -0
  70. data/vendor/plugins/attachment_fu/test/fixtures/files/foo.txt +1 -0
  71. data/vendor/plugins/attachment_fu/test/fixtures/files/rails.png +0 -0
  72. data/vendor/plugins/attachment_fu/test/geometry_test.rb +108 -0
  73. data/vendor/plugins/attachment_fu/test/processors/core_image_test.rb +37 -0
  74. data/vendor/plugins/attachment_fu/test/processors/gd2_test.rb +31 -0
  75. data/vendor/plugins/attachment_fu/test/processors/image_science_test.rb +31 -0
  76. data/vendor/plugins/attachment_fu/test/processors/mini_magick_test.rb +103 -0
  77. data/vendor/plugins/attachment_fu/test/processors/rmagick_test.rb +255 -0
  78. data/vendor/plugins/attachment_fu/test/schema.rb +134 -0
  79. data/vendor/plugins/attachment_fu/test/test_helper.rb +150 -0
  80. data/vendor/plugins/attachment_fu/test/validation_test.rb +55 -0
  81. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/color.rb +27 -0
  82. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/effects.rb +31 -0
  83. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/perspective.rb +25 -0
  84. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/quality.rb +25 -0
  85. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/scale.rb +47 -0
  86. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/filters/watermark.rb +32 -0
  87. data/vendor/plugins/attachment_fu/vendor/red_artisan/core_image/processor.rb +123 -0
  88. metadata +178 -0
@@ -0,0 +1,19 @@
1
+ module PageAttachmentsInterface
2
+ def self.included(base)
3
+ base.class_eval {
4
+ before_filter :add_page_attachment_partials,
5
+ :only => [:edit, :new]
6
+ include InstanceMethods
7
+ }
8
+ end
9
+
10
+ module InstanceMethods
11
+ def add_page_attachment_partials
12
+ @buttons_partials ||= []
13
+ @buttons_partials << "attachments_box"
14
+ include_javascript 'admin/dragdrop'
15
+ include_javascript 'admin/page_attachments'
16
+ include_stylesheet 'admin/page_attachments'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ %li{:id => "attachment_#{attachment.id}", :class =>"attachment clearfix"}
2
+ = hidden_field_tag "page[attachments_attributes][#{attachment_counter}][id]", attachment.id
3
+ = hidden_field_tag "page[attachments_attributes][#{attachment_counter}][_delete]", "0"
4
+ = hidden_field_tag "page[attachments_attributes][#{attachment_counter}][position]", attachment.position
5
+ - unless attachment.first? && attachment.last?
6
+ = image_tag 'admin/drag_order.png', :alt => "Drag handle", :title => "Drag to change order", :class => 'drag_order'
7
+ %div= image_tag "admin/minus.png", :alt => "delete", :class => 'delete'
8
+ - unless attachment.thumbnails.empty?
9
+ = link_to image_tag(attachment.public_filename("icon")), attachment.public_filename, :class => 'thumbnail'
10
+ - unless attachment.title.blank?
11
+ %p= h attachment.short_title
12
+ = link_to attachment.short_filename, attachment.public_filename
@@ -0,0 +1,12 @@
1
+ #attachments
2
+ .toolbar
3
+ = image_tag('admin/plus.png', :alt => 'add')
4
+ = hidden_field_tag('attachment_index', @page.attachments.size, :id => 'attachment_index_field')
5
+ %h3
6
+ Attachments (
7
+ %span#attachment_count>= @page.attachments.count
8
+ )
9
+ - unless @page.attachments.count.zero?
10
+ %ol#attachment_list
11
+ = render :partial => 'attachment', :collection => @page.attachments
12
+ %div{:style => "clear:both;"}
@@ -0,0 +1,22 @@
1
+ class CreatePageAttachmentsExtensionSchema < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "page_attachments" do |t|
4
+ t.column "content_type", :string
5
+ t.column "filename", :string
6
+ t.column "size", :integer
7
+ t.column "parent_id", :integer
8
+ t.column "thumbnail", :string
9
+ t.column "width", :integer
10
+ t.column "height", :integer
11
+ t.column "created_at", :datetime
12
+ t.column "created_by", :integer
13
+ t.column "updated_at", :datetime
14
+ t.column "updated_by", :integer
15
+ t.column "page_id", :integer
16
+ end
17
+ end
18
+
19
+ def self.down
20
+ drop_table "page_attachments"
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ class AddPageAttachmentsFields < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :page_attachments, :title, :string
4
+ add_column :page_attachments, :description, :string
5
+ add_column :page_attachments, :position, :integer
6
+ pages_with_attachments = PageAttachment.find_by_sql('select page_id from page_attachments where page_id is not null group by page_id')
7
+ pages_with_attachments.each do |pa|
8
+ attaches = PageAttachment.find(:all, :conditions => ['page_id = ?',pa.page_id], :order => :id)
9
+ i=1
10
+ attaches.each do |attach|
11
+ attach.position = i
12
+ attach.save
13
+ i = i + 1
14
+ end
15
+ end
16
+ end
17
+
18
+ def self.down
19
+ remove_column :page_attachments, :title
20
+ remove_column :page_attachments, :description
21
+ remove_column :page_attachments, :position
22
+ end
23
+ end
@@ -0,0 +1,42 @@
1
+ Feature: attachments
2
+ As a content editor
3
+ I should be able to add, reorder, and delete attachments
4
+
5
+ Background:
6
+ Given I am logged in as admin
7
+
8
+ Scenario: attach a file
9
+ Given I have a page with no attachments
10
+ When I edit the page
11
+ And I click the plus icon
12
+ And I attach the Rails logo
13
+ And I save
14
+ Then the page should have a new attachment
15
+
16
+ Scenario: don't change attachments
17
+ Given I have a page with 2 attachments
18
+ When I edit the page
19
+ And I save
20
+ Then the page should have 2 attachments
21
+
22
+ Scenario: attach another file
23
+ Given I have a page with 2 attachments
24
+ When I edit the page
25
+ And I click the plus icon
26
+ And I attach the Rails logo
27
+ And I save
28
+ Then the page should have 3 attachments
29
+
30
+ Scenario: delete a file
31
+ Given I have a page with 2 attachments
32
+ When I edit the page
33
+ And I delete the first attachment
34
+ And I save
35
+ Then the page should have 1 attachment
36
+
37
+ Scenario: reorder attachments
38
+ Given I have a page with 2 attachments
39
+ When I edit the page
40
+ And I drag attachment 2 above attachment 1
41
+ And I save
42
+ Then attachment 2 should be in position 1
@@ -0,0 +1,61 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
2
+
3
+ Given /^I am logged in as (.*)(?: user)?$/ do |username|
4
+ visit login_path
5
+ fill_in "Username", :with => username
6
+ fill_in "Password", :with => "password"
7
+ click_button "Login"
8
+ end
9
+
10
+ Given /^I have a page$/ do
11
+ @page = pages(:home)
12
+ end
13
+
14
+ Given /^I have a page with (\d+) attachments$/ do |number|
15
+ Given "I have a page"
16
+ @page.attachments.length.should == number.to_i
17
+ end
18
+
19
+ Given /^I have a page with no attachments$/ do
20
+ @page = pages(:first)
21
+ @page.attachments.should be_empty
22
+ end
23
+
24
+ When /^I edit the page$/ do
25
+ visit edit_admin_page_path(@page)
26
+ end
27
+
28
+ When /^I click the plus icon$/ do
29
+ selenium.click "xpath=id('attachments')//img[@alt='Add']"
30
+ end
31
+
32
+ When /^I attach the Rails logo$/ do
33
+ attach_file "file_input", "#{PageAttachmentsExtension.root}/spec/fixtures/rails.png"
34
+ end
35
+
36
+ When /^I delete the first attachment$/ do
37
+ selenium.click "xpath=id('attachment_list')/li[1]//img[@alt='Delete']"
38
+ end
39
+
40
+ When /^I drag attachment 2 above attachment 1$/ do
41
+ @attachment = @page.attachments[1]
42
+ @attachment.position.should == 2
43
+ selenium.dragdrop("id=attachment_#{@attachment.id}", "0, -200")
44
+ end
45
+
46
+ When /^I save$/ do
47
+ click_button "Save"
48
+ response.should_not contain("errors")
49
+ end
50
+
51
+ Then /^the page should have a new attachment$/ do
52
+ @page.reload.attachments.should_not be_empty
53
+ end
54
+
55
+ Then /^the page should have (\d+) attachment(?:s)?$/ do |number|
56
+ @page.reload.attachments.length.should == number.to_i
57
+ end
58
+
59
+ Then /^attachment 2 should be in position 1$/ do
60
+ @attachment.reload.position.should == 1
61
+ end
@@ -0,0 +1,57 @@
1
+ # Sets up the Rails environment for Cucumber
2
+ ENV["RAILS_ENV"] = "test"
3
+ require File.expand_path(File.dirname(__FILE__) + '/../../../../../config/environment')
4
+
5
+ require 'cucumber/rails/world'
6
+ require 'cucumber/formatter/unicode' # Comment out this line if you don't want Cucumber Unicode support
7
+ require 'webrat'
8
+ raise "Update the version of Webrat you specify in test.rb." if Webrat.const_defined?(:VERSION) && Webrat::VERSION < '0.5.1' # Webrat 0.4.4 won't work with selenium-client 1.2.16
9
+
10
+ Webrat.configure do |config|
11
+ config.mode = :selenium
12
+ config.selenium_browser_key = "*chrome"
13
+ end
14
+
15
+ # this is necessary to have webrat "wait_for" the response body to be available
16
+ # when writing steps that match against the response body returned by selenium
17
+ World(Webrat::Selenium::Matchers)
18
+
19
+ # Patch in attach_file functionality
20
+ module Webrat
21
+ class SeleniumSession
22
+ def attach_file(field_locator, path, content_type = nil)
23
+ fill_in(field_locator, :with => path)
24
+ end
25
+ end
26
+ end
27
+
28
+ require 'cucumber/rails/rspec'
29
+ require 'dataset'
30
+
31
+ module Dataset
32
+ module Extensions # :nodoc:
33
+ # Selenium can't handle transactions, so we have to disable them in Dataset
34
+ module CucumberWorldNoTransactions # :nodoc:
35
+ def dataset(*datasets, &block)
36
+ add_dataset(*datasets, &block)
37
+
38
+ load = nil
39
+ $__cucumber_toplevel.Before do
40
+ Dataset::Database::Base.new.clear # Empty all tables
41
+ dataset_session.instance_variable_set("@load_stack", []) # notify load_stack that nothing's loaded
42
+ load = dataset_session.load_datasets_for(self.class)
43
+ extend_from_dataset_load(load)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Cucumber::Rails::World.class_eval do
51
+ include Dataset
52
+ self.extend Dataset::Extensions::CucumberWorldNoTransactions
53
+ datasets_directory "#{RADIANT_ROOT}/spec/datasets"
54
+ Dataset::Resolver.default << (File.dirname(__FILE__) + "/../../spec/datasets")
55
+ self.datasets_database_dump_path = "#{Rails.root}/tmp/dataset"
56
+ dataset :pages_with_layouts, :users, :page_attachments
57
+ end
@@ -0,0 +1,14 @@
1
+ def path_to(page_name)
2
+ case page_name
3
+
4
+ when /the homepage/i
5
+ root_path
6
+
7
+ when /edit the page/i
8
+ edit_admin_page_path(@page)
9
+ # Add more page name => path mappings here
10
+
11
+ else
12
+ raise "Can't find mapping from \"#{page_name}\" to a path."
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module DifferenceTestHelper
2
+ # http://project.ioni.st/post/217#post-217
3
+ #
4
+ # def test_new_publication
5
+ # assert_difference(Publication, :count) do
6
+ # post :create, :publication => {...}
7
+ # # ...
8
+ # end
9
+ # end
10
+ #
11
+ def assert_difference(object, method = nil, difference = 1)
12
+ initial_value = object.send(method)
13
+ yield
14
+ assert_equal initial_value + difference, object.send(method), "#{object}##{method}"
15
+ end
16
+
17
+ def assert_no_difference(object, method, &block)
18
+ assert_difference object, method, 0, &block
19
+ end
20
+ end
File without changes
@@ -0,0 +1,28 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :page_attachments do
4
+
5
+ desc "Runs the migration of the Page Attachments extension"
6
+ task :migrate => :environment do
7
+ require 'radiant/extension_migrator'
8
+ if ENV["VERSION"]
9
+ PageAttachmentsExtension.migrator.migrate(ENV["VERSION"].to_i)
10
+ else
11
+ PageAttachmentsExtension.migrator.migrate
12
+ end
13
+ end
14
+
15
+ desc "Copies public assets of the Page Attachments to the instance public/ directory."
16
+ task :update => :environment do
17
+ is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
18
+ puts "Copying assets from PageAttachmentsExtension"
19
+ Dir[PageAttachmentsExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
20
+ path = file.sub(PageAttachmentsExtension.root, '')
21
+ directory = File.dirname(path)
22
+ mkdir_p RAILS_ROOT + directory
23
+ cp file, RAILS_ROOT + path
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ require_dependency 'application_controller'
2
+ # require File.dirname(__FILE__) + '/lib/geometry'
3
+ # require 'tempfile'
4
+
5
+ class PageAttachmentsExtension < Radiant::Extension
6
+ version "1.0"
7
+ description "Adds page-attachment-style asset management."
8
+ url "http://radiantcms.org"
9
+
10
+ define_routes do |map|
11
+ map.connect 'page_attachments/:action/:id', :controller => 'page_attachments'
12
+ end
13
+
14
+ def activate
15
+ # Regular page attachments stuff
16
+ Page.class_eval {
17
+ include PageAttachmentAssociations
18
+ include PageAttachmentTags
19
+ }
20
+ UserActionObserver.send :include, ObservePageAttachments
21
+ Admin::PagesController.send :include, PageAttachmentsInterface
22
+ end
23
+
24
+ def deactivate
25
+ end
26
+
27
+ end
Binary file
@@ -0,0 +1,30 @@
1
+ Event.addBehavior({
2
+
3
+ '#attachment_list': function() {
4
+ Sortable.create('attachment_list', {
5
+ onUpdate: function(container) {
6
+ container.select(".attachment").each(function(e, i) {
7
+ e.down('input[name*="position"]').setValue(i+1);
8
+ });
9
+ }
10
+ });
11
+ },
12
+
13
+ '#attachments:click': function(event) {
14
+ var target = $(event.target);
15
+ if (target.match('img[alt=add]')) {
16
+ var upload = '<div class="attachment_upload"><p class="title">Upload file</p><table><tr><th><label for="title_input">Title:</label></th><td><input id="title_input" size="60" name="page[attachments_attributes][][title]"></td></tr><tr><th><label for="description_input">Description:</label></th><td><input id="description_input" type="text" size="60" name="page[attachments_attributes][][description]"></td></tr><tr><th><label for="file_input">File:</label></th><td><input id="file_input" type="file" size="60" name="page[attachments_attributes][][uploaded_data]" /><img src="/images/admin/minus.png" alt="cancel" /></td></tr></table></div>';
17
+ $('attachment_index_field').value = parseInt($('attachment_index_field').value) + 1;
18
+ $('attachments').insert(upload.gsub(/\[\]/, '[' + $('attachment_index_field').value + ']'));
19
+ } else if (target.match('img[alt=cancel]')) {
20
+ event.findElement('.attachment_upload').remove();
21
+ event.stop();
22
+ } else if (target.match('img[alt=delete]')) {
23
+ var attachment = event.findElement('.attachment');
24
+ attachment.addClassName('deleted');
25
+ attachment.insert("<em>Attachment will be deleted when page is saved.</em>");
26
+ attachment.down('input[name*="_delete"]').setValue('true');
27
+ }
28
+ }
29
+
30
+ });
@@ -0,0 +1,133 @@
1
+ #attachments {
2
+ clear: both;
3
+ color: #333;
4
+ background: #f5f1e2 url(/images/admin/vertical_tan_gradient.png) repeat-x top;
5
+ margin: 10px 0;
6
+ border-radius: 8px;
7
+ -moz-border-radius: 8px;
8
+ -webkit-border-radius: 8px;
9
+ overflow: hidden;
10
+ }
11
+ #attachments .toolbar {
12
+ float: right;
13
+ padding: 6px 6px 0;
14
+ width: 50px;
15
+ text-align: right;
16
+ }
17
+ #attachments .toolbar img {
18
+ padding: 5px;
19
+ cursor: pointer;
20
+ }
21
+ #attachments h3 {
22
+ font-size: 16px;
23
+ padding: 7px 0;
24
+ }
25
+ #attachments h3, #attachments p.notice {
26
+ background: #eae3c5;
27
+ margin: 0;
28
+ padding: 0.5em;
29
+ }
30
+ #attachments .attachment_upload {
31
+ padding: 0 0.8em 0.8em 0.8em;
32
+ }
33
+ #attachments p.notice {
34
+ padding: .5em .8em;
35
+ font-style: italic;
36
+ font-size: 90%;
37
+ color: red;
38
+ }
39
+ #attachments .attachment_upload img,
40
+ #attachments .attachment img.delete {
41
+ cursor: pointer;
42
+ padding: 2px;
43
+ margin-left:7px;
44
+ }
45
+ #attachments .attachment img.drag_order {
46
+ cursor: move;
47
+ float: right;
48
+ padding: 2px;
49
+ margin-right:6px;
50
+ }
51
+ #attachments ol {
52
+ list-style: none;
53
+ padding: 0 10px 0 10px;
54
+ margin: 0;
55
+ }
56
+ #attachments ol li {
57
+ margin-left: 0;
58
+ }
59
+ #attachments ol li div {
60
+ float: left;
61
+ width: 25px;
62
+ }
63
+ #attachments ol li a.thumbnail {
64
+ float: left;
65
+ margin: 0 10px 0 10px;
66
+ }
67
+ #attachments ol li p {
68
+ margin: 0 0 5px 0;
69
+ }
70
+ #attachments ol li {
71
+ border-bottom: 1px dashed #cccccc;
72
+ width: 100%;
73
+ padding: 8px 0;
74
+ }
75
+ #attachments ol li:last-child {
76
+ border-bottom: none;
77
+ }
78
+ #attachments .attachment .thumbnail img {
79
+ background: white;
80
+ border: 1px solid #d4cba4;
81
+ padding: 3px;
82
+ border-radius: 3px;
83
+ -moz-border-radius: 3px;
84
+ -webkit-border-radius: 3px;
85
+ }
86
+ #attachments p.title {
87
+ border-bottom: 1px #eae3c5 solid;
88
+ width: 66%;
89
+ font-size: 17px;
90
+ font-weight: bold;
91
+ margin: 1em 0 ;
92
+ }
93
+ #attachments table {
94
+ margin-top: 1em;
95
+ }
96
+ #attachments table th {
97
+ font-weight: bold;
98
+ text-align: right;
99
+ padding-right: 10px;
100
+ width: 120px;
101
+ padding-bottom: 5px;
102
+ }
103
+ #attachments table td {
104
+ padding-bottom: 5px;
105
+ }
106
+ #attachments li.attachment.deleted em {
107
+ color: #ff0000;
108
+ margin: 0 0 10px 20px;
109
+ }
110
+ #attachments li.attachment.deleted a {
111
+ opacity: 0.5;
112
+ text-decoration: line-through;
113
+ }
114
+ #attachments li.attachment.deleted img.delete {
115
+ visibility: hidden;
116
+ }
117
+
118
+ .clearfix:after {
119
+ content: ".";
120
+ display: block;
121
+ height: 0;
122
+ clear: both;
123
+ visibility: hidden;
124
+ }
125
+ .clearfix {
126
+ display:inline-block;
127
+ }
128
+ .clearfix {
129
+ display:block;
130
+ }
131
+ li.clearfix {
132
+ display: list-item;
133
+ }