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 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 and application/x-yaml are enabled. For application/xml, a XmlSimple class with
269
- # the same param name as the root will be instanciated in the @params. This allows XML requests to mask themselves
270
- # as regular form submissions, so you can have one action serve both regular forms and web service requests. For
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
- @@param_parsers = { Mime::XML => :xml_simple, Mime::YAML => :yaml }
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")
@@ -416,7 +416,7 @@ module ActionController #:nodoc:
416
416
  end
417
417
 
418
418
  def read(name, options = nil) #:nodoc:
419
- IO.read(real_file_path(name)) rescue nil
419
+ File.open(real_file_path(name), 'rb') { |f| f.read } rescue nil
420
420
  end
421
421
 
422
422
  def delete(name, options) #:nodoc:
@@ -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 %> in
3
- <%=h (@request.parameters["controller"] || "<controller not set>").capitalize %>#<%=h @request.parameters["action"] || "<action not set>" %>
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
 
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
4
  MINOR = 12
5
- TINY = 0
5
+ TINY = 1
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -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
- @@cached_template_extension[template_path] ||=
316
- if match = delegate_template_exists?(template_path)
317
- match.first.to_sym
318
- elsif erb_template_exists?(template_path): :rhtml
319
- elsif builder_template_exists?(template_path): :rxml
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
- @@cached_template_extension[template_path] ||
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))] + @@javascript_default_sources.dup + sources[(sources.index(:defaults) + 1)..sources.length]
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) and File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")
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 = "/#{dir}/#{source}" unless source.first == "/" || source.include?(":")
149
- source = "#{source}.#{ext}" unless source.split("/").last.include?(".")
150
- source = "#{@controller.request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ 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
- { :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
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 parentNode = element.parentNode;
43
- return drop._containers.detect(function(c) { return parentNode == c });
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
- if(drop.onHover)
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
- this.handle = Element.childrenWithClassName(this.element, options.handle, true)[0];
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
- this.draw(Draggables._lastPointer);
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: new Array(),
526
+ sortables: {},
496
527
 
497
- options: function(element){
498
- element = $(element);
499
- return this.sortables.detect(function(s) { return s.element == element });
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
- element = $(element);
504
- this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
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
- this.sortables = this.sortables.reject(function(s) { return s.element == element });
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, // fixme: unimplemented
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.push(options);
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
- if(!element.hasChildNodes()) return null;
609
- var elements = [];
610
- var only = options.only ? [options.only].flatten() : null;
611
- $A(element.childNodes).each( function(e) {
612
- if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
613
- (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
614
- elements.push(e);
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(overlap>0.5) {
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
- if(element.parentNode!=dropon) {
651
- var oldParentNode = element.parentNode;
652
- dropon.appendChild(element);
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
- Sortable.options(dropon).onChange(element);
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
- var n = nodeMap[ident];
709
- if (n) {
710
- n[1].appendChild(n[0]);
711
- delete nodeMap[ident];
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
- return Sortable.sequence(element, arguments[1]).map( function(item) {
721
- return name + "[]=" + encodeURIComponent(item);
722
- }).join('&');
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
- return [$A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) {
81
- return c.className ? Element.hasClassName(c, className) : false;
82
- })].flatten();
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.0_pre1
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.0_pre1',
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 (value >= (result || value))
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 (value <= (result || value))
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 = 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] = value.bind(null, element);
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
- if (this.element.tagName.toLowerCase() == 'tbody') {
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 = new Array();
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
- var optValue = opt.value;
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
- Event.observe(window, 'unload', Event.unloadCache, false);
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
@@ -425,7 +425,7 @@ module ActionView
425
425
  #
426
426
  # # Controller action
427
427
  # def poll
428
- # render :update { |page| page.update_time }
428
+ # render(:update) { |page| page.update_time }
429
429
  # end
430
430
  #
431
431
  # You can also use PrototypeHelper#update_page_tag instead of
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.0' + PKG_BUILD)
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
@@ -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){Alert('me');}})\n//]]>\n</script>),
35
- auto_complete_field("some_input", :url => { :action => "autocomplete" }, :on_hide => "function(element, update){Alert('me');}");
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.0
7
- date: 2006-03-27 00:00:00 -06:00
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.0
322
+ version: 1.3.1
320
323
  version: