rails 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rails might be problematic. Click here for more details.
- data/CHANGELOG +39 -0
- data/README +4 -2
- data/Rakefile +7 -7
- data/bin/rails +10 -2
- data/builtin/rails_info/rails/info.rb +7 -5
- data/builtin/rails_info/rails/info_controller.rb +7 -9
- data/builtin/rails_info/rails/info_helper.rb +2 -0
- data/builtin/rails_info/rails_info_controller.rb +2 -0
- data/configs/lighttpd.conf +19 -12
- data/environments/boot.rb +21 -2
- data/environments/development.rb +1 -0
- data/environments/environment.rb +3 -0
- data/html/index.html +1 -1
- data/html/javascripts/dragdrop.js +252 -63
- data/html/javascripts/effects.js +15 -10
- data/html/javascripts/prototype.js +59 -38
- data/lib/commands/console.rb +1 -1
- data/lib/commands/plugin.rb +11 -6
- data/lib/commands/process/spawner.rb +21 -8
- data/lib/dispatcher.rb +20 -2
- data/lib/{rails_version.rb → rails/version.rb} +1 -1
- data/lib/rails_generator/generators/applications/app/app_generator.rb +11 -6
- data/lib/tasks/databases.rake +1 -0
- data/lib/tasks/framework.rake +19 -12
- data/lib/tasks/tmp.rake +1 -1
- metadata +12 -9
data/CHANGELOG
CHANGED
@@ -1,3 +1,42 @@
|
|
1
|
+
*1.1.1* (April 6th, 2005)
|
2
|
+
|
3
|
+
* Enhances plugin#discover allowing it to discover svn:// like URIs (closes #4565) [ruben.nine@gmail.com]
|
4
|
+
|
5
|
+
* Update to Prototype 1.5.0_rc0 [Sam Stephenson]
|
6
|
+
|
7
|
+
* Fixed that the -r/--ruby path option of the rails command was not being respected #4549 [ryan.raaum@gmail.com]
|
8
|
+
|
9
|
+
* Added that Dispatcher exceptions should not be shown to the user unless a default log has not been configured. Instead show public/500.html [DHH]
|
10
|
+
|
11
|
+
* Fixed that rake clone_structure_to_test should quit on pgsql if the dump is unsuccesful #4585 [augustz@augustz.com]
|
12
|
+
|
13
|
+
* Fixed that rails --version should have the return code of 0 (success) #4560 [blair@orcaware.com]
|
14
|
+
|
15
|
+
* Install alias so Rails::InfoController is accessible at /rails_info. Closes #4546. [Nicholas Seckar]
|
16
|
+
|
17
|
+
* Fixed that spawner should daemonize if running in repeat mode [DHH]
|
18
|
+
|
19
|
+
* Added TAG option for rake rails:freeze:edge, so you can say rake rails:freeze:edge TAG=rel_1-1-0 to lock to the 1.1.0 release [DHH]
|
20
|
+
|
21
|
+
* Applied Prototype $() performance patches (#4465, #4477) and updated script.aculo.us [Sam Stephenson, Thomas Fuchs]
|
22
|
+
|
23
|
+
* Use --simple-prompt instead of --prompt-mode simple for console compatibility with Windows/Ruby 1.8.2 #4532 [starr@starrnhorne.com]
|
24
|
+
|
25
|
+
* Make Rails::VERSION implicitly loadable #4491. [Nicholas Seckar]
|
26
|
+
|
27
|
+
* Fixed rake rails:freeze:gems #4518 [benji@silverinsanity.com]
|
28
|
+
|
29
|
+
* Added -f/--freeze option to rails command for freezing the application to the Rails version it was generated with [DHH]
|
30
|
+
|
31
|
+
* Added gem binding of apps generated through the rails command to the gems of they were generated with [Nicholas Seckar]
|
32
|
+
|
33
|
+
* Added expiration settings for JavaScript, CSS, HTML, and images to default lighttpd.conf [DHH]
|
34
|
+
|
35
|
+
* Added gzip compression for JavaScript, CSS, and HTML to default lighttpd.conf [DHH]
|
36
|
+
|
37
|
+
* Avoid passing escapeHTML non-string in Rails' info controller [Nicholas Seckar]
|
38
|
+
|
39
|
+
|
1
40
|
*1.1.0* (March 27th, 2005)
|
2
41
|
|
3
42
|
* Allow db:fixtures:load to load a subset of the applications fixtures. [Chad Fowler]
|
data/README
CHANGED
@@ -48,8 +48,10 @@ Mongrel. It's a Ruby-based web server with a C-component (so it requires compila
|
|
48
48
|
also works very well with Windows. See more at http://mongrel.rubyforge.org/.
|
49
49
|
|
50
50
|
But of course its also possible to run Rails with the premiere open source web server Apache.
|
51
|
-
To get decent performance, though, you'll need to install FastCGI.
|
52
|
-
|
51
|
+
To get decent performance, though, you'll need to install FastCGI. For Apache 1.3, you want
|
52
|
+
to use mod_fastcgi. For Apache 2.0+, you want to use mod_fcgid.
|
53
|
+
|
54
|
+
See http://wiki.rubyonrails.com/rails/pages/FastCGI for more information on FastCGI.
|
53
55
|
|
54
56
|
== Example for Apache conf
|
55
57
|
|
data/Rakefile
CHANGED
@@ -7,7 +7,7 @@ require 'rake/contrib/rubyforgepublisher'
|
|
7
7
|
require 'date'
|
8
8
|
require 'rbconfig'
|
9
9
|
|
10
|
-
require File.join(File.dirname(__FILE__), 'lib', '
|
10
|
+
require File.join(File.dirname(__FILE__), 'lib/rails', 'version')
|
11
11
|
|
12
12
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
13
13
|
PKG_NAME = 'rails'
|
@@ -277,12 +277,12 @@ spec = Gem::Specification.new do |s|
|
|
277
277
|
on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.
|
278
278
|
EOF
|
279
279
|
|
280
|
-
s.add_dependency('rake', '>= 0.7.
|
281
|
-
s.add_dependency('activesupport', '= 1.3.
|
282
|
-
s.add_dependency('activerecord', '= 1.14.
|
283
|
-
s.add_dependency('actionpack', '= 1.12.
|
284
|
-
s.add_dependency('actionmailer', '= 1.2.
|
285
|
-
s.add_dependency('actionwebservice', '= 1.1.
|
280
|
+
s.add_dependency('rake', '>= 0.7.1')
|
281
|
+
s.add_dependency('activesupport', '= 1.3.1' + PKG_BUILD)
|
282
|
+
s.add_dependency('activerecord', '= 1.14.1' + PKG_BUILD)
|
283
|
+
s.add_dependency('actionpack', '= 1.12.1' + PKG_BUILD)
|
284
|
+
s.add_dependency('actionmailer', '= 1.2.1' + PKG_BUILD)
|
285
|
+
s.add_dependency('actionwebservice', '= 1.1.1' + PKG_BUILD)
|
286
286
|
|
287
287
|
s.rdoc_options << '--exclude' << '.'
|
288
288
|
s.has_rdoc = false
|
data/bin/rails
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../lib/ruby_version_check'
|
2
2
|
Signal.trap("INT") { puts; exit }
|
3
3
|
|
4
|
-
require File.dirname(__FILE__) + '/../lib/
|
5
|
-
|
4
|
+
require File.dirname(__FILE__) + '/../lib/rails/version'
|
5
|
+
if %w(--version -v).include? ARGV.first
|
6
|
+
puts "Rails #{Rails::VERSION::STRING}"
|
7
|
+
exit(0)
|
8
|
+
end
|
9
|
+
|
10
|
+
freeze = ARGV.any? { |option| %w(--freeze -f).include?(option) }
|
11
|
+
app_path = ARGV.first
|
6
12
|
|
7
13
|
require File.dirname(__FILE__) + '/../lib/rails_generator'
|
8
14
|
|
9
15
|
require 'rails_generator/scripts/generate'
|
10
16
|
Rails::Generator::Base.use_application_sources!
|
11
17
|
Rails::Generator::Scripts::Generate.new.run(ARGV, :generator => 'app')
|
18
|
+
|
19
|
+
Dir.chdir(app_path) { `rake rails:freeze:gems`; puts "froze" } if freeze
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'rails_version'
|
2
|
-
|
3
1
|
module Rails
|
4
2
|
module Info
|
5
3
|
mattr_accessor :properties
|
@@ -35,7 +33,11 @@ module Rails
|
|
35
33
|
|
36
34
|
def freeze_edge_version
|
37
35
|
if File.exists?(rails_vendor_root)
|
38
|
-
|
36
|
+
begin
|
37
|
+
Dir[File.join(rails_vendor_root, 'REVISION_*')].first.scan(/_(\d+)$/).first.first
|
38
|
+
rescue
|
39
|
+
Dir[File.join(rails_vendor_root, 'TAG_*')].first.scan(/_(.+)$/).first.first rescue 'unknown'
|
40
|
+
end
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
@@ -51,8 +53,8 @@ module Rails
|
|
51
53
|
def to_html
|
52
54
|
returning table = '<table>' do
|
53
55
|
properties.each do |(name, value)|
|
54
|
-
table << %(<tr><td class="name">#{CGI.escapeHTML(name)}</td>)
|
55
|
-
table << %(<td class="value">#{CGI.escapeHTML(value)}</td></tr>)
|
56
|
+
table << %(<tr><td class="name">#{CGI.escapeHTML(name.to_s)}</td>)
|
57
|
+
table << %(<td class="value">#{CGI.escapeHTML(value.to_s)}</td></tr>)
|
56
58
|
end
|
57
59
|
table << '</table>'
|
58
60
|
end
|
@@ -1,11 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => 500
|
8
|
-
end
|
1
|
+
class Rails::InfoController < ActionController::Base
|
2
|
+
def properties
|
3
|
+
if local_request?
|
4
|
+
render :inline => Rails::Info.to_html
|
5
|
+
else
|
6
|
+
render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => 500
|
9
7
|
end
|
10
8
|
end
|
11
|
-
end
|
9
|
+
end
|
data/configs/lighttpd.conf
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# Default configuration file for the lighttpd web server
|
2
2
|
# Start using ./script/server lighttpd
|
3
3
|
|
4
|
+
server.bind = "0.0.0.0"
|
4
5
|
server.port = 3000
|
5
6
|
|
6
|
-
server.modules = ( "mod_rewrite", "mod_accesslog", "mod_fastcgi" )
|
7
|
+
server.modules = ( "mod_rewrite", "mod_accesslog", "mod_fastcgi", "mod_compress", "mod_expire" )
|
8
|
+
|
7
9
|
server.error-handler-404 = "/dispatch.fcgi"
|
8
10
|
server.document-root = CWD + "/public/"
|
9
11
|
|
@@ -12,19 +14,24 @@ accesslog.filename = CWD + "/log/lighttpd.access.log"
|
|
12
14
|
|
13
15
|
url.rewrite = ( "^/$" => "index.html", "^([^.]+)$" => "$1.html" )
|
14
16
|
|
17
|
+
compress.filetype = ( "text/plain", "text/html", "text/css", "text/javascript" )
|
18
|
+
compress.cache-dir = CWD + "/tmp/cache"
|
19
|
+
|
20
|
+
expire.url = ( "/favicon.ico" => "access 3 days",
|
21
|
+
"/images/" => "access 3 days",
|
22
|
+
"/stylesheets/" => "access 3 days",
|
23
|
+
"/javascripts/" => "access 3 days" )
|
24
|
+
|
25
|
+
|
15
26
|
# Change *-procs to 2 if you need to use Upload Progress or other tasks that
|
16
27
|
# *need* to execute a second request while the first is still pending.
|
17
|
-
fastcgi.server
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
"bin-environment" => ( "RAILS_ENV" => "development" )
|
25
|
-
)
|
26
|
-
)
|
27
|
-
)
|
28
|
+
fastcgi.server = ( ".fcgi" => ( "localhost" => (
|
29
|
+
"min-procs" => 1,
|
30
|
+
"max-procs" => 1,
|
31
|
+
"socket" => CWD + "/tmp/sockets/fcgi.socket",
|
32
|
+
"bin-path" => CWD + "/public/dispatch.fcgi",
|
33
|
+
"bin-environment" => ( "RAILS_ENV" => "development" )
|
34
|
+
) ) )
|
28
35
|
|
29
36
|
mimetype.assign = (
|
30
37
|
".css" => "text/css",
|
data/environments/boot.rb
CHANGED
@@ -13,7 +13,26 @@ if File.directory?("#{RAILS_ROOT}/vendor/rails")
|
|
13
13
|
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
|
14
14
|
else
|
15
15
|
require 'rubygems'
|
16
|
-
|
16
|
+
|
17
|
+
if !defined?(RAILS_GEM_VERSION) && File.read(File.dirname(__FILE__) + '/environment.rb') =~ /RAILS_GEM_VERSION = '([\d.]+)'/
|
18
|
+
RAILS_GEM_VERSION = $1
|
19
|
+
end
|
20
|
+
|
21
|
+
if defined?(RAILS_GEM_VERSION)
|
22
|
+
rails_gem = Gem.cache.search('rails', "=#{RAILS_GEM_VERSION}").first
|
23
|
+
|
24
|
+
if rails_gem
|
25
|
+
require rails_gem.full_gem_path + '/lib/initializer'
|
26
|
+
else
|
27
|
+
STDERR.puts %(Cannot find gem for Rails =#{RAILS_GEM_VERSION}:
|
28
|
+
Install the missing gem with 'gem install -v=#{RAILS_GEM_VERSION} rails', or
|
29
|
+
change environment.rb to define RAILS_GEM_VERSION with your desired version.
|
30
|
+
)
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
else
|
34
|
+
require 'initializer'
|
35
|
+
end
|
17
36
|
end
|
18
37
|
|
19
|
-
Rails::Initializer.run(:set_load_path)
|
38
|
+
Rails::Initializer.run(:set_load_path)
|
data/environments/development.rb
CHANGED
@@ -14,6 +14,7 @@ config.breakpoint_server = true
|
|
14
14
|
# Show full error reports and disable caching
|
15
15
|
config.action_controller.consider_all_requests_local = true
|
16
16
|
config.action_controller.perform_caching = false
|
17
|
+
config.action_view.cache_template_extensions = false
|
17
18
|
config.action_view.debug_rjs = true
|
18
19
|
|
19
20
|
# Don't care if the mailer can't send
|
data/environments/environment.rb
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
# you don't control web/app server and can't set it the proper way
|
5
5
|
# ENV['RAILS_ENV'] ||= 'production'
|
6
6
|
|
7
|
+
# Specifies gem version of Rails to use when vendor/rails is not present
|
8
|
+
<%= '# ' if freeze %>RAILS_GEM_VERSION = '<%= Rails::VERSION::STRING %>'
|
9
|
+
|
7
10
|
# Bootstrap the Rails environment, frameworks, and default configuration
|
8
11
|
require File.join(File.dirname(__FILE__), 'boot')
|
9
12
|
|
data/html/index.html
CHANGED
@@ -244,7 +244,7 @@
|
|
244
244
|
</div>
|
245
245
|
|
246
246
|
<div id="about">
|
247
|
-
<h3><a href="
|
247
|
+
<h3><a href="rails/info/properties" onclick="about(); return false">About your application’s environment</a></h3>
|
248
248
|
<div id="about-content" style="display: none"></div>
|
249
249
|
</div>
|
250
250
|
|
@@ -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
|
+
}
|