entp-ruby-openid 2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +215 -0
- data/INSTALL +47 -0
- data/LICENSE +210 -0
- data/NOTICE +2 -0
- data/README +85 -0
- data/UPGRADE +127 -0
- data/admin/runtests.rb +45 -0
- data/examples/README +32 -0
- data/examples/active_record_openid_store/README +58 -0
- data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +24 -0
- data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
- data/examples/active_record_openid_store/init.rb +8 -0
- data/examples/active_record_openid_store/lib/association.rb +10 -0
- data/examples/active_record_openid_store/lib/nonce.rb +3 -0
- data/examples/active_record_openid_store/lib/open_id_setting.rb +4 -0
- data/examples/active_record_openid_store/lib/openid_ar_store.rb +57 -0
- data/examples/active_record_openid_store/test/store_test.rb +212 -0
- data/examples/discover +49 -0
- data/examples/rails_openid/README +153 -0
- data/examples/rails_openid/Rakefile +10 -0
- data/examples/rails_openid/app/controllers/application.rb +4 -0
- data/examples/rails_openid/app/controllers/consumer_controller.rb +125 -0
- data/examples/rails_openid/app/controllers/login_controller.rb +45 -0
- data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
- data/examples/rails_openid/app/helpers/application_helper.rb +3 -0
- data/examples/rails_openid/app/helpers/login_helper.rb +2 -0
- data/examples/rails_openid/app/helpers/server_helper.rb +9 -0
- data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
- data/examples/rails_openid/app/views/layouts/server.rhtml +68 -0
- data/examples/rails_openid/app/views/login/index.rhtml +56 -0
- data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
- data/examples/rails_openid/config/boot.rb +19 -0
- data/examples/rails_openid/config/database.yml +74 -0
- data/examples/rails_openid/config/environment.rb +54 -0
- data/examples/rails_openid/config/environments/development.rb +19 -0
- data/examples/rails_openid/config/environments/production.rb +19 -0
- data/examples/rails_openid/config/environments/test.rb +19 -0
- data/examples/rails_openid/config/routes.rb +24 -0
- data/examples/rails_openid/doc/README_FOR_APP +2 -0
- data/examples/rails_openid/public/404.html +8 -0
- data/examples/rails_openid/public/500.html +8 -0
- data/examples/rails_openid/public/dispatch.cgi +12 -0
- data/examples/rails_openid/public/dispatch.fcgi +26 -0
- data/examples/rails_openid/public/dispatch.rb +12 -0
- data/examples/rails_openid/public/favicon.ico +0 -0
- data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
- data/examples/rails_openid/public/javascripts/controls.js +750 -0
- data/examples/rails_openid/public/javascripts/dragdrop.js +584 -0
- data/examples/rails_openid/public/javascripts/effects.js +854 -0
- data/examples/rails_openid/public/javascripts/prototype.js +1785 -0
- data/examples/rails_openid/public/robots.txt +1 -0
- data/examples/rails_openid/script/about +3 -0
- data/examples/rails_openid/script/breakpointer +3 -0
- data/examples/rails_openid/script/console +3 -0
- data/examples/rails_openid/script/destroy +3 -0
- data/examples/rails_openid/script/generate +3 -0
- data/examples/rails_openid/script/performance/benchmarker +3 -0
- data/examples/rails_openid/script/performance/profiler +3 -0
- data/examples/rails_openid/script/plugin +3 -0
- data/examples/rails_openid/script/process/reaper +3 -0
- data/examples/rails_openid/script/process/spawner +3 -0
- data/examples/rails_openid/script/process/spinner +3 -0
- data/examples/rails_openid/script/runner +3 -0
- data/examples/rails_openid/script/server +3 -0
- data/examples/rails_openid/test/functional/login_controller_test.rb +18 -0
- data/examples/rails_openid/test/functional/server_controller_test.rb +18 -0
- data/examples/rails_openid/test/test_helper.rb +28 -0
- data/lib/hmac/hmac.rb +112 -0
- data/lib/hmac/sha1.rb +11 -0
- data/lib/hmac/sha2.rb +25 -0
- data/lib/openid.rb +22 -0
- data/lib/openid/association.rb +249 -0
- data/lib/openid/consumer.rb +395 -0
- data/lib/openid/consumer/associationmanager.rb +344 -0
- data/lib/openid/consumer/checkid_request.rb +186 -0
- data/lib/openid/consumer/discovery.rb +497 -0
- data/lib/openid/consumer/discovery_manager.rb +123 -0
- data/lib/openid/consumer/html_parse.rb +134 -0
- data/lib/openid/consumer/idres.rb +523 -0
- data/lib/openid/consumer/responses.rb +150 -0
- data/lib/openid/cryptutil.rb +115 -0
- data/lib/openid/dh.rb +89 -0
- data/lib/openid/extension.rb +39 -0
- data/lib/openid/extensions/ax.rb +539 -0
- data/lib/openid/extensions/oauth.rb +91 -0
- data/lib/openid/extensions/pape.rb +179 -0
- data/lib/openid/extensions/sreg.rb +277 -0
- data/lib/openid/extras.rb +11 -0
- data/lib/openid/fetchers.rb +258 -0
- data/lib/openid/kvform.rb +136 -0
- data/lib/openid/kvpost.rb +58 -0
- data/lib/openid/message.rb +553 -0
- data/lib/openid/protocolerror.rb +12 -0
- data/lib/openid/server.rb +1544 -0
- data/lib/openid/store.rb +10 -0
- data/lib/openid/store/filesystem.rb +272 -0
- data/lib/openid/store/interface.rb +75 -0
- data/lib/openid/store/memcache.rb +109 -0
- data/lib/openid/store/memory.rb +84 -0
- data/lib/openid/store/nonce.rb +68 -0
- data/lib/openid/trustroot.rb +349 -0
- data/lib/openid/urinorm.rb +75 -0
- data/lib/openid/util.rb +119 -0
- data/lib/openid/version.rb +3 -0
- data/lib/openid/yadis.rb +15 -0
- data/lib/openid/yadis/accept.rb +148 -0
- data/lib/openid/yadis/constants.rb +21 -0
- data/lib/openid/yadis/discovery.rb +153 -0
- data/lib/openid/yadis/filters.rb +205 -0
- data/lib/openid/yadis/htmltokenizer.rb +305 -0
- data/lib/openid/yadis/parsehtml.rb +45 -0
- data/lib/openid/yadis/services.rb +42 -0
- data/lib/openid/yadis/xrds.rb +155 -0
- data/lib/openid/yadis/xri.rb +90 -0
- data/lib/openid/yadis/xrires.rb +91 -0
- data/test/data/test_discover/openid_utf8.html +11 -0
- data/test/support/test_data_mixin.rb +127 -0
- data/test/support/test_util.rb +53 -0
- data/test/support/yadis_data.rb +131 -0
- data/test/support/yadis_data/accept.txt +124 -0
- data/test/support/yadis_data/dh.txt +29 -0
- data/test/support/yadis_data/example-xrds.xml +14 -0
- data/test/support/yadis_data/linkparse.txt +587 -0
- data/test/support/yadis_data/n2b64 +650 -0
- data/test/support/yadis_data/test1-discover.txt +137 -0
- data/test/support/yadis_data/test1-parsehtml.txt +152 -0
- data/test/support/yadis_data/test_discover/malformed_meta_tag.html +19 -0
- data/test/support/yadis_data/test_discover/openid.html +11 -0
- data/test/support/yadis_data/test_discover/openid2.html +11 -0
- data/test/support/yadis_data/test_discover/openid2_xrds.xml +12 -0
- data/test/support/yadis_data/test_discover/openid2_xrds_no_local_id.xml +11 -0
- data/test/support/yadis_data/test_discover/openid_1_and_2.html +11 -0
- data/test/support/yadis_data/test_discover/openid_1_and_2_xrds.xml +16 -0
- data/test/support/yadis_data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
- data/test/support/yadis_data/test_discover/openid_and_yadis.html +12 -0
- data/test/support/yadis_data/test_discover/openid_no_delegate.html +10 -0
- data/test/support/yadis_data/test_discover/openid_utf8.html +11 -0
- data/test/support/yadis_data/test_discover/yadis_0entries.xml +12 -0
- data/test/support/yadis_data/test_discover/yadis_2_bad_local_id.xml +15 -0
- data/test/support/yadis_data/test_discover/yadis_2entries_delegate.xml +22 -0
- data/test/support/yadis_data/test_discover/yadis_2entries_idp.xml +21 -0
- data/test/support/yadis_data/test_discover/yadis_another_delegate.xml +14 -0
- data/test/support/yadis_data/test_discover/yadis_idp.xml +12 -0
- data/test/support/yadis_data/test_discover/yadis_idp_delegate.xml +13 -0
- data/test/support/yadis_data/test_discover/yadis_no_delegate.xml +11 -0
- data/test/support/yadis_data/test_xrds/=j3h.2007.11.14.xrds +25 -0
- data/test/support/yadis_data/test_xrds/README +12 -0
- data/test/support/yadis_data/test_xrds/delegated-20060809-r1.xrds +34 -0
- data/test/support/yadis_data/test_xrds/delegated-20060809-r2.xrds +34 -0
- data/test/support/yadis_data/test_xrds/delegated-20060809.xrds +34 -0
- data/test/support/yadis_data/test_xrds/no-xrd.xml +7 -0
- data/test/support/yadis_data/test_xrds/not-xrds.xml +2 -0
- data/test/support/yadis_data/test_xrds/prefixsometimes.xrds +34 -0
- data/test/support/yadis_data/test_xrds/ref.xrds +109 -0
- data/test/support/yadis_data/test_xrds/sometimesprefix.xrds +34 -0
- data/test/support/yadis_data/test_xrds/spoof1.xrds +25 -0
- data/test/support/yadis_data/test_xrds/spoof2.xrds +25 -0
- data/test/support/yadis_data/test_xrds/spoof3.xrds +37 -0
- data/test/support/yadis_data/test_xrds/status222.xrds +9 -0
- data/test/support/yadis_data/test_xrds/subsegments.xrds +58 -0
- data/test/support/yadis_data/test_xrds/valid-populated-xrds.xml +39 -0
- data/test/support/yadis_data/trustroot.txt +153 -0
- data/test/support/yadis_data/urinorm.txt +79 -0
- data/test/test_accept.rb +170 -0
- data/test/test_association.rb +268 -0
- data/test/test_associationmanager.rb +918 -0
- data/test/test_ax.rb +690 -0
- data/test/test_checkid_request.rb +293 -0
- data/test/test_consumer.rb +260 -0
- data/test/test_cryptutil.rb +119 -0
- data/test/test_dh.rb +85 -0
- data/test/test_discover.rb +848 -0
- data/test/test_discovery_manager.rb +259 -0
- data/test/test_extension.rb +46 -0
- data/test/test_extras.rb +35 -0
- data/test/test_fetchers.rb +554 -0
- data/test/test_filters.rb +269 -0
- data/test/test_helper.rb +4 -0
- data/test/test_idres.rb +961 -0
- data/test/test_kvform.rb +164 -0
- data/test/test_kvpost.rb +64 -0
- data/test/test_linkparse.rb +100 -0
- data/test/test_message.rb +1115 -0
- data/test/test_nonce.rb +89 -0
- data/test/test_oauth.rb +176 -0
- data/test/test_openid_yadis.rb +177 -0
- data/test/test_pape.rb +248 -0
- data/test/test_parsehtml.rb +79 -0
- data/test/test_responses.rb +63 -0
- data/test/test_server.rb +2455 -0
- data/test/test_sreg.rb +479 -0
- data/test/test_stores.rb +292 -0
- data/test/test_trustroot.rb +111 -0
- data/test/test_urinorm.rb +34 -0
- data/test/test_util.rb +145 -0
- data/test/test_xrds.rb +167 -0
- data/test/test_xri.rb +48 -0
- data/test/test_xrires.rb +67 -0
- data/test/test_yadis_discovery.rb +218 -0
- metadata +268 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
<% if session[:username].nil? %>
|
|
4
|
+
|
|
5
|
+
<div id="login-form">
|
|
6
|
+
<form method="get" action="<%= url_for :controller => 'login', :action => 'submit' %>">
|
|
7
|
+
Type a username:
|
|
8
|
+
<input type="text" name="username" />
|
|
9
|
+
<input type="submit" value="Log In" />
|
|
10
|
+
</form>
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
<p> Welcome to the Ruby OpenID example. This code is a starting point
|
|
17
|
+
for developers wishing to implement an OpenID provider or relying
|
|
18
|
+
party. We've used the <a href="http://rubyonrails.org/">Rails</a>
|
|
19
|
+
platform to demonstrate, but the library code is not Rails specific.</p>
|
|
20
|
+
|
|
21
|
+
<h2>To use the example provider</h2>
|
|
22
|
+
<p>
|
|
23
|
+
<ol>
|
|
24
|
+
|
|
25
|
+
<li>Enter a username in the form above. You will be "Logged In"
|
|
26
|
+
to the server, at which point you may authenticate using an OpenID
|
|
27
|
+
consumer. Your OpenID URL will be displayed after you log
|
|
28
|
+
in.<p>The server will automatically create an identity page for
|
|
29
|
+
you at <%= @base_url %>user/<i>name</i></p></li>
|
|
30
|
+
|
|
31
|
+
<li><p>Because WEBrick can only handle one thing at a time, you'll need to
|
|
32
|
+
run another instance of the example on another port if you want to use
|
|
33
|
+
a relying party to use with this example provider:</p>
|
|
34
|
+
<blockquote>
|
|
35
|
+
<code>script/server --port=3001</code>
|
|
36
|
+
</blockquote>
|
|
37
|
+
|
|
38
|
+
<p>(The RP needs to be able to access the provider, so unless you're
|
|
39
|
+
running this example on a public IP, you can't use the live example
|
|
40
|
+
at <a href="http://openidenabled.com/">openidenabled.com</a> on
|
|
41
|
+
your local provider.)</p>
|
|
42
|
+
</li>
|
|
43
|
+
|
|
44
|
+
<li>Point your browser to this new instance and follow the directions
|
|
45
|
+
below.</li>
|
|
46
|
+
<!-- Fun fact: 'url_for :port => 3001' doesn't work very well. -->
|
|
47
|
+
</ol>
|
|
48
|
+
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<h2>To use the example relying party</h2>
|
|
52
|
+
|
|
53
|
+
<p>Visit <a href="<%= url_for :controller => 'consumer' %>">/consumer</a>
|
|
54
|
+
and enter your OpenID.</p>
|
|
55
|
+
</p>
|
|
56
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<form method="post" action="<%= url_for :controller => 'server', :action => 'decision' %>">
|
|
2
|
+
|
|
3
|
+
<table>
|
|
4
|
+
<tr><td>Site:</td><td><%= @oidreq.trust_root %></td></tr>
|
|
5
|
+
|
|
6
|
+
<% if @oidreq.id_select %>
|
|
7
|
+
<tr>
|
|
8
|
+
<td colspan="2">
|
|
9
|
+
You entered the server identifier at the relying party.
|
|
10
|
+
You'll need to send an identifier of your choosing. Enter a
|
|
11
|
+
username below.
|
|
12
|
+
</td>
|
|
13
|
+
</tr>
|
|
14
|
+
<tr>
|
|
15
|
+
<td>Identity to send:</td>
|
|
16
|
+
<td><input type="text" name="id_to_send" size="25" /></td>
|
|
17
|
+
</tr>
|
|
18
|
+
<% else %>
|
|
19
|
+
<tr><td>Identity:</td><td><%= @oidreq.identity %></td></tr>
|
|
20
|
+
<% end %>
|
|
21
|
+
</table>
|
|
22
|
+
|
|
23
|
+
<input type="submit" name="yes" value="yes" />
|
|
24
|
+
<input type="submit" name="no" value="no" />
|
|
25
|
+
|
|
26
|
+
</form>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Don't change this file. Configuration is done in config/environment.rb and config/environments/*.rb
|
|
2
|
+
|
|
3
|
+
unless defined?(RAILS_ROOT)
|
|
4
|
+
root_path = File.join(File.dirname(__FILE__), '..')
|
|
5
|
+
unless RUBY_PLATFORM =~ /mswin32/
|
|
6
|
+
require 'pathname'
|
|
7
|
+
root_path = Pathname.new(root_path).cleanpath(true).to_s
|
|
8
|
+
end
|
|
9
|
+
RAILS_ROOT = root_path
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
if File.directory?("#{RAILS_ROOT}/vendor/rails")
|
|
13
|
+
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
|
|
14
|
+
else
|
|
15
|
+
require 'rubygems'
|
|
16
|
+
require 'initializer'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Rails::Initializer.run(:set_load_path)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# MySQL (default setup). Versions 4.1 and 5.0 are recommended.
|
|
2
|
+
#
|
|
3
|
+
# Get the fast C bindings:
|
|
4
|
+
# gem install mysql
|
|
5
|
+
# (on OS X: gem install mysql -- --include=/usr/local/lib)
|
|
6
|
+
# And be sure to use new-style password hashing:
|
|
7
|
+
# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
|
|
8
|
+
development:
|
|
9
|
+
adapter: sqlite3
|
|
10
|
+
database: db/development.sqlite3
|
|
11
|
+
|
|
12
|
+
# Warning: The database defined as 'test' will be erased and
|
|
13
|
+
# re-generated from your development database when you run 'rake'.
|
|
14
|
+
# Do not set this db to the same as development or production.
|
|
15
|
+
test:
|
|
16
|
+
adapter: sqlite3
|
|
17
|
+
database: ":memory:"
|
|
18
|
+
|
|
19
|
+
production:
|
|
20
|
+
adapter: mysql
|
|
21
|
+
database: rails_server_production
|
|
22
|
+
username: root
|
|
23
|
+
password:
|
|
24
|
+
socket: /path/to/your/mysql.sock
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# PostgreSQL versions 7.4 - 8.1
|
|
28
|
+
#
|
|
29
|
+
# Get the C bindings:
|
|
30
|
+
# gem install postgres
|
|
31
|
+
# or use the pure-Ruby bindings on Windows:
|
|
32
|
+
# gem install postgres-pr
|
|
33
|
+
postgresql_example:
|
|
34
|
+
adapter: postgresql
|
|
35
|
+
database: rails_server_development
|
|
36
|
+
username: rails_server
|
|
37
|
+
password:
|
|
38
|
+
|
|
39
|
+
# Connect on a TCP socket. Omitted by default since the client uses a
|
|
40
|
+
# domain socket that doesn't need configuration.
|
|
41
|
+
#host: remote-database
|
|
42
|
+
#port: 5432
|
|
43
|
+
|
|
44
|
+
# Schema search path. The server defaults to $user,public
|
|
45
|
+
#schema_search_path: myapp,sharedapp,public
|
|
46
|
+
|
|
47
|
+
# Character set encoding. The server defaults to sql_ascii.
|
|
48
|
+
#encoding: UTF8
|
|
49
|
+
|
|
50
|
+
# Minimum log levels, in increasing order:
|
|
51
|
+
# debug5, debug4, debug3, debug2, debug1,
|
|
52
|
+
# info, notice, warning, error, log, fatal, or panic
|
|
53
|
+
# The server defaults to notice.
|
|
54
|
+
#min_messages: warning
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# SQLite version 2.x
|
|
58
|
+
# gem install sqlite-ruby
|
|
59
|
+
sqlite_example:
|
|
60
|
+
adapter: sqlite
|
|
61
|
+
database: db/development.sqlite2
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# SQLite version 3.x
|
|
65
|
+
# gem install sqlite3-ruby
|
|
66
|
+
sqlite3_example:
|
|
67
|
+
adapter: sqlite3
|
|
68
|
+
database: db/development.sqlite3
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# In-memory SQLite 3 database. Useful for tests.
|
|
72
|
+
sqlite3_in_memory_example:
|
|
73
|
+
adapter: sqlite3
|
|
74
|
+
database: ":memory:"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Be sure to restart your web server when you modify this file.
|
|
2
|
+
|
|
3
|
+
# Uncomment below to force Rails into production mode when
|
|
4
|
+
# you don't control web/app server and can't set it the proper way
|
|
5
|
+
# ENV['RAILS_ENV'] ||= 'production'
|
|
6
|
+
|
|
7
|
+
# Bootstrap the Rails environment, frameworks, and default configuration
|
|
8
|
+
require File.join(File.dirname(__FILE__), 'boot')
|
|
9
|
+
|
|
10
|
+
Rails::Initializer.run do |config|
|
|
11
|
+
# Settings in config/environments/* take precedence those specified here
|
|
12
|
+
|
|
13
|
+
# Skip frameworks you're not going to use
|
|
14
|
+
# config.frameworks -= [ :action_web_service, :action_mailer ]
|
|
15
|
+
|
|
16
|
+
# Add additional load paths for your own custom dirs
|
|
17
|
+
# config.load_paths += %W( #{RAILS_ROOT}/extras )
|
|
18
|
+
|
|
19
|
+
# Force all environments to use the same logger level
|
|
20
|
+
# (by default production uses :info, the others :debug)
|
|
21
|
+
# config.log_level = :debug
|
|
22
|
+
|
|
23
|
+
# Use the database for sessions instead of the file system
|
|
24
|
+
# (create the session table with 'rake create_sessions_table')
|
|
25
|
+
# config.action_controller.session_store = :active_record_store
|
|
26
|
+
|
|
27
|
+
# Enable page/fragment caching by setting a file-based store
|
|
28
|
+
# (remember to create the caching directory and make it readable to the application)
|
|
29
|
+
# config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache"
|
|
30
|
+
|
|
31
|
+
# Activate observers that should always be running
|
|
32
|
+
# config.active_record.observers = :cacher, :garbage_collector
|
|
33
|
+
|
|
34
|
+
# Make Active Record use UTC-base instead of local time
|
|
35
|
+
# config.active_record.default_timezone = :utc
|
|
36
|
+
|
|
37
|
+
# Use Active Record's schema dumper instead of SQL when creating the test database
|
|
38
|
+
# (enables use of different database adapters for development and test environments)
|
|
39
|
+
# config.active_record.schema_format = :ruby
|
|
40
|
+
|
|
41
|
+
# See Rails::Configuration for more options
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Add new inflection rules using the following format
|
|
45
|
+
# (all these examples are active by default):
|
|
46
|
+
# Inflector.inflections do |inflect|
|
|
47
|
+
# inflect.plural /^(ox)$/i, '\1en'
|
|
48
|
+
# inflect.singular /^(ox)en/i, '\1'
|
|
49
|
+
# inflect.irregular 'person', 'people'
|
|
50
|
+
# inflect.uncountable %w( fish sheep )
|
|
51
|
+
# end
|
|
52
|
+
|
|
53
|
+
# Include your application configuration below
|
|
54
|
+
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_key] = '_session_id_2'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Settings specified here will take precedence over those in config/environment.rb
|
|
2
|
+
|
|
3
|
+
# In the development environment your application's code is reloaded on
|
|
4
|
+
# every request. This slows down response time but is perfect for development
|
|
5
|
+
# since you don't have to restart the webserver when you make code changes.
|
|
6
|
+
config.cache_classes = false
|
|
7
|
+
|
|
8
|
+
# Log error messages when you accidentally call methods on nil.
|
|
9
|
+
config.whiny_nils = true
|
|
10
|
+
|
|
11
|
+
# Enable the breakpoint server that script/breakpointer connects to
|
|
12
|
+
config.breakpoint_server = true
|
|
13
|
+
|
|
14
|
+
# Show full error reports and disable caching
|
|
15
|
+
config.action_controller.consider_all_requests_local = true
|
|
16
|
+
config.action_controller.perform_caching = false
|
|
17
|
+
|
|
18
|
+
# Don't care if the mailer can't send
|
|
19
|
+
config.action_mailer.raise_delivery_errors = false
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Settings specified here will take precedence over those in config/environment.rb
|
|
2
|
+
|
|
3
|
+
# The production environment is meant for finished, "live" apps.
|
|
4
|
+
# Code is not reloaded between requests
|
|
5
|
+
config.cache_classes = true
|
|
6
|
+
|
|
7
|
+
# Use a different logger for distributed setups
|
|
8
|
+
# config.logger = SyslogLogger.new
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Full error reports are disabled and caching is turned on
|
|
12
|
+
config.action_controller.consider_all_requests_local = false
|
|
13
|
+
config.action_controller.perform_caching = true
|
|
14
|
+
|
|
15
|
+
# Enable serving of images, stylesheets, and javascripts from an asset server
|
|
16
|
+
# config.action_controller.asset_host = "http://assets.example.com"
|
|
17
|
+
|
|
18
|
+
# Disable delivery errors if you bad email addresses should just be ignored
|
|
19
|
+
# config.action_mailer.raise_delivery_errors = false
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Settings specified here will take precedence over those in config/environment.rb
|
|
2
|
+
|
|
3
|
+
# The test environment is used exclusively to run your application's
|
|
4
|
+
# test suite. You never need to work with it otherwise. Remember that
|
|
5
|
+
# your test database is "scratch space" for the test suite and is wiped
|
|
6
|
+
# and recreated between test runs. Don't rely on the data there!
|
|
7
|
+
config.cache_classes = true
|
|
8
|
+
|
|
9
|
+
# Log error messages when you accidentally call methods on nil.
|
|
10
|
+
config.whiny_nils = true
|
|
11
|
+
|
|
12
|
+
# Show full error reports and disable caching
|
|
13
|
+
config.action_controller.consider_all_requests_local = true
|
|
14
|
+
config.action_controller.perform_caching = false
|
|
15
|
+
|
|
16
|
+
# Tell ActionMailer not to deliver emails to the real world.
|
|
17
|
+
# The :test delivery method accumulates sent emails in the
|
|
18
|
+
# ActionMailer::Base.deliveries array.
|
|
19
|
+
config.action_mailer.delivery_method = :test
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
ActionController::Routing::Routes.draw do |map|
|
|
2
|
+
# Add your own custom routes here.
|
|
3
|
+
# The priority is based upon order of creation: first created -> highest priority.
|
|
4
|
+
|
|
5
|
+
# Here's a sample route:
|
|
6
|
+
# map.connect 'products/:id', :controller => 'catalog', :action => 'view'
|
|
7
|
+
# Keep in mind you can assign values other than :controller and :action
|
|
8
|
+
|
|
9
|
+
# You can have the root of your site routed by hooking up ''
|
|
10
|
+
# -- just remember to delete public/index.html.
|
|
11
|
+
# map.connect '', :controller => "welcome"
|
|
12
|
+
|
|
13
|
+
map.connect '', :controller => 'login'
|
|
14
|
+
map.connect 'server/xrds', :controller => 'server', :action => 'idp_xrds'
|
|
15
|
+
map.connect 'user/:username', :controller => 'server', :action => 'user_page'
|
|
16
|
+
map.connect 'user/:username/xrds', :controller => 'server', :action => 'user_xrds'
|
|
17
|
+
|
|
18
|
+
# Allow downloading Web Service WSDL as a file with an extension
|
|
19
|
+
# instead of a file named 'wsdl'
|
|
20
|
+
map.connect ':controller/service.wsdl', :action => 'wsdl'
|
|
21
|
+
|
|
22
|
+
# Install the default route as the lowest priority.
|
|
23
|
+
map.connect ':controller/:action/:id'
|
|
24
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
|
2
|
+
"http://www.w3.org/TR/html4/loose.dtd">
|
|
3
|
+
<html>
|
|
4
|
+
<body>
|
|
5
|
+
<h1>Application error (Apache)</h1>
|
|
6
|
+
<p>Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html</p>
|
|
7
|
+
</body>
|
|
8
|
+
</html>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/ruby1.8
|
|
2
|
+
|
|
3
|
+
#!/usr/local/bin/ruby
|
|
4
|
+
|
|
5
|
+
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
|
|
6
|
+
|
|
7
|
+
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
|
|
8
|
+
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
|
|
9
|
+
require "dispatcher"
|
|
10
|
+
|
|
11
|
+
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
|
|
12
|
+
Dispatcher.dispatch
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/ruby1.8
|
|
2
|
+
|
|
3
|
+
#!/usr/local/bin/ruby
|
|
4
|
+
#
|
|
5
|
+
# You may specify the path to the FastCGI crash log (a log of unhandled
|
|
6
|
+
# exceptions which forced the FastCGI instance to exit, great for debugging)
|
|
7
|
+
# and the number of requests to process before running garbage collection.
|
|
8
|
+
#
|
|
9
|
+
# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
|
|
10
|
+
# and the GC period is nil (turned off). A reasonable number of requests
|
|
11
|
+
# could range from 10-100 depending on the memory footprint of your app.
|
|
12
|
+
#
|
|
13
|
+
# Example:
|
|
14
|
+
# # Default log path, normal GC behavior.
|
|
15
|
+
# RailsFCGIHandler.process!
|
|
16
|
+
#
|
|
17
|
+
# # Default log path, 50 requests between GC.
|
|
18
|
+
# RailsFCGIHandler.process! nil, 50
|
|
19
|
+
#
|
|
20
|
+
# # Custom log path, normal GC behavior.
|
|
21
|
+
# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
|
|
22
|
+
#
|
|
23
|
+
require File.dirname(__FILE__) + "/../config/environment"
|
|
24
|
+
require 'fcgi_handler'
|
|
25
|
+
|
|
26
|
+
RailsFCGIHandler.process!
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/ruby1.8
|
|
2
|
+
|
|
3
|
+
#!/usr/local/bin/ruby
|
|
4
|
+
|
|
5
|
+
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
|
|
6
|
+
|
|
7
|
+
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
|
|
8
|
+
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
|
|
9
|
+
require "dispatcher"
|
|
10
|
+
|
|
11
|
+
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
|
|
12
|
+
Dispatcher.dispatch
|
|
File without changes
|
|
Binary file
|
|
@@ -0,0 +1,750 @@
|
|
|
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)
|
|
3
|
+
// (c) 2005 Jon Tirsen (http://www.tirsen.com)
|
|
4
|
+
// Contributors:
|
|
5
|
+
// Richard Livsey
|
|
6
|
+
// Rahul Bhargava
|
|
7
|
+
// Rob Wills
|
|
8
|
+
//
|
|
9
|
+
// See scriptaculous.js for full license.
|
|
10
|
+
|
|
11
|
+
// Autocompleter.Base handles all the autocompletion functionality
|
|
12
|
+
// that's independent of the data source for autocompletion. This
|
|
13
|
+
// includes drawing the autocompletion menu, observing keyboard
|
|
14
|
+
// and mouse events, and similar.
|
|
15
|
+
//
|
|
16
|
+
// Specific autocompleters need to provide, at the very least,
|
|
17
|
+
// a getUpdatedChoices function that will be invoked every time
|
|
18
|
+
// the text inside the monitored textbox changes. This method
|
|
19
|
+
// should get the text for which to provide autocompletion by
|
|
20
|
+
// invoking this.getToken(), NOT by directly accessing
|
|
21
|
+
// this.element.value. This is to allow incremental tokenized
|
|
22
|
+
// autocompletion. Specific auto-completion logic (AJAX, etc)
|
|
23
|
+
// belongs in getUpdatedChoices.
|
|
24
|
+
//
|
|
25
|
+
// Tokenized incremental autocompletion is enabled automatically
|
|
26
|
+
// when an autocompleter is instantiated with the 'tokens' option
|
|
27
|
+
// in the options parameter, e.g.:
|
|
28
|
+
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
|
|
29
|
+
// will incrementally autocomplete with a comma as the token.
|
|
30
|
+
// Additionally, ',' in the above example can be replaced with
|
|
31
|
+
// a token array, e.g. { tokens: [',', '\n'] } which
|
|
32
|
+
// enables autocompletion on multiple tokens. This is most
|
|
33
|
+
// useful when one of the tokens is \n (a newline), as it
|
|
34
|
+
// allows smart autocompletion after linebreaks.
|
|
35
|
+
|
|
36
|
+
var Autocompleter = {}
|
|
37
|
+
Autocompleter.Base = function() {};
|
|
38
|
+
Autocompleter.Base.prototype = {
|
|
39
|
+
baseInitialize: function(element, update, options) {
|
|
40
|
+
this.element = $(element);
|
|
41
|
+
this.update = $(update);
|
|
42
|
+
this.hasFocus = false;
|
|
43
|
+
this.changed = false;
|
|
44
|
+
this.active = false;
|
|
45
|
+
this.index = 0;
|
|
46
|
+
this.entryCount = 0;
|
|
47
|
+
|
|
48
|
+
if (this.setOptions)
|
|
49
|
+
this.setOptions(options);
|
|
50
|
+
else
|
|
51
|
+
this.options = options || {};
|
|
52
|
+
|
|
53
|
+
this.options.paramName = this.options.paramName || this.element.name;
|
|
54
|
+
this.options.tokens = this.options.tokens || [];
|
|
55
|
+
this.options.frequency = this.options.frequency || 0.4;
|
|
56
|
+
this.options.minChars = this.options.minChars || 1;
|
|
57
|
+
this.options.onShow = this.options.onShow ||
|
|
58
|
+
function(element, update){
|
|
59
|
+
if(!update.style.position || update.style.position=='absolute') {
|
|
60
|
+
update.style.position = 'absolute';
|
|
61
|
+
Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
|
|
62
|
+
}
|
|
63
|
+
Effect.Appear(update,{duration:0.15});
|
|
64
|
+
};
|
|
65
|
+
this.options.onHide = this.options.onHide ||
|
|
66
|
+
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
|
67
|
+
|
|
68
|
+
if (typeof(this.options.tokens) == 'string')
|
|
69
|
+
this.options.tokens = new Array(this.options.tokens);
|
|
70
|
+
|
|
71
|
+
this.observer = null;
|
|
72
|
+
|
|
73
|
+
this.element.setAttribute('autocomplete','off');
|
|
74
|
+
|
|
75
|
+
Element.hide(this.update);
|
|
76
|
+
|
|
77
|
+
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
|
|
78
|
+
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
show: function() {
|
|
82
|
+
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
|
|
83
|
+
if(!this.iefix &&
|
|
84
|
+
(navigator.appVersion.indexOf('MSIE')>0) &&
|
|
85
|
+
(navigator.userAgent.indexOf('Opera')<0) &&
|
|
86
|
+
(Element.getStyle(this.update, 'position')=='absolute')) {
|
|
87
|
+
new Insertion.After(this.update,
|
|
88
|
+
'<iframe id="' + this.update.id + '_iefix" '+
|
|
89
|
+
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
|
|
90
|
+
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
|
|
91
|
+
this.iefix = $(this.update.id+'_iefix');
|
|
92
|
+
}
|
|
93
|
+
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
fixIEOverlapping: function() {
|
|
97
|
+
Position.clone(this.update, this.iefix);
|
|
98
|
+
this.iefix.style.zIndex = 1;
|
|
99
|
+
this.update.style.zIndex = 2;
|
|
100
|
+
Element.show(this.iefix);
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
hide: function() {
|
|
104
|
+
this.stopIndicator();
|
|
105
|
+
if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
|
|
106
|
+
if(this.iefix) Element.hide(this.iefix);
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
startIndicator: function() {
|
|
110
|
+
if(this.options.indicator) Element.show(this.options.indicator);
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
stopIndicator: function() {
|
|
114
|
+
if(this.options.indicator) Element.hide(this.options.indicator);
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
onKeyPress: function(event) {
|
|
118
|
+
if(this.active)
|
|
119
|
+
switch(event.keyCode) {
|
|
120
|
+
case Event.KEY_TAB:
|
|
121
|
+
case Event.KEY_RETURN:
|
|
122
|
+
this.selectEntry();
|
|
123
|
+
Event.stop(event);
|
|
124
|
+
case Event.KEY_ESC:
|
|
125
|
+
this.hide();
|
|
126
|
+
this.active = false;
|
|
127
|
+
Event.stop(event);
|
|
128
|
+
return;
|
|
129
|
+
case Event.KEY_LEFT:
|
|
130
|
+
case Event.KEY_RIGHT:
|
|
131
|
+
return;
|
|
132
|
+
case Event.KEY_UP:
|
|
133
|
+
this.markPrevious();
|
|
134
|
+
this.render();
|
|
135
|
+
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
|
|
136
|
+
return;
|
|
137
|
+
case Event.KEY_DOWN:
|
|
138
|
+
this.markNext();
|
|
139
|
+
this.render();
|
|
140
|
+
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
else
|
|
144
|
+
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
|
|
145
|
+
return;
|
|
146
|
+
|
|
147
|
+
this.changed = true;
|
|
148
|
+
this.hasFocus = true;
|
|
149
|
+
|
|
150
|
+
if(this.observer) clearTimeout(this.observer);
|
|
151
|
+
this.observer =
|
|
152
|
+
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
onHover: function(event) {
|
|
156
|
+
var element = Event.findElement(event, 'LI');
|
|
157
|
+
if(this.index != element.autocompleteIndex)
|
|
158
|
+
{
|
|
159
|
+
this.index = element.autocompleteIndex;
|
|
160
|
+
this.render();
|
|
161
|
+
}
|
|
162
|
+
Event.stop(event);
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
onClick: function(event) {
|
|
166
|
+
var element = Event.findElement(event, 'LI');
|
|
167
|
+
this.index = element.autocompleteIndex;
|
|
168
|
+
this.selectEntry();
|
|
169
|
+
this.hide();
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
onBlur: function(event) {
|
|
173
|
+
// needed to make click events working
|
|
174
|
+
setTimeout(this.hide.bind(this), 250);
|
|
175
|
+
this.hasFocus = false;
|
|
176
|
+
this.active = false;
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
render: function() {
|
|
180
|
+
if(this.entryCount > 0) {
|
|
181
|
+
for (var i = 0; i < this.entryCount; i++)
|
|
182
|
+
this.index==i ?
|
|
183
|
+
Element.addClassName(this.getEntry(i),"selected") :
|
|
184
|
+
Element.removeClassName(this.getEntry(i),"selected");
|
|
185
|
+
|
|
186
|
+
if(this.hasFocus) {
|
|
187
|
+
this.show();
|
|
188
|
+
this.active = true;
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
this.active = false;
|
|
192
|
+
this.hide();
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
markPrevious: function() {
|
|
197
|
+
if(this.index > 0) this.index--
|
|
198
|
+
else this.index = this.entryCount-1;
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
markNext: function() {
|
|
202
|
+
if(this.index < this.entryCount-1) this.index++
|
|
203
|
+
else this.index = 0;
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
getEntry: function(index) {
|
|
207
|
+
return this.update.firstChild.childNodes[index];
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
getCurrentEntry: function() {
|
|
211
|
+
return this.getEntry(this.index);
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
selectEntry: function() {
|
|
215
|
+
this.active = false;
|
|
216
|
+
this.updateElement(this.getCurrentEntry());
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
updateElement: function(selectedElement) {
|
|
220
|
+
if (this.options.updateElement) {
|
|
221
|
+
this.options.updateElement(selectedElement);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
|
|
226
|
+
var lastTokenPos = this.findLastToken();
|
|
227
|
+
if (lastTokenPos != -1) {
|
|
228
|
+
var newValue = this.element.value.substr(0, lastTokenPos + 1);
|
|
229
|
+
var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
|
|
230
|
+
if (whitespace)
|
|
231
|
+
newValue += whitespace[0];
|
|
232
|
+
this.element.value = newValue + value;
|
|
233
|
+
} else {
|
|
234
|
+
this.element.value = value;
|
|
235
|
+
}
|
|
236
|
+
this.element.focus();
|
|
237
|
+
|
|
238
|
+
if (this.options.afterUpdateElement)
|
|
239
|
+
this.options.afterUpdateElement(this.element, selectedElement);
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
updateChoices: function(choices) {
|
|
243
|
+
if(!this.changed && this.hasFocus) {
|
|
244
|
+
this.update.innerHTML = choices;
|
|
245
|
+
Element.cleanWhitespace(this.update);
|
|
246
|
+
Element.cleanWhitespace(this.update.firstChild);
|
|
247
|
+
|
|
248
|
+
if(this.update.firstChild && this.update.firstChild.childNodes) {
|
|
249
|
+
this.entryCount =
|
|
250
|
+
this.update.firstChild.childNodes.length;
|
|
251
|
+
for (var i = 0; i < this.entryCount; i++) {
|
|
252
|
+
var entry = this.getEntry(i);
|
|
253
|
+
entry.autocompleteIndex = i;
|
|
254
|
+
this.addObservers(entry);
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
this.entryCount = 0;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this.stopIndicator();
|
|
261
|
+
|
|
262
|
+
this.index = 0;
|
|
263
|
+
this.render();
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
addObservers: function(element) {
|
|
268
|
+
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
|
269
|
+
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
onObserverEvent: function() {
|
|
273
|
+
this.changed = false;
|
|
274
|
+
if(this.getToken().length>=this.options.minChars) {
|
|
275
|
+
this.startIndicator();
|
|
276
|
+
this.getUpdatedChoices();
|
|
277
|
+
} else {
|
|
278
|
+
this.active = false;
|
|
279
|
+
this.hide();
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
getToken: function() {
|
|
284
|
+
var tokenPos = this.findLastToken();
|
|
285
|
+
if (tokenPos != -1)
|
|
286
|
+
var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
|
|
287
|
+
else
|
|
288
|
+
var ret = this.element.value;
|
|
289
|
+
|
|
290
|
+
return /\n/.test(ret) ? '' : ret;
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
findLastToken: function() {
|
|
294
|
+
var lastTokenPos = -1;
|
|
295
|
+
|
|
296
|
+
for (var i=0; i<this.options.tokens.length; i++) {
|
|
297
|
+
var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
|
|
298
|
+
if (thisTokenPos > lastTokenPos)
|
|
299
|
+
lastTokenPos = thisTokenPos;
|
|
300
|
+
}
|
|
301
|
+
return lastTokenPos;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
Ajax.Autocompleter = Class.create();
|
|
306
|
+
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
|
|
307
|
+
initialize: function(element, update, url, options) {
|
|
308
|
+
this.baseInitialize(element, update, options);
|
|
309
|
+
this.options.asynchronous = true;
|
|
310
|
+
this.options.onComplete = this.onComplete.bind(this);
|
|
311
|
+
this.options.defaultParams = this.options.parameters || null;
|
|
312
|
+
this.url = url;
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
getUpdatedChoices: function() {
|
|
316
|
+
entry = encodeURIComponent(this.options.paramName) + '=' +
|
|
317
|
+
encodeURIComponent(this.getToken());
|
|
318
|
+
|
|
319
|
+
this.options.parameters = this.options.callback ?
|
|
320
|
+
this.options.callback(this.element, entry) : entry;
|
|
321
|
+
|
|
322
|
+
if(this.options.defaultParams)
|
|
323
|
+
this.options.parameters += '&' + this.options.defaultParams;
|
|
324
|
+
|
|
325
|
+
new Ajax.Request(this.url, this.options);
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
onComplete: function(request) {
|
|
329
|
+
this.updateChoices(request.responseText);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// The local array autocompleter. Used when you'd prefer to
|
|
335
|
+
// inject an array of autocompletion options into the page, rather
|
|
336
|
+
// than sending out Ajax queries, which can be quite slow sometimes.
|
|
337
|
+
//
|
|
338
|
+
// The constructor takes four parameters. The first two are, as usual,
|
|
339
|
+
// the id of the monitored textbox, and id of the autocompletion menu.
|
|
340
|
+
// The third is the array you want to autocomplete from, and the fourth
|
|
341
|
+
// is the options block.
|
|
342
|
+
//
|
|
343
|
+
// Extra local autocompletion options:
|
|
344
|
+
// - choices - How many autocompletion choices to offer
|
|
345
|
+
//
|
|
346
|
+
// - partialSearch - If false, the autocompleter will match entered
|
|
347
|
+
// text only at the beginning of strings in the
|
|
348
|
+
// autocomplete array. Defaults to true, which will
|
|
349
|
+
// match text at the beginning of any *word* in the
|
|
350
|
+
// strings in the autocomplete array. If you want to
|
|
351
|
+
// search anywhere in the string, additionally set
|
|
352
|
+
// the option fullSearch to true (default: off).
|
|
353
|
+
//
|
|
354
|
+
// - fullSsearch - Search anywhere in autocomplete array strings.
|
|
355
|
+
//
|
|
356
|
+
// - partialChars - How many characters to enter before triggering
|
|
357
|
+
// a partial match (unlike minChars, which defines
|
|
358
|
+
// how many characters are required to do any match
|
|
359
|
+
// at all). Defaults to 2.
|
|
360
|
+
//
|
|
361
|
+
// - ignoreCase - Whether to ignore case when autocompleting.
|
|
362
|
+
// Defaults to true.
|
|
363
|
+
//
|
|
364
|
+
// It's possible to pass in a custom function as the 'selector'
|
|
365
|
+
// option, if you prefer to write your own autocompletion logic.
|
|
366
|
+
// In that case, the other options above will not apply unless
|
|
367
|
+
// you support them.
|
|
368
|
+
|
|
369
|
+
Autocompleter.Local = Class.create();
|
|
370
|
+
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
|
371
|
+
initialize: function(element, update, array, options) {
|
|
372
|
+
this.baseInitialize(element, update, options);
|
|
373
|
+
this.options.array = array;
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
getUpdatedChoices: function() {
|
|
377
|
+
this.updateChoices(this.options.selector(this));
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
setOptions: function(options) {
|
|
381
|
+
this.options = Object.extend({
|
|
382
|
+
choices: 10,
|
|
383
|
+
partialSearch: true,
|
|
384
|
+
partialChars: 2,
|
|
385
|
+
ignoreCase: true,
|
|
386
|
+
fullSearch: false,
|
|
387
|
+
selector: function(instance) {
|
|
388
|
+
var ret = []; // Beginning matches
|
|
389
|
+
var partial = []; // Inside matches
|
|
390
|
+
var entry = instance.getToken();
|
|
391
|
+
var count = 0;
|
|
392
|
+
|
|
393
|
+
for (var i = 0; i < instance.options.array.length &&
|
|
394
|
+
ret.length < instance.options.choices ; i++) {
|
|
395
|
+
|
|
396
|
+
var elem = instance.options.array[i];
|
|
397
|
+
var foundPos = instance.options.ignoreCase ?
|
|
398
|
+
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
|
399
|
+
elem.indexOf(entry);
|
|
400
|
+
|
|
401
|
+
while (foundPos != -1) {
|
|
402
|
+
if (foundPos == 0 && elem.length != entry.length) {
|
|
403
|
+
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
|
404
|
+
elem.substr(entry.length) + "</li>");
|
|
405
|
+
break;
|
|
406
|
+
} else if (entry.length >= instance.options.partialChars &&
|
|
407
|
+
instance.options.partialSearch && foundPos != -1) {
|
|
408
|
+
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
|
|
409
|
+
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
|
|
410
|
+
elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
|
|
411
|
+
foundPos + entry.length) + "</li>");
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
foundPos = instance.options.ignoreCase ?
|
|
417
|
+
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
|
|
418
|
+
elem.indexOf(entry, foundPos + 1);
|
|
419
|
+
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (partial.length)
|
|
423
|
+
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
|
424
|
+
return "<ul>" + ret.join('') + "</ul>";
|
|
425
|
+
}
|
|
426
|
+
}, options || {});
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// AJAX in-place editor
|
|
431
|
+
//
|
|
432
|
+
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
|
|
433
|
+
|
|
434
|
+
// Use this if you notice weird scrolling problems on some browsers,
|
|
435
|
+
// the DOM might be a bit confused when this gets called so do this
|
|
436
|
+
// waits 1 ms (with setTimeout) until it does the activation
|
|
437
|
+
Field.scrollFreeActivate = function(field) {
|
|
438
|
+
setTimeout(function() {
|
|
439
|
+
Field.activate(field);
|
|
440
|
+
}, 1);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
Ajax.InPlaceEditor = Class.create();
|
|
444
|
+
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
|
|
445
|
+
Ajax.InPlaceEditor.prototype = {
|
|
446
|
+
initialize: function(element, url, options) {
|
|
447
|
+
this.url = url;
|
|
448
|
+
this.element = $(element);
|
|
449
|
+
|
|
450
|
+
this.options = Object.extend({
|
|
451
|
+
okText: "ok",
|
|
452
|
+
cancelText: "cancel",
|
|
453
|
+
savingText: "Saving...",
|
|
454
|
+
clickToEditText: "Click to edit",
|
|
455
|
+
okText: "ok",
|
|
456
|
+
rows: 1,
|
|
457
|
+
onComplete: function(transport, element) {
|
|
458
|
+
new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
|
|
459
|
+
},
|
|
460
|
+
onFailure: function(transport) {
|
|
461
|
+
alert("Error communicating with the server: " + transport.responseText.stripTags());
|
|
462
|
+
},
|
|
463
|
+
callback: function(form) {
|
|
464
|
+
return Form.serialize(form);
|
|
465
|
+
},
|
|
466
|
+
handleLineBreaks: true,
|
|
467
|
+
loadingText: 'Loading...',
|
|
468
|
+
savingClassName: 'inplaceeditor-saving',
|
|
469
|
+
loadingClassName: 'inplaceeditor-loading',
|
|
470
|
+
formClassName: 'inplaceeditor-form',
|
|
471
|
+
highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
|
|
472
|
+
highlightendcolor: "#FFFFFF",
|
|
473
|
+
externalControl: null,
|
|
474
|
+
ajaxOptions: {}
|
|
475
|
+
}, options || {});
|
|
476
|
+
|
|
477
|
+
if(!this.options.formId && this.element.id) {
|
|
478
|
+
this.options.formId = this.element.id + "-inplaceeditor";
|
|
479
|
+
if ($(this.options.formId)) {
|
|
480
|
+
// there's already a form with that name, don't specify an id
|
|
481
|
+
this.options.formId = null;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (this.options.externalControl) {
|
|
486
|
+
this.options.externalControl = $(this.options.externalControl);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
this.originalBackground = Element.getStyle(this.element, 'background-color');
|
|
490
|
+
if (!this.originalBackground) {
|
|
491
|
+
this.originalBackground = "transparent";
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
this.element.title = this.options.clickToEditText;
|
|
495
|
+
|
|
496
|
+
this.onclickListener = this.enterEditMode.bindAsEventListener(this);
|
|
497
|
+
this.mouseoverListener = this.enterHover.bindAsEventListener(this);
|
|
498
|
+
this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
|
|
499
|
+
Event.observe(this.element, 'click', this.onclickListener);
|
|
500
|
+
Event.observe(this.element, 'mouseover', this.mouseoverListener);
|
|
501
|
+
Event.observe(this.element, 'mouseout', this.mouseoutListener);
|
|
502
|
+
if (this.options.externalControl) {
|
|
503
|
+
Event.observe(this.options.externalControl, 'click', this.onclickListener);
|
|
504
|
+
Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
|
|
505
|
+
Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
enterEditMode: function(evt) {
|
|
509
|
+
if (this.saving) return;
|
|
510
|
+
if (this.editing) return;
|
|
511
|
+
this.editing = true;
|
|
512
|
+
this.onEnterEditMode();
|
|
513
|
+
if (this.options.externalControl) {
|
|
514
|
+
Element.hide(this.options.externalControl);
|
|
515
|
+
}
|
|
516
|
+
Element.hide(this.element);
|
|
517
|
+
this.createForm();
|
|
518
|
+
this.element.parentNode.insertBefore(this.form, this.element);
|
|
519
|
+
Field.scrollFreeActivate(this.editField);
|
|
520
|
+
// stop the event to avoid a page refresh in Safari
|
|
521
|
+
if (evt) {
|
|
522
|
+
Event.stop(evt);
|
|
523
|
+
}
|
|
524
|
+
return false;
|
|
525
|
+
},
|
|
526
|
+
createForm: function() {
|
|
527
|
+
this.form = document.createElement("form");
|
|
528
|
+
this.form.id = this.options.formId;
|
|
529
|
+
Element.addClassName(this.form, this.options.formClassName)
|
|
530
|
+
this.form.onsubmit = this.onSubmit.bind(this);
|
|
531
|
+
|
|
532
|
+
this.createEditField();
|
|
533
|
+
|
|
534
|
+
if (this.options.textarea) {
|
|
535
|
+
var br = document.createElement("br");
|
|
536
|
+
this.form.appendChild(br);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
okButton = document.createElement("input");
|
|
540
|
+
okButton.type = "submit";
|
|
541
|
+
okButton.value = this.options.okText;
|
|
542
|
+
this.form.appendChild(okButton);
|
|
543
|
+
|
|
544
|
+
cancelLink = document.createElement("a");
|
|
545
|
+
cancelLink.href = "#";
|
|
546
|
+
cancelLink.appendChild(document.createTextNode(this.options.cancelText));
|
|
547
|
+
cancelLink.onclick = this.onclickCancel.bind(this);
|
|
548
|
+
this.form.appendChild(cancelLink);
|
|
549
|
+
},
|
|
550
|
+
hasHTMLLineBreaks: function(string) {
|
|
551
|
+
if (!this.options.handleLineBreaks) return false;
|
|
552
|
+
return string.match(/<br/i) || string.match(/<p>/i);
|
|
553
|
+
},
|
|
554
|
+
convertHTMLLineBreaks: function(string) {
|
|
555
|
+
return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
|
|
556
|
+
},
|
|
557
|
+
createEditField: function() {
|
|
558
|
+
var text;
|
|
559
|
+
if(this.options.loadTextURL) {
|
|
560
|
+
text = this.options.loadingText;
|
|
561
|
+
} else {
|
|
562
|
+
text = this.getText();
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
|
|
566
|
+
this.options.textarea = false;
|
|
567
|
+
var textField = document.createElement("input");
|
|
568
|
+
textField.type = "text";
|
|
569
|
+
textField.name = "value";
|
|
570
|
+
textField.value = text;
|
|
571
|
+
textField.style.backgroundColor = this.options.highlightcolor;
|
|
572
|
+
var size = this.options.size || this.options.cols || 0;
|
|
573
|
+
if (size != 0) textField.size = size;
|
|
574
|
+
this.editField = textField;
|
|
575
|
+
} else {
|
|
576
|
+
this.options.textarea = true;
|
|
577
|
+
var textArea = document.createElement("textarea");
|
|
578
|
+
textArea.name = "value";
|
|
579
|
+
textArea.value = this.convertHTMLLineBreaks(text);
|
|
580
|
+
textArea.rows = this.options.rows;
|
|
581
|
+
textArea.cols = this.options.cols || 40;
|
|
582
|
+
this.editField = textArea;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if(this.options.loadTextURL) {
|
|
586
|
+
this.loadExternalText();
|
|
587
|
+
}
|
|
588
|
+
this.form.appendChild(this.editField);
|
|
589
|
+
},
|
|
590
|
+
getText: function() {
|
|
591
|
+
return this.element.innerHTML;
|
|
592
|
+
},
|
|
593
|
+
loadExternalText: function() {
|
|
594
|
+
Element.addClassName(this.form, this.options.loadingClassName);
|
|
595
|
+
this.editField.disabled = true;
|
|
596
|
+
new Ajax.Request(
|
|
597
|
+
this.options.loadTextURL,
|
|
598
|
+
Object.extend({
|
|
599
|
+
asynchronous: true,
|
|
600
|
+
onComplete: this.onLoadedExternalText.bind(this)
|
|
601
|
+
}, this.options.ajaxOptions)
|
|
602
|
+
);
|
|
603
|
+
},
|
|
604
|
+
onLoadedExternalText: function(transport) {
|
|
605
|
+
Element.removeClassName(this.form, this.options.loadingClassName);
|
|
606
|
+
this.editField.disabled = false;
|
|
607
|
+
this.editField.value = transport.responseText.stripTags();
|
|
608
|
+
},
|
|
609
|
+
onclickCancel: function() {
|
|
610
|
+
this.onComplete();
|
|
611
|
+
this.leaveEditMode();
|
|
612
|
+
return false;
|
|
613
|
+
},
|
|
614
|
+
onFailure: function(transport) {
|
|
615
|
+
this.options.onFailure(transport);
|
|
616
|
+
if (this.oldInnerHTML) {
|
|
617
|
+
this.element.innerHTML = this.oldInnerHTML;
|
|
618
|
+
this.oldInnerHTML = null;
|
|
619
|
+
}
|
|
620
|
+
return false;
|
|
621
|
+
},
|
|
622
|
+
onSubmit: function() {
|
|
623
|
+
// onLoading resets these so we need to save them away for the Ajax call
|
|
624
|
+
var form = this.form;
|
|
625
|
+
var value = this.editField.value;
|
|
626
|
+
|
|
627
|
+
// do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
|
|
628
|
+
// which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
|
|
629
|
+
// to be displayed indefinitely
|
|
630
|
+
this.onLoading();
|
|
631
|
+
|
|
632
|
+
new Ajax.Updater(
|
|
633
|
+
{
|
|
634
|
+
success: this.element,
|
|
635
|
+
// don't update on failure (this could be an option)
|
|
636
|
+
failure: null
|
|
637
|
+
},
|
|
638
|
+
this.url,
|
|
639
|
+
Object.extend({
|
|
640
|
+
parameters: this.options.callback(form, value),
|
|
641
|
+
onComplete: this.onComplete.bind(this),
|
|
642
|
+
onFailure: this.onFailure.bind(this)
|
|
643
|
+
}, this.options.ajaxOptions)
|
|
644
|
+
);
|
|
645
|
+
// stop the event to avoid a page refresh in Safari
|
|
646
|
+
if (arguments.length > 1) {
|
|
647
|
+
Event.stop(arguments[0]);
|
|
648
|
+
}
|
|
649
|
+
return false;
|
|
650
|
+
},
|
|
651
|
+
onLoading: function() {
|
|
652
|
+
this.saving = true;
|
|
653
|
+
this.removeForm();
|
|
654
|
+
this.leaveHover();
|
|
655
|
+
this.showSaving();
|
|
656
|
+
},
|
|
657
|
+
showSaving: function() {
|
|
658
|
+
this.oldInnerHTML = this.element.innerHTML;
|
|
659
|
+
this.element.innerHTML = this.options.savingText;
|
|
660
|
+
Element.addClassName(this.element, this.options.savingClassName);
|
|
661
|
+
this.element.style.backgroundColor = this.originalBackground;
|
|
662
|
+
Element.show(this.element);
|
|
663
|
+
},
|
|
664
|
+
removeForm: function() {
|
|
665
|
+
if(this.form) {
|
|
666
|
+
if (this.form.parentNode) Element.remove(this.form);
|
|
667
|
+
this.form = null;
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
enterHover: function() {
|
|
671
|
+
if (this.saving) return;
|
|
672
|
+
this.element.style.backgroundColor = this.options.highlightcolor;
|
|
673
|
+
if (this.effect) {
|
|
674
|
+
this.effect.cancel();
|
|
675
|
+
}
|
|
676
|
+
Element.addClassName(this.element, this.options.hoverClassName)
|
|
677
|
+
},
|
|
678
|
+
leaveHover: function() {
|
|
679
|
+
if (this.options.backgroundColor) {
|
|
680
|
+
this.element.style.backgroundColor = this.oldBackground;
|
|
681
|
+
}
|
|
682
|
+
Element.removeClassName(this.element, this.options.hoverClassName)
|
|
683
|
+
if (this.saving) return;
|
|
684
|
+
this.effect = new Effect.Highlight(this.element, {
|
|
685
|
+
startcolor: this.options.highlightcolor,
|
|
686
|
+
endcolor: this.options.highlightendcolor,
|
|
687
|
+
restorecolor: this.originalBackground
|
|
688
|
+
});
|
|
689
|
+
},
|
|
690
|
+
leaveEditMode: function() {
|
|
691
|
+
Element.removeClassName(this.element, this.options.savingClassName);
|
|
692
|
+
this.removeForm();
|
|
693
|
+
this.leaveHover();
|
|
694
|
+
this.element.style.backgroundColor = this.originalBackground;
|
|
695
|
+
Element.show(this.element);
|
|
696
|
+
if (this.options.externalControl) {
|
|
697
|
+
Element.show(this.options.externalControl);
|
|
698
|
+
}
|
|
699
|
+
this.editing = false;
|
|
700
|
+
this.saving = false;
|
|
701
|
+
this.oldInnerHTML = null;
|
|
702
|
+
this.onLeaveEditMode();
|
|
703
|
+
},
|
|
704
|
+
onComplete: function(transport) {
|
|
705
|
+
this.leaveEditMode();
|
|
706
|
+
this.options.onComplete.bind(this)(transport, this.element);
|
|
707
|
+
},
|
|
708
|
+
onEnterEditMode: function() {},
|
|
709
|
+
onLeaveEditMode: function() {},
|
|
710
|
+
dispose: function() {
|
|
711
|
+
if (this.oldInnerHTML) {
|
|
712
|
+
this.element.innerHTML = this.oldInnerHTML;
|
|
713
|
+
}
|
|
714
|
+
this.leaveEditMode();
|
|
715
|
+
Event.stopObserving(this.element, 'click', this.onclickListener);
|
|
716
|
+
Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
|
|
717
|
+
Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
|
|
718
|
+
if (this.options.externalControl) {
|
|
719
|
+
Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
|
|
720
|
+
Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
|
|
721
|
+
Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
// Delayed observer, like Form.Element.Observer,
|
|
727
|
+
// but waits for delay after last key input
|
|
728
|
+
// Ideal for live-search fields
|
|
729
|
+
|
|
730
|
+
Form.Element.DelayedObserver = Class.create();
|
|
731
|
+
Form.Element.DelayedObserver.prototype = {
|
|
732
|
+
initialize: function(element, delay, callback) {
|
|
733
|
+
this.delay = delay || 0.5;
|
|
734
|
+
this.element = $(element);
|
|
735
|
+
this.callback = callback;
|
|
736
|
+
this.timer = null;
|
|
737
|
+
this.lastValue = $F(this.element);
|
|
738
|
+
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
|
|
739
|
+
},
|
|
740
|
+
delayedListener: function(event) {
|
|
741
|
+
if(this.lastValue == $F(this.element)) return;
|
|
742
|
+
if(this.timer) clearTimeout(this.timer);
|
|
743
|
+
this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
|
|
744
|
+
this.lastValue = $F(this.element);
|
|
745
|
+
},
|
|
746
|
+
onTimerEvent: function() {
|
|
747
|
+
this.timer = null;
|
|
748
|
+
this.callback(this.element, $F(this.element));
|
|
749
|
+
}
|
|
750
|
+
};
|