rails 0.12.1 → 0.13.0
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 +59 -10
- data/Rakefile +23 -11
- data/bin/console +6 -5
- data/bin/console_sandbox +0 -6
- data/bin/listener +86 -0
- data/bin/profiler +27 -10
- data/bin/rails +3 -1
- data/bin/runner +24 -0
- data/bin/server +1 -0
- data/bin/tracker +69 -0
- data/configs/database.yml +3 -0
- data/dispatches/dispatch.fcgi +22 -25
- data/dispatches/gateway.cgi +97 -0
- data/environments/development.rb +2 -0
- data/environments/environment.rb +1 -0
- data/environments/test.rb +2 -0
- data/fresh_rakefile +9 -4
- data/helpers/test_helper.rb +16 -5
- data/html/404.html +2 -0
- data/html/500.html +2 -0
- data/html/index.html +3 -0
- data/html/javascripts/controls.js +261 -0
- data/html/javascripts/dragdrop.js +476 -0
- data/html/javascripts/effects.js +570 -0
- data/html/javascripts/prototype.js +633 -371
- data/lib/console_sandbox.rb +6 -0
- data/lib/dispatcher.rb +13 -11
- data/lib/fcgi_handler.rb +166 -0
- data/lib/rails_generator/generators/applications/app/app_generator.rb +16 -12
- data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +2 -2
- data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +3 -1
- data/lib/rails_generator/generators/components/migration/USAGE +14 -0
- data/lib/rails_generator/generators/components/migration/migration_generator.rb +9 -0
- data/lib/rails_generator/generators/components/migration/templates/migration.rb +7 -0
- data/lib/rails_generator/generators/components/model/model_generator.rb +1 -1
- data/lib/rails_generator/generators/components/scaffold/USAGE +1 -1
- data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +11 -11
- data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +38 -20
- data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +2 -0
- data/lib/rails_generator/generators/components/scaffold/templates/style.css +22 -1
- data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +2 -2
- data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +5 -5
- data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +1 -1
- data/lib/rubyprof_ext.rb +35 -0
- data/lib/webrick_server.rb +84 -43
- metadata +22 -8
data/configs/database.yml
CHANGED
@@ -5,6 +5,9 @@ development:
|
|
5
5
|
username: root
|
6
6
|
password:
|
7
7
|
|
8
|
+
# Warning: The database defined as 'test' will be erased and
|
9
|
+
# re-generated from your development database when you run 'rake'.
|
10
|
+
# Do not set this db to the same as development or production.
|
8
11
|
test:
|
9
12
|
adapter: mysql
|
10
13
|
database: rails_test
|
data/dispatches/dispatch.fcgi
CHANGED
@@ -1,27 +1,24 @@
|
|
1
1
|
#!/usr/local/bin/ruby
|
2
|
+
#
|
3
|
+
# You may specify the path to the FastCGI crash log (a log of unhandled
|
4
|
+
# exceptions which forced the FastCGI instance to exit, great for debugging)
|
5
|
+
# and the number of requests to process before running garbage collection.
|
6
|
+
#
|
7
|
+
# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
|
8
|
+
# and the GC period is nil (turned off). A reasonable number of requests
|
9
|
+
# could range from 10-100 depending on the memory footprint of your app.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
# # Default log path, normal GC behavior.
|
13
|
+
# RailsFCGIHandler.process!
|
14
|
+
#
|
15
|
+
# # Default log path, 50 requests between GC.
|
16
|
+
# RailsFCGIHandler.process! nil, 50
|
17
|
+
#
|
18
|
+
# # Custom log path, normal GC behavior.
|
19
|
+
# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
|
20
|
+
#
|
21
|
+
require File.dirname(__FILE__) + "/../config/environment"
|
22
|
+
require 'fcgi_handler'
|
2
23
|
|
3
|
-
|
4
|
-
error_message =
|
5
|
-
"[#{Time.now}] Dispatcher failed to catch: #{e} (#{e.class})\n #{e.backtrace.join("\n ")}\n#{msg}"
|
6
|
-
Logger.new(path).fatal(error_message)
|
7
|
-
rescue Object => log_error
|
8
|
-
STDERR << "Couldn't write to #{path} (#{e} [#{e.class}])\n" << error_message
|
9
|
-
end
|
10
|
-
|
11
|
-
begin
|
12
|
-
require File.dirname(__FILE__) + "/../config/environment"
|
13
|
-
require 'dispatcher'
|
14
|
-
require 'fcgi'
|
15
|
-
|
16
|
-
log_file_path = "#{RAILS_ROOT}/log/fastcgi.crash.log"
|
17
|
-
|
18
|
-
FCGI.each_cgi do |cgi|
|
19
|
-
begin
|
20
|
-
Dispatcher.dispatch(cgi)
|
21
|
-
rescue Object => rails_error
|
22
|
-
dispatcher_error(log_file_path, rails_error)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
rescue Object => fcgi_error
|
26
|
-
dispatcher_error(log_file_path, fcgi_error, "FCGI process #{$$} killed by this error\n")
|
27
|
-
end
|
24
|
+
RailsFCGIHandler.process!
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require 'drb'
|
4
|
+
|
5
|
+
# This file includes an experimental gateway CGI implementation. It will work
|
6
|
+
# only on platforms which support both fork and sockets.
|
7
|
+
#
|
8
|
+
# To enable it edit public/.htaccess and replace dispatch.cgi with gateway.cgi.
|
9
|
+
#
|
10
|
+
# Next, create the directory log/drb_gateway and grant the apache user rw access
|
11
|
+
# to said directory.
|
12
|
+
#
|
13
|
+
# On the next request to your server, the gateway tracker should start up, along
|
14
|
+
# with a few listener processes. This setup should provide you with much better
|
15
|
+
# speeds than dispatch.cgi.
|
16
|
+
#
|
17
|
+
# Keep in mind that the first request made to the server will be slow, as the
|
18
|
+
# tracker and listeners will have to load. Also, the tracker and listeners will
|
19
|
+
# shutdown after a period if inactivity. You can set this value below -- the
|
20
|
+
# default is 90 seconds.
|
21
|
+
|
22
|
+
TrackerSocket = File.expand_path(File.join(File.dirname(__FILE__), '../log/drb_gateway/tracker.sock'))
|
23
|
+
DieAfter = 90 # Seconds
|
24
|
+
Listeners = 3
|
25
|
+
|
26
|
+
def message(s)
|
27
|
+
$stderr.puts "gateway.cgi: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def listener_socket(number)
|
31
|
+
File.expand_path(File.join(File.dirname(__FILE__), "../log/drb_gateway/listener_#{number}.sock"))
|
32
|
+
end
|
33
|
+
|
34
|
+
unless File.exists? TrackerSocket
|
35
|
+
message "Starting tracker and #{Listeners} listeners"
|
36
|
+
fork do
|
37
|
+
Process.setsid
|
38
|
+
STDIN.reopen "/dev/null"
|
39
|
+
STDOUT.reopen "/dev/null", "a"
|
40
|
+
|
41
|
+
root = File.expand_path(File.dirname(__FILE__) + '/..')
|
42
|
+
|
43
|
+
message "starting tracker"
|
44
|
+
fork do
|
45
|
+
ARGV.clear
|
46
|
+
ARGV << TrackerSocket << Listeners.to_s << DieAfter.to_s
|
47
|
+
load File.join(root, 'script', 'tracker')
|
48
|
+
end
|
49
|
+
|
50
|
+
message "starting listeners"
|
51
|
+
require File.join(root, 'config/environment.rb')
|
52
|
+
Listeners.times do |number|
|
53
|
+
fork do
|
54
|
+
ARGV.clear
|
55
|
+
ARGV << listener_socket(number) << DieAfter.to_s
|
56
|
+
load File.join(root, 'script', 'listener')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
message "waiting for tracker and listener to arise..."
|
62
|
+
ready = false
|
63
|
+
10.times do
|
64
|
+
sleep 0.5
|
65
|
+
break if (ready = File.exists?(TrackerSocket) && File.exists?(listener_socket(0)))
|
66
|
+
end
|
67
|
+
|
68
|
+
if ready
|
69
|
+
message "tracker and listener are ready"
|
70
|
+
else
|
71
|
+
message "Waited 5 seconds, listener and tracker not ready... dropping request"
|
72
|
+
Kernel.exit 1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
DRb.start_service
|
77
|
+
|
78
|
+
message "connecting to tracker"
|
79
|
+
tracker = DRbObject.new_with_uri("drbunix:#{TrackerSocket}")
|
80
|
+
|
81
|
+
input = $stdin.read
|
82
|
+
$stdin.close
|
83
|
+
|
84
|
+
env = ENV.inspect
|
85
|
+
|
86
|
+
output = nil
|
87
|
+
tracker.with_listener do |number|
|
88
|
+
message "connecting to listener #{number}"
|
89
|
+
socket = listener_socket(number)
|
90
|
+
listener = DRbObject.new_with_uri("drbunix:#{socket}")
|
91
|
+
output = listener.process(env, input)
|
92
|
+
message "listener #{number} has finished, writing output"
|
93
|
+
end
|
94
|
+
|
95
|
+
$stdout.write output
|
96
|
+
$stdout.flush
|
97
|
+
$stdout.close
|
data/environments/development.rb
CHANGED
data/environments/environment.rb
CHANGED
@@ -50,6 +50,7 @@ ActiveRecord::Base.establish_connection
|
|
50
50
|
# Configure defaults if the included environment did not.
|
51
51
|
begin
|
52
52
|
RAILS_DEFAULT_LOGGER = Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}.log")
|
53
|
+
RAILS_DEFAULT_LOGGER.level = (RAILS_ENV == 'production' ? Logger::INFO : Logger::DEBUG)
|
53
54
|
rescue StandardError
|
54
55
|
RAILS_DEFAULT_LOGGER = Logger.new(STDERR)
|
55
56
|
RAILS_DEFAULT_LOGGER.level = Logger::WARN
|
data/environments/test.rb
CHANGED
data/fresh_rakefile
CHANGED
@@ -16,7 +16,7 @@ task :environment do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
desc "Generate API
|
19
|
+
desc "Generate API documentation, show coding stats"
|
20
20
|
task :doc => [ :appdoc, :stats ]
|
21
21
|
|
22
22
|
|
@@ -131,7 +131,7 @@ task :clone_structure_to_test => [ :db_structure_dump, :purge_test_database ] do
|
|
131
131
|
when "postgresql"
|
132
132
|
ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
|
133
133
|
ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
|
134
|
-
ENV['PGPASSWORD'] = abcs["test"]["password"]
|
134
|
+
ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
|
135
135
|
`psql -U "#{abcs["test"]["username"]}" -f db/#{RAILS_ENV}_structure.sql #{abcs["test"]["database"]}`
|
136
136
|
when "sqlite", "sqlite3"
|
137
137
|
`#{abcs[RAILS_ENV]["adapter"]} #{abcs["test"]["dbfile"]} < db/#{RAILS_ENV}_structure.sql`
|
@@ -150,7 +150,7 @@ task :db_structure_dump => :environment do
|
|
150
150
|
when "postgresql"
|
151
151
|
ENV['PGHOST'] = abcs[RAILS_ENV]["host"] if abcs[RAILS_ENV]["host"]
|
152
152
|
ENV['PGPORT'] = abcs[RAILS_ENV]["port"].to_s if abcs[RAILS_ENV]["port"]
|
153
|
-
ENV['PGPASSWORD'] = abcs[RAILS_ENV]["password"]
|
153
|
+
ENV['PGPASSWORD'] = abcs[RAILS_ENV]["password"].to_s if abcs[RAILS_ENV]["password"]
|
154
154
|
`pg_dump -U "#{abcs[RAILS_ENV]["username"]}" -s -x -O -f db/#{RAILS_ENV}_structure.sql #{abcs[RAILS_ENV]["database"]}`
|
155
155
|
when "sqlite", "sqlite3"
|
156
156
|
`#{abcs[RAILS_ENV]["adapter"]} #{abcs[RAILS_ENV]["dbfile"]} .schema > db/#{RAILS_ENV}_structure.sql`
|
@@ -169,7 +169,7 @@ task :purge_test_database => :environment do
|
|
169
169
|
when "postgresql"
|
170
170
|
ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
|
171
171
|
ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
|
172
|
-
ENV['PGPASSWORD'] = abcs["test"]["password"]
|
172
|
+
ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
|
173
173
|
`dropdb -U "#{abcs["test"]["username"]}" #{abcs["test"]["database"]}`
|
174
174
|
`createdb -T template0 -U "#{abcs["test"]["username"]}" #{abcs["test"]["database"]}`
|
175
175
|
when "sqlite","sqlite3"
|
@@ -185,4 +185,9 @@ task :clear_logs => :environment do
|
|
185
185
|
f = File.open(log_file, "w")
|
186
186
|
f.close
|
187
187
|
end
|
188
|
+
end
|
189
|
+
|
190
|
+
desc "Migrate the database according to the migrate scripts in db/migrate"
|
191
|
+
task :migrate => :environment do
|
192
|
+
ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/db/migrate/')
|
188
193
|
end
|
data/helpers/test_helper.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
ENV["RAILS_ENV"] = "test"
|
2
|
-
|
2
|
+
|
3
|
+
# Expand the path to environment so that Ruby does not load it multiple times
|
4
|
+
# File.expand_path can be removed if Ruby 1.9 is in use.
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
|
3
6
|
require 'application'
|
4
7
|
|
5
8
|
require 'test/unit'
|
@@ -8,8 +11,16 @@ require 'action_controller/test_process'
|
|
8
11
|
require 'action_web_service/test_invoke'
|
9
12
|
require 'breakpoint'
|
10
13
|
|
11
|
-
def create_fixtures(*table_names)
|
12
|
-
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures", table_names)
|
13
|
-
end
|
14
|
-
|
15
14
|
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
15
|
+
|
16
|
+
class Test::Unit::TestCase
|
17
|
+
# Turn these on to use transactional fixtures with table_name(:fixture_name) instantiation of fixtures
|
18
|
+
# self.use_transactional_fixtures = true
|
19
|
+
# self.use_instantiated_fixtures = false
|
20
|
+
|
21
|
+
def create_fixtures(*table_names)
|
22
|
+
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures", table_names)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Add more helper methods to be used by all tests here...
|
26
|
+
end
|
data/html/404.html
CHANGED
data/html/500.html
CHANGED
data/html/index.html
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/html4/loose.dtd">
|
1
3
|
<html>
|
2
4
|
<head>
|
3
5
|
<title>Rails: Welcome on board</title>
|
@@ -58,6 +60,7 @@
|
|
58
60
|
<li>See all the tests run by running <code>rake</code>.
|
59
61
|
<li>Develop your Rails application!
|
60
62
|
<li>Setup Apache with <a href="http://www.fastcgi.com">FastCGI</a> (and <a href="http://raa.ruby-lang.org/list.rhtml?name=fcgi">Ruby bindings</a>), if you need better performance
|
63
|
+
<li>Remove the dispatches you don't use (so if you're on FastCGI, delete/move dispatch.rb, dispatch.cgi and gateway.cgi)</li>
|
61
64
|
</ol>
|
62
65
|
|
63
66
|
<p>
|
@@ -0,0 +1,261 @@
|
|
1
|
+
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
2
|
+
//
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
// a copy of this software and associated documentation files (the
|
5
|
+
// "Software"), to deal in the Software without restriction, including
|
6
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
// distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
// permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
// the following conditions:
|
10
|
+
//
|
11
|
+
// The above copyright notice and this permission notice shall be
|
12
|
+
// included in all copies or substantial portions of the Software.
|
13
|
+
//
|
14
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
|
23
|
+
Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
24
|
+
var children = $(element).childNodes;
|
25
|
+
var text = "";
|
26
|
+
var classtest = new RegExp("^([^ ]+ )*" + ignoreclass+ "( [^ ]+)*$","i");
|
27
|
+
|
28
|
+
for (var i = 0; i < children.length; i++) {
|
29
|
+
if(children[i].nodeType==3) {
|
30
|
+
text+=children[i].nodeValue;
|
31
|
+
} else {
|
32
|
+
if((!children[i].className.match(classtest)) && children[i].hasChildNodes())
|
33
|
+
text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
return text;
|
38
|
+
}
|
39
|
+
|
40
|
+
Ajax.Autocompleter = Class.create();
|
41
|
+
Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
42
|
+
initialize: function(element, update, url, options) {
|
43
|
+
this.element = $(element);
|
44
|
+
this.update = $(update);
|
45
|
+
this.has_focus = false;
|
46
|
+
this.changed = false;
|
47
|
+
this.active = false;
|
48
|
+
this.index = 0;
|
49
|
+
this.entry_count = 0;
|
50
|
+
this.url = url;
|
51
|
+
|
52
|
+
this.setOptions(options);
|
53
|
+
this.options.asynchronous = true;
|
54
|
+
this.options.onComplete = this.onComplete.bind(this)
|
55
|
+
this.options.frequency = this.options.frequency || 0.4;
|
56
|
+
this.options.min_chars = this.options.min_chars || 1;
|
57
|
+
this.options.method = 'post';
|
58
|
+
|
59
|
+
this.options.onShow = this.options.onShow ||
|
60
|
+
function(element, update){
|
61
|
+
if(!update.style.position || update.style.position=='absolute') {
|
62
|
+
update.style.position = 'absolute';
|
63
|
+
var offsets = Position.cumulativeOffset(element);
|
64
|
+
update.style.left = offsets[0] + 'px';
|
65
|
+
update.style.top = (offsets[1] + element.offsetHeight) + 'px';
|
66
|
+
update.style.width = element.offsetWidth + 'px';
|
67
|
+
}
|
68
|
+
new Effect.Appear(update,{duration:0.3});
|
69
|
+
};
|
70
|
+
this.options.onHide = this.options.onHide ||
|
71
|
+
function(element, update){ new Effect.Fade(update,{duration:0.3}) };
|
72
|
+
|
73
|
+
|
74
|
+
if(this.options.indicator)
|
75
|
+
this.indicator = $(this.options.indicator);
|
76
|
+
|
77
|
+
this.observer = null;
|
78
|
+
|
79
|
+
Element.hide(this.update);
|
80
|
+
|
81
|
+
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
|
82
|
+
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
|
83
|
+
},
|
84
|
+
|
85
|
+
show: function() {
|
86
|
+
if(this.update.style.display=='none') this.options.onShow(this.element, this.update);
|
87
|
+
if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && this.update.style.position=='absolute') {
|
88
|
+
new Insertion.After(this.update,
|
89
|
+
'<iframe id="' + this.update.id + '_iefix" '+
|
90
|
+
'style="display:none;filter:progid:DXImageTransform.Microsoft.Alpha(apacity=0);" ' +
|
91
|
+
'src="javascript:;" frameborder="0" scrolling="no"></iframe>');
|
92
|
+
this.iefix = $(this.update.id+'_iefix');
|
93
|
+
}
|
94
|
+
if(this.iefix) {
|
95
|
+
Position.clone(this.update, this.iefix);
|
96
|
+
this.iefix.style.zIndex = 1;
|
97
|
+
this.update.style.zIndex = 2;
|
98
|
+
Element.show(this.iefix);
|
99
|
+
}
|
100
|
+
},
|
101
|
+
|
102
|
+
hide: function() {
|
103
|
+
if(this.update.style.display=='') this.options.onHide(this.element, this.update);
|
104
|
+
if(this.iefix) Element.hide(this.iefix);
|
105
|
+
},
|
106
|
+
|
107
|
+
startIndicator: function() {
|
108
|
+
if(this.indicator) Element.show(this.indicator);
|
109
|
+
},
|
110
|
+
|
111
|
+
stopIndicator: function() {
|
112
|
+
if(this.indicator) Element.hide(this.indicator);
|
113
|
+
},
|
114
|
+
|
115
|
+
onObserverEvent: function() {
|
116
|
+
this.changed = false;
|
117
|
+
if(this.element.value.length>=this.options.min_chars) {
|
118
|
+
this.startIndicator();
|
119
|
+
this.options.parameters = this.options.callback ?
|
120
|
+
this.options.callback(this.element, Form.Element.getValue(this.element)) :
|
121
|
+
Form.Element.serialize(this.element);
|
122
|
+
new Ajax.Request(this.url, this.options);
|
123
|
+
} else {
|
124
|
+
this.active = false;
|
125
|
+
this.hide();
|
126
|
+
}
|
127
|
+
},
|
128
|
+
|
129
|
+
addObservers: function(element) {
|
130
|
+
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
131
|
+
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
132
|
+
},
|
133
|
+
|
134
|
+
onComplete: function(request) {
|
135
|
+
if(!this.changed && this.has_focus) {
|
136
|
+
this.update.innerHTML = request.responseText;
|
137
|
+
Element.cleanWhitespace(this.update);
|
138
|
+
Element.cleanWhitespace(this.update.firstChild);
|
139
|
+
|
140
|
+
if(this.update.firstChild && this.update.firstChild.childNodes) {
|
141
|
+
this.entry_count =
|
142
|
+
this.update.firstChild.childNodes.length;
|
143
|
+
for (var i = 0; i < this.entry_count; i++) {
|
144
|
+
entry = this.get_entry(i);
|
145
|
+
entry.autocompleteIndex = i;
|
146
|
+
this.addObservers(entry);
|
147
|
+
}
|
148
|
+
} else {
|
149
|
+
this.entry_count = 0;
|
150
|
+
}
|
151
|
+
|
152
|
+
this.stopIndicator();
|
153
|
+
|
154
|
+
this.index = 0;
|
155
|
+
this.render();
|
156
|
+
}
|
157
|
+
},
|
158
|
+
|
159
|
+
onKeyPress: function(event) {
|
160
|
+
if(this.active)
|
161
|
+
switch(event.keyCode) {
|
162
|
+
case Event.KEY_TAB:
|
163
|
+
case Event.KEY_RETURN:
|
164
|
+
this.select_entry();
|
165
|
+
Event.stop(event);
|
166
|
+
case Event.KEY_ESC:
|
167
|
+
this.hide();
|
168
|
+
this.active = false;
|
169
|
+
return;
|
170
|
+
case Event.KEY_LEFT:
|
171
|
+
case Event.KEY_RIGHT:
|
172
|
+
return;
|
173
|
+
case Event.KEY_UP:
|
174
|
+
this.mark_previous();
|
175
|
+
this.render();
|
176
|
+
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
|
177
|
+
return;
|
178
|
+
case Event.KEY_DOWN:
|
179
|
+
this.mark_next();
|
180
|
+
this.render();
|
181
|
+
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
|
182
|
+
return;
|
183
|
+
}
|
184
|
+
else
|
185
|
+
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
|
186
|
+
return;
|
187
|
+
|
188
|
+
this.changed = true;
|
189
|
+
this.has_focus = true;
|
190
|
+
|
191
|
+
if(this.observer) clearTimeout(this.observer);
|
192
|
+
this.observer =
|
193
|
+
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
|
194
|
+
},
|
195
|
+
|
196
|
+
onHover: function(event) {
|
197
|
+
var element = Event.findElement(event, 'LI');
|
198
|
+
if(this.index != element.autocompleteIndex)
|
199
|
+
{
|
200
|
+
this.index = element.autocompleteIndex;
|
201
|
+
this.render();
|
202
|
+
}
|
203
|
+
Event.stop(event);
|
204
|
+
},
|
205
|
+
|
206
|
+
onClick: function(event) {
|
207
|
+
var element = Event.findElement(event, 'LI');
|
208
|
+
this.index = element.autocompleteIndex;
|
209
|
+
this.select_entry();
|
210
|
+
Event.stop(event);
|
211
|
+
},
|
212
|
+
|
213
|
+
onBlur: function(event) {
|
214
|
+
// needed to make click events working
|
215
|
+
setTimeout(this.hide.bind(this), 250);
|
216
|
+
this.has_focus = false;
|
217
|
+
this.active = false;
|
218
|
+
},
|
219
|
+
|
220
|
+
render: function() {
|
221
|
+
if(this.entry_count > 0) {
|
222
|
+
for (var i = 0; i < this.entry_count; i++)
|
223
|
+
this.index==i ?
|
224
|
+
Element.addClassName(this.get_entry(i),"selected") :
|
225
|
+
Element.removeClassName(this.get_entry(i),"selected");
|
226
|
+
|
227
|
+
if(this.has_focus) {
|
228
|
+
if(this.get_current_entry().scrollIntoView)
|
229
|
+
this.get_current_entry().scrollIntoView(false);
|
230
|
+
|
231
|
+
this.show();
|
232
|
+
this.active = true;
|
233
|
+
}
|
234
|
+
} else this.hide();
|
235
|
+
},
|
236
|
+
|
237
|
+
mark_previous: function() {
|
238
|
+
if(this.index > 0) this.index--
|
239
|
+
else this.index = this.entry_count-1;
|
240
|
+
},
|
241
|
+
|
242
|
+
mark_next: function() {
|
243
|
+
if(this.index < this.entry_count-1) this.index++
|
244
|
+
else this.index = 0;
|
245
|
+
},
|
246
|
+
|
247
|
+
get_entry: function(index) {
|
248
|
+
return this.update.firstChild.childNodes[index];
|
249
|
+
},
|
250
|
+
|
251
|
+
get_current_entry: function() {
|
252
|
+
return this.get_entry(this.index);
|
253
|
+
},
|
254
|
+
|
255
|
+
select_entry: function() {
|
256
|
+
this.active = false;
|
257
|
+
value = Element.collectTextNodesIgnoreClass(this.get_current_entry(), 'informal').unescapeHTML();
|
258
|
+
this.element.value = value;
|
259
|
+
this.element.focus();
|
260
|
+
}
|
261
|
+
});
|