rails 0.13.0 → 0.13.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 +14 -1
- data/Rakefile +7 -7
- data/bin/rails +10 -1
- data/environments/development.rb +9 -1
- data/environments/environment.rb +17 -2
- data/environments/production.rb +6 -1
- data/environments/test.rb +12 -1
- data/fresh_rakefile +11 -2
- data/html/javascripts/controls.js +254 -69
- data/html/javascripts/dragdrop.js +131 -70
- data/html/javascripts/effects.js +140 -98
- data/html/javascripts/prototype.js +50 -39
- data/lib/webrick_server.rb +2 -0
- metadata +9 -9
data/CHANGELOG
CHANGED
@@ -1,4 +1,17 @@
|
|
1
|
-
*
|
1
|
+
*0.13.1* (11 July, 2005)
|
2
|
+
|
3
|
+
* Fixed that each request with the WEBrick adapter would open a new database connection #1685 [Sam Stephenson]
|
4
|
+
|
5
|
+
* Added support for SQL Server in the database rake tasks #1652 [ken.barker@gmail.com] Note: osql and scptxfr may need to be installed on your development environment. This involves getting the .exes and a .rll (scptxfr) from a production SQL Server (not developer level SQL Server). Add their location to your Environment PATH and you are all set.
|
6
|
+
|
7
|
+
* Added a VERSION parameter to the migrate task that allows you to do "rake migrate VERSION=34" to migrate to the 34th version traveling up or down depending on the current version
|
8
|
+
|
9
|
+
* Extend Ruby version check to include RUBY_RELEASE_DATE >= '2005-12-25', the final Ruby 1.8.2 release #1674 [court3nay@gmail.com]
|
10
|
+
|
11
|
+
* Improved documentation for environment config files #1625 [court3nay@gmail.com]
|
12
|
+
|
13
|
+
|
14
|
+
*0.13.0* (6 July, 2005)
|
2
15
|
|
3
16
|
* Changed the default logging level in config/environment.rb to INFO for production (so SQL statements won't be logged)
|
4
17
|
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ require 'rbconfig'
|
|
9
9
|
|
10
10
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
11
11
|
PKG_NAME = 'rails'
|
12
|
-
PKG_VERSION = '0.13.
|
12
|
+
PKG_VERSION = '0.13.1' + PKG_BUILD
|
13
13
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
14
14
|
PKG_DESTINATION = ENV["RAILS_PKG_DESTINATION"] || "../#{PKG_NAME}"
|
15
15
|
|
@@ -247,15 +247,15 @@ spec = Gem::Specification.new do |s|
|
|
247
247
|
s.summary = "Web-application framework with template engine, control-flow layer, and ORM."
|
248
248
|
s.description = <<-EOF
|
249
249
|
Rails is a framework for building web-application using CGI, FCGI, mod_ruby, or WEBrick
|
250
|
-
on top of either MySQL, PostgreSQL, or
|
250
|
+
on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.
|
251
251
|
EOF
|
252
252
|
|
253
253
|
s.add_dependency('rake', '>= 0.5.3')
|
254
|
-
s.add_dependency('activesupport', '= 1.1.
|
255
|
-
s.add_dependency('activerecord', '= 1.11.
|
256
|
-
s.add_dependency('actionpack', '= 1.9.
|
257
|
-
s.add_dependency('actionmailer', '= 1.0.
|
258
|
-
s.add_dependency('actionwebservice', '= 0.8.
|
254
|
+
s.add_dependency('activesupport', '= 1.1.1' + PKG_BUILD)
|
255
|
+
s.add_dependency('activerecord', '= 1.11.1' + PKG_BUILD)
|
256
|
+
s.add_dependency('actionpack', '= 1.9.1' + PKG_BUILD)
|
257
|
+
s.add_dependency('actionmailer', '= 1.0.1' + PKG_BUILD)
|
258
|
+
s.add_dependency('actionwebservice', '= 0.8.1' + PKG_BUILD)
|
259
259
|
|
260
260
|
s.rdoc_options << '--exclude' << '.'
|
261
261
|
s.has_rdoc = false
|
data/bin/rails
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
|
1
|
+
min_release = "1.8.2 (2004-12-25)"
|
2
|
+
ruby_release = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
|
3
|
+
if ruby_release < min_release
|
4
|
+
abort <<-end_message
|
5
|
+
|
6
|
+
Rails requires Ruby version #{min_release} or later.
|
7
|
+
You're running #{ruby_release}; please upgrade to continue.
|
8
|
+
|
9
|
+
end_message
|
10
|
+
end
|
2
11
|
|
3
12
|
Signal.trap("INT") { puts; exit }
|
4
13
|
|
data/environments/development.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
+
# In the development environment your application's code is reloaded on
|
2
|
+
# every request. This slows down response time but is perfect for development
|
3
|
+
# since you don't have to restart the webserver when you make code changes.
|
4
|
+
|
5
|
+
# Log error messages when you accidentally call methods on nil.
|
1
6
|
require 'active_support/whiny_nil'
|
2
7
|
|
8
|
+
# Reload code; show full error reports; disable caching.
|
3
9
|
Dependencies.mechanism = :load
|
4
10
|
ActionController::Base.consider_all_requests_local = true
|
5
11
|
ActionController::Base.perform_caching = false
|
6
|
-
|
12
|
+
|
13
|
+
# The breakpoint server port that script/breakpointer connects to.
|
14
|
+
BREAKPOINT_SERVER_PORT = 42531
|
data/environments/environment.rb
CHANGED
@@ -1,8 +1,20 @@
|
|
1
|
-
|
1
|
+
# Load the Rails framework and configure your application.
|
2
|
+
# You can include your own configuration at the end of this file.
|
3
|
+
#
|
4
|
+
# Be sure to restart your webserver when you modify this file.
|
5
|
+
|
6
|
+
# The path to the root directory of your application.
|
7
|
+
RAILS_ROOT = File.join(File.dirname(__FILE__), '..')
|
8
|
+
|
9
|
+
# The environment your application is currently running. Don't set
|
10
|
+
# this here; put it in your webserver's configuration as the RAILS_ENV
|
11
|
+
# environment variable instead.
|
12
|
+
#
|
13
|
+
# See config/environments/*.rb for environment-specific configuration.
|
2
14
|
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
|
3
15
|
|
4
16
|
|
5
|
-
#
|
17
|
+
# Load the Rails framework. Mock classes for testing come first.
|
6
18
|
ADDITIONAL_LOAD_PATHS = ["#{RAILS_ROOT}/test/mocks/#{RAILS_ENV}"]
|
7
19
|
|
8
20
|
# Then model subdirectories.
|
@@ -62,6 +74,8 @@ end
|
|
62
74
|
|
63
75
|
[ActiveRecord, ActionController, ActionMailer].each { |mod| mod::Base.logger ||= RAILS_DEFAULT_LOGGER }
|
64
76
|
[ActionController, ActionMailer].each { |mod| mod::Base.template_root ||= "#{RAILS_ROOT}/app/views/" }
|
77
|
+
|
78
|
+
# Set up routes.
|
65
79
|
ActionController::Routing::Routes.reload
|
66
80
|
|
67
81
|
Controllers = Dependencies::LoadingModule.root(
|
@@ -70,3 +84,4 @@ Controllers = Dependencies::LoadingModule.root(
|
|
70
84
|
)
|
71
85
|
|
72
86
|
# Include your app's configuration here:
|
87
|
+
|
data/environments/production.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# The production environment is meant for finished, "live" apps.
|
2
|
+
# Code is not reloaded between requests, full error reports are disabled,
|
3
|
+
# and caching is turned on.
|
4
|
+
|
5
|
+
# Don't reload code; don't show full error reports; enable caching.
|
1
6
|
Dependencies.mechanism = :require
|
2
7
|
ActionController::Base.consider_all_requests_local = false
|
3
|
-
ActionController::Base.perform_caching = true
|
8
|
+
ActionController::Base.perform_caching = true
|
data/environments/test.rb
CHANGED
@@ -1,6 +1,17 @@
|
|
1
|
+
# The test environment is used exclusively to run your application's
|
2
|
+
# test suite. You never need to work with it otherwise. Remember that
|
3
|
+
# your test database is "scratch space" for the test suite and is wiped
|
4
|
+
# and recreated between test runs. Don't rely on the data there!
|
5
|
+
|
6
|
+
# Log error messages when you accidentally call methods on nil.
|
1
7
|
require 'active_support/whiny_nil'
|
2
8
|
|
9
|
+
# Don't reload code; show full error reports; disable caching.
|
3
10
|
Dependencies.mechanism = :require
|
4
11
|
ActionController::Base.consider_all_requests_local = true
|
5
12
|
ActionController::Base.perform_caching = false
|
6
|
-
|
13
|
+
|
14
|
+
# Tell ActionMailer not to deliver emails to the real world.
|
15
|
+
# The :test delivery method accumulates sent emails in the
|
16
|
+
# ActionMailer::Base.deliveries array.
|
17
|
+
ActionMailer::Base.delivery_method = :test
|
data/fresh_rakefile
CHANGED
@@ -135,6 +135,8 @@ task :clone_structure_to_test => [ :db_structure_dump, :purge_test_database ] do
|
|
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`
|
138
|
+
when "sqlserver"
|
139
|
+
`osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{RAILS_ENV}_structure.sql`
|
138
140
|
else
|
139
141
|
raise "Unknown database adapter '#{abcs["test"]["adapter"]}'"
|
140
142
|
end
|
@@ -154,6 +156,9 @@ task :db_structure_dump => :environment do
|
|
154
156
|
`pg_dump -U "#{abcs[RAILS_ENV]["username"]}" -s -x -O -f db/#{RAILS_ENV}_structure.sql #{abcs[RAILS_ENV]["database"]}`
|
155
157
|
when "sqlite", "sqlite3"
|
156
158
|
`#{abcs[RAILS_ENV]["adapter"]} #{abcs[RAILS_ENV]["dbfile"]} .schema > db/#{RAILS_ENV}_structure.sql`
|
159
|
+
when "sqlserver"
|
160
|
+
`scptxfr /s #{abcs[RAILS_ENV]["host"]} /d #{abcs[RAILS_ENV]["database"]} /I /f db\\#{RAILS_ENV}_structure.sql /q /A /r`
|
161
|
+
`scptxfr /s #{abcs[RAILS_ENV]["host"]} /d #{abcs[RAILS_ENV]["database"]} /I /F db\ /q /A /r`
|
157
162
|
else
|
158
163
|
raise "Unknown database adapter '#{abcs["test"]["adapter"]}'"
|
159
164
|
end
|
@@ -174,6 +179,10 @@ task :purge_test_database => :environment do
|
|
174
179
|
`createdb -T template0 -U "#{abcs["test"]["username"]}" #{abcs["test"]["database"]}`
|
175
180
|
when "sqlite","sqlite3"
|
176
181
|
File.delete(abcs["test"]["dbfile"]) if File.exist?(abcs["test"]["dbfile"])
|
182
|
+
when "sqlserver"
|
183
|
+
dropfkscript = "#{abcs["test"]["host"]}.#{abcs["test"]["database"]}.DP1".gsub(/\\/,'-')
|
184
|
+
`osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{dropfkscript}`
|
185
|
+
`osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{RAILS_ENV}_structure.sql`
|
177
186
|
else
|
178
187
|
raise "Unknown database adapter '#{abcs["test"]["adapter"]}'"
|
179
188
|
end
|
@@ -187,7 +196,7 @@ task :clear_logs => :environment do
|
|
187
196
|
end
|
188
197
|
end
|
189
198
|
|
190
|
-
desc "Migrate the database according to the migrate scripts in db/migrate"
|
199
|
+
desc "Migrate the database according to the migrate scripts in db/migrate (only supported on PG/MySQL). A specific version can be targetted with VERSION=x"
|
191
200
|
task :migrate => :environment do
|
192
|
-
ActiveRecord::Migrator.
|
201
|
+
ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/db/migrate/', ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
193
202
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
2
|
+
// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
2
3
|
//
|
3
4
|
// Permission is hereby granted, free of charge, to any person obtaining
|
4
5
|
// a copy of this software and associated documentation files (the
|
@@ -19,7 +20,6 @@
|
|
19
20
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
21
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
22
|
|
22
|
-
|
23
23
|
Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
24
24
|
var children = $(element).childNodes;
|
25
25
|
var text = "";
|
@@ -37,42 +37,70 @@ Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
|
|
37
37
|
return text;
|
38
38
|
}
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
// Autocompleter.Base handles all the autocompletion functionality
|
41
|
+
// that's independent of the data source for autocompletion. This
|
42
|
+
// includes drawing the autocompletion menu, observing keyboard
|
43
|
+
// and mouse events, and similar.
|
44
|
+
//
|
45
|
+
// Specific autocompleters need to provide, at the very least,
|
46
|
+
// a getUpdatedChoices function that will be invoked every time
|
47
|
+
// the text inside the monitored textbox changes. This method
|
48
|
+
// should get the text for which to provide autocompletion by
|
49
|
+
// invoking this.getEntry(), NOT by directly accessing
|
50
|
+
// this.element.value. This is to allow incremental tokenized
|
51
|
+
// autocompletion. Specific auto-completion logic (AJAX, etc)
|
52
|
+
// belongs in getUpdatedChoices.
|
53
|
+
//
|
54
|
+
// Tokenized incremental autocompletion is enabled automatically
|
55
|
+
// when an autocompleter is instantiated with the 'tokens' option
|
56
|
+
// in the options parameter, e.g.:
|
57
|
+
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
|
58
|
+
// will incrementally autocomplete with a comma as the token.
|
59
|
+
// Additionally, ',' in the above example can be replaced with
|
60
|
+
// a token array, e.g. { tokens: new Array (',', '\n') } which
|
61
|
+
// enables autocompletion on multiple tokens. This is most
|
62
|
+
// useful when one of the tokens is \n (a newline), as it
|
63
|
+
// allows smart autocompletion after linebreaks.
|
64
|
+
|
65
|
+
var Autocompleter = {}
|
66
|
+
Autocompleter.Base = function() {};
|
67
|
+
Autocompleter.Base.prototype = {
|
68
|
+
base_initialize: function(element, update, options) {
|
43
69
|
this.element = $(element);
|
44
70
|
this.update = $(update);
|
45
71
|
this.has_focus = false;
|
46
72
|
this.changed = false;
|
47
73
|
this.active = false;
|
48
74
|
this.index = 0;
|
49
|
-
this.entry_count = 0;
|
50
|
-
this.url = url;
|
75
|
+
this.entry_count = 0;
|
51
76
|
|
52
|
-
this.setOptions
|
53
|
-
|
54
|
-
|
77
|
+
if (this.setOptions)
|
78
|
+
this.setOptions(options);
|
79
|
+
else
|
80
|
+
this.options = {}
|
81
|
+
|
82
|
+
this.options.tokens = this.options.tokens || new Array();
|
55
83
|
this.options.frequency = this.options.frequency || 0.4;
|
56
84
|
this.options.min_chars = this.options.min_chars || 1;
|
57
|
-
this.options.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
if(!update.style.position || update.style.position=='absolute') {
|
62
|
-
update.style.position = 'absolute';
|
85
|
+
this.options.onShow = this.options.onShow ||
|
86
|
+
function(element, update){
|
87
|
+
if(!update.style.position || update.style.position=='absolute') {
|
88
|
+
update.style.position = 'absolute';
|
63
89
|
var offsets = Position.cumulativeOffset(element);
|
64
90
|
update.style.left = offsets[0] + 'px';
|
65
91
|
update.style.top = (offsets[1] + element.offsetHeight) + 'px';
|
66
92
|
update.style.width = element.offsetWidth + 'px';
|
67
|
-
|
68
|
-
|
69
|
-
|
93
|
+
}
|
94
|
+
new Effect.Appear(update,{duration:0.15});
|
95
|
+
};
|
70
96
|
this.options.onHide = this.options.onHide ||
|
71
|
-
|
72
|
-
|
97
|
+
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
73
98
|
|
74
99
|
if(this.options.indicator)
|
75
100
|
this.indicator = $(this.options.indicator);
|
101
|
+
|
102
|
+
if (typeof(this.options.tokens) == 'string')
|
103
|
+
this.options.tokens = new Array(this.options.tokens);
|
76
104
|
|
77
105
|
this.observer = null;
|
78
106
|
|
@@ -81,14 +109,14 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
|
81
109
|
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
|
82
110
|
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
|
83
111
|
},
|
84
|
-
|
112
|
+
|
85
113
|
show: function() {
|
86
114
|
if(this.update.style.display=='none') this.options.onShow(this.element, this.update);
|
87
115
|
if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && this.update.style.position=='absolute') {
|
88
116
|
new Insertion.After(this.update,
|
89
117
|
'<iframe id="' + this.update.id + '_iefix" '+
|
90
|
-
'style="display:none;filter:progid:DXImageTransform.Microsoft.Alpha(
|
91
|
-
'src="javascript
|
118
|
+
'style="display:none;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
|
119
|
+
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
|
92
120
|
this.iefix = $(this.update.id+'_iefix');
|
93
121
|
}
|
94
122
|
if(this.iefix) {
|
@@ -111,51 +139,7 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
|
111
139
|
stopIndicator: function() {
|
112
140
|
if(this.indicator) Element.hide(this.indicator);
|
113
141
|
},
|
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
142
|
|
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
143
|
onKeyPress: function(event) {
|
160
144
|
if(this.active)
|
161
145
|
switch(event.keyCode) {
|
@@ -255,7 +239,208 @@ Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({
|
|
255
239
|
select_entry: function() {
|
256
240
|
this.active = false;
|
257
241
|
value = Element.collectTextNodesIgnoreClass(this.get_current_entry(), 'informal').unescapeHTML();
|
258
|
-
this.
|
242
|
+
this.updateElement(value);
|
259
243
|
this.element.focus();
|
244
|
+
},
|
245
|
+
|
246
|
+
updateElement: function(value) {
|
247
|
+
var last_token_pos = this.findLastToken();
|
248
|
+
if (last_token_pos != -1) {
|
249
|
+
var new_value = this.element.value.substr(0, last_token_pos + 1);
|
250
|
+
var whitespace = this.element.value.substr(last_token_pos + 1).match(/^\s+/);
|
251
|
+
if (whitespace)
|
252
|
+
new_value += whitespace[0];
|
253
|
+
this.element.value = new_value + value;
|
254
|
+
} else {
|
255
|
+
this.element.value = value;
|
256
|
+
}
|
257
|
+
},
|
258
|
+
|
259
|
+
updateChoices: function(choices) {
|
260
|
+
if(!this.changed && this.has_focus) {
|
261
|
+
this.update.innerHTML = choices;
|
262
|
+
Element.cleanWhitespace(this.update);
|
263
|
+
Element.cleanWhitespace(this.update.firstChild);
|
264
|
+
|
265
|
+
if(this.update.firstChild && this.update.firstChild.childNodes) {
|
266
|
+
this.entry_count =
|
267
|
+
this.update.firstChild.childNodes.length;
|
268
|
+
for (var i = 0; i < this.entry_count; i++) {
|
269
|
+
entry = this.get_entry(i);
|
270
|
+
entry.autocompleteIndex = i;
|
271
|
+
this.addObservers(entry);
|
272
|
+
}
|
273
|
+
} else {
|
274
|
+
this.entry_count = 0;
|
275
|
+
}
|
276
|
+
|
277
|
+
this.stopIndicator();
|
278
|
+
|
279
|
+
this.index = 0;
|
280
|
+
this.render();
|
281
|
+
}
|
282
|
+
},
|
283
|
+
|
284
|
+
addObservers: function(element) {
|
285
|
+
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
286
|
+
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
287
|
+
},
|
288
|
+
|
289
|
+
onObserverEvent: function() {
|
290
|
+
this.changed = false;
|
291
|
+
if(this.getEntry().length>=this.options.min_chars) {
|
292
|
+
this.startIndicator();
|
293
|
+
this.getUpdatedChoices();
|
294
|
+
} else {
|
295
|
+
this.active = false;
|
296
|
+
this.hide();
|
297
|
+
}
|
298
|
+
},
|
299
|
+
|
300
|
+
getEntry: function() {
|
301
|
+
var token_pos = this.findLastToken();
|
302
|
+
if (token_pos != -1)
|
303
|
+
var ret = this.element.value.substr(token_pos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
|
304
|
+
else
|
305
|
+
var ret = this.element.value;
|
306
|
+
|
307
|
+
return /\n/.test(ret) ? '' : ret;
|
308
|
+
},
|
309
|
+
|
310
|
+
findLastToken: function() {
|
311
|
+
var last_token_pos = -1;
|
312
|
+
|
313
|
+
for (var i=0; i<this.options.tokens.length; i++) {
|
314
|
+
var this_token_pos = this.element.value.lastIndexOf(this.options.tokens[i]);
|
315
|
+
if (this_token_pos > last_token_pos)
|
316
|
+
last_token_pos = this_token_pos;
|
317
|
+
}
|
318
|
+
return last_token_pos;
|
319
|
+
}
|
320
|
+
}
|
321
|
+
|
322
|
+
Ajax.Autocompleter = Class.create();
|
323
|
+
Ajax.Autocompleter.prototype = Object.extend(new Autocompleter.Base(),
|
324
|
+
Object.extend(new Ajax.Base(), {
|
325
|
+
initialize: function(element, update, url, options) {
|
326
|
+
this.base_initialize(element, update, options);
|
327
|
+
this.options.asynchronous = true;
|
328
|
+
this.options.onComplete = this.onComplete.bind(this)
|
329
|
+
this.options.method = 'post';
|
330
|
+
this.options.defaultParams = this.options.parameters || null;
|
331
|
+
this.url = url;
|
332
|
+
},
|
333
|
+
|
334
|
+
getUpdatedChoices: function() {
|
335
|
+
entry = encodeURIComponent(this.element.name) + '=' +
|
336
|
+
encodeURIComponent(this.getEntry());
|
337
|
+
|
338
|
+
this.options.parameters = this.options.callback ?
|
339
|
+
this.options.callback(this.element, entry) : entry;
|
340
|
+
|
341
|
+
if(this.options.defaultParams)
|
342
|
+
this.options.parameters += '&' + this.options.defaultParams;
|
343
|
+
|
344
|
+
new Ajax.Request(this.url, this.options);
|
345
|
+
},
|
346
|
+
|
347
|
+
onComplete: function(request) {
|
348
|
+
this.updateChoices(request.responseText);
|
349
|
+
}
|
350
|
+
|
351
|
+
}));
|
352
|
+
|
353
|
+
// The local array autocompleter. Used when you'd prefer to
|
354
|
+
// inject an array of autocompletion options into the page, rather
|
355
|
+
// than sending out Ajax queries, which can be quite slow sometimes.
|
356
|
+
//
|
357
|
+
// The constructor takes four parameters. The first two are, as usual,
|
358
|
+
// the id of the monitored textbox, and id of the autocompletion menu.
|
359
|
+
// The third is the array you want to autocomplete from, and the fourth
|
360
|
+
// is the options block.
|
361
|
+
//
|
362
|
+
// Extra local autocompletion options:
|
363
|
+
// - choices - How many autocompletion choices to offer
|
364
|
+
//
|
365
|
+
// - partial_search - If false, the autocompleter will match entered
|
366
|
+
// text only at the beginning of strings in the
|
367
|
+
// autocomplete array. Defaults to true, which will
|
368
|
+
// match text at the beginning of any *word* in the
|
369
|
+
// strings in the autocomplete array. If you want to
|
370
|
+
// search anywhere in the string, additionally set
|
371
|
+
// the option full_search to true (default: off).
|
372
|
+
//
|
373
|
+
// - full_search - Search anywhere in autocomplete array strings.
|
374
|
+
//
|
375
|
+
// - partial_chars - How many characters to enter before triggering
|
376
|
+
// a partial match (unlike min_chars, which defines
|
377
|
+
// how many characters are required to do any match
|
378
|
+
// at all). Defaults to 2.
|
379
|
+
//
|
380
|
+
// - ignore_case - Whether to ignore case when autocompleting.
|
381
|
+
// Defaults to true.
|
382
|
+
//
|
383
|
+
// It's possible to pass in a custom function as the 'selector'
|
384
|
+
// option, if you prefer to write your own autocompletion logic.
|
385
|
+
// In that case, the other options above will not apply unless
|
386
|
+
// you support them.
|
387
|
+
|
388
|
+
Autocompleter.Local = Class.create();
|
389
|
+
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
390
|
+
initialize: function(element, update, array, options) {
|
391
|
+
this.base_initialize(element, update, options);
|
392
|
+
this.options.array = array;
|
393
|
+
},
|
394
|
+
|
395
|
+
getUpdatedChoices: function() {
|
396
|
+
this.updateChoices(this.options.selector(this));
|
397
|
+
},
|
398
|
+
|
399
|
+
setOptions: function(options) {
|
400
|
+
this.options = Object.extend({
|
401
|
+
choices: 10,
|
402
|
+
partial_search: true,
|
403
|
+
partial_chars: 2,
|
404
|
+
ignore_case: true,
|
405
|
+
full_search: false,
|
406
|
+
selector: function(instance) {
|
407
|
+
var ret = new Array(); // Beginning matches
|
408
|
+
var partial = new Array(); // Inside matches
|
409
|
+
var entry = instance.getEntry();
|
410
|
+
var count = 0;
|
411
|
+
|
412
|
+
for (var i = 0; i < instance.options.array.length &&
|
413
|
+
ret.length < instance.options.choices ; i++) {
|
414
|
+
var elem = instance.options.array[i];
|
415
|
+
var found_pos = instance.options.ignore_case ?
|
416
|
+
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
417
|
+
elem.indexOf(entry);
|
418
|
+
|
419
|
+
while (found_pos != -1) {
|
420
|
+
if (found_pos == 0 && elem.length != entry.length) {
|
421
|
+
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
422
|
+
elem.substr(entry.length) + "</li>");
|
423
|
+
break;
|
424
|
+
} else if (entry.length >= instance.options.partial_chars &&
|
425
|
+
instance.options.partial_search && found_pos != -1) {
|
426
|
+
if (instance.options.full_search || /\s/.test(elem.substr(found_pos-1,1))) {
|
427
|
+
partial.push("<li>" + elem.substr(0, found_pos) + "<strong>" +
|
428
|
+
elem.substr(found_pos, entry.length) + "</strong>" + elem.substr(
|
429
|
+
found_pos + entry.length) + "</li>");
|
430
|
+
break;
|
431
|
+
}
|
432
|
+
}
|
433
|
+
|
434
|
+
found_pos = instance.options.ignore_case ?
|
435
|
+
elem.toLowerCase().indexOf(entry.toLowerCase(), found_pos + 1) :
|
436
|
+
elem.indexOf(entry, found_pos + 1);
|
437
|
+
|
438
|
+
}
|
439
|
+
}
|
440
|
+
if (partial.length)
|
441
|
+
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
442
|
+
return "<ul>" + ret.join('') + "</ul>";
|
443
|
+
}
|
444
|
+
}, options || {});
|
260
445
|
}
|
261
|
-
});
|
446
|
+
});
|