Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 15
- Log:
Attempt to update Typo to a Typo SVN HEAD release from around the
time the prototype installation was set up on the RISC OS Open Limited
web site. Timestamps place this at 04-Jul so a revision from 05-Jul or
earlier was pulled and copied over the 2.6.0 tarball stable code.
- Author:
- adh
- Date:
- Sat Jul 22 23:27:35 +0100 2006
- Size:
- 11584 Bytes
1 | module UploadProgress |
2 | def self.append_features(base) #:nodoc: |
3 | super |
4 | base.extend(ClassMethods) |
5 | base.helper_method :upload_progress, :next_upload_id, :last_upload_id, :current_upload_id |
6 | end |
7 | |
8 | # == Action Pack Upload Progress for multipart uploads |
9 | # |
10 | # The UploadProgress module aids in the process of viewing an Ajax driven |
11 | # upload status when working with multipart forms. It offers a macro that |
12 | # will prepare an action for handling the cleanup of the Ajax updating including |
13 | # passing the redirect URL and custom parameters to the Javascript finish handler. |
14 | # |
15 | # UploadProgress is available for all multipart uploads when the +upload_status_for+ |
16 | # macro is called in one of your controllers. |
17 | # |
18 | # The progress is stored as an UploadProgress::Progress object in the session and |
19 | # is accessible in the controller and view with the +upload_progress+ method. |
20 | # |
21 | # For help rendering the UploadProgress enabled form and supported elements, see |
22 | # ActionView::Helpers::UploadProgressHelper. |
23 | # |
24 | # === Automatic updating on upload actions |
25 | # |
26 | # class DocumentController < ApplicationController |
27 | # upload_status_for :create |
28 | # |
29 | # def create |
30 | # # ... Your document creation action |
31 | # end |
32 | # end |
33 | # |
34 | # The +upload_status_for+ macro will override the rendering of the action passed |
35 | # if +upload_id+ is found in the query string. This allows for default |
36 | # behavior if Javascript is disabled. If you are tracking the upload progress |
37 | # then +create+ will now return the cleanup scripts that will terminate the polling |
38 | # of the upload status. |
39 | # |
40 | # === Customized status rendering |
41 | # |
42 | # class DocumentController < ApplicationController |
43 | # upload_status_for :create, :status => :custom_status |
44 | # |
45 | # def create |
46 | # # ... Your document creation action |
47 | # end |
48 | # |
49 | # def custom_status |
50 | # # ... Override this action to return content to be replaced in |
51 | # # the status container |
52 | # render :inline => "<%= upload_progress.completed_percent rescue 0 %> % complete", :layout => false |
53 | # end |
54 | # |
55 | # The default status action is +upload_status+. The results of this action |
56 | # are added used to replace the contents of the HTML elements defined in |
57 | # +upload_status_tag+. Within +upload_status+, you can load the Progress |
58 | # object from the session with the +upload_progress+ method and display your own |
59 | # results. |
60 | # |
61 | # Completion of the upload status updating occurs automatically with an +after_filter+ call to |
62 | # +finish_upload_status+. Because the upload must be posted into a hidden IFRAME to enable |
63 | # Ajax updates during the upload, +finish_upload_status+ overwrites the results of any previous |
64 | # +render+ or +redirect_to+ so it can render the necessary Javascript that will properly terminate |
65 | # the status updating loop, trigger the completion callback or redirect to the appropriate URL. |
66 | # |
67 | # ==== Basic Example (View): |
68 | # |
69 | # <%= form_tag_with_upload_progress({:action => 'create'}, {:finish => 'alert("Document Uploaded")'}) %> |
70 | # <%= upload_status_tag %> |
71 | # <%= file_field 'document', 'file' %> |
72 | # <%= end_form_tag %> |
73 | # |
74 | # ==== Basic Example (Controller): |
75 | # |
76 | # class DocumentController < ApplicationController |
77 | # upload_status_for :create |
78 | # |
79 | # def create |
80 | # @document = Document.create(params[:document]) |
81 | # end |
82 | # end |
83 | # |
84 | # ==== Extended Example (View): |
85 | # |
86 | # <%= form_tag_with_upload_progress({:action => 'create'}, {}, {:action => :custom_status}) %> |
87 | # <%= upload_status_tag %> |
88 | # <%= file_field 'document', 'file' %> |
89 | # <%= submit_tag "Upload" %> |
90 | # <%= end_form_tag %> |
91 | # |
92 | # <%= form_tag_with_upload_progress({:action => 'add_preview'}, {:finish => 'alert(arguments[0])'}, {:action => :custom_status}) %> |
93 | # <%= upload_status_tag %> |
94 | # <%= submit_tag "Upload" %> |
95 | # <%= file_field 'preview', 'file' %> |
96 | # <%= end_form_tag %> |
97 | # |
98 | # ==== Extended Example (Controller): |
99 | # |
100 | # class DocumentController < ApplicationController |
101 | # upload_status_for :add_preview, :create, {:status => :custom_status} |
102 | # |
103 | # def add_preview |
104 | # @document = Document.find(params[:id]) |
105 | # @document.preview = Preview.create(params[:preview]) |
106 | # if @document.save |
107 | # finish_upload_status "'Preview added'" |
108 | # else |
109 | # finish_upload_status "'Preview not added'" |
110 | # end |
111 | # end |
112 | # |
113 | # def create |
114 | # @document = Document.new(params[:document]) |
115 | # |
116 | # upload_progress.message = "Processing document..." |
117 | # session.update |
118 | # |
119 | # @document.save |
120 | # redirect_to :action => 'show', :id => @document.id |
121 | # end |
122 | # |
123 | # def custom_status |
124 | # render :inline => '<%= upload_progress_status %> <div>Updated at <%= Time.now %></div>', :layout => false |
125 | # end |
126 | # |
127 | # ==== Environment checklist |
128 | # |
129 | # This is an experimental feature that requires a specific webserver environment. Use the following checklist |
130 | # to confirm that you have an environment that supports upload progress. |
131 | # |
132 | # ===== Ruby: |
133 | # |
134 | # * Running the command `ruby -v` should print "ruby 1.8.2 (2004-12-25)" or older |
135 | # |
136 | # ===== Web server: |
137 | # |
138 | # * Apache 1.3, Apache 2.0 or Lighttpd *1.4* (need to build lighttpd from CVS) |
139 | # |
140 | # ===== FastCGI bindings: |
141 | # |
142 | # * > 0.8.6 and must be the compiled C version of the bindings |
143 | # * The command `ruby -e "p require('fcgi.so')"` should print "true" |
144 | # |
145 | # ===== Apache/Lighttpd FastCGI directives: |
146 | # |
147 | # * You must allow more than one FCGI server process to allow concurrent requests. |
148 | # * If there is only a single FCGI process you will not get the upload status updates. |
149 | # * You can check this by taking a look for running FCGI servers in your process list during a progress upload. |
150 | # * Apache directive: FastCGIConfig -minProcesses 2 |
151 | # * Lighttpd directives taken from config/lighttpd.conf (min-procs): |
152 | # |
153 | # fastcgi.server = ( |
154 | # ".fcgi" => ( |
155 | # "APP_NAME" => ( |
156 | # "socket" => "/tmp/APP_NAME1.socket", |
157 | # "bin-path" => "RAILS_ROOT/public/dispatch.fcgi", |
158 | # "min-procs" => 2 |
159 | # ) |
160 | # ) |
161 | # ) |
162 | # |
163 | # ===== config/environment.rb: |
164 | # |
165 | # * Add the following line to your config/environment.rb and restart your web server. |
166 | # * <tt>ActionController::Base.enable_upload_progress</tt> |
167 | # |
168 | # ===== Development log: |
169 | # |
170 | # * When the upload progress is enabled by you will find something the following lines: |
171 | # * "Multipart upload with progress (id: 1, size: 85464)" |
172 | # * "Finished processing multipart upload in 0.363729s" |
173 | # * If you are properly running multiple FCGI processes, then you will see multiple entries for rendering the "upload_status" action before the "Finish processing..." log entry. This is a *good thing* :) |
174 | # |
175 | module ClassMethods |
176 | # Creates an +after_filter+ which will call +finish_upload_status+ |
177 | # creating the document that will be loaded into the hidden IFRAME, terminating |
178 | # the status polling forms created with +form_with_upload_progress+. |
179 | # |
180 | # Also defines an action +upload_status+ or a action name passed as |
181 | # the <tt>:status</tt> option. This status action must match the one expected |
182 | # in the +form_tag_with_upload_progress+ helper. |
183 | # |
184 | def upload_status_for(*actions) |
185 | after_filter :finish_upload_status, :only => actions |
186 | |
187 | define_method(actions.last.is_a?(Hash) && actions.last[:status] || :upload_status) do |
188 | render(:inline => '<%= upload_progress_status %>', :layout => false) |
189 | end |
190 | end |
191 | end |
192 | |
193 | # Overwrites the body rendered if the upload comes from a form that tracks |
194 | # the progress of the upload. After clearing the body and any redirects, this |
195 | # method then renders the helper +finish_upload_status+ |
196 | # |
197 | # This method only needs to be called if you wish to pass a |
198 | # javascript parameter to your finish event handler that you optionally |
199 | # define in +form_with_upload_progress+ |
200 | # |
201 | # === Parameter: |
202 | # |
203 | # client_js_argument:: a string containing a Javascript expression that will |
204 | # be evaluated and passed to your +finish+ handler of |
205 | # +form_tag_with_upload_progress+. |
206 | # |
207 | # You can pass a String, Number or Boolean. |
208 | # |
209 | # === Strings |
210 | # |
211 | # Strings contain Javascript code that will be evaluated on the client. If you |
212 | # wish to pass a string to the client finish callback, you will need to include |
213 | # quotes in the +client_js_argument+ you pass to this method. |
214 | # |
215 | # ==== Example |
216 | # |
217 | # finish_upload_status("\"Finished\"") |
218 | # finish_upload_status("'Finished #{@document.title}'") |
219 | # finish_upload_status("{success: true, message: 'Done!'}") |
220 | # finish_upload_status("function() { alert('Uploaded!'); }") |
221 | # |
222 | # === Numbers / Booleans |
223 | # |
224 | # Numbers and Booleans can either be passed as Number objects or string versions |
225 | # of number objects as they are evaluated by Javascript the same way as in Ruby. |
226 | # |
227 | # ==== Example |
228 | # |
229 | # finish_upload_status(0) |
230 | # finish_upload_status(@document.file.size) |
231 | # finish_upload_status("10") |
232 | # |
233 | # === Nil |
234 | # |
235 | # To pass +nil+ to the finish callback, use a string "undefined" |
236 | # |
237 | # ==== Example |
238 | # |
239 | # finish_upload_status(@message || "undefined") |
240 | # |
241 | # == Redirection |
242 | # |
243 | # If you action performs a redirection then +finish_upload_status+ will recognize |
244 | # the redirection and properly create the Javascript to perform the redirection in |
245 | # the proper location. |
246 | # |
247 | # It is possible to redirect and pass a parameter to the finish callback. |
248 | # |
249 | # ==== Example |
250 | # |
251 | # redirect_to :action => 'show', :id => @document.id |
252 | # finish_upload_status("'Redirecting you to your new file'") |
253 | # |
254 | # |
255 | def finish_upload_status(client_js_argument='') |
256 | if not @rendered_finish_upload_status and params[:upload_id] |
257 | @rendered_finish_upload_status = true |
258 | |
259 | erase_render_results |
260 | location = erase_redirect_results || '' |
261 | |
262 | ## TODO determine if #inspect is the appropriate way to marshall values |
263 | ## in inline templates |
264 | |
265 | template = "<%= finish_upload_status({" |
266 | template << ":client_js_argument => #{client_js_argument.inspect}, " |
267 | template << ":redirect_to => #{location.to_s.inspect}, " |
268 | template << "}) %>" |
269 | |
270 | render({ :inline => template, :layout => false }) |
271 | end |
272 | end |
273 | |
274 | # Returns and saves the next unique +upload_id+ in the instance variable |
275 | # <tt>@upload_id</tt> |
276 | def next_upload_id |
277 | @upload_id = last_upload_id.succ |
278 | end |
279 | |
280 | # Either returns the last saved +upload_id+ or looks in the session |
281 | # for the last used +upload_id+ and saves it as the intance variable |
282 | # <tt>@upload_id</tt> |
283 | def last_upload_id |
284 | @upload_id ||= ((session[:uploads] || {}).keys.map{|k| k.to_i}.sort.last || 0).to_s |
285 | end |
286 | |
287 | # Returns the +upload_id+ from the query parameters or if it cannot be found |
288 | # in the query parameters, then return the +last_upload_id+ |
289 | def current_upload_id |
290 | params[:upload_id] or last_upload_id |
291 | end |
292 | |
293 | # Get the UploadProgress::Progress object for the supplied +upload_id+ from the |
294 | # session. If no +upload_id+ is given, then use the +current_upload_id+ |
295 | # |
296 | # If an UploadProgress::Progress object cannot be found, a new instance will be |
297 | # returned with <code>total_bytes == 0</code>, <code>started? == false</code>, |
298 | # and <code>finished? == true</code>. |
299 | def upload_progress(upload_id = nil) |
300 | upload_id ||= current_upload_id |
301 | session[:uploads] && session[:uploads][upload_id] || UploadProgress::Progress.new(0) |
302 | end |
303 | end |