actionpack 1.12.0 → 1.12.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +32 -0
- data/lib/action_controller/base.rb +9 -7
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/filters.rb +13 -0
- data/lib/action_controller/integration.rb +1 -1
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +4 -2
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_view/base.rb +26 -10
- data/lib/action_view/helpers/asset_tag_helper.rb +16 -5
- data/lib/action_view/helpers/java_script_macros_helper.rb +10 -1
- data/lib/action_view/helpers/javascripts/dragdrop.js +252 -63
- data/lib/action_view/helpers/javascripts/effects.js +15 -10
- data/lib/action_view/helpers/javascripts/prototype.js +59 -38
- data/lib/action_view/helpers/prototype_helper.rb +1 -1
- data/rakefile +1 -1
- data/test/controller/filters_test.rb +31 -2
- data/test/fixtures/public/images/rails.png +0 -0
- data/test/template/asset_tag_helper_test.rb +21 -0
- data/test/template/java_script_macros_helper_test.rb +7 -2
- metadata +6 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,35 @@
|
|
1
|
+
*1.12.1* (April 6th, 2005)
|
2
|
+
|
3
|
+
* Fixed that template extensions would be cached development mode #4624 [Stefan Kaes]
|
4
|
+
|
5
|
+
* Update to Prototype 1.5.0_rc0 [Sam Stephenson]
|
6
|
+
|
7
|
+
* Honor skipping filters conditionally for only certain actions even when the parent class sets that filter to conditionally be executed only for the same actions. #4522 [Marcel Molina Jr.]
|
8
|
+
|
9
|
+
* Delegate xml_http_request in integration tests to the session instance. [Jamis Buck]
|
10
|
+
|
11
|
+
* Update the diagnostics template skip the useless '<controller not set>' text. [Nicholas Seckar]
|
12
|
+
|
13
|
+
* CHANGED DEFAULT: Don't parse YAML input by default, but keep it available as an easy option [DHH]
|
14
|
+
|
15
|
+
* Add additional autocompleter options [aballai, Thomas Fuchs]
|
16
|
+
|
17
|
+
* Fixed fragment caching of binary data on Windows #4493 [bellis@deepthought.org]
|
18
|
+
|
19
|
+
* Applied Prototype $() performance patches (#4465, #4477) and updated script.aculo.us [Sam Stephenson, Thomas Fuchs]
|
20
|
+
|
21
|
+
* Added automated timestamping to AssetTagHelper methods for stylesheets, javascripts, and images when Action Controller is run under Rails [DHH]. Example:
|
22
|
+
|
23
|
+
image_tag("rails.png") # => '<img alt="Rails" src="/images/rails.png?1143664135" />'
|
24
|
+
|
25
|
+
...to avoid frequent stats (not a problem for most people), you can set RAILS_ASSET_ID in the ENV to avoid stats:
|
26
|
+
|
27
|
+
ENV["RAILS_ASSET_ID"] = "2345"
|
28
|
+
image_tag("rails.png") # => '<img alt="Rails" src="/images/rails.png?2345" />'
|
29
|
+
|
30
|
+
This can be used by deployment managers to set the asset id by application revision
|
31
|
+
|
32
|
+
|
1
33
|
*1.12.0* (March 27th, 2005)
|
2
34
|
|
3
35
|
* Add documentation for respond_to. [Jamis Buck]
|
@@ -265,11 +265,9 @@ module ActionController #:nodoc:
|
|
265
265
|
# The param_parsers hash lets you register handlers wich will process the http body and add parameters to the
|
266
266
|
# @params hash. These handlers are invoked for post and put requests.
|
267
267
|
#
|
268
|
-
# By default application/xml
|
269
|
-
#
|
270
|
-
#
|
271
|
-
# application/x-yaml, the YAML document is merged into the parameters and appears to the application as if the
|
272
|
-
# YAML elements were simply form submissions.
|
268
|
+
# By default application/xml is enabled. A XmlSimple class with the same param name as the root will be instanciated
|
269
|
+
# in the @params. This allows XML requests to mask themselves as regular form submissions, so you can have one
|
270
|
+
# action serve both regular forms and web service requests.
|
273
271
|
#
|
274
272
|
# Example of doing your own parser for a custom content type:
|
275
273
|
#
|
@@ -283,9 +281,13 @@ module ActionController #:nodoc:
|
|
283
281
|
# in params[:r][:name] for "David" instead of params[:name]. To get the old behavior, you can
|
284
282
|
# re-register XmlSimple as application/xml handler ike this:
|
285
283
|
#
|
286
|
-
# ActionController::Base.param_parsers[Mime::XML]
|
284
|
+
# ActionController::Base.param_parsers[Mime::XML] =
|
287
285
|
# Proc.new { |data| XmlSimple.xml_in(data, 'ForceArray' => false) }
|
288
|
-
|
286
|
+
#
|
287
|
+
# A YAML parser is also available and can be turned on with:
|
288
|
+
#
|
289
|
+
# ActionController::Base.param_parsers[Mime::YAML] = :yaml
|
290
|
+
@@param_parsers = { Mime::XML => :xml_simple }
|
289
291
|
cattr_accessor :param_parsers
|
290
292
|
|
291
293
|
# Template root determines the base from which template references will be made. So a call to render("test/template")
|
@@ -255,6 +255,7 @@ module ActionController #:nodoc:
|
|
255
255
|
# just like when you apply the filters.
|
256
256
|
def skip_before_filter(*filters)
|
257
257
|
if conditions = extract_conditions!(filters)
|
258
|
+
remove_contradicting_conditions!(filters, conditions)
|
258
259
|
conditions[:only], conditions[:except] = conditions[:except], conditions[:only]
|
259
260
|
add_action_conditions(filters, conditions)
|
260
261
|
else
|
@@ -272,6 +273,7 @@ module ActionController #:nodoc:
|
|
272
273
|
# just like when you apply the filters.
|
273
274
|
def skip_after_filter(*filters)
|
274
275
|
if conditions = extract_conditions!(filters)
|
276
|
+
remove_contradicting_conditions!(filters, conditions)
|
275
277
|
conditions[:only], conditions[:except] = conditions[:except], conditions[:only]
|
276
278
|
add_action_conditions(filters, conditions)
|
277
279
|
else
|
@@ -332,6 +334,17 @@ module ActionController #:nodoc:
|
|
332
334
|
def condition_hash(filters, *actions)
|
333
335
|
filters.inject({}) {|hash, filter| hash.merge(filter => actions.flatten.map {|action| action.to_s})}
|
334
336
|
end
|
337
|
+
|
338
|
+
def remove_contradicting_conditions!(filters, conditions)
|
339
|
+
return unless conditions[:only]
|
340
|
+
filters.each do |filter|
|
341
|
+
next unless included_actions_for_filter = (read_inheritable_attribute('included_actions') || {})[filter]
|
342
|
+
[*conditions[:only]].each do |conditional_action|
|
343
|
+
conditional_action = conditional_action.to_s
|
344
|
+
included_actions_for_filter.delete(conditional_action) if included_actions_for_filter.include?(conditional_action)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
335
348
|
end
|
336
349
|
|
337
350
|
module InstanceMethods # :nodoc:
|
@@ -464,7 +464,7 @@ module ActionController
|
|
464
464
|
@integration_session = open_session
|
465
465
|
end
|
466
466
|
|
467
|
-
%w(get post cookies assigns).each do |method|
|
467
|
+
%w(get post cookies assigns xml_http_request).each do |method|
|
468
468
|
define_method(method) do |*args|
|
469
469
|
reset! unless @integration_session
|
470
470
|
returning @integration_session.send(method, *args) do
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<h1>
|
2
|
-
<%=h @exception.class.to_s %>
|
3
|
-
|
2
|
+
<%=h @exception.class.to_s %>
|
3
|
+
<% if @request.parameters['controller'] %>
|
4
|
+
in <%=h @request.parameters['controller'].humanize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
|
5
|
+
<% end %>
|
4
6
|
</h1>
|
5
7
|
<pre><%=h @exception.clean_message %></pre>
|
6
8
|
|
data/lib/action_pack/version.rb
CHANGED
data/lib/action_view/base.rb
CHANGED
@@ -157,6 +157,11 @@ module ActionView #:nodoc:
|
|
157
157
|
@@cache_template_loading = false
|
158
158
|
cattr_accessor :cache_template_loading
|
159
159
|
|
160
|
+
# Specify whether file extension lookup should be cached.
|
161
|
+
# Should be +false+ for development environments. Defaults to +true+.
|
162
|
+
@@cache_template_extensions = true
|
163
|
+
cattr_accessor :cache_template_extensions
|
164
|
+
|
160
165
|
# Specify whether local_assigns should be able to use string keys.
|
161
166
|
# Defaults to +true+. String keys are deprecated and will be removed
|
162
167
|
# shortly.
|
@@ -312,15 +317,11 @@ module ActionView #:nodoc:
|
|
312
317
|
end
|
313
318
|
|
314
319
|
def pick_template_extension(template_path)#:nodoc:
|
315
|
-
@@
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
elsif javascript_template_exists?(template_path): :rjs
|
321
|
-
else
|
322
|
-
raise ActionViewError, "No rhtml, rxml, rjs or delegate template found for #{template_path}"
|
323
|
-
end
|
320
|
+
if @@cache_template_extensions
|
321
|
+
@@cached_template_extension[template_path] ||= find_template_extension_for(template_path)
|
322
|
+
else
|
323
|
+
find_template_extension_for(template_path)
|
324
|
+
end
|
324
325
|
end
|
325
326
|
|
326
327
|
def delegate_template_exists?(template_path)#:nodoc:
|
@@ -345,7 +346,7 @@ module ActionView #:nodoc:
|
|
345
346
|
if template_file_extension
|
346
347
|
template_exists?(template_file_name, template_file_extension)
|
347
348
|
else
|
348
|
-
|
349
|
+
cached_template_extension(template_path) ||
|
349
350
|
%w(erb builder javascript delegate).any? do |template_type|
|
350
351
|
send("#{template_type}_template_exists?", template_path)
|
351
352
|
end
|
@@ -371,6 +372,21 @@ module ActionView #:nodoc:
|
|
371
372
|
template_path_without_extension = template_path.sub(/\.(\w+)$/, '')
|
372
373
|
[ template_path_without_extension, $1 ]
|
373
374
|
end
|
375
|
+
|
376
|
+
def cached_template_extension(template_path)
|
377
|
+
@@cache_template_extensions && @@cached_template_extension[template_path]
|
378
|
+
end
|
379
|
+
|
380
|
+
def find_template_extension_for(template_path)
|
381
|
+
if match = delegate_template_exists?(template_path)
|
382
|
+
match.first.to_sym
|
383
|
+
elsif erb_template_exists?(template_path): :rhtml
|
384
|
+
elsif builder_template_exists?(template_path): :rxml
|
385
|
+
elsif javascript_template_exists?(template_path): :rjs
|
386
|
+
else
|
387
|
+
raise ActionViewError, "No rhtml, rxml, rjs or delegate template found for #{template_path}"
|
388
|
+
end
|
389
|
+
end
|
374
390
|
|
375
391
|
# This method reads a template file.
|
376
392
|
def read_template_file(template_path, extension)
|
@@ -59,11 +59,16 @@ module ActionView
|
|
59
59
|
# <tt>controllers/application.rb</tt> and <tt>helpers/application_helper.rb</tt>.
|
60
60
|
def javascript_include_tag(*sources)
|
61
61
|
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
|
62
|
+
|
62
63
|
if sources.include?(:defaults)
|
63
|
-
sources = sources[0..(sources.index(:defaults))] +
|
64
|
+
sources = sources[0..(sources.index(:defaults))] +
|
65
|
+
@@javascript_default_sources.dup +
|
66
|
+
sources[(sources.index(:defaults) + 1)..sources.length]
|
67
|
+
|
64
68
|
sources.delete(:defaults)
|
65
|
-
sources << "application" if defined?(RAILS_ROOT)
|
69
|
+
sources << "application" if defined?(RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")
|
66
70
|
end
|
71
|
+
|
67
72
|
sources.collect { |source|
|
68
73
|
source = javascript_path(source)
|
69
74
|
content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
|
@@ -145,12 +150,18 @@ module ActionView
|
|
145
150
|
|
146
151
|
private
|
147
152
|
def compute_public_path(source, dir, ext)
|
148
|
-
source
|
149
|
-
source
|
150
|
-
source
|
153
|
+
source = "/#{dir}/#{source}" unless source.first == "/" || source.include?(":")
|
154
|
+
source << ".#{ext}" unless source.split("/").last.include?(".")
|
155
|
+
source << '?' + rails_asset_id(source) if defined?(RAILS_ROOT) && %r{^[-a-z]+://} !~ source
|
156
|
+
source = "#{@controller.request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ source
|
151
157
|
source = ActionController::Base.asset_host + source unless source.include?(":")
|
152
158
|
source
|
153
159
|
end
|
160
|
+
|
161
|
+
def rails_asset_id(source)
|
162
|
+
ENV["RAILS_ASSET_ID"] ||
|
163
|
+
File.mtime("#{RAILS_ROOT}/public/#{source}").to_i.to_s rescue ""
|
164
|
+
end
|
154
165
|
end
|
155
166
|
end
|
156
167
|
end
|
@@ -101,6 +101,8 @@ module ActionView
|
|
101
101
|
# <tt>:with</tt>:: A JavaScript expression specifying the
|
102
102
|
# parameters for the XMLHttpRequest. This defaults
|
103
103
|
# to 'fieldname=value'.
|
104
|
+
# <tt>:frequency</tt>:: Determines the time to wait after the last keystroke
|
105
|
+
# for the AJAX request to be initiated.
|
104
106
|
# <tt>:indicator</tt>:: Specifies the DOM ID of an element which will be
|
105
107
|
# displayed while autocomplete is running.
|
106
108
|
# <tt>:tokens</tt>:: A string or an array of strings containing
|
@@ -119,6 +121,11 @@ module ActionView
|
|
119
121
|
# innerHTML is replaced.
|
120
122
|
# <tt>:on_show</tt>:: Like on_hide, only now the expression is called
|
121
123
|
# then the div is shown.
|
124
|
+
# <tt>:after_update_element</tt>:: A Javascript expression that is called when the
|
125
|
+
# user has selected one of the proposed values.
|
126
|
+
# The expression should take two variables: element and value.
|
127
|
+
# Element is a DOM element for the field, value
|
128
|
+
# is the value selected by the user.
|
122
129
|
# <tt>:select</tt>:: Pick the class of the element from which the value for
|
123
130
|
# insertion should be extracted. If this is not specified,
|
124
131
|
# the entire element is used.
|
@@ -133,8 +140,10 @@ module ActionView
|
|
133
140
|
js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
|
134
141
|
js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
|
135
142
|
js_options[:select] = "'#{options[:select]}'" if options[:select]
|
143
|
+
js_options[:frequency] = "#{options[:frequency]}" if options[:frequency]
|
136
144
|
|
137
|
-
{ :
|
145
|
+
{ :after_update_element => :afterUpdateElement,
|
146
|
+
:on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
|
138
147
|
js_options[v] = options[k] if options[k]
|
139
148
|
end
|
140
149
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
2
|
+
// (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
|
2
3
|
//
|
3
4
|
// See scriptaculous.js for full license.
|
4
5
|
|
@@ -15,7 +16,8 @@ var Droppables = {
|
|
15
16
|
element = $(element);
|
16
17
|
var options = Object.extend({
|
17
18
|
greedy: true,
|
18
|
-
hoverclass: null
|
19
|
+
hoverclass: null,
|
20
|
+
tree: false
|
19
21
|
}, arguments[1] || {});
|
20
22
|
|
21
23
|
// cache containers
|
@@ -37,12 +39,27 @@ var Droppables = {
|
|
37
39
|
|
38
40
|
this.drops.push(options);
|
39
41
|
},
|
42
|
+
|
43
|
+
findDeepestChild: function(drops) {
|
44
|
+
deepest = drops[0];
|
45
|
+
|
46
|
+
for (i = 1; i < drops.length; ++i)
|
47
|
+
if (Element.isParent(drops[i].element, deepest.element))
|
48
|
+
deepest = drops[i];
|
49
|
+
|
50
|
+
return deepest;
|
51
|
+
},
|
40
52
|
|
41
53
|
isContained: function(element, drop) {
|
42
|
-
var
|
43
|
-
|
54
|
+
var containmentNode;
|
55
|
+
if(drop.tree) {
|
56
|
+
containmentNode = element.treeNode;
|
57
|
+
} else {
|
58
|
+
containmentNode = element.parentNode;
|
59
|
+
}
|
60
|
+
return drop._containers.detect(function(c) { return containmentNode == c });
|
44
61
|
},
|
45
|
-
|
62
|
+
|
46
63
|
isAffected: function(point, element, drop) {
|
47
64
|
return (
|
48
65
|
(drop.element!=element) &&
|
@@ -68,18 +85,22 @@ var Droppables = {
|
|
68
85
|
|
69
86
|
show: function(point, element) {
|
70
87
|
if(!this.drops.length) return;
|
88
|
+
var affected = [];
|
71
89
|
|
72
90
|
if(this.last_active) this.deactivate(this.last_active);
|
73
91
|
this.drops.each( function(drop) {
|
74
|
-
if(Droppables.isAffected(point, element, drop))
|
75
|
-
|
76
|
-
drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
|
77
|
-
if(drop.greedy) {
|
78
|
-
Droppables.activate(drop);
|
79
|
-
throw $break;
|
80
|
-
}
|
81
|
-
}
|
92
|
+
if(Droppables.isAffected(point, element, drop))
|
93
|
+
affected.push(drop);
|
82
94
|
});
|
95
|
+
|
96
|
+
if(affected.length>0) {
|
97
|
+
drop = Droppables.findDeepestChild(affected);
|
98
|
+
Position.within(drop.element, point[0], point[1]);
|
99
|
+
if(drop.onHover)
|
100
|
+
drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
|
101
|
+
|
102
|
+
Droppables.activate(drop);
|
103
|
+
}
|
83
104
|
},
|
84
105
|
|
85
106
|
fire: function(event, element) {
|
@@ -207,8 +228,10 @@ Draggable.prototype = {
|
|
207
228
|
|
208
229
|
this.element = $(element);
|
209
230
|
|
210
|
-
if(options.handle && (typeof options.handle == 'string'))
|
211
|
-
|
231
|
+
if(options.handle && (typeof options.handle == 'string')) {
|
232
|
+
var h = Element.childrenWithClassName(this.element, options.handle, true);
|
233
|
+
if(h.length>0) this.handle = h[0];
|
234
|
+
}
|
212
235
|
if(!this.handle) this.handle = $(options.handle);
|
213
236
|
if(!this.handle) this.handle = this.element;
|
214
237
|
|
@@ -412,6 +435,7 @@ Draggable.prototype = {
|
|
412
435
|
if(this.scrollInterval) {
|
413
436
|
clearInterval(this.scrollInterval);
|
414
437
|
this.scrollInterval = null;
|
438
|
+
Draggables._lastScrollPointer = null;
|
415
439
|
}
|
416
440
|
},
|
417
441
|
|
@@ -440,7 +464,14 @@ Draggable.prototype = {
|
|
440
464
|
Position.prepare();
|
441
465
|
Droppables.show(Draggables._lastPointer, this.element);
|
442
466
|
Draggables.notify('onDrag', this);
|
443
|
-
|
467
|
+
Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
|
468
|
+
Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
|
469
|
+
Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
|
470
|
+
if (Draggables._lastScrollPointer[0] < 0)
|
471
|
+
Draggables._lastScrollPointer[0] = 0;
|
472
|
+
if (Draggables._lastScrollPointer[1] < 0)
|
473
|
+
Draggables._lastScrollPointer[1] = 0;
|
474
|
+
this.draw(Draggables._lastScrollPointer);
|
444
475
|
|
445
476
|
if(this.options.change) this.options.change(this);
|
446
477
|
},
|
@@ -492,30 +523,41 @@ SortableObserver.prototype = {
|
|
492
523
|
}
|
493
524
|
|
494
525
|
var Sortable = {
|
495
|
-
sortables:
|
526
|
+
sortables: {},
|
496
527
|
|
497
|
-
|
498
|
-
element
|
499
|
-
|
528
|
+
_findRootElement: function(element) {
|
529
|
+
while (element.tagName != "BODY") {
|
530
|
+
if(element.id && Sortable.sortables[element.id]) return element;
|
531
|
+
element = element.parentNode;
|
532
|
+
}
|
533
|
+
},
|
534
|
+
|
535
|
+
options: function(element) {
|
536
|
+
element = Sortable._findRootElement($(element));
|
537
|
+
if(!element) return;
|
538
|
+
return Sortable.sortables[element.id];
|
500
539
|
},
|
501
540
|
|
502
541
|
destroy: function(element){
|
503
|
-
|
504
|
-
|
542
|
+
var s = Sortable.options(element);
|
543
|
+
|
544
|
+
if(s) {
|
505
545
|
Draggables.removeObserver(s.element);
|
506
546
|
s.droppables.each(function(d){ Droppables.remove(d) });
|
507
547
|
s.draggables.invoke('destroy');
|
508
|
-
|
509
|
-
|
548
|
+
|
549
|
+
delete Sortable.sortables[s.element.id];
|
550
|
+
}
|
510
551
|
},
|
511
|
-
|
552
|
+
|
512
553
|
create: function(element) {
|
513
554
|
element = $(element);
|
514
555
|
var options = Object.extend({
|
515
556
|
element: element,
|
516
557
|
tag: 'li', // assumes li children, override with tag: 'tagname'
|
517
558
|
dropOnEmpty: false,
|
518
|
-
tree: false,
|
559
|
+
tree: false,
|
560
|
+
treeTag: 'ul',
|
519
561
|
overlap: 'vertical', // one of 'vertical', 'horizontal'
|
520
562
|
constraint: 'vertical', // one of 'vertical', 'horizontal', false
|
521
563
|
containment: element, // also takes array of elements (or id's); or false
|
@@ -565,9 +607,17 @@ var Sortable = {
|
|
565
607
|
var options_for_droppable = {
|
566
608
|
overlap: options.overlap,
|
567
609
|
containment: options.containment,
|
610
|
+
tree: options.tree,
|
568
611
|
hoverclass: options.hoverclass,
|
569
|
-
onHover: Sortable.onHover
|
570
|
-
greedy: !options.dropOnEmpty
|
612
|
+
onHover: Sortable.onHover
|
613
|
+
//greedy: !options.dropOnEmpty
|
614
|
+
}
|
615
|
+
|
616
|
+
var options_for_tree = {
|
617
|
+
onHover: Sortable.onEmptyHover,
|
618
|
+
overlap: options.overlap,
|
619
|
+
containment: options.containment,
|
620
|
+
hoverclass: options.hoverclass
|
571
621
|
}
|
572
622
|
|
573
623
|
// fix for gecko engine
|
@@ -576,12 +626,9 @@ var Sortable = {
|
|
576
626
|
options.draggables = [];
|
577
627
|
options.droppables = [];
|
578
628
|
|
579
|
-
// make it so
|
580
|
-
|
581
629
|
// drop on empty handling
|
582
|
-
if(options.dropOnEmpty) {
|
583
|
-
Droppables.add(element,
|
584
|
-
{containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
|
630
|
+
if(options.dropOnEmpty || options.tree) {
|
631
|
+
Droppables.add(element, options_for_tree);
|
585
632
|
options.droppables.push(element);
|
586
633
|
}
|
587
634
|
|
@@ -592,11 +639,20 @@ var Sortable = {
|
|
592
639
|
options.draggables.push(
|
593
640
|
new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
|
594
641
|
Droppables.add(e, options_for_droppable);
|
642
|
+
if(options.tree) e.treeNode = element;
|
595
643
|
options.droppables.push(e);
|
596
644
|
});
|
645
|
+
|
646
|
+
if(options.tree) {
|
647
|
+
(Sortable.findTreeElements(element, options) || []).each( function(e) {
|
648
|
+
Droppables.add(e, options_for_tree);
|
649
|
+
e.treeNode = element;
|
650
|
+
options.droppables.push(e);
|
651
|
+
});
|
652
|
+
}
|
597
653
|
|
598
654
|
// keep reference
|
599
|
-
this.sortables.
|
655
|
+
this.sortables[element.id] = options;
|
600
656
|
|
601
657
|
// for onupdate
|
602
658
|
Draggables.addObserver(new SortableObserver(element, options.onUpdate));
|
@@ -605,24 +661,21 @@ var Sortable = {
|
|
605
661
|
|
606
662
|
// return all suitable-for-sortable elements in a guaranteed order
|
607
663
|
findElements: function(element, options) {
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
if(options.tree) {
|
616
|
-
var grandchildren = this.findElements(e, options);
|
617
|
-
if(grandchildren) elements.push(grandchildren);
|
618
|
-
}
|
619
|
-
});
|
620
|
-
|
621
|
-
return (elements.length>0 ? elements.flatten() : null);
|
664
|
+
return Element.findChildren(
|
665
|
+
element, options.only, options.tree ? true : false, options.tag);
|
666
|
+
},
|
667
|
+
|
668
|
+
findTreeElements: function(element, options) {
|
669
|
+
return Element.findChildren(
|
670
|
+
element, options.only, options.tree ? true : false, options.treeTag);
|
622
671
|
},
|
623
672
|
|
624
673
|
onHover: function(element, dropon, overlap) {
|
625
|
-
if(
|
674
|
+
if(Element.isParent(dropon, element)) return;
|
675
|
+
|
676
|
+
if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
|
677
|
+
return;
|
678
|
+
} else if(overlap>0.5) {
|
626
679
|
Sortable.mark(dropon, 'before');
|
627
680
|
if(dropon.previousSibling != element) {
|
628
681
|
var oldParentNode = element.parentNode;
|
@@ -645,13 +698,37 @@ var Sortable = {
|
|
645
698
|
}
|
646
699
|
}
|
647
700
|
},
|
648
|
-
|
649
|
-
onEmptyHover: function(element, dropon) {
|
650
|
-
|
651
|
-
|
652
|
-
|
701
|
+
|
702
|
+
onEmptyHover: function(element, dropon, overlap) {
|
703
|
+
var oldParentNode = element.parentNode;
|
704
|
+
var droponOptions = Sortable.options(dropon);
|
705
|
+
|
706
|
+
if(!Element.isParent(dropon, element)) {
|
707
|
+
var index;
|
708
|
+
|
709
|
+
var children = Sortable.findElements(dropon, {tag: droponOptions.tag});
|
710
|
+
var child = null;
|
711
|
+
|
712
|
+
if(children) {
|
713
|
+
var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
|
714
|
+
|
715
|
+
for (index = 0; index < children.length; index += 1) {
|
716
|
+
if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
|
717
|
+
offset -= Element.offsetSize (children[index], droponOptions.overlap);
|
718
|
+
} else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
|
719
|
+
child = index + 1 < children.length ? children[index + 1] : null;
|
720
|
+
break;
|
721
|
+
} else {
|
722
|
+
child = children[index];
|
723
|
+
break;
|
724
|
+
}
|
725
|
+
}
|
726
|
+
}
|
727
|
+
|
728
|
+
dropon.insertBefore(element, child);
|
729
|
+
|
653
730
|
Sortable.options(oldParentNode).onChange(element);
|
654
|
-
|
731
|
+
droponOptions.onChange(element);
|
655
732
|
}
|
656
733
|
},
|
657
734
|
|
@@ -683,6 +760,75 @@ var Sortable = {
|
|
683
760
|
|
684
761
|
Element.show(Sortable._marker);
|
685
762
|
},
|
763
|
+
|
764
|
+
_tree: function(element, options, parent) {
|
765
|
+
var children = Sortable.findElements(element, options) || [];
|
766
|
+
|
767
|
+
for (var i = 0; i < children.length; ++i) {
|
768
|
+
var match = children[i].id.match(options.format);
|
769
|
+
|
770
|
+
if (!match) continue;
|
771
|
+
|
772
|
+
var child = {
|
773
|
+
id: encodeURIComponent(match ? match[1] : null),
|
774
|
+
element: element,
|
775
|
+
parent: parent,
|
776
|
+
children: new Array,
|
777
|
+
position: parent.children.length,
|
778
|
+
container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())
|
779
|
+
}
|
780
|
+
|
781
|
+
/* Get the element containing the children and recurse over it */
|
782
|
+
if (child.container)
|
783
|
+
this._tree(child.container, options, child)
|
784
|
+
|
785
|
+
parent.children.push (child);
|
786
|
+
}
|
787
|
+
|
788
|
+
return parent;
|
789
|
+
},
|
790
|
+
|
791
|
+
/* Finds the first element of the given tag type within a parent element.
|
792
|
+
Used for finding the first LI[ST] within a L[IST]I[TEM].*/
|
793
|
+
_findChildrenElement: function (element, containerTag) {
|
794
|
+
if (element && element.hasChildNodes)
|
795
|
+
for (var i = 0; i < element.childNodes.length; ++i)
|
796
|
+
if (element.childNodes[i].tagName == containerTag)
|
797
|
+
return element.childNodes[i];
|
798
|
+
|
799
|
+
return null;
|
800
|
+
},
|
801
|
+
|
802
|
+
tree: function(element) {
|
803
|
+
element = $(element);
|
804
|
+
var sortableOptions = this.options(element);
|
805
|
+
var options = Object.extend({
|
806
|
+
tag: sortableOptions.tag,
|
807
|
+
treeTag: sortableOptions.treeTag,
|
808
|
+
only: sortableOptions.only,
|
809
|
+
name: element.id,
|
810
|
+
format: sortableOptions.format
|
811
|
+
}, arguments[1] || {});
|
812
|
+
|
813
|
+
var root = {
|
814
|
+
id: null,
|
815
|
+
parent: null,
|
816
|
+
children: new Array,
|
817
|
+
container: element,
|
818
|
+
position: 0
|
819
|
+
}
|
820
|
+
|
821
|
+
return Sortable._tree (element, options, root);
|
822
|
+
},
|
823
|
+
|
824
|
+
/* Construct a [i] index for a particular node */
|
825
|
+
_constructIndex: function(node) {
|
826
|
+
var index = '';
|
827
|
+
do {
|
828
|
+
if (node.id) index = '[' + node.position + ']' + index;
|
829
|
+
} while ((node = node.parent) != null);
|
830
|
+
return index;
|
831
|
+
},
|
686
832
|
|
687
833
|
sequence: function(element) {
|
688
834
|
element = $(element);
|
@@ -705,20 +851,63 @@ var Sortable = {
|
|
705
851
|
});
|
706
852
|
|
707
853
|
new_sequence.each(function(ident) {
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
854
|
+
var n = nodeMap[ident];
|
855
|
+
if (n) {
|
856
|
+
n[1].appendChild(n[0]);
|
857
|
+
delete nodeMap[ident];
|
858
|
+
}
|
713
859
|
});
|
714
860
|
},
|
715
|
-
|
861
|
+
|
716
862
|
serialize: function(element) {
|
717
863
|
element = $(element);
|
864
|
+
var options = Object.extend(Sortable.options(element), arguments[1] || {});
|
718
865
|
var name = encodeURIComponent(
|
719
866
|
(arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
|
720
|
-
|
721
|
-
|
722
|
-
|
867
|
+
|
868
|
+
if (options.tree) {
|
869
|
+
return Sortable.tree(element, arguments[1]).children.map( function (item) {
|
870
|
+
return [name + Sortable._constructIndex(item) + "=" +
|
871
|
+
encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
|
872
|
+
}).flatten().join('&');
|
873
|
+
} else {
|
874
|
+
return Sortable.sequence(element, arguments[1]).map( function(item) {
|
875
|
+
return name + "[]=" + encodeURIComponent(item);
|
876
|
+
}).join('&');
|
877
|
+
}
|
723
878
|
}
|
724
879
|
}
|
880
|
+
|
881
|
+
/* Returns true if child is contained within element */
|
882
|
+
Element.isParent = function(child, element) {
|
883
|
+
if (!child.parentNode || child == element) return false;
|
884
|
+
|
885
|
+
if (child.parentNode == element) return true;
|
886
|
+
|
887
|
+
return Element.isParent(child.parentNode, element);
|
888
|
+
}
|
889
|
+
|
890
|
+
Element.findChildren = function(element, only, recursive, tagName) {
|
891
|
+
if(!element.hasChildNodes()) return null;
|
892
|
+
tagName = tagName.toUpperCase();
|
893
|
+
if(only) only = [only].flatten();
|
894
|
+
var elements = [];
|
895
|
+
$A(element.childNodes).each( function(e) {
|
896
|
+
if(e.tagName && e.tagName.toUpperCase()==tagName &&
|
897
|
+
(!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
|
898
|
+
elements.push(e);
|
899
|
+
if(recursive) {
|
900
|
+
var grandchildren = Element.findChildren(e, only, recursive, tagName);
|
901
|
+
if(grandchildren) elements.push(grandchildren);
|
902
|
+
}
|
903
|
+
});
|
904
|
+
|
905
|
+
return (elements.length>0 ? elements.flatten() : []);
|
906
|
+
}
|
907
|
+
|
908
|
+
Element.offsetSize = function (element, type) {
|
909
|
+
if (type == 'vertical' || type == 'height')
|
910
|
+
return element.offsetHeight;
|
911
|
+
else
|
912
|
+
return element.offsetWidth;
|
913
|
+
}
|
@@ -77,9 +77,12 @@ Element.getInlineOpacity = function(element){
|
|
77
77
|
}
|
78
78
|
|
79
79
|
Element.childrenWithClassName = function(element, className, findFirst) {
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
|
81
|
+
var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) {
|
82
|
+
return (c.className && c.className.match(classNameRegExp));
|
83
|
+
});
|
84
|
+
if(!results) results = [];
|
85
|
+
return results;
|
83
86
|
}
|
84
87
|
|
85
88
|
Element.forceRerendering = function(element) {
|
@@ -91,11 +94,6 @@ Element.forceRerendering = function(element) {
|
|
91
94
|
} catch(e) { }
|
92
95
|
};
|
93
96
|
|
94
|
-
['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
|
95
|
-
'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each(
|
96
|
-
function(f) { Element.Methods[f] = Element[f]; }
|
97
|
-
);
|
98
|
-
|
99
97
|
/*--------------------------------------------------------------------------*/
|
100
98
|
|
101
99
|
Array.prototype.call = function() {
|
@@ -943,11 +941,18 @@ Effect.Fold = function(element) {
|
|
943
941
|
effect.element.setStyle(oldStyle);
|
944
942
|
} });
|
945
943
|
}}, arguments[1] || {}));
|
946
|
-
}
|
944
|
+
};
|
945
|
+
|
946
|
+
['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
|
947
|
+
'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each(
|
948
|
+
function(f) { Element.Methods[f] = Element[f]; }
|
949
|
+
);
|
947
950
|
|
948
951
|
Element.Methods.visualEffect = function(element, effect, options) {
|
949
952
|
s = effect.gsub(/_/, '-').camelize();
|
950
953
|
effect_class = s.charAt(0).toUpperCase() + s.substring(1);
|
951
954
|
new Effect[effect_class](element, options);
|
952
955
|
return $(element);
|
953
|
-
};
|
956
|
+
};
|
957
|
+
|
958
|
+
Element.addMethods();
|
@@ -1,4 +1,4 @@
|
|
1
|
-
/* Prototype JavaScript framework, version 1.5.
|
1
|
+
/* Prototype JavaScript framework, version 1.5.0_rc0
|
2
2
|
* (c) 2005 Sam Stephenson <sam@conio.net>
|
3
3
|
*
|
4
4
|
* Prototype is freely distributable under the terms of an MIT-style license.
|
@@ -7,7 +7,7 @@
|
|
7
7
|
/*--------------------------------------------------------------------------*/
|
8
8
|
|
9
9
|
var Prototype = {
|
10
|
-
Version: '1.5.
|
10
|
+
Version: '1.5.0_rc0',
|
11
11
|
ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
|
12
12
|
|
13
13
|
emptyFunction: function() {},
|
@@ -25,7 +25,7 @@ var Class = {
|
|
25
25
|
var Abstract = new Object();
|
26
26
|
|
27
27
|
Object.extend = function(destination, source) {
|
28
|
-
for (property in source) {
|
28
|
+
for (var property in source) {
|
29
29
|
destination[property] = source[property];
|
30
30
|
}
|
31
31
|
return destination;
|
@@ -176,7 +176,7 @@ Object.extend(String.prototype, {
|
|
176
176
|
},
|
177
177
|
|
178
178
|
evalScripts: function() {
|
179
|
-
return this.extractScripts().map(eval);
|
179
|
+
return this.extractScripts().map(function(script) { return eval(script) });
|
180
180
|
},
|
181
181
|
|
182
182
|
escapeHTML: function() {
|
@@ -355,7 +355,7 @@ var Enumerable = {
|
|
355
355
|
var result;
|
356
356
|
this.each(function(value, index) {
|
357
357
|
value = (iterator || Prototype.K)(value, index);
|
358
|
-
if (
|
358
|
+
if (result == undefined || value >= result)
|
359
359
|
result = value;
|
360
360
|
});
|
361
361
|
return result;
|
@@ -365,7 +365,7 @@ var Enumerable = {
|
|
365
365
|
var result;
|
366
366
|
this.each(function(value, index) {
|
367
367
|
value = (iterator || Prototype.K)(value, index);
|
368
|
-
if (
|
368
|
+
if (result == undefined || value < result)
|
369
369
|
result = value;
|
370
370
|
});
|
371
371
|
return result;
|
@@ -447,7 +447,8 @@ var $A = Array.from = function(iterable) {
|
|
447
447
|
|
448
448
|
Object.extend(Array.prototype, Enumerable);
|
449
449
|
|
450
|
-
Array.prototype._reverse
|
450
|
+
if (!Array.prototype._reverse)
|
451
|
+
Array.prototype._reverse = Array.prototype.reverse;
|
451
452
|
|
452
453
|
Object.extend(Array.prototype, {
|
453
454
|
_each: function(iterator) {
|
@@ -476,7 +477,7 @@ Object.extend(Array.prototype, {
|
|
476
477
|
|
477
478
|
flatten: function() {
|
478
479
|
return this.inject([], function(array, value) {
|
479
|
-
return array.concat(value.constructor == Array ?
|
480
|
+
return array.concat(value && value.constructor == Array ?
|
480
481
|
value.flatten() : [value]);
|
481
482
|
});
|
482
483
|
},
|
@@ -498,21 +499,13 @@ Object.extend(Array.prototype, {
|
|
498
499
|
return (inline !== false ? this : this.toArray())._reverse();
|
499
500
|
},
|
500
501
|
|
501
|
-
shift: function() {
|
502
|
-
var result = this[0];
|
503
|
-
for (var i = 0; i < this.length - 1; i++)
|
504
|
-
this[i] = this[i + 1];
|
505
|
-
this.length--;
|
506
|
-
return result;
|
507
|
-
},
|
508
|
-
|
509
502
|
inspect: function() {
|
510
503
|
return '[' + this.map(Object.inspect).join(', ') + ']';
|
511
504
|
}
|
512
505
|
});
|
513
506
|
var Hash = {
|
514
507
|
_each: function(iterator) {
|
515
|
-
for (key in this) {
|
508
|
+
for (var key in this) {
|
516
509
|
var value = this[key];
|
517
510
|
if (typeof value == 'function') continue;
|
518
511
|
|
@@ -590,9 +583,9 @@ var $R = function(start, end, exclusive) {
|
|
590
583
|
var Ajax = {
|
591
584
|
getTransport: function() {
|
592
585
|
return Try.these(
|
586
|
+
function() {return new XMLHttpRequest()},
|
593
587
|
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
|
594
|
-
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
|
595
|
-
function() {return new XMLHttpRequest()}
|
588
|
+
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
|
596
589
|
) || false;
|
597
590
|
},
|
598
591
|
|
@@ -644,6 +637,7 @@ Ajax.Base.prototype = {
|
|
644
637
|
this.options = {
|
645
638
|
method: 'post',
|
646
639
|
asynchronous: true,
|
640
|
+
contentType: 'application/x-www-form-urlencoded',
|
647
641
|
parameters: ''
|
648
642
|
}
|
649
643
|
Object.extend(this.options, options || {});
|
@@ -707,8 +701,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
|
|
707
701
|
'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
|
708
702
|
|
709
703
|
if (this.options.method == 'post') {
|
710
|
-
requestHeaders.push('Content-type',
|
711
|
-
'application/x-www-form-urlencoded');
|
704
|
+
requestHeaders.push('Content-type', this.options.contentType);
|
712
705
|
|
713
706
|
/* Force "Connection: close" for Mozilla browsers to work around
|
714
707
|
* a bug where XMLHttpReqeuest sends an incorrect Content-length
|
@@ -739,7 +732,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
|
|
739
732
|
|
740
733
|
evalJSON: function() {
|
741
734
|
try {
|
742
|
-
return eval(this.header('X-JSON'));
|
735
|
+
return eval('(' + this.header('X-JSON') + ')');
|
743
736
|
} catch (e) {}
|
744
737
|
},
|
745
738
|
|
@@ -900,13 +893,14 @@ if (!window.Element)
|
|
900
893
|
|
901
894
|
Element.extend = function(element) {
|
902
895
|
if (!element) return;
|
896
|
+
if (_nativeExtensions) return element;
|
903
897
|
|
904
898
|
if (!element._extended && element.tagName && element != window) {
|
905
|
-
var methods = Element.Methods;
|
899
|
+
var methods = Element.Methods, cache = Element.extend.cache;
|
906
900
|
for (property in methods) {
|
907
901
|
var value = methods[property];
|
908
902
|
if (typeof value == 'function')
|
909
|
-
element[property] =
|
903
|
+
element[property] = cache.findOrStore(value);
|
910
904
|
}
|
911
905
|
}
|
912
906
|
|
@@ -914,6 +908,14 @@ Element.extend = function(element) {
|
|
914
908
|
return element;
|
915
909
|
}
|
916
910
|
|
911
|
+
Element.extend.cache = {
|
912
|
+
findOrStore: function(value) {
|
913
|
+
return this[value] = this[value] || function() {
|
914
|
+
return value.apply(null, [this].concat($A(arguments)));
|
915
|
+
}
|
916
|
+
}
|
917
|
+
}
|
918
|
+
|
917
919
|
Element.Methods = {
|
918
920
|
visible: function(element) {
|
919
921
|
return $(element).style.display != 'none';
|
@@ -1035,7 +1037,7 @@ Element.Methods = {
|
|
1035
1037
|
|
1036
1038
|
setStyle: function(element, style) {
|
1037
1039
|
element = $(element);
|
1038
|
-
for (name in style)
|
1040
|
+
for (var name in style)
|
1039
1041
|
element.style[name.camelize()] = style[name];
|
1040
1042
|
},
|
1041
1043
|
|
@@ -1105,6 +1107,29 @@ Element.Methods = {
|
|
1105
1107
|
|
1106
1108
|
Object.extend(Element, Element.Methods);
|
1107
1109
|
|
1110
|
+
var _nativeExtensions = false;
|
1111
|
+
|
1112
|
+
if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
|
1113
|
+
var HTMLElement = {}
|
1114
|
+
HTMLElement.prototype = document.createElement('div').__proto__;
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
Element.addMethods = function(methods) {
|
1118
|
+
Object.extend(Element.Methods, methods || {});
|
1119
|
+
|
1120
|
+
if(typeof HTMLElement != 'undefined') {
|
1121
|
+
var methods = Element.Methods, cache = Element.extend.cache;
|
1122
|
+
for (property in methods) {
|
1123
|
+
var value = methods[property];
|
1124
|
+
if (typeof value == 'function')
|
1125
|
+
HTMLElement.prototype[property] = cache.findOrStore(value);
|
1126
|
+
}
|
1127
|
+
_nativeExtensions = true;
|
1128
|
+
}
|
1129
|
+
}
|
1130
|
+
|
1131
|
+
Element.addMethods();
|
1132
|
+
|
1108
1133
|
var Toggle = new Object();
|
1109
1134
|
Toggle.display = Element.toggle;
|
1110
1135
|
|
@@ -1123,7 +1148,8 @@ Abstract.Insertion.prototype = {
|
|
1123
1148
|
try {
|
1124
1149
|
this.element.insertAdjacentHTML(this.adjacency, this.content);
|
1125
1150
|
} catch (e) {
|
1126
|
-
|
1151
|
+
var tagName = this.element.tagName.toLowerCase();
|
1152
|
+
if (tagName == 'tbody' || tagName == 'tr') {
|
1127
1153
|
this.insertContent(this.contentFromAnonymousTable());
|
1128
1154
|
} else {
|
1129
1155
|
throw e;
|
@@ -1396,7 +1422,7 @@ var Form = {
|
|
1396
1422
|
form = $(form);
|
1397
1423
|
var elements = new Array();
|
1398
1424
|
|
1399
|
-
for (tagName in Form.Element.Serializers) {
|
1425
|
+
for (var tagName in Form.Element.Serializers) {
|
1400
1426
|
var tagElements = form.getElementsByTagName(tagName);
|
1401
1427
|
for (var j = 0; j < tagElements.length; j++)
|
1402
1428
|
elements.push(tagElements[j]);
|
@@ -1518,23 +1544,17 @@ Form.Element.Serializers = {
|
|
1518
1544
|
var value = '', opt, index = element.selectedIndex;
|
1519
1545
|
if (index >= 0) {
|
1520
1546
|
opt = element.options[index];
|
1521
|
-
value = opt.value;
|
1522
|
-
if (!value && !('value' in opt))
|
1523
|
-
value = opt.text;
|
1547
|
+
value = opt.value || opt.text;
|
1524
1548
|
}
|
1525
1549
|
return [element.name, value];
|
1526
1550
|
},
|
1527
1551
|
|
1528
1552
|
selectMany: function(element) {
|
1529
|
-
var value =
|
1553
|
+
var value = [];
|
1530
1554
|
for (var i = 0; i < element.length; i++) {
|
1531
1555
|
var opt = element.options[i];
|
1532
|
-
if (opt.selected)
|
1533
|
-
|
1534
|
-
if (!optValue && !('value' in opt))
|
1535
|
-
optValue = opt.text;
|
1536
|
-
value.push(optValue);
|
1537
|
-
}
|
1556
|
+
if (opt.selected)
|
1557
|
+
value.push(opt.value || opt.text);
|
1538
1558
|
}
|
1539
1559
|
return [element.name, value];
|
1540
1560
|
}
|
@@ -1751,7 +1771,8 @@ Object.extend(Event, {
|
|
1751
1771
|
});
|
1752
1772
|
|
1753
1773
|
/* prevent memory leaks in IE */
|
1754
|
-
|
1774
|
+
if (navigator.appVersion.match(/\bMSIE\b/))
|
1775
|
+
Event.observe(window, 'unload', Event.unloadCache, false);
|
1755
1776
|
var Position = {
|
1756
1777
|
// set to true if needed, warning: firefox performance problems
|
1757
1778
|
// NOT neeeded for page scrolling, only if draggable contained in
|
data/rakefile
CHANGED
@@ -68,7 +68,7 @@ spec = Gem::Specification.new do |s|
|
|
68
68
|
s.has_rdoc = true
|
69
69
|
s.requirements << 'none'
|
70
70
|
|
71
|
-
s.add_dependency('activesupport', '= 1.3.
|
71
|
+
s.add_dependency('activesupport', '= 1.3.1' + PKG_BUILD)
|
72
72
|
|
73
73
|
s.require_path = 'lib'
|
74
74
|
s.autorequire = 'action_controller'
|
@@ -117,6 +117,8 @@ class FilterTest < Test::Unit::TestCase
|
|
117
117
|
class ConditionalSkippingController < TestController
|
118
118
|
skip_before_filter :ensure_login, :only => [ :login ]
|
119
119
|
skip_after_filter :clean_up, :only => [ :login ]
|
120
|
+
|
121
|
+
before_filter :find_user, :only => [ :change_password ]
|
120
122
|
|
121
123
|
def login
|
122
124
|
render :inline => "ran action"
|
@@ -125,8 +127,30 @@ class FilterTest < Test::Unit::TestCase
|
|
125
127
|
def change_password
|
126
128
|
render :inline => "ran action"
|
127
129
|
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
def find_user
|
133
|
+
@ran_filter ||= []
|
134
|
+
@ran_filter << "find_user"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class ConditionalParentOfConditionalSkippingController < ConditionalFilterController
|
139
|
+
before_filter :conditional_in_parent, :only => [:show, :another_action]
|
140
|
+
after_filter :conditional_in_parent, :only => [:show, :another_action]
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def conditional_in_parent
|
145
|
+
@ran_filter ||= []
|
146
|
+
@ran_filter << 'conditional_in_parent'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
|
151
|
+
skip_before_filter :conditional_in_parent, :only => :another_action
|
152
|
+
skip_after_filter :conditional_in_parent, :only => :another_action
|
128
153
|
end
|
129
|
-
|
130
154
|
|
131
155
|
class ProcController < PrependingController
|
132
156
|
before_filter(proc { |c| c.assigns["ran_proc_filter"] = true })
|
@@ -366,12 +390,17 @@ class FilterTest < Test::Unit::TestCase
|
|
366
390
|
|
367
391
|
def test_conditional_skipping_of_filters
|
368
392
|
assert_nil test_process(ConditionalSkippingController, "login").template.assigns["ran_filter"]
|
369
|
-
assert_equal %w( ensure_login ), test_process(ConditionalSkippingController, "change_password").template.assigns["ran_filter"]
|
393
|
+
assert_equal %w( ensure_login find_user ), test_process(ConditionalSkippingController, "change_password").template.assigns["ran_filter"]
|
370
394
|
|
371
395
|
assert_nil test_process(ConditionalSkippingController, "login").template.controller.instance_variable_get("@ran_after_filter")
|
372
396
|
assert_equal %w( clean_up ), test_process(ConditionalSkippingController, "change_password").template.controller.instance_variable_get("@ran_after_filter")
|
373
397
|
end
|
374
398
|
|
399
|
+
def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional
|
400
|
+
assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter']
|
401
|
+
assert_nil test_process(ChildOfConditionalParentController, 'another_action').template.assigns['ran_filter']
|
402
|
+
end
|
403
|
+
|
375
404
|
private
|
376
405
|
def test_process(controller, action = "show")
|
377
406
|
request = ActionController::TestRequest.new
|
Binary file
|
@@ -27,6 +27,11 @@ class AssetTagHelperTest < Test::Unit::TestCase
|
|
27
27
|
ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
|
28
28
|
end
|
29
29
|
|
30
|
+
def teardown
|
31
|
+
Object.send(:remove_const, :RAILS_ROOT) if defined?(RAILS_ROOT)
|
32
|
+
ENV["RAILS_ASSET_ID"] = nil
|
33
|
+
end
|
34
|
+
|
30
35
|
AutoDiscoveryToTag = {
|
31
36
|
%(auto_discovery_link_tag) => %(<link href="http://www.example.com" rel="alternate" title="RSS" type="application/rss+xml" />),
|
32
37
|
%(auto_discovery_link_tag(:atom)) => %(<link href="http://www.example.com" rel="alternate" title="ATOM" type="application/atom+xml" />),
|
@@ -115,6 +120,22 @@ class AssetTagHelperTest < Test::Unit::TestCase
|
|
115
120
|
ImageLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
|
116
121
|
end
|
117
122
|
|
123
|
+
def test_timebased_asset_id
|
124
|
+
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/")
|
125
|
+
expected_time = File.stat(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).mtime.to_i.to_s
|
126
|
+
assert_equal %(<img alt="Rails" src="/images/rails.png?#{expected_time}" />), image_tag("rails.png")
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_skipping_asset_id_on_complete_url
|
130
|
+
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/")
|
131
|
+
assert_equal %(<img alt="Rails" src="http://www.example.com/rails.png" />), image_tag("http://www.example.com/rails.png")
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_preset_asset_id
|
135
|
+
Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/")
|
136
|
+
ENV["RAILS_ASSET_ID"] = "4500"
|
137
|
+
assert_equal %(<img alt="Rails" src="/images/rails.png?4500" />), image_tag("rails.png")
|
138
|
+
end
|
118
139
|
end
|
119
140
|
|
120
141
|
class AssetTagHelperNonVhostTest < Test::Unit::TestCase
|
@@ -31,8 +31,13 @@ class JavaScriptMacrosHelperTest < Test::Unit::TestCase
|
|
31
31
|
auto_complete_field("some_input", :url => { :action => "autocomplete" }, :tokens => [',']);
|
32
32
|
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {minChars:3})\n//]]>\n</script>),
|
33
33
|
auto_complete_field("some_input", :url => { :action => "autocomplete" }, :min_chars => 3);
|
34
|
-
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {onHide:function(element, update){
|
35
|
-
auto_complete_field("some_input", :url => { :action => "autocomplete" }, :on_hide => "function(element, update){
|
34
|
+
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {onHide:function(element, update){alert('me');}})\n//]]>\n</script>),
|
35
|
+
auto_complete_field("some_input", :url => { :action => "autocomplete" }, :on_hide => "function(element, update){alert('me');}");
|
36
|
+
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {frequency:2})\n//]]>\n</script>),
|
37
|
+
auto_complete_field("some_input", :url => { :action => "autocomplete" }, :frequency => 2);
|
38
|
+
assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {afterUpdateElement:function(element,value){alert('You have chosen: '+value)}})\n//]]>\n</script>),
|
39
|
+
auto_complete_field("some_input", :url => { :action => "autocomplete" },
|
40
|
+
:after_update_element => "function(element,value){alert('You have chosen: '+value)}");
|
36
41
|
end
|
37
42
|
|
38
43
|
def test_auto_complete_result
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: actionpack
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.12.
|
7
|
-
date: 2006-
|
6
|
+
version: 1.12.1
|
7
|
+
date: 2006-04-06 00:00:00 -05:00
|
8
8
|
summary: Web-flow and rendering framework putting the VC in MVC.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -193,6 +193,7 @@ files:
|
|
193
193
|
- test/fixtures/multipart
|
194
194
|
- test/fixtures/project.rb
|
195
195
|
- test/fixtures/projects.yml
|
196
|
+
- test/fixtures/public
|
196
197
|
- test/fixtures/replies.yml
|
197
198
|
- test/fixtures/reply.rb
|
198
199
|
- test/fixtures/respond_to
|
@@ -226,6 +227,8 @@ files:
|
|
226
227
|
- test/fixtures/multipart/mona_lisa.jpg
|
227
228
|
- test/fixtures/multipart/single_parameter
|
228
229
|
- test/fixtures/multipart/text_file
|
230
|
+
- test/fixtures/public/images
|
231
|
+
- test/fixtures/public/images/rails.png
|
229
232
|
- test/fixtures/respond_to/all_types_with_layout.rhtml
|
230
233
|
- test/fixtures/respond_to/all_types_with_layout.rjs
|
231
234
|
- test/fixtures/respond_to/layouts
|
@@ -316,5 +319,5 @@ dependencies:
|
|
316
319
|
requirements:
|
317
320
|
- - "="
|
318
321
|
- !ruby/object:Gem::Version
|
319
|
-
version: 1.3.
|
322
|
+
version: 1.3.1
|
320
323
|
version:
|