refinerycms-imajax 2.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # refinerycms-imajax: extension for Refinery CMS.
2
+ ---
3
+ This is a small and simple extension that replaces the default behavior for image uploading. By default, all images are uploaded on a single form post. That can lead to timeouts on Heroku (to name one) if you upload too many files at once. What refinerycms-imajax does is simply uploading the files one by one. It will only work with modern browsers that supports FileList and FormData (Chrome is one that supports those) but fallbacks to default behavior.
4
+
5
+ ## Requirements
6
+ ---
7
+
8
+ You should have a Rails project with Refinery (>= 2.0.0 but only tested with 2.0.2).
9
+
10
+ ## Install
11
+ ---
12
+ Add refinerycms-imajax to your `Gemfile`:
13
+
14
+ gem 'refinerycms-imajax', "~> 2.0.0.beta1"
15
+
16
+ run
17
+
18
+ $ bundle install
19
+ $ rails s
20
+
21
+ It should now work!
22
+
23
+
24
+ ## TODO
25
+ ---
26
+ - Set valid file types based on image model validation (images.js.coffee.erb)
27
+ - Manage locales and remove hard coded ones
28
+ - Add a progress bar for each file maybe?
29
+ - Setup TravisCI to test over multiple Ruby, Rails and Refinery versions
30
+ - Fix Capybara so that it can test multiple file uploads
31
+
32
+
33
+ ## Tests
34
+ ---
35
+ There is only one request spec actually which is a copy of the refinerycms-images gem. Why? It is not currently possible to test multiple file uploads with Capybara: [https://github.com/jnicklas/capybara/issues/37](https://github.com/jnicklas/capybara/issues/37).
36
+
37
+ ### Run tests
38
+
39
+ 1. You need a dummy app first:
40
+
41
+ $ bundle exec rake refinery:testing:dummy_app
42
+
43
+ 2. Run tests:
44
+
45
+ $ bundle exec rake
46
+
47
+
48
+
49
+ ### How to build this extension as a gem
50
+
51
+ cd [imajax directory]
52
+ gem build refinerycms-imajax.gemspec
53
+ gem install refinerycms-imajax.gem
54
+
55
+ # Sign up for a http://rubygems.org/ account and publish the gem
56
+ gem push refinerycms-imajax.gem
@@ -0,0 +1,118 @@
1
+ $(document).ready ->
2
+ images = new Images
3
+ $("#new_image").submit (e) ->
4
+ if window.FileList && FormData
5
+ e.preventDefault()
6
+ images.upload_all()
7
+ $("#image_image").change (e) ->
8
+ images.file_list = e.target.files
9
+ parent.$(".ui-icon-closethick").click (e) ->
10
+ e.preventDefault()
11
+ parent.window.location.href = parent.window.location.href
12
+
13
+
14
+ class Images
15
+ # TODO:
16
+ # - add a progress bar for each file maybe?
17
+ # - refresh images index after closing the dialog box...
18
+ constructor: ->
19
+ @authenticity_token = $("meta[name=\"csrf-token\"]").attr("content")
20
+ @form_action = "/refinery/images/ajax_create"
21
+ @cache_dom()
22
+
23
+ cache_dom: ->
24
+ @error_list = $("#error_list")
25
+ @success_list = $("#flash")
26
+ @error_explanation = $("#errorExplanation")
27
+ @upload_progress = $("#upload_progress")
28
+
29
+ before_upload_all: ->
30
+ @files = []
31
+ @errors = []
32
+ @total_files = @file_list.length
33
+ @uploaded = 0
34
+ @error_explanation.hide()
35
+
36
+ upload_all: ->
37
+ @before_upload_all()
38
+ for file in @file_list
39
+ @validate(file)
40
+ @files.push file
41
+ return @render_errors() if @errors.length > 0
42
+ $("#submit_button").hide()
43
+ $(".field").hide()
44
+ @progress "Uploading..."
45
+ @upload_next()
46
+
47
+ after_upload_all: ->
48
+ $(".save-loader").hide()
49
+ @upload_progress.hide()
50
+ if @errors.length > 0
51
+ @progress "There was #{@errors.length} error#{(if @errors.length > 1 then "s" else "")}"
52
+ @render_errors()
53
+ @success_list.show()
54
+
55
+ validate: (file) ->
56
+ max_file_size = <%= Refinery::Images.max_image_size %>
57
+ if file.size > max_file_size
58
+ @errors.push "#{file.name} should be smaller than #{max_file_size} bytes in size"
59
+ # TODO: set valid file types based on image model validation
60
+ valid_file_types = ["image/jpeg", "image/png", "image/gif", "image/tiff"]
61
+ if valid_file_types.indexOf(file.type) == -1
62
+ @errors.push "#{file.name} should be either a JPG, PNG or GIF"
63
+
64
+ upload_next: ->
65
+ @do_upload(@files[0]) unless @files.length == 0
66
+ if @total_files > 0 && @files.length == 0
67
+ @after_upload_all()
68
+
69
+ do_upload: (file) =>
70
+ form = new FormData();
71
+ form.append "image", file
72
+ form.append "authenticity_token", @authenticity_token
73
+ _this = @
74
+ $.ajax
75
+ type: 'POST'
76
+ url: @form_action
77
+ data: form
78
+ contentType: false
79
+ processData: false
80
+ success: (data) ->
81
+ _this.post_success(file)
82
+ error: (data) ->
83
+ _this.post_error(file, data.responseText)
84
+
85
+ after_do_upload: (file) ->
86
+ @files.remove file
87
+ @upload_next()
88
+
89
+ post_success: (file) ->
90
+ @progress file.name + " uploaded"
91
+ @success_list.append("#{file.name} <br />")
92
+ @update_progress file
93
+ @after_do_upload file
94
+
95
+ post_error: (file, errors) ->
96
+ errors = JSON.parse(errors).image
97
+ @update_progress file, errors
98
+ for e in errors
99
+ @errors.push "#{file.name}: #{e}"
100
+ @after_do_upload file
101
+
102
+ render_errors: ->
103
+ $(".save-loader").hide()
104
+ @error_list.html("")
105
+ for error in @errors
106
+ @error_list.append("<li>#{error}</li>")
107
+ @error_explanation.show()
108
+
109
+ update_progress: (file, error = null) ->
110
+ @uploaded++
111
+ message = error || "Last upload complete: #{file.name}"
112
+ @progress "#{@uploaded}/#{@total_files} uploaded | #{message}"
113
+
114
+ progress: (text) ->
115
+ @upload_progress.html(text);
116
+
117
+ # adds a remove method to Array
118
+ Array::remove = (e) -> @[t..t] = [] if (t = @indexOf(e)) > -1
@@ -0,0 +1,15 @@
1
+ ::Refinery::Admin::ImagesController.class_eval do
2
+
3
+ def ajax_create
4
+ params[:image] = images = {image: params[:image]}
5
+ params[:image].each do |image|
6
+ @image = ::Refinery::Image.create(params[:image])
7
+ end
8
+ unless @image.errors.any?
9
+ render :json => { redirect_to: refinery.admin_images_path }
10
+ else
11
+ render :json => @image.errors, status: 406
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,76 @@
1
+ <%### imajax specific do %>
2
+ <% content_for :after_javascript_libraries, javascript_include_tag('refinery/images') %>
3
+ <%### END imajax specific %>
4
+
5
+ <%= form_for @image, :url => (@url_override or @image.persisted? ? refinery.admin_image_path(@image) : refinery.admin_images_path),
6
+ :html => { :multipart => true } do |f| %>
7
+
8
+ <%= render '/refinery/admin/error_messages',
9
+ :object => @image,
10
+ :include_object_name => false %>
11
+
12
+ <%########################%>
13
+ <%### imajax specific do %>
14
+ <% unless @image.errors.any? %>
15
+ <div id="upload_progress"></div>
16
+
17
+ <div class="errorExplanation" id="errorExplanation" style="display:none;">
18
+ <p><%= t("refinery.admin.error_messages.problems_in_following_fields")%></p>
19
+ <ul id="error_list">
20
+
21
+ </ul>
22
+ </div>
23
+
24
+ <div id="flash_container">
25
+ <div id="flash" class="flash flash_notice" style="width: auto; display:none;">
26
+ <h3><%= t("refinery.imajax.uploaded_successfully") %>:</h3>
27
+
28
+ </div>
29
+ </div>
30
+ <% end %>
31
+ <%### END imajax specific %>
32
+ <%########################%>
33
+
34
+ <div class='field'>
35
+ <% if action_name =~ /(edit)|(update)/ %>
36
+ <p>
37
+ <%= t('.use_current_image') %>
38
+ <em><%= t('.or') %></em><%= t('.replace_image') %>
39
+ </p>
40
+ <p>
41
+ <%= f.file_field :image %>
42
+ </p>
43
+ <% else %>
44
+ <% # we must only hint at multiple when it's a new record otherwise update fails. %>
45
+ <%= f.file_field :image, :multiple => true %>
46
+ <% end %>
47
+ </div>
48
+
49
+ <div class='field'>
50
+ <label><%= t('.maximum_image_size', :bytes => number_to_human_size(Refinery::Images.max_image_size)) %></label>
51
+ </div>
52
+
53
+ <input type='hidden' name='wymeditor' value='<%= params[:wymeditor] %>'>
54
+
55
+ <%= render '/refinery/admin/form_actions', :f => f,
56
+ :continue_editing => false,
57
+ :hide_cancel => (@app_dialog or action_name == "insert" or from_dialog?),
58
+ :delete_title => t('delete', :scope => 'refinery.admin.images'),
59
+ :delete_confirmation => t('message', :scope => 'refinery.admin.delete', :title => @image.image_name) -%>
60
+
61
+ <% if @app_dialog %>
62
+ <input type='hidden' name='app_dialog' value='<%= @app_dialog %>' />
63
+ <input type='hidden' name='field' value='<%= @field %>' />
64
+ <input type='hidden' name='update_image' value='<%= @update_image %>' />
65
+ <input type='hidden' name='thumbnail' value='<%= @thumbnail %>' />
66
+ <input type='hidden' name='callback' value='<%= @callback %>' />
67
+ <input type='hidden' name='conditions' value='<%= @conditions %>' />
68
+ <% end %>
69
+ <% end %>
70
+
71
+ <% if action_name =~ /(edit)|(update)/ %>
72
+ <div id='existing_image'>
73
+ <label><%=t('.current_image') %></label>
74
+ <%= image_fu @image, '225x255>', :class => "brown_border" %>
75
+ </div>
76
+ <% end %>
@@ -0,0 +1,21 @@
1
+ en:
2
+ refinery:
3
+ imajax:
4
+ uploading:
5
+ "Uploading..."
6
+ there_was:
7
+ "There was"
8
+ error:
9
+ "error"
10
+ should_be_smaller:
11
+ "should be smaller than"
12
+ bytes_in_size:
13
+ "bytes in size"
14
+ image_type:
15
+ "should be either a JPG, PNG or GIF"
16
+ uploaded:
17
+ "uploaded"
18
+ last_complete:
19
+ "Last upload complete"
20
+ uploaded_successfully:
21
+ "Uploaded successfully"
@@ -0,0 +1,21 @@
1
+ fr:
2
+ refinery:
3
+ imajax:
4
+ uploading:
5
+ "Transfert en cours..."
6
+ there_was:
7
+ "Il y a"
8
+ error:
9
+ "erreur"
10
+ should_be_smaller:
11
+ "devrait être plus petit que"
12
+ bytes_in_size:
13
+ "octets"
14
+ image_type:
15
+ "devrait être un fichier JPG, PNG ou GIF"
16
+ uploaded:
17
+ "transféré"
18
+ last_complete:
19
+ "Dernier transfert complété"
20
+ uploaded_successfully:
21
+ "Transféré avec succès"
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ Refinery::Core::Engine.routes.append do
2
+ namespace :admin, :path => 'refinery' do
3
+ post "images/ajax_create", to: "images#ajax_create"
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ require 'refinerycms-core'
2
+
3
+ module Refinery
4
+ autoload :ImajaxGenerator, 'generators/refinery/imajax_generator'
5
+
6
+ module Imajax
7
+ require 'refinery/imajax/engine'
8
+
9
+ class << self
10
+ attr_writer :root
11
+
12
+ def root
13
+ @root ||= Pathname.new(File.expand_path('../../../', __FILE__))
14
+ end
15
+
16
+ def factory_paths
17
+ @factory_paths ||= [ root.join('spec', 'factories').to_s ]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module Refinery
2
+ module Imajax
3
+ class Engine < Rails::Engine
4
+ include Refinery::Engine
5
+ isolate_namespace Refinery::Imajax
6
+
7
+ engine_name :refinery_imajax
8
+
9
+ config.to_prepare do
10
+ #loads the decorators
11
+ Dir.glob(File.join(File.dirname(__FILE__), "../../../app/decorators/**/*_decorator*.rb")) do |c|
12
+ Rails.configuration.cache_classes ? require(c) : load(c)
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1 @@
1
+ require 'refinery/imajax'
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: refinerycms-imajax
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0.beta2
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Jean-Philippe Boily | @jipiboily
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: refinerycms-core
16
+ requirement: &70223676441800 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70223676441800
25
+ - !ruby/object:Gem::Dependency
26
+ name: refinerycms-testing
27
+ requirement: &70223676440380 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70223676440380
36
+ description: Replacing default bulk image uploading with an Ajaxy, one by one, upload
37
+ method to prevent timeouts
38
+ email:
39
+ - j@jipi.ca
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - app/assets/javascripts/refinery/images.js.coffee.erb
45
+ - app/decorators/controllers/refinery/images_controller_decorator.rb
46
+ - app/views/refinery/admin/images/_form.html.erb
47
+ - config/locales/en.yml
48
+ - config/locales/fr.yml
49
+ - config/routes.rb
50
+ - lib/refinery/imajax/engine.rb
51
+ - lib/refinery/imajax.rb
52
+ - lib/refinerycms-imajax.rb
53
+ - README.md
54
+ homepage:
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>'
70
+ - !ruby/object:Gem::Version
71
+ version: 1.3.1
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 1.8.17
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Ajax image uploading for Refinery CMS
78
+ test_files: []