summaryrefslogtreecommitdiffstats
path: root/public
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2006-12-05 20:45:04 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2006-12-05 20:45:04 +0000
commit96f83cc8f0f032554f771a59da22303cd473b878 (patch)
tree355a0d2ed653a5426c59ebf6a1fe65eba024b4d0 /public
parenteabc04d8368824965d3ac8de3fa84502e9c05d38 (diff)
downloadredmine-96f83cc8f0f032554f771a59da22303cd473b878.tar.gz
redmine-96f83cc8f0f032554f771a59da22303cd473b878.zip
trunk moved from /trunk/redmine to /trunk
git-svn-id: http://redmine.rubyforge.org/svn/trunk@67 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'public')
-rw-r--r--public/.htaccess40
-rw-r--r--public/404.html23
-rw-r--r--public/500.html24
-rw-r--r--public/dispatch.cgi10
-rw-r--r--public/dispatch.fcgi24
-rw-r--r--public/dispatch.rb10
-rw-r--r--public/favicon.ico0
-rw-r--r--public/images/add.pngbin0 -> 336 bytes
-rw-r--r--public/images/admin.pngbin0 -> 716 bytes
-rw-r--r--public/images/alert.pngbin0 -> 483 bytes
-rw-r--r--public/images/arrow_bw.pngbin0 -> 997 bytes
-rw-r--r--public/images/arrow_from.pngbin0 -> 994 bytes
-rw-r--r--public/images/arrow_to.pngbin0 -> 991 bytes
-rw-r--r--public/images/attachment.pngbin0 -> 259 bytes
-rw-r--r--public/images/bulletgreen.pngbin0 -> 193 bytes
-rw-r--r--public/images/bulletred.pngbin0 -> 193 bytes
-rw-r--r--public/images/calendar.pngbin0 -> 196 bytes
-rw-r--r--public/images/close.pngbin0 -> 200 bytes
-rw-r--r--public/images/close_hl.pngbin0 -> 199 bytes
-rw-r--r--public/images/delete.pngbin0 -> 320 bytes
-rw-r--r--public/images/details.pngbin0 -> 224 bytes
-rw-r--r--public/images/dir.pngbin0 -> 314 bytes
-rw-r--r--public/images/dir_new.pngbin0 -> 321 bytes
-rw-r--r--public/images/dir_open.pngbin0 -> 1030 bytes
-rw-r--r--public/images/document.pngbin0 -> 1014 bytes
-rw-r--r--public/images/edit_small.pngbin0 -> 238 bytes
-rw-r--r--public/images/file_new.pngbin0 -> 253 bytes
-rw-r--r--public/images/gantt.pngbin0 -> 218 bytes
-rw-r--r--public/images/help.pngbin0 -> 1079 bytes
-rw-r--r--public/images/home.pngbin0 -> 301 bytes
-rw-r--r--public/images/issues.pngbin0 -> 356 bytes
-rw-r--r--public/images/jstoolbar/bt_br.pngbin0 -> 244 bytes
-rw-r--r--public/images/jstoolbar/bt_code.pngbin0 -> 338 bytes
-rw-r--r--public/images/jstoolbar/bt_del.pngbin0 -> 368 bytes
-rw-r--r--public/images/jstoolbar/bt_em.pngbin0 -> 311 bytes
-rw-r--r--public/images/jstoolbar/bt_ins.pngbin0 -> 322 bytes
-rw-r--r--public/images/jstoolbar/bt_link.pngbin0 -> 900 bytes
-rw-r--r--public/images/jstoolbar/bt_ol.pngbin0 -> 249 bytes
-rw-r--r--public/images/jstoolbar/bt_quote.pngbin0 -> 323 bytes
-rw-r--r--public/images/jstoolbar/bt_strong.pngbin0 -> 355 bytes
-rw-r--r--public/images/jstoolbar/bt_ul.pngbin0 -> 239 bytes
-rw-r--r--public/images/loading.gifbin0 -> 1553 bytes
-rw-r--r--public/images/locked.pngbin0 -> 437 bytes
-rw-r--r--public/images/login.pngbin0 -> 1082 bytes
-rw-r--r--public/images/mailer.pngbin0 -> 294 bytes
-rw-r--r--public/images/notes.pngbin0 -> 996 bytes
-rw-r--r--public/images/options.pngbin0 -> 1005 bytes
-rw-r--r--public/images/package.pngbin0 -> 298 bytes
-rw-r--r--public/images/projects.pngbin0 -> 299 bytes
-rw-r--r--public/images/rails.pngbin0 -> 1787 bytes
-rw-r--r--public/images/rails_powered.pngbin0 -> 262 bytes
-rw-r--r--public/images/rails_small.pngbin0 -> 1140 bytes
-rw-r--r--public/images/role.pngbin0 -> 293 bytes
-rw-r--r--public/images/rss.pngbin0 -> 256 bytes
-rw-r--r--public/images/sort_asc.pngbin0 -> 215 bytes
-rw-r--r--public/images/sort_desc.pngbin0 -> 217 bytes
-rw-r--r--public/images/tracker.pngbin0 -> 356 bytes
-rw-r--r--public/images/true.pngbin0 -> 183 bytes
-rw-r--r--public/images/user.pngbin0 -> 236 bytes
-rw-r--r--public/images/user_new.pngbin0 -> 215 bytes
-rw-r--r--public/images/user_page.pngbin0 -> 292 bytes
-rw-r--r--public/images/users.pngbin0 -> 242 bytes
-rw-r--r--public/images/workflow.pngbin0 -> 285 bytes
-rw-r--r--public/images/zoom_in.pngbin0 -> 593 bytes
-rw-r--r--public/images/zoom_in_g.pngbin0 -> 312 bytes
-rw-r--r--public/images/zoom_out.pngbin0 -> 588 bytes
-rw-r--r--public/images/zoom_out_g.pngbin0 -> 311 bytes
-rw-r--r--public/javascripts/application.js20
-rw-r--r--public/javascripts/calendar/calendar-setup.js200
-rw-r--r--public/javascripts/calendar/calendar.js1806
-rw-r--r--public/javascripts/calendar/lang/calendar-de.js128
-rw-r--r--public/javascripts/calendar/lang/calendar-en.js127
-rw-r--r--public/javascripts/calendar/lang/calendar-es.js129
-rw-r--r--public/javascripts/calendar/lang/calendar-fr.js129
-rw-r--r--public/javascripts/controls.js750
-rw-r--r--public/javascripts/dragdrop.js584
-rw-r--r--public/javascripts/effects.js854
-rw-r--r--public/javascripts/jstoolbar.js440
-rw-r--r--public/javascripts/menu.js556
-rw-r--r--public/javascripts/prototype.js1785
-rw-r--r--public/manual/en/ch01.html3
-rw-r--r--public/manual/en/ch01s01.html3
-rw-r--r--public/manual/en/ch01s02.html3
-rw-r--r--public/manual/en/ch01s03.html3
-rw-r--r--public/manual/en/ch01s04.html3
-rw-r--r--public/manual/en/ch01s05.html3
-rw-r--r--public/manual/en/ch01s06.html3
-rw-r--r--public/manual/en/ch01s07.html3
-rw-r--r--public/manual/en/ch01s08.html3
-rw-r--r--public/manual/en/ch01s09.html3
-rw-r--r--public/manual/en/ch01s10.html3
-rw-r--r--public/manual/en/ch02.html3
-rw-r--r--public/manual/en/ch02s01.html3
-rw-r--r--public/manual/en/ch02s02.html3
-rw-r--r--public/manual/en/ch02s03.html3
-rw-r--r--public/manual/en/ch02s04.html3
-rw-r--r--public/manual/en/ch02s05.html3
-rw-r--r--public/manual/en/ch02s06.html3
-rw-r--r--public/manual/en/ch02s07.html3
-rw-r--r--public/manual/en/ch02s08.html3
-rw-r--r--public/manual/en/html.css55
-rw-r--r--public/manual/en/index.html3
-rw-r--r--public/manual/en/resources/issues_list.pngbin0 -> 8233 bytes
-rw-r--r--public/manual/en/resources/users_list.pngbin0 -> 6502 bytes
-rw-r--r--public/manual/en/resources/workflow.pngbin0 -> 6503 bytes
-rw-r--r--public/manual/fr/ch01.html3
-rw-r--r--public/manual/fr/ch01s01.html3
-rw-r--r--public/manual/fr/ch01s02.html3
-rw-r--r--public/manual/fr/ch01s03.html3
-rw-r--r--public/manual/fr/ch01s04.html3
-rw-r--r--public/manual/fr/ch01s05.html3
-rw-r--r--public/manual/fr/ch01s06.html3
-rw-r--r--public/manual/fr/ch01s07.html3
-rw-r--r--public/manual/fr/ch01s08.html3
-rw-r--r--public/manual/fr/ch01s09.html3
-rw-r--r--public/manual/fr/ch01s10.html3
-rw-r--r--public/manual/fr/ch02.html3
-rw-r--r--public/manual/fr/ch02s01.html3
-rw-r--r--public/manual/fr/ch02s02.html3
-rw-r--r--public/manual/fr/ch02s03.html3
-rw-r--r--public/manual/fr/ch02s04.html3
-rw-r--r--public/manual/fr/ch02s05.html3
-rw-r--r--public/manual/fr/ch02s06.html3
-rw-r--r--public/manual/fr/ch02s07.html3
-rw-r--r--public/manual/fr/ch02s08.html3
-rw-r--r--public/manual/fr/html.css55
-rw-r--r--public/manual/fr/index.html3
-rw-r--r--public/manual/fr/resources/issues_list.pngbin0 -> 8233 bytes
-rw-r--r--public/manual/fr/resources/users_list.pngbin0 -> 6502 bytes
-rw-r--r--public/manual/fr/resources/workflow.pngbin0 -> 6503 bytes
-rw-r--r--public/robots.txt1
-rw-r--r--public/stylesheets/application.css484
-rw-r--r--public/stylesheets/calendar.css231
-rw-r--r--public/stylesheets/jstoolbar.css79
-rw-r--r--public/stylesheets/menu.css39
-rw-r--r--public/stylesheets/rails.css57
136 files changed, 8766 insertions, 0 deletions
diff --git a/public/.htaccess b/public/.htaccess
new file mode 100644
index 000000000..d3c998345
--- /dev/null
+++ b/public/.htaccess
@@ -0,0 +1,40 @@
+# General Apache options
+AddHandler fastcgi-script .fcgi
+AddHandler cgi-script .cgi
+Options +FollowSymLinks +ExecCGI
+
+# If you don't want Rails to look in certain directories,
+# use the following rewrite rules so that Apache won't rewrite certain requests
+#
+# Example:
+# RewriteCond %{REQUEST_URI} ^/notrails.*
+# RewriteRule .* - [L]
+
+# Redirect all requests not available on the filesystem to Rails
+# By default the cgi dispatcher is used which is very slow
+#
+# For better performance replace the dispatcher with the fastcgi one
+#
+# Example:
+# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
+RewriteEngine On
+
+# If your Rails application is accessed via an Alias directive,
+# then you MUST also set the RewriteBase in this htaccess file.
+#
+# Example:
+# Alias /myrailsapp /path/to/myrailsapp/public
+# RewriteBase /myrailsapp
+
+RewriteRule ^$ index.html [QSA]
+RewriteRule ^([^.]+)$ $1.html [QSA]
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
+
+# In case Rails experiences terminal errors
+# Instead of displaying this message you can supply a file here which will be rendered instead
+#
+# Example:
+# ErrorDocument 500 /500.html
+
+ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly" \ No newline at end of file
diff --git a/public/404.html b/public/404.html
new file mode 100644
index 000000000..ddf424b09
--- /dev/null
+++ b/public/404.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<title>redMine 404 error</title>
+<style>
+body{
+font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
+color:#303030;
+margin:10px;
+}
+h1{
+font-size:1.5em;
+}
+p{
+font-size:0.8em;
+}
+</style>
+<body>
+ <h1>Page not found</h1>
+ <p>The page you were trying to access doesn't exist or has been removed.</p>
+ <p><a href="javascript:history.back()">Back</a></p>
+</body>
+</html> \ No newline at end of file
diff --git a/public/500.html b/public/500.html
new file mode 100644
index 000000000..93eb0f128
--- /dev/null
+++ b/public/500.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<title>redMine 500 error</title>
+<style>
+body{
+font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
+color:#303030;
+margin:10px;
+}
+h1{
+font-size:1.5em;
+}
+p{
+font-size:0.8em;
+}
+</style>
+<body>
+ <h1>Internal error</h1>
+ <p>An error occurred on the page you were trying to access.<br />
+ If you continue to experience problems please contact your redMine administrator for assistance.</p>
+ <p><a href="javascript:history.back()">Back</a></p>
+</body>
+</html> \ No newline at end of file
diff --git a/public/dispatch.cgi b/public/dispatch.cgi
new file mode 100644
index 000000000..9730473f2
--- /dev/null
+++ b/public/dispatch.cgi
@@ -0,0 +1,10 @@
+#!/usr/bin/ruby
+
+require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
+
+# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
+# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
+require "dispatcher"
+
+ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
+Dispatcher.dispatch \ No newline at end of file
diff --git a/public/dispatch.fcgi b/public/dispatch.fcgi
new file mode 100644
index 000000000..f934b3002
--- /dev/null
+++ b/public/dispatch.fcgi
@@ -0,0 +1,24 @@
+#!/usr/bin/ruby
+#
+# You may specify the path to the FastCGI crash log (a log of unhandled
+# exceptions which forced the FastCGI instance to exit, great for debugging)
+# and the number of requests to process before running garbage collection.
+#
+# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
+# and the GC period is nil (turned off). A reasonable number of requests
+# could range from 10-100 depending on the memory footprint of your app.
+#
+# Example:
+# # Default log path, normal GC behavior.
+# RailsFCGIHandler.process!
+#
+# # Default log path, 50 requests between GC.
+# RailsFCGIHandler.process! nil, 50
+#
+# # Custom log path, normal GC behavior.
+# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
+#
+require File.dirname(__FILE__) + "/../config/environment"
+require 'fcgi_handler'
+
+RailsFCGIHandler.process!
diff --git a/public/dispatch.rb b/public/dispatch.rb
new file mode 100644
index 000000000..9730473f2
--- /dev/null
+++ b/public/dispatch.rb
@@ -0,0 +1,10 @@
+#!/usr/bin/ruby
+
+require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
+
+# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
+# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
+require "dispatcher"
+
+ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
+Dispatcher.dispatch \ No newline at end of file
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/public/favicon.ico
diff --git a/public/images/add.png b/public/images/add.png
new file mode 100644
index 000000000..90032e9d8
--- /dev/null
+++ b/public/images/add.png
Binary files differ
diff --git a/public/images/admin.png b/public/images/admin.png
new file mode 100644
index 000000000..0c190984f
--- /dev/null
+++ b/public/images/admin.png
Binary files differ
diff --git a/public/images/alert.png b/public/images/alert.png
new file mode 100644
index 000000000..ba107e83b
--- /dev/null
+++ b/public/images/alert.png
Binary files differ
diff --git a/public/images/arrow_bw.png b/public/images/arrow_bw.png
new file mode 100644
index 000000000..52dfc96f0
--- /dev/null
+++ b/public/images/arrow_bw.png
Binary files differ
diff --git a/public/images/arrow_from.png b/public/images/arrow_from.png
new file mode 100644
index 000000000..4d5eeb9ea
--- /dev/null
+++ b/public/images/arrow_from.png
Binary files differ
diff --git a/public/images/arrow_to.png b/public/images/arrow_to.png
new file mode 100644
index 000000000..4f969716f
--- /dev/null
+++ b/public/images/arrow_to.png
Binary files differ
diff --git a/public/images/attachment.png b/public/images/attachment.png
new file mode 100644
index 000000000..eea26921b
--- /dev/null
+++ b/public/images/attachment.png
Binary files differ
diff --git a/public/images/bulletgreen.png b/public/images/bulletgreen.png
new file mode 100644
index 000000000..abe41592b
--- /dev/null
+++ b/public/images/bulletgreen.png
Binary files differ
diff --git a/public/images/bulletred.png b/public/images/bulletred.png
new file mode 100644
index 000000000..26a121057
--- /dev/null
+++ b/public/images/bulletred.png
Binary files differ
diff --git a/public/images/calendar.png b/public/images/calendar.png
new file mode 100644
index 000000000..aa269da38
--- /dev/null
+++ b/public/images/calendar.png
Binary files differ
diff --git a/public/images/close.png b/public/images/close.png
new file mode 100644
index 000000000..3501ed4d5
--- /dev/null
+++ b/public/images/close.png
Binary files differ
diff --git a/public/images/close_hl.png b/public/images/close_hl.png
new file mode 100644
index 000000000..a433f7515
--- /dev/null
+++ b/public/images/close_hl.png
Binary files differ
diff --git a/public/images/delete.png b/public/images/delete.png
new file mode 100644
index 000000000..2ed33bdf3
--- /dev/null
+++ b/public/images/delete.png
Binary files differ
diff --git a/public/images/details.png b/public/images/details.png
new file mode 100644
index 000000000..7c813b04a
--- /dev/null
+++ b/public/images/details.png
Binary files differ
diff --git a/public/images/dir.png b/public/images/dir.png
new file mode 100644
index 000000000..d078094ac
--- /dev/null
+++ b/public/images/dir.png
Binary files differ
diff --git a/public/images/dir_new.png b/public/images/dir_new.png
new file mode 100644
index 000000000..2d29814f2
--- /dev/null
+++ b/public/images/dir_new.png
Binary files differ
diff --git a/public/images/dir_open.png b/public/images/dir_open.png
new file mode 100644
index 000000000..a248cba3c
--- /dev/null
+++ b/public/images/dir_open.png
Binary files differ
diff --git a/public/images/document.png b/public/images/document.png
new file mode 100644
index 000000000..34fde6eb3
--- /dev/null
+++ b/public/images/document.png
Binary files differ
diff --git a/public/images/edit_small.png b/public/images/edit_small.png
new file mode 100644
index 000000000..dea7c92ea
--- /dev/null
+++ b/public/images/edit_small.png
Binary files differ
diff --git a/public/images/file_new.png b/public/images/file_new.png
new file mode 100644
index 000000000..9a12ca732
--- /dev/null
+++ b/public/images/file_new.png
Binary files differ
diff --git a/public/images/gantt.png b/public/images/gantt.png
new file mode 100644
index 000000000..2673d23d2
--- /dev/null
+++ b/public/images/gantt.png
Binary files differ
diff --git a/public/images/help.png b/public/images/help.png
new file mode 100644
index 000000000..da8feb993
--- /dev/null
+++ b/public/images/help.png
Binary files differ
diff --git a/public/images/home.png b/public/images/home.png
new file mode 100644
index 000000000..7a12add6a
--- /dev/null
+++ b/public/images/home.png
Binary files differ
diff --git a/public/images/issues.png b/public/images/issues.png
new file mode 100644
index 000000000..e6948bff7
--- /dev/null
+++ b/public/images/issues.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_br.png b/public/images/jstoolbar/bt_br.png
new file mode 100644
index 000000000..f8211a997
--- /dev/null
+++ b/public/images/jstoolbar/bt_br.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_code.png b/public/images/jstoolbar/bt_code.png
new file mode 100644
index 000000000..52924abf7
--- /dev/null
+++ b/public/images/jstoolbar/bt_code.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_del.png b/public/images/jstoolbar/bt_del.png
new file mode 100644
index 000000000..c6f3a8b40
--- /dev/null
+++ b/public/images/jstoolbar/bt_del.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_em.png b/public/images/jstoolbar/bt_em.png
new file mode 100644
index 000000000..f08de4f30
--- /dev/null
+++ b/public/images/jstoolbar/bt_em.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_ins.png b/public/images/jstoolbar/bt_ins.png
new file mode 100644
index 000000000..f6697db51
--- /dev/null
+++ b/public/images/jstoolbar/bt_ins.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_link.png b/public/images/jstoolbar/bt_link.png
new file mode 100644
index 000000000..9b3acbae5
--- /dev/null
+++ b/public/images/jstoolbar/bt_link.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_ol.png b/public/images/jstoolbar/bt_ol.png
new file mode 100644
index 000000000..2dfaec7c7
--- /dev/null
+++ b/public/images/jstoolbar/bt_ol.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_quote.png b/public/images/jstoolbar/bt_quote.png
new file mode 100644
index 000000000..25b2b8abe
--- /dev/null
+++ b/public/images/jstoolbar/bt_quote.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_strong.png b/public/images/jstoolbar/bt_strong.png
new file mode 100644
index 000000000..7e200d3f6
--- /dev/null
+++ b/public/images/jstoolbar/bt_strong.png
Binary files differ
diff --git a/public/images/jstoolbar/bt_ul.png b/public/images/jstoolbar/bt_ul.png
new file mode 100644
index 000000000..6e20851ec
--- /dev/null
+++ b/public/images/jstoolbar/bt_ul.png
Binary files differ
diff --git a/public/images/loading.gif b/public/images/loading.gif
new file mode 100644
index 000000000..085ccaeca
--- /dev/null
+++ b/public/images/loading.gif
Binary files differ
diff --git a/public/images/locked.png b/public/images/locked.png
new file mode 100644
index 000000000..5199dfe22
--- /dev/null
+++ b/public/images/locked.png
Binary files differ
diff --git a/public/images/login.png b/public/images/login.png
new file mode 100644
index 000000000..7e0c62d9c
--- /dev/null
+++ b/public/images/login.png
Binary files differ
diff --git a/public/images/mailer.png b/public/images/mailer.png
new file mode 100644
index 000000000..8008bb84b
--- /dev/null
+++ b/public/images/mailer.png
Binary files differ
diff --git a/public/images/notes.png b/public/images/notes.png
new file mode 100644
index 000000000..d26b1d577
--- /dev/null
+++ b/public/images/notes.png
Binary files differ
diff --git a/public/images/options.png b/public/images/options.png
new file mode 100644
index 000000000..a907c20f1
--- /dev/null
+++ b/public/images/options.png
Binary files differ
diff --git a/public/images/package.png b/public/images/package.png
new file mode 100644
index 000000000..634d13d9f
--- /dev/null
+++ b/public/images/package.png
Binary files differ
diff --git a/public/images/projects.png b/public/images/projects.png
new file mode 100644
index 000000000..b42347a92
--- /dev/null
+++ b/public/images/projects.png
Binary files differ
diff --git a/public/images/rails.png b/public/images/rails.png
new file mode 100644
index 000000000..b8441f182
--- /dev/null
+++ b/public/images/rails.png
Binary files differ
diff --git a/public/images/rails_powered.png b/public/images/rails_powered.png
new file mode 100644
index 000000000..5255e62de
--- /dev/null
+++ b/public/images/rails_powered.png
Binary files differ
diff --git a/public/images/rails_small.png b/public/images/rails_small.png
new file mode 100644
index 000000000..aff4b7a84
--- /dev/null
+++ b/public/images/rails_small.png
Binary files differ
diff --git a/public/images/role.png b/public/images/role.png
new file mode 100644
index 000000000..ad36d1ca8
--- /dev/null
+++ b/public/images/role.png
Binary files differ
diff --git a/public/images/rss.png b/public/images/rss.png
new file mode 100644
index 000000000..89ce35f80
--- /dev/null
+++ b/public/images/rss.png
Binary files differ
diff --git a/public/images/sort_asc.png b/public/images/sort_asc.png
new file mode 100644
index 000000000..05dfa15f4
--- /dev/null
+++ b/public/images/sort_asc.png
Binary files differ
diff --git a/public/images/sort_desc.png b/public/images/sort_desc.png
new file mode 100644
index 000000000..f82d53917
--- /dev/null
+++ b/public/images/sort_desc.png
Binary files differ
diff --git a/public/images/tracker.png b/public/images/tracker.png
new file mode 100644
index 000000000..f29cfb2af
--- /dev/null
+++ b/public/images/tracker.png
Binary files differ
diff --git a/public/images/true.png b/public/images/true.png
new file mode 100644
index 000000000..9afc0b52a
--- /dev/null
+++ b/public/images/true.png
Binary files differ
diff --git a/public/images/user.png b/public/images/user.png
new file mode 100644
index 000000000..89d591c0b
--- /dev/null
+++ b/public/images/user.png
Binary files differ
diff --git a/public/images/user_new.png b/public/images/user_new.png
new file mode 100644
index 000000000..c7c718822
--- /dev/null
+++ b/public/images/user_new.png
Binary files differ
diff --git a/public/images/user_page.png b/public/images/user_page.png
new file mode 100644
index 000000000..940a7b8e1
--- /dev/null
+++ b/public/images/user_page.png
Binary files differ
diff --git a/public/images/users.png b/public/images/users.png
new file mode 100644
index 000000000..3b9fc5aa9
--- /dev/null
+++ b/public/images/users.png
Binary files differ
diff --git a/public/images/workflow.png b/public/images/workflow.png
new file mode 100644
index 000000000..868332fed
--- /dev/null
+++ b/public/images/workflow.png
Binary files differ
diff --git a/public/images/zoom_in.png b/public/images/zoom_in.png
new file mode 100644
index 000000000..d9abe7f52
--- /dev/null
+++ b/public/images/zoom_in.png
Binary files differ
diff --git a/public/images/zoom_in_g.png b/public/images/zoom_in_g.png
new file mode 100644
index 000000000..72b271c5e
--- /dev/null
+++ b/public/images/zoom_in_g.png
Binary files differ
diff --git a/public/images/zoom_out.png b/public/images/zoom_out.png
new file mode 100644
index 000000000..906e4a4e5
--- /dev/null
+++ b/public/images/zoom_out.png
Binary files differ
diff --git a/public/images/zoom_out_g.png b/public/images/zoom_out_g.png
new file mode 100644
index 000000000..7f2416be2
--- /dev/null
+++ b/public/images/zoom_out_g.png
Binary files differ
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
new file mode 100644
index 000000000..46649130e
--- /dev/null
+++ b/public/javascripts/application.js
@@ -0,0 +1,20 @@
+function checkAll (id, checked) {
+ var el = document.getElementById(id);
+ for (var i = 0; i < el.elements.length; i++) {
+ if (el.elements[i].disabled==false) {
+ el.elements[i].checked = checked;
+ }
+ }
+}
+
+function addFileField() {
+ var f = document.createElement("input");
+ f.type = "file";
+ f.name = "attachments[]";
+ f.size = 30;
+
+ p = document.getElementById("attachments_p");
+ p.appendChild(document.createElement("br"));
+ p.appendChild(document.createElement("br"));
+ p.appendChild(f);
+} \ No newline at end of file
diff --git a/public/javascripts/calendar/calendar-setup.js b/public/javascripts/calendar/calendar-setup.js
new file mode 100644
index 000000000..f2b485430
--- /dev/null
+++ b/public/javascripts/calendar/calendar-setup.js
@@ -0,0 +1,200 @@
+/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/
+ * ---------------------------------------------------------------------------
+ *
+ * The DHTML Calendar
+ *
+ * Details and latest version at:
+ * http://dynarch.com/mishoo/calendar.epl
+ *
+ * This script is distributed under the GNU Lesser General Public License.
+ * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
+ *
+ * This file defines helper functions for setting up the calendar. They are
+ * intended to help non-programmers get a working calendar on their site
+ * quickly. This script should not be seen as part of the calendar. It just
+ * shows you what one can do with the calendar, while in the same time
+ * providing a quick and simple method for setting it up. If you need
+ * exhaustive customization of the calendar creation process feel free to
+ * modify this code to suit your needs (this is recommended and much better
+ * than modifying calendar.js itself).
+ */
+
+// $Id: calendar-setup.js,v 1.25 2005/03/07 09:51:33 mishoo Exp $
+
+/**
+ * This function "patches" an input field (or other element) to use a calendar
+ * widget for date selection.
+ *
+ * The "params" is a single object that can have the following properties:
+ *
+ * prop. name | description
+ * -------------------------------------------------------------------------------------------------
+ * inputField | the ID of an input field to store the date
+ * displayArea | the ID of a DIV or other element to show the date
+ * button | ID of a button or other element that will trigger the calendar
+ * eventName | event that will trigger the calendar, without the "on" prefix (default: "click")
+ * ifFormat | date format that will be stored in the input field
+ * daFormat | the date format that will be used to display the date in displayArea
+ * singleClick | (true/false) wether the calendar is in single click mode or not (default: true)
+ * firstDay | numeric: 0 to 6. "0" means display Sunday first, "1" means display Monday first, etc.
+ * align | alignment (default: "Br"); if you don't know what's this see the calendar documentation
+ * range | array with 2 elements. Default: [1900, 2999] -- the range of years available
+ * weekNumbers | (true/false) if it's true (default) the calendar will display week numbers
+ * flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
+ * flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
+ * disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
+ * onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay)
+ * onClose | function that gets called when the calendar is closed. [default]
+ * onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar.
+ * date | the date that the calendar will be initially displayed to
+ * showsTime | default: false; if true the calendar will include a time selector
+ * timeFormat | the time format; can be "12" or "24", default is "12"
+ * electric | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
+ * step | configures the step of the years in drop-down boxes; default: 2
+ * position | configures the calendar absolute position; default: null
+ * cache | if "true" (but default: "false") it will reuse the same calendar object, where possible
+ * showOthers | if "true" (but default: "false") it will show days from other months too
+ *
+ * None of them is required, they all have default values. However, if you
+ * pass none of "inputField", "displayArea" or "button" you'll get a warning
+ * saying "nothing to setup".
+ */
+Calendar.setup = function (params) {
+ function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };
+
+ param_default("inputField", null);
+ param_default("displayArea", null);
+ param_default("button", null);
+ param_default("eventName", "click");
+ param_default("ifFormat", "%Y/%m/%d");
+ param_default("daFormat", "%Y/%m/%d");
+ param_default("singleClick", true);
+ param_default("disableFunc", null);
+ param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined
+ param_default("dateText", null);
+ param_default("firstDay", null);
+ param_default("align", "Br");
+ param_default("range", [1900, 2999]);
+ param_default("weekNumbers", true);
+ param_default("flat", null);
+ param_default("flatCallback", null);
+ param_default("onSelect", null);
+ param_default("onClose", null);
+ param_default("onUpdate", null);
+ param_default("date", null);
+ param_default("showsTime", false);
+ param_default("timeFormat", "24");
+ param_default("electric", true);
+ param_default("step", 2);
+ param_default("position", null);
+ param_default("cache", false);
+ param_default("showOthers", false);
+ param_default("multiple", null);
+
+ var tmp = ["inputField", "displayArea", "button"];
+ for (var i in tmp) {
+ if (typeof params[tmp[i]] == "string") {
+ params[tmp[i]] = document.getElementById(params[tmp[i]]);
+ }
+ }
+ if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
+ alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code");
+ return false;
+ }
+
+ function onSelect(cal) {
+ var p = cal.params;
+ var update = (cal.dateClicked || p.electric);
+ if (update && p.inputField) {
+ p.inputField.value = cal.date.print(p.ifFormat);
+ if (typeof p.inputField.onchange == "function")
+ p.inputField.onchange();
+ }
+ if (update && p.displayArea)
+ p.displayArea.innerHTML = cal.date.print(p.daFormat);
+ if (update && typeof p.onUpdate == "function")
+ p.onUpdate(cal);
+ if (update && p.flat) {
+ if (typeof p.flatCallback == "function")
+ p.flatCallback(cal);
+ }
+ if (update && p.singleClick && cal.dateClicked)
+ cal.callCloseHandler();
+ };
+
+ if (params.flat != null) {
+ if (typeof params.flat == "string")
+ params.flat = document.getElementById(params.flat);
+ if (!params.flat) {
+ alert("Calendar.setup:\n Flat specified but can't find parent.");
+ return false;
+ }
+ var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);
+ cal.showsOtherMonths = params.showOthers;
+ cal.showsTime = params.showsTime;
+ cal.time24 = (params.timeFormat == "24");
+ cal.params = params;
+ cal.weekNumbers = params.weekNumbers;
+ cal.setRange(params.range[0], params.range[1]);
+ cal.setDateStatusHandler(params.dateStatusFunc);
+ cal.getDateText = params.dateText;
+ if (params.ifFormat) {
+ cal.setDateFormat(params.ifFormat);
+ }
+ if (params.inputField && typeof params.inputField.value == "string") {
+ cal.parseDate(params.inputField.value);
+ }
+ cal.create(params.flat);
+ cal.show();
+ return false;
+ }
+
+ var triggerEl = params.button || params.displayArea || params.inputField;
+ triggerEl["on" + params.eventName] = function() {
+ var dateEl = params.inputField || params.displayArea;
+ var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
+ var mustCreate = false;
+ var cal = window.calendar;
+ if (dateEl)
+ params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
+ if (!(cal && params.cache)) {
+ window.calendar = cal = new Calendar(params.firstDay,
+ params.date,
+ params.onSelect || onSelect,
+ params.onClose || function(cal) { cal.hide(); });
+ cal.showsTime = params.showsTime;
+ cal.time24 = (params.timeFormat == "24");
+ cal.weekNumbers = params.weekNumbers;
+ mustCreate = true;
+ } else {
+ if (params.date)
+ cal.setDate(params.date);
+ cal.hide();
+ }
+ if (params.multiple) {
+ cal.multiple = {};
+ for (var i = params.multiple.length; --i >= 0;) {
+ var d = params.multiple[i];
+ var ds = d.print("%Y%m%d");
+ cal.multiple[ds] = d;
+ }
+ }
+ cal.showsOtherMonths = params.showOthers;
+ cal.yearStep = params.step;
+ cal.setRange(params.range[0], params.range[1]);
+ cal.params = params;
+ cal.setDateStatusHandler(params.dateStatusFunc);
+ cal.getDateText = params.dateText;
+ cal.setDateFormat(dateFmt);
+ if (mustCreate)
+ cal.create();
+ cal.refresh();
+ if (!params.position)
+ cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
+ else
+ cal.showAt(params.position[0], params.position[1]);
+ return false;
+ };
+
+ return cal;
+};
diff --git a/public/javascripts/calendar/calendar.js b/public/javascripts/calendar/calendar.js
new file mode 100644
index 000000000..9088e0e89
--- /dev/null
+++ b/public/javascripts/calendar/calendar.js
@@ -0,0 +1,1806 @@
+/* Copyright Mihai Bazon, 2002-2005 | www.bazon.net/mishoo
+ * -----------------------------------------------------------
+ *
+ * The DHTML Calendar, version 1.0 "It is happening again"
+ *
+ * Details and latest version at:
+ * www.dynarch.com/projects/calendar
+ *
+ * This script is developed by Dynarch.com. Visit us at www.dynarch.com.
+ *
+ * This script is distributed under the GNU Lesser General Public License.
+ * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
+ */
+
+// $Id: calendar.js,v 1.51 2005/03/07 16:44:31 mishoo Exp $
+
+/** The Calendar object constructor. */
+Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) {
+ // member variables
+ this.activeDiv = null;
+ this.currentDateEl = null;
+ this.getDateStatus = null;
+ this.getDateToolTip = null;
+ this.getDateText = null;
+ this.timeout = null;
+ this.onSelected = onSelected || null;
+ this.onClose = onClose || null;
+ this.dragging = false;
+ this.hidden = false;
+ this.minYear = 1970;
+ this.maxYear = 2050;
+ this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"];
+ this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"];
+ this.isPopup = true;
+ this.weekNumbers = true;
+ this.firstDayOfWeek = typeof firstDayOfWeek == "number" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc.
+ this.showsOtherMonths = false;
+ this.dateStr = dateStr;
+ this.ar_days = null;
+ this.showsTime = false;
+ this.time24 = true;
+ this.yearStep = 2;
+ this.hiliteToday = true;
+ this.multiple = null;
+ // HTML elements
+ this.table = null;
+ this.element = null;
+ this.tbody = null;
+ this.firstdayname = null;
+ // Combo boxes
+ this.monthsCombo = null;
+ this.yearsCombo = null;
+ this.hilitedMonth = null;
+ this.activeMonth = null;
+ this.hilitedYear = null;
+ this.activeYear = null;
+ // Information
+ this.dateClicked = false;
+
+ // one-time initializations
+ if (typeof Calendar._SDN == "undefined") {
+ // table of short day names
+ if (typeof Calendar._SDN_len == "undefined")
+ Calendar._SDN_len = 3;
+ var ar = new Array();
+ for (var i = 8; i > 0;) {
+ ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len);
+ }
+ Calendar._SDN = ar;
+ // table of short month names
+ if (typeof Calendar._SMN_len == "undefined")
+ Calendar._SMN_len = 3;
+ ar = new Array();
+ for (var i = 12; i > 0;) {
+ ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len);
+ }
+ Calendar._SMN = ar;
+ }
+};
+
+// ** constants
+
+/// "static", needed for event handlers.
+Calendar._C = null;
+
+/// detect a special case of "web browser"
+Calendar.is_ie = ( /msie/i.test(navigator.userAgent) &&
+ !/opera/i.test(navigator.userAgent) );
+
+Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) );
+
+/// detect Opera browser
+Calendar.is_opera = /opera/i.test(navigator.userAgent);
+
+/// detect KHTML-based browsers
+Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent);
+
+// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate
+// library, at some point.
+
+Calendar.getAbsolutePos = function(el) {
+ var SL = 0, ST = 0;
+ var is_div = /^div$/i.test(el.tagName);
+ if (is_div && el.scrollLeft)
+ SL = el.scrollLeft;
+ if (is_div && el.scrollTop)
+ ST = el.scrollTop;
+ var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
+ if (el.offsetParent) {
+ var tmp = this.getAbsolutePos(el.offsetParent);
+ r.x += tmp.x;
+ r.y += tmp.y;
+ }
+ return r;
+};
+
+Calendar.isRelated = function (el, evt) {
+ var related = evt.relatedTarget;
+ if (!related) {
+ var type = evt.type;
+ if (type == "mouseover") {
+ related = evt.fromElement;
+ } else if (type == "mouseout") {
+ related = evt.toElement;
+ }
+ }
+ while (related) {
+ if (related == el) {
+ return true;
+ }
+ related = related.parentNode;
+ }
+ return false;
+};
+
+Calendar.removeClass = function(el, className) {
+ if (!(el && el.className)) {
+ return;
+ }
+ var cls = el.className.split(" ");
+ var ar = new Array();
+ for (var i = cls.length; i > 0;) {
+ if (cls[--i] != className) {
+ ar[ar.length] = cls[i];
+ }
+ }
+ el.className = ar.join(" ");
+};
+
+Calendar.addClass = function(el, className) {
+ Calendar.removeClass(el, className);
+ el.className += " " + className;
+};
+
+// FIXME: the following 2 functions totally suck, are useless and should be replaced immediately.
+Calendar.getElement = function(ev) {
+ var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget;
+ while (f.nodeType != 1 || /^div$/i.test(f.tagName))
+ f = f.parentNode;
+ return f;
+};
+
+Calendar.getTargetElement = function(ev) {
+ var f = Calendar.is_ie ? window.event.srcElement : ev.target;
+ while (f.nodeType != 1)
+ f = f.parentNode;
+ return f;
+};
+
+Calendar.stopEvent = function(ev) {
+ ev || (ev = window.event);
+ if (Calendar.is_ie) {
+ ev.cancelBubble = true;
+ ev.returnValue = false;
+ } else {
+ ev.preventDefault();
+ ev.stopPropagation();
+ }
+ return false;
+};
+
+Calendar.addEvent = function(el, evname, func) {
+ if (el.attachEvent) { // IE
+ el.attachEvent("on" + evname, func);
+ } else if (el.addEventListener) { // Gecko / W3C
+ el.addEventListener(evname, func, true);
+ } else {
+ el["on" + evname] = func;
+ }
+};
+
+Calendar.removeEvent = function(el, evname, func) {
+ if (el.detachEvent) { // IE
+ el.detachEvent("on" + evname, func);
+ } else if (el.removeEventListener) { // Gecko / W3C
+ el.removeEventListener(evname, func, true);
+ } else {
+ el["on" + evname] = null;
+ }
+};
+
+Calendar.createElement = function(type, parent) {
+ var el = null;
+ if (document.createElementNS) {
+ // use the XHTML namespace; IE won't normally get here unless
+ // _they_ "fix" the DOM2 implementation.
+ el = document.createElementNS("http://www.w3.org/1999/xhtml", type);
+ } else {
+ el = document.createElement(type);
+ }
+ if (typeof parent != "undefined") {
+ parent.appendChild(el);
+ }
+ return el;
+};
+
+// END: UTILITY FUNCTIONS
+
+// BEGIN: CALENDAR STATIC FUNCTIONS
+
+/** Internal -- adds a set of events to make some element behave like a button. */
+Calendar._add_evs = function(el) {
+ with (Calendar) {
+ addEvent(el, "mouseover", dayMouseOver);
+ addEvent(el, "mousedown", dayMouseDown);
+ addEvent(el, "mouseout", dayMouseOut);
+ if (is_ie) {
+ addEvent(el, "dblclick", dayMouseDblClick);
+ el.setAttribute("unselectable", true);
+ }
+ }
+};
+
+Calendar.findMonth = function(el) {
+ if (typeof el.month != "undefined") {
+ return el;
+ } else if (typeof el.parentNode.month != "undefined") {
+ return el.parentNode;
+ }
+ return null;
+};
+
+Calendar.findYear = function(el) {
+ if (typeof el.year != "undefined") {
+ return el;
+ } else if (typeof el.parentNode.year != "undefined") {
+ return el.parentNode;
+ }
+ return null;
+};
+
+Calendar.showMonthsCombo = function () {
+ var cal = Calendar._C;
+ if (!cal) {
+ return false;
+ }
+ var cal = cal;
+ var cd = cal.activeDiv;
+ var mc = cal.monthsCombo;
+ if (cal.hilitedMonth) {
+ Calendar.removeClass(cal.hilitedMonth, "hilite");
+ }
+ if (cal.activeMonth) {
+ Calendar.removeClass(cal.activeMonth, "active");
+ }
+ var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];
+ Calendar.addClass(mon, "active");
+ cal.activeMonth = mon;
+ var s = mc.style;
+ s.display = "block";
+ if (cd.navtype < 0)
+ s.left = cd.offsetLeft + "px";
+ else {
+ var mcw = mc.offsetWidth;
+ if (typeof mcw == "undefined")
+ // Konqueror brain-dead techniques
+ mcw = 50;
+ s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px";
+ }
+ s.top = (cd.offsetTop + cd.offsetHeight) + "px";
+};
+
+Calendar.showYearsCombo = function (fwd) {
+ var cal = Calendar._C;
+ if (!cal) {
+ return false;
+ }
+ var cal = cal;
+ var cd = cal.activeDiv;
+ var yc = cal.yearsCombo;
+ if (cal.hilitedYear) {
+ Calendar.removeClass(cal.hilitedYear, "hilite");
+ }
+ if (cal.activeYear) {
+ Calendar.removeClass(cal.activeYear, "active");
+ }
+ cal.activeYear = null;
+ var Y = cal.date.getFullYear() + (fwd ? 1 : -1);
+ var yr = yc.firstChild;
+ var show = false;
+ for (var i = 12; i > 0; --i) {
+ if (Y >= cal.minYear && Y <= cal.maxYear) {
+ yr.innerHTML = Y;
+ yr.year = Y;
+ yr.style.display = "block";
+ show = true;
+ } else {
+ yr.style.display = "none";
+ }
+ yr = yr.nextSibling;
+ Y += fwd ? cal.yearStep : -cal.yearStep;
+ }
+ if (show) {
+ var s = yc.style;
+ s.display = "block";
+ if (cd.navtype < 0)
+ s.left = cd.offsetLeft + "px";
+ else {
+ var ycw = yc.offsetWidth;
+ if (typeof ycw == "undefined")
+ // Konqueror brain-dead techniques
+ ycw = 50;
+ s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px";
+ }
+ s.top = (cd.offsetTop + cd.offsetHeight) + "px";
+ }
+};
+
+// event handlers
+
+Calendar.tableMouseUp = function(ev) {
+ var cal = Calendar._C;
+ if (!cal) {
+ return false;
+ }
+ if (cal.timeout) {
+ clearTimeout(cal.timeout);
+ }
+ var el = cal.activeDiv;
+ if (!el) {
+ return false;
+ }
+ var target = Calendar.getTargetElement(ev);
+ ev || (ev = window.event);
+ Calendar.removeClass(el, "active");
+ if (target == el || target.parentNode == el) {
+ Calendar.cellClick(el, ev);
+ }
+ var mon = Calendar.findMonth(target);
+ var date = null;
+ if (mon) {
+ date = new Date(cal.date);
+ if (mon.month != date.getMonth()) {
+ date.setMonth(mon.month);
+ cal.setDate(date);
+ cal.dateClicked = false;
+ cal.callHandler();
+ }
+ } else {
+ var year = Calendar.findYear(target);
+ if (year) {
+ date = new Date(cal.date);
+ if (year.year != date.getFullYear()) {
+ date.setFullYear(year.year);
+ cal.setDate(date);
+ cal.dateClicked = false;
+ cal.callHandler();
+ }
+ }
+ }
+ with (Calendar) {
+ removeEvent(document, "mouseup", tableMouseUp);
+ removeEvent(document, "mouseover", tableMouseOver);
+ removeEvent(document, "mousemove", tableMouseOver);
+ cal._hideCombos();
+ _C = null;
+ return stopEvent(ev);
+ }
+};
+
+Calendar.tableMouseOver = function (ev) {
+ var cal = Calendar._C;
+ if (!cal) {
+ return;
+ }
+ var el = cal.activeDiv;
+ var target = Calendar.getTargetElement(ev);
+ if (target == el || target.parentNode == el) {
+ Calendar.addClass(el, "hilite active");
+ Calendar.addClass(el.parentNode, "rowhilite");
+ } else {
+ if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2)))
+ Calendar.removeClass(el, "active");
+ Calendar.removeClass(el, "hilite");
+ Calendar.removeClass(el.parentNode, "rowhilite");
+ }
+ ev || (ev = window.event);
+ if (el.navtype == 50 && target != el) {
+ var pos = Calendar.getAbsolutePos(el);
+ var w = el.offsetWidth;
+ var x = ev.clientX;
+ var dx;
+ var decrease = true;
+ if (x > pos.x + w) {
+ dx = x - pos.x - w;
+ decrease = false;
+ } else
+ dx = pos.x - x;
+
+ if (dx < 0) dx = 0;
+ var range = el._range;
+ var current = el._current;
+ var count = Math.floor(dx / 10) % range.length;
+ for (var i = range.length; --i >= 0;)
+ if (range[i] == current)
+ break;
+ while (count-- > 0)
+ if (decrease) {
+ if (--i < 0)
+ i = range.length - 1;
+ } else if ( ++i >= range.length )
+ i = 0;
+ var newval = range[i];
+ el.innerHTML = newval;
+
+ cal.onUpdateTime();
+ }
+ var mon = Calendar.findMonth(target);
+ if (mon) {
+ if (mon.month != cal.date.getMonth()) {
+ if (cal.hilitedMonth) {
+ Calendar.removeClass(cal.hilitedMonth, "hilite");
+ }
+ Calendar.addClass(mon, "hilite");
+ cal.hilitedMonth = mon;
+ } else if (cal.hilitedMonth) {
+ Calendar.removeClass(cal.hilitedMonth, "hilite");
+ }
+ } else {
+ if (cal.hilitedMonth) {
+ Calendar.removeClass(cal.hilitedMonth, "hilite");
+ }
+ var year = Calendar.findYear(target);
+ if (year) {
+ if (year.year != cal.date.getFullYear()) {
+ if (cal.hilitedYear) {
+ Calendar.removeClass(cal.hilitedYear, "hilite");
+ }
+ Calendar.addClass(year, "hilite");
+ cal.hilitedYear = year;
+ } else if (cal.hilitedYear) {
+ Calendar.removeClass(cal.hilitedYear, "hilite");
+ }
+ } else if (cal.hilitedYear) {
+ Calendar.removeClass(cal.hilitedYear, "hilite");
+ }
+ }
+ return Calendar.stopEvent(ev);
+};
+
+Calendar.tableMouseDown = function (ev) {
+ if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {
+ return Calendar.stopEvent(ev);
+ }
+};
+
+Calendar.calDragIt = function (ev) {
+ var cal = Calendar._C;
+ if (!(cal && cal.dragging)) {
+ return false;
+ }
+ var posX;
+ var posY;
+ if (Calendar.is_ie) {
+ posY = window.event.clientY + document.body.scrollTop;
+ posX = window.event.clientX + document.body.scrollLeft;
+ } else {
+ posX = ev.pageX;
+ posY = ev.pageY;
+ }
+ cal.hideShowCovered();
+ var st = cal.element.style;
+ st.left = (posX - cal.xOffs) + "px";
+ st.top = (posY - cal.yOffs) + "px";
+ return Calendar.stopEvent(ev);
+};
+
+Calendar.calDragEnd = function (ev) {
+ var cal = Calendar._C;
+ if (!cal) {
+ return false;
+ }
+ cal.dragging = false;
+ with (Calendar) {
+ removeEvent(document, "mousemove", calDragIt);
+ removeEvent(document, "mouseup", calDragEnd);
+ tableMouseUp(ev);
+ }
+ cal.hideShowCovered();
+};
+
+Calendar.dayMouseDown = function(ev) {
+ var el = Calendar.getElement(ev);
+ if (el.disabled) {
+ return false;
+ }
+ var cal = el.calendar;
+ cal.activeDiv = el;
+ Calendar._C = cal;
+ if (el.navtype != 300) with (Calendar) {
+ if (el.navtype == 50) {
+ el._current = el.innerHTML;
+ addEvent(document, "mousemove", tableMouseOver);
+ } else
+ addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver);
+ addClass(el, "hilite active");
+ addEvent(document, "mouseup", tableMouseUp);
+ } else if (cal.isPopup) {
+ cal._dragStart(ev);
+ }
+ if (el.navtype == -1 || el.navtype == 1) {
+ if (cal.timeout) clearTimeout(cal.timeout);
+ cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250);
+ } else if (el.navtype == -2 || el.navtype == 2) {
+ if (cal.timeout) clearTimeout(cal.timeout);
+ cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250);
+ } else {
+ cal.timeout = null;
+ }
+ return Calendar.stopEvent(ev);
+};
+
+Calendar.dayMouseDblClick = function(ev) {
+ Calendar.cellClick(Calendar.getElement(ev), ev || window.event);
+ if (Calendar.is_ie) {
+ document.selection.empty();
+ }
+};
+
+Calendar.dayMouseOver = function(ev) {
+ var el = Calendar.getElement(ev);
+ if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {
+ return false;
+ }
+ if (el.ttip) {
+ if (el.ttip.substr(0, 1) == "_") {
+ el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1);
+ }
+ el.calendar.tooltips.innerHTML = el.ttip;
+ }
+ if (el.navtype != 300) {
+ Calendar.addClass(el, "hilite");
+ if (el.caldate) {
+ Calendar.addClass(el.parentNode, "rowhilite");
+ }
+ }
+ return Calendar.stopEvent(ev);
+};
+
+Calendar.dayMouseOut = function(ev) {
+ with (Calendar) {
+ var el = getElement(ev);
+ if (isRelated(el, ev) || _C || el.disabled)
+ return false;
+ removeClass(el, "hilite");
+ if (el.caldate)
+ removeClass(el.parentNode, "rowhilite");
+ if (el.calendar)
+ el.calendar.tooltips.innerHTML = _TT["SEL_DATE"];
+ return stopEvent(ev);
+ }
+};
+
+/**
+ * A generic "click" handler :) handles all types of buttons defined in this
+ * calendar.
+ */
+Calendar.cellClick = function(el, ev) {
+ var cal = el.calendar;
+ var closing = false;
+ var newdate = false;
+ var date = null;
+ if (typeof el.navtype == "undefined") {
+ if (cal.currentDateEl) {
+ Calendar.removeClass(cal.currentDateEl, "selected");
+ Calendar.addClass(el, "selected");
+ closing = (cal.currentDateEl == el);
+ if (!closing) {
+ cal.currentDateEl = el;
+ }
+ }
+ cal.date.setDateOnly(el.caldate);
+ date = cal.date;
+ var other_month = !(cal.dateClicked = !el.otherMonth);
+ if (!other_month && !cal.currentDateEl)
+ cal._toggleMultipleDate(new Date(date));
+ else
+ newdate = !el.disabled;
+ // a date was clicked
+ if (other_month)
+ cal._init(cal.firstDayOfWeek, date);
+ } else {
+ if (el.navtype == 200) {
+ Calendar.removeClass(el, "hilite");
+ cal.callCloseHandler();
+ return;
+ }
+ date = new Date(cal.date);
+ if (el.navtype == 0)
+ date.setDateOnly(new Date()); // TODAY
+ // unless "today" was clicked, we assume no date was clicked so
+ // the selected handler will know not to close the calenar when
+ // in single-click mode.
+ // cal.dateClicked = (el.navtype == 0);
+ cal.dateClicked = false;
+ var year = date.getFullYear();
+ var mon = date.getMonth();
+ function setMonth(m) {
+ var day = date.getDate();
+ var max = date.getMonthDays(m);
+ if (day > max) {
+ date.setDate(max);
+ }
+ date.setMonth(m);
+ };
+ switch (el.navtype) {
+ case 400:
+ Calendar.removeClass(el, "hilite");
+ var text = Calendar._TT["ABOUT"];
+ if (typeof text != "undefined") {
+ text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : "";
+ } else {
+ // FIXME: this should be removed as soon as lang files get updated!
+ text = "Help and about box text is not translated into this language.\n" +
+ "If you know this language and you feel generous please update\n" +
+ "the corresponding file in \"lang\" subdir to match calendar-en.js\n" +
+ "and send it back to <mihai_bazon@yahoo.com> to get it into the distribution ;-)\n\n" +
+ "Thank you!\n" +
+ "http://dynarch.com/mishoo/calendar.epl\n";
+ }
+ alert(text);
+ return;
+ case -2:
+ if (year > cal.minYear) {
+ date.setFullYear(year - 1);
+ }
+ break;
+ case -1:
+ if (mon > 0) {
+ setMonth(mon - 1);
+ } else if (year-- > cal.minYear) {
+ date.setFullYear(year);
+ setMonth(11);
+ }
+ break;
+ case 1:
+ if (mon < 11) {
+ setMonth(mon + 1);
+ } else if (year < cal.maxYear) {
+ date.setFullYear(year + 1);
+ setMonth(0);
+ }
+ break;
+ case 2:
+ if (year < cal.maxYear) {
+ date.setFullYear(year + 1);
+ }
+ break;
+ case 100:
+ cal.setFirstDayOfWeek(el.fdow);
+ return;
+ case 50:
+ var range = el._range;
+ var current = el.innerHTML;
+ for (var i = range.length; --i >= 0;)
+ if (range[i] == current)
+ break;
+ if (ev && ev.shiftKey) {
+ if (--i < 0)
+ i = range.length - 1;
+ } else if ( ++i >= range.length )
+ i = 0;
+ var newval = range[i];
+ el.innerHTML = newval;
+ cal.onUpdateTime();
+ return;
+ case 0:
+ // TODAY will bring us here
+ if ((typeof cal.getDateStatus == "function") &&
+ cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) {
+ return false;
+ }
+ break;
+ }
+ if (!date.equalsTo(cal.date)) {
+ cal.setDate(date);
+ newdate = true;
+ } else if (el.navtype == 0)
+ newdate = closing = true;
+ }
+ if (newdate) {
+ ev && cal.callHandler();
+ }
+ if (closing) {
+ Calendar.removeClass(el, "hilite");
+ ev && cal.callCloseHandler();
+ }
+};
+
+// END: CALENDAR STATIC FUNCTIONS
+
+// BEGIN: CALENDAR OBJECT FUNCTIONS
+
+/**
+ * This function creates the calendar inside the given parent. If _par is
+ * null than it creates a popup calendar inside the BODY element. If _par is
+ * an element, be it BODY, then it creates a non-popup calendar (still
+ * hidden). Some properties need to be set before calling this function.
+ */
+Calendar.prototype.create = function (_par) {
+ var parent = null;
+ if (! _par) {
+ // default parent is the document body, in which case we create
+ // a popup calendar.
+ parent = document.getElementsByTagName("body")[0];
+ this.isPopup = true;
+ } else {
+ parent = _par;
+ this.isPopup = false;
+ }
+ this.date = this.dateStr ? new Date(this.dateStr) : new Date();
+
+ var table = Calendar.createElement("table");
+ this.table = table;
+ table.cellSpacing = 0;
+ table.cellPadding = 0;
+ table.calendar = this;
+ Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown);
+
+ var div = Calendar.createElement("div");
+ this.element = div;
+ div.className = "calendar";
+ if (this.isPopup) {
+ div.style.position = "absolute";
+ div.style.display = "none";
+ }
+ div.appendChild(table);
+
+ var thead = Calendar.createElement("thead", table);
+ var cell = null;
+ var row = null;
+
+ var cal = this;
+ var hh = function (text, cs, navtype) {
+ cell = Calendar.createElement("td", row);
+ cell.colSpan = cs;
+ cell.className = "button";
+ if (navtype != 0 && Math.abs(navtype) <= 2)
+ cell.className += " nav";
+ Calendar._add_evs(cell);
+ cell.calendar = cal;
+ cell.navtype = navtype;
+ cell.innerHTML = "<div unselectable='on'>" + text + "</div>";
+ return cell;
+ };
+
+ row = Calendar.createElement("tr", thead);
+ var title_length = 6;
+ (this.isPopup) && --title_length;
+ (this.weekNumbers) && ++title_length;
+
+ hh("?", 1, 400).ttip = Calendar._TT["INFO"];
+ this.title = hh("", title_length, 300);
+ this.title.className = "title";
+ if (this.isPopup) {
+ this.title.ttip = Calendar._TT["DRAG_TO_MOVE"];
+ this.title.style.cursor = "move";
+ hh("&#x00d7;", 1, 200).ttip = Calendar._TT["CLOSE"];
+ }
+
+ row = Calendar.createElement("tr", thead);
+ row.className = "headrow";
+
+ this._nav_py = hh("&#x00ab;", 1, -2);
+ this._nav_py.ttip = Calendar._TT["PREV_YEAR"];
+
+ this._nav_pm = hh("&#x2039;", 1, -1);
+ this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];
+
+ this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0);
+ this._nav_now.ttip = Calendar._TT["GO_TODAY"];
+
+ this._nav_nm = hh("&#x203a;", 1, 1);
+ this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];
+
+ this._nav_ny = hh("&#x00bb;", 1, 2);
+ this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"];
+
+ // day names
+ row = Calendar.createElement("tr", thead);
+ row.className = "daynames";
+ if (this.weekNumbers) {
+ cell = Calendar.createElement("td", row);
+ cell.className = "name wn";
+ cell.innerHTML = Calendar._TT["WK"];
+ }
+ for (var i = 7; i > 0; --i) {
+ cell = Calendar.createElement("td", row);
+ if (!i) {
+ cell.navtype = 100;
+ cell.calendar = this;
+ Calendar._add_evs(cell);
+ }
+ }
+ this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;
+ this._displayWeekdays();
+
+ var tbody = Calendar.createElement("tbody", table);
+ this.tbody = tbody;
+
+ for (i = 6; i > 0; --i) {
+ row = Calendar.createElement("tr", tbody);
+ if (this.weekNumbers) {
+ cell = Calendar.createElement("td", row);
+ }
+ for (var j = 7; j > 0; --j) {
+ cell = Calendar.createElement("td", row);
+ cell.calendar = this;
+ Calendar._add_evs(cell);
+ }
+ }
+
+ if (this.showsTime) {
+ row = Calendar.createElement("tr", tbody);
+ row.className = "time";
+
+ cell = Calendar.createElement("td", row);
+ cell.className = "time";
+ cell.colSpan = 2;
+ cell.innerHTML = Calendar._TT["TIME"] || "&nbsp;";
+
+ cell = Calendar.createElement("td", row);
+ cell.className = "time";
+ cell.colSpan = this.weekNumbers ? 4 : 3;
+
+ (function(){
+ function makeTimePart(className, init, range_start, range_end) {
+ var part = Calendar.createElement("span", cell);
+ part.className = className;
+ part.innerHTML = init;
+ part.calendar = cal;
+ part.ttip = Calendar._TT["TIME_PART"];
+ part.navtype = 50;
+ part._range = [];
+ if (typeof range_start != "number")
+ part._range = range_start;
+ else {
+ for (var i = range_start; i <= range_end; ++i) {
+ var txt;
+ if (i < 10 && range_end >= 10) txt = '0' + i;
+ else txt = '' + i;
+ part._range[part._range.length] = txt;
+ }
+ }
+ Calendar._add_evs(part);
+ return part;
+ };
+ var hrs = cal.date.getHours();
+ var mins = cal.date.getMinutes();
+ var t12 = !cal.time24;
+ var pm = (hrs > 12);
+ if (t12 && pm) hrs -= 12;
+ var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23);
+ var span = Calendar.createElement("span", cell);
+ span.innerHTML = ":";
+ span.className = "colon";
+ var M = makeTimePart("minute", mins, 0, 59);
+ var AP = null;
+ cell = Calendar.createElement("td", row);
+ cell.className = "time";
+ cell.colSpan = 2;
+ if (t12)
+ AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]);
+ else
+ cell.innerHTML = "&nbsp;";
+
+ cal.onSetTime = function() {
+ var pm, hrs = this.date.getHours(),
+ mins = this.date.getMinutes();
+ if (t12) {
+ pm = (hrs >= 12);
+ if (pm) hrs -= 12;
+ if (hrs == 0) hrs = 12;
+ AP.innerHTML = pm ? "pm" : "am";
+ }
+ H.innerHTML = (hrs < 10) ? ("0" + hrs) : hrs;
+ M.innerHTML = (mins < 10) ? ("0" + mins) : mins;
+ };
+
+ cal.onUpdateTime = function() {
+ var date = this.date;
+ var h = parseInt(H.innerHTML, 10);
+ if (t12) {
+ if (/pm/i.test(AP.innerHTML) && h < 12)
+ h += 12;
+ else if (/am/i.test(AP.innerHTML) && h == 12)
+ h = 0;
+ }
+ var d = date.getDate();
+ var m = date.getMonth();
+ var y = date.getFullYear();
+ date.setHours(h);
+ date.setMinutes(parseInt(M.innerHTML, 10));
+ date.setFullYear(y);
+ date.setMonth(m);
+ date.setDate(d);
+ this.dateClicked = false;
+ this.callHandler();
+ };
+ })();
+ } else {
+ this.onSetTime = this.onUpdateTime = function() {};
+ }
+
+ var tfoot = Calendar.createElement("tfoot", table);
+
+ row = Calendar.createElement("tr", tfoot);
+ row.className = "footrow";
+
+ cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300);
+ cell.className = "ttip";
+ if (this.isPopup) {
+ cell.ttip = Calendar._TT["DRAG_TO_MOVE"];
+ cell.style.cursor = "move";
+ }
+ this.tooltips = cell;
+
+ div = Calendar.createElement("div", this.element);
+ this.monthsCombo = div;
+ div.className = "combo";
+ for (i = 0; i < Calendar._MN.length; ++i) {
+ var mn = Calendar.createElement("div");
+ mn.className = Calendar.is_ie ? "label-IEfix" : "label";
+ mn.month = i;
+ mn.innerHTML = Calendar._SMN[i];
+ div.appendChild(mn);
+ }
+
+ div = Calendar.createElement("div", this.element);
+ this.yearsCombo = div;
+ div.className = "combo";
+ for (i = 12; i > 0; --i) {
+ var yr = Calendar.createElement("div");
+ yr.className = Calendar.is_ie ? "label-IEfix" : "label";
+ div.appendChild(yr);
+ }
+
+ this._init(this.firstDayOfWeek, this.date);
+ parent.appendChild(this.element);
+};
+
+/** keyboard navigation, only for popup calendars */
+Calendar._keyEvent = function(ev) {
+ var cal = window._dynarch_popupCalendar;
+ if (!cal || cal.multiple)
+ return false;
+ (Calendar.is_ie) && (ev = window.event);
+ var act = (Calendar.is_ie || ev.type == "keypress"),
+ K = ev.keyCode;
+ if (ev.ctrlKey) {
+ switch (K) {
+ case 37: // KEY left
+ act && Calendar.cellClick(cal._nav_pm);
+ break;
+ case 38: // KEY up
+ act && Calendar.cellClick(cal._nav_py);
+ break;
+ case 39: // KEY right
+ act && Calendar.cellClick(cal._nav_nm);
+ break;
+ case 40: // KEY down
+ act && Calendar.cellClick(cal._nav_ny);
+ break;
+ default:
+ return false;
+ }
+ } else switch (K) {
+ case 32: // KEY space (now)
+ Calendar.cellClick(cal._nav_now);
+ break;
+ case 27: // KEY esc
+ act && cal.callCloseHandler();
+ break;
+ case 37: // KEY left
+ case 38: // KEY up
+ case 39: // KEY right
+ case 40: // KEY down
+ if (act) {
+ var prev, x, y, ne, el, step;
+ prev = K == 37 || K == 38;
+ step = (K == 37 || K == 39) ? 1 : 7;
+ function setVars() {
+ el = cal.currentDateEl;
+ var p = el.pos;
+ x = p & 15;
+ y = p >> 4;
+ ne = cal.ar_days[y][x];
+ };setVars();
+ function prevMonth() {
+ var date = new Date(cal.date);
+ date.setDate(date.getDate() - step);
+ cal.setDate(date);
+ };
+ function nextMonth() {
+ var date = new Date(cal.date);
+ date.setDate(date.getDate() + step);
+ cal.setDate(date);
+ };
+ while (1) {
+ switch (K) {
+ case 37: // KEY left
+ if (--x >= 0)
+ ne = cal.ar_days[y][x];
+ else {
+ x = 6;
+ K = 38;
+ continue;
+ }
+ break;
+ case 38: // KEY up
+ if (--y >= 0)
+ ne = cal.ar_days[y][x];
+ else {
+ prevMonth();
+ setVars();
+ }
+ break;
+ case 39: // KEY right
+ if (++x < 7)
+ ne = cal.ar_days[y][x];
+ else {
+ x = 0;
+ K = 40;
+ continue;
+ }
+ break;
+ case 40: // KEY down
+ if (++y < cal.ar_days.length)
+ ne = cal.ar_days[y][x];
+ else {
+ nextMonth();
+ setVars();
+ }
+ break;
+ }
+ break;
+ }
+ if (ne) {
+ if (!ne.disabled)
+ Calendar.cellClick(ne);
+ else if (prev)
+ prevMonth();
+ else
+ nextMonth();
+ }
+ }
+ break;
+ case 13: // KEY enter
+ if (act)
+ Calendar.cellClick(cal.currentDateEl, ev);
+ break;
+ default:
+ return false;
+ }
+ return Calendar.stopEvent(ev);
+};
+
+/**
+ * (RE)Initializes the calendar to the given date and firstDayOfWeek
+ */
+Calendar.prototype._init = function (firstDayOfWeek, date) {
+ var today = new Date(),
+ TY = today.getFullYear(),
+ TM = today.getMonth(),
+ TD = today.getDate();
+ this.table.style.visibility = "hidden";
+ var year = date.getFullYear();
+ if (year < this.minYear) {
+ year = this.minYear;
+ date.setFullYear(year);
+ } else if (year > this.maxYear) {
+ year = this.maxYear;
+ date.setFullYear(year);
+ }
+ this.firstDayOfWeek = firstDayOfWeek;
+ this.date = new Date(date);
+ var month = date.getMonth();
+ var mday = date.getDate();
+ var no_days = date.getMonthDays();
+
+ // calendar voodoo for computing the first day that would actually be
+ // displayed in the calendar, even if it's from the previous month.
+ // WARNING: this is magic. ;-)
+ date.setDate(1);
+ var day1 = (date.getDay() - this.firstDayOfWeek) % 7;
+ if (day1 < 0)
+ day1 += 7;
+ date.setDate(-day1);
+ date.setDate(date.getDate() + 1);
+
+ var row = this.tbody.firstChild;
+ var MN = Calendar._SMN[month];
+ var ar_days = this.ar_days = new Array();
+ var weekend = Calendar._TT["WEEKEND"];
+ var dates = this.multiple ? (this.datesCells = {}) : null;
+ for (var i = 0; i < 6; ++i, row = row.nextSibling) {
+ var cell = row.firstChild;
+ if (this.weekNumbers) {
+ cell.className = "day wn";
+ cell.innerHTML = date.getWeekNumber();
+ cell = cell.nextSibling;
+ }
+ row.className = "daysrow";
+ var hasdays = false, iday, dpos = ar_days[i] = [];
+ for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) {
+ iday = date.getDate();
+ var wday = date.getDay();
+ cell.className = "day";
+ cell.pos = i << 4 | j;
+ dpos[j] = cell;
+ var current_month = (date.getMonth() == month);
+ if (!current_month) {
+ if (this.showsOtherMonths) {
+ cell.className += " othermonth";
+ cell.otherMonth = true;
+ } else {
+ cell.className = "emptycell";
+ cell.innerHTML = "&nbsp;";
+ cell.disabled = true;
+ continue;
+ }
+ } else {
+ cell.otherMonth = false;
+ hasdays = true;
+ }
+ cell.disabled = false;
+ cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday;
+ if (dates)
+ dates[date.print("%Y%m%d")] = cell;
+ if (this.getDateStatus) {
+ var status = this.getDateStatus(date, year, month, iday);
+ if (this.getDateToolTip) {
+ var toolTip = this.getDateToolTip(date, year, month, iday);
+ if (toolTip)
+ cell.title = toolTip;
+ }
+ if (status === true) {
+ cell.className += " disabled";
+ cell.disabled = true;
+ } else {
+ if (/disabled/i.test(status))
+ cell.disabled = true;
+ cell.className += " " + status;
+ }
+ }
+ if (!cell.disabled) {
+ cell.caldate = new Date(date);
+ cell.ttip = "_";
+ if (!this.multiple && current_month
+ && iday == mday && this.hiliteToday) {
+ cell.className += " selected";
+ this.currentDateEl = cell;
+ }
+ if (date.getFullYear() == TY &&
+ date.getMonth() == TM &&
+ iday == TD) {
+ cell.className += " today";
+ cell.ttip += Calendar._TT["PART_TODAY"];
+ }
+ if (weekend.indexOf(wday.toString()) != -1)
+ cell.className += cell.otherMonth ? " oweekend" : " weekend";
+ }
+ }
+ if (!(hasdays || this.showsOtherMonths))
+ row.className = "emptyrow";
+ }
+ this.title.innerHTML = Calendar._MN[month] + ", " + year;
+ this.onSetTime();
+ this.table.style.visibility = "visible";
+ this._initMultipleDates();
+ // PROFILE
+ // this.tooltips.innerHTML = "Generated in " + ((new Date()) - today) + " ms";
+};
+
+Calendar.prototype._initMultipleDates = function() {
+ if (this.multiple) {
+ for (var i in this.multiple) {
+ var cell = this.datesCells[i];
+ var d = this.multiple[i];
+ if (!d)
+ continue;
+ if (cell)
+ cell.className += " selected";
+ }
+ }
+};
+
+Calendar.prototype._toggleMultipleDate = function(date) {
+ if (this.multiple) {
+ var ds = date.print("%Y%m%d");
+ var cell = this.datesCells[ds];
+ if (cell) {
+ var d = this.multiple[ds];
+ if (!d) {
+ Calendar.addClass(cell, "selected");
+ this.multiple[ds] = date;
+ } else {
+ Calendar.removeClass(cell, "selected");
+ delete this.multiple[ds];
+ }
+ }
+ }
+};
+
+Calendar.prototype.setDateToolTipHandler = function (unaryFunction) {
+ this.getDateToolTip = unaryFunction;
+};
+
+/**
+ * Calls _init function above for going to a certain date (but only if the
+ * date is different than the currently selected one).
+ */
+Calendar.prototype.setDate = function (date) {
+ if (!date.equalsTo(this.date)) {
+ this._init(this.firstDayOfWeek, date);
+ }
+};
+
+/**
+ * Refreshes the calendar. Useful if the "disabledHandler" function is
+ * dynamic, meaning that the list of disabled date can change at runtime.
+ * Just * call this function if you think that the list of disabled dates
+ * should * change.
+ */
+Calendar.prototype.refresh = function () {
+ this._init(this.firstDayOfWeek, this.date);
+};
+
+/** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */
+Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) {
+ this._init(firstDayOfWeek, this.date);
+ this._displayWeekdays();
+};
+
+/**
+ * Allows customization of what dates are enabled. The "unaryFunction"
+ * parameter must be a function object that receives the date (as a JS Date
+ * object) and returns a boolean value. If the returned value is true then
+ * the passed date will be marked as disabled.
+ */
+Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) {
+ this.getDateStatus = unaryFunction;
+};
+
+/** Customization of allowed year range for the calendar. */
+Calendar.prototype.setRange = function (a, z) {
+ this.minYear = a;
+ this.maxYear = z;
+};
+
+/** Calls the first user handler (selectedHandler). */
+Calendar.prototype.callHandler = function () {
+ if (this.onSelected) {
+ this.onSelected(this, this.date.print(this.dateFormat));
+ }
+};
+
+/** Calls the second user handler (closeHandler). */
+Calendar.prototype.callCloseHandler = function () {
+ if (this.onClose) {
+ this.onClose(this);
+ }
+ this.hideShowCovered();
+};
+
+/** Removes the calendar object from the DOM tree and destroys it. */
+Calendar.prototype.destroy = function () {
+ var el = this.element.parentNode;
+ el.removeChild(this.element);
+ Calendar._C = null;
+ window._dynarch_popupCalendar = null;
+};
+
+/**
+ * Moves the calendar element to a different section in the DOM tree (changes
+ * its parent).
+ */
+Calendar.prototype.reparent = function (new_parent) {
+ var el = this.element;
+ el.parentNode.removeChild(el);
+ new_parent.appendChild(el);
+};
+
+// This gets called when the user presses a mouse button anywhere in the
+// document, if the calendar is shown. If the click was outside the open
+// calendar this function closes it.
+Calendar._checkCalendar = function(ev) {
+ var calendar = window._dynarch_popupCalendar;
+ if (!calendar) {
+ return false;
+ }
+ var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);
+ for (; el != null && el != calendar.element; el = el.parentNode);
+ if (el == null) {
+ // calls closeHandler which should hide the calendar.
+ window._dynarch_popupCalendar.callCloseHandler();
+ return Calendar.stopEvent(ev);
+ }
+};
+
+/** Shows the calendar. */
+Calendar.prototype.show = function () {
+ var rows = this.table.getElementsByTagName("tr");
+ for (var i = rows.length; i > 0;) {
+ var row = rows[--i];
+ Calendar.removeClass(row, "rowhilite");
+ var cells = row.getElementsByTagName("td");
+ for (var j = cells.length; j > 0;) {
+ var cell = cells[--j];
+ Calendar.removeClass(cell, "hilite");
+ Calendar.removeClass(cell, "active");
+ }
+ }
+ this.element.style.display = "block";
+ this.hidden = false;
+ if (this.isPopup) {
+ window._dynarch_popupCalendar = this;
+ Calendar.addEvent(document, "keydown", Calendar._keyEvent);
+ Calendar.addEvent(document, "keypress", Calendar._keyEvent);
+ Calendar.addEvent(document, "mousedown", Calendar._checkCalendar);
+ }
+ this.hideShowCovered();
+};
+
+/**
+ * Hides the calendar. Also removes any "hilite" from the class of any TD
+ * element.
+ */
+Calendar.prototype.hide = function () {
+ if (this.isPopup) {
+ Calendar.removeEvent(document, "keydown", Calendar._keyEvent);
+ Calendar.removeEvent(document, "keypress", Calendar._keyEvent);
+ Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar);
+ }
+ this.element.style.display = "none";
+ this.hidden = true;
+ this.hideShowCovered();
+};
+
+/**
+ * Shows the calendar at a given absolute position (beware that, depending on
+ * the calendar element style -- position property -- this might be relative
+ * to the parent's containing rectangle).
+ */
+Calendar.prototype.showAt = function (x, y) {
+ var s = this.element.style;
+ s.left = x + "px";
+ s.top = y + "px";
+ this.show();
+};
+
+/** Shows the calendar near a given element. */
+Calendar.prototype.showAtElement = function (el, opts) {
+ var self = this;
+ var p = Calendar.getAbsolutePos(el);
+ if (!opts || typeof opts != "string") {
+ this.showAt(p.x, p.y + el.offsetHeight);
+ return true;
+ }
+ function fixPosition(box) {
+ if (box.x < 0)
+ box.x = 0;
+ if (box.y < 0)
+ box.y = 0;
+ var cp = document.createElement("div");
+ var s = cp.style;
+ s.position = "absolute";
+ s.right = s.bottom = s.width = s.height = "0px";
+ document.body.appendChild(cp);
+ var br = Calendar.getAbsolutePos(cp);
+ document.body.removeChild(cp);
+ if (Calendar.is_ie) {
+ br.y += document.body.scrollTop;
+ br.x += document.body.scrollLeft;
+ } else {
+ br.y += window.scrollY;
+ br.x += window.scrollX;
+ }
+ var tmp = box.x + box.width - br.x;
+ if (tmp > 0) box.x -= tmp;
+ tmp = box.y + box.height - br.y;
+ if (tmp > 0) box.y -= tmp;
+ };
+ this.element.style.display = "block";
+ Calendar.continuation_for_the_fucking_khtml_browser = function() {
+ var w = self.element.offsetWidth;
+ var h = self.element.offsetHeight;
+ self.element.style.display = "none";
+ var valign = opts.substr(0, 1);
+ var halign = "l";
+ if (opts.length > 1) {
+ halign = opts.substr(1, 1);
+ }
+ // vertical alignment
+ switch (valign) {
+ case "T": p.y -= h; break;
+ case "B": p.y += el.offsetHeight; break;
+ case "C": p.y += (el.offsetHeight - h) / 2; break;
+ case "t": p.y += el.offsetHeight - h; break;
+ case "b": break; // already there
+ }
+ // horizontal alignment
+ switch (halign) {
+ case "L": p.x -= w; break;
+ case "R": p.x += el.offsetWidth; break;
+ case "C": p.x += (el.offsetWidth - w) / 2; break;
+ case "l": p.x += el.offsetWidth - w; break;
+ case "r": break; // already there
+ }
+ p.width = w;
+ p.height = h + 40;
+ self.monthsCombo.style.display = "none";
+ fixPosition(p);
+ self.showAt(p.x, p.y);
+ };
+ if (Calendar.is_khtml)
+ setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
+ else
+ Calendar.continuation_for_the_fucking_khtml_browser();
+};
+
+/** Customizes the date format. */
+Calendar.prototype.setDateFormat = function (str) {
+ this.dateFormat = str;
+};
+
+/** Customizes the tooltip date format. */
+Calendar.prototype.setTtDateFormat = function (str) {
+ this.ttDateFormat = str;
+};
+
+/**
+ * Tries to identify the date represented in a string. If successful it also
+ * calls this.setDate which moves the calendar to the given date.
+ */
+Calendar.prototype.parseDate = function(str, fmt) {
+ if (!fmt)
+ fmt = this.dateFormat;
+ this.setDate(Date.parseDate(str, fmt));
+};
+
+Calendar.prototype.hideShowCovered = function () {
+ if (!Calendar.is_ie && !Calendar.is_opera)
+ return;
+ function getVisib(obj){
+ var value = obj.style.visibility;
+ if (!value) {
+ if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
+ if (!Calendar.is_khtml)
+ value = document.defaultView.
+ getComputedStyle(obj, "").getPropertyValue("visibility");
+ else
+ value = '';
+ } else if (obj.currentStyle) { // IE
+ value = obj.currentStyle.visibility;
+ } else
+ value = '';
+ }
+ return value;
+ };
+
+ var tags = new Array("applet", "iframe", "select");
+ var el = this.element;
+
+ var p = Calendar.getAbsolutePos(el);
+ var EX1 = p.x;
+ var EX2 = el.offsetWidth + EX1;
+ var EY1 = p.y;
+ var EY2 = el.offsetHeight + EY1;
+
+ for (var k = tags.length; k > 0; ) {
+ var ar = document.getElementsByTagName(tags[--k]);
+ var cc = null;
+
+ for (var i = ar.length; i > 0;) {
+ cc = ar[--i];
+
+ p = Calendar.getAbsolutePos(cc);
+ var CX1 = p.x;
+ var CX2 = cc.offsetWidth + CX1;
+ var CY1 = p.y;
+ var CY2 = cc.offsetHeight + CY1;
+
+ if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
+ if (!cc.__msh_save_visibility) {
+ cc.__msh_save_visibility = getVisib(cc);
+ }
+ cc.style.visibility = cc.__msh_save_visibility;
+ } else {
+ if (!cc.__msh_save_visibility) {
+ cc.__msh_save_visibility = getVisib(cc);
+ }
+ cc.style.visibility = "hidden";
+ }
+ }
+ }
+};
+
+/** Internal function; it displays the bar with the names of the weekday. */
+Calendar.prototype._displayWeekdays = function () {
+ var fdow = this.firstDayOfWeek;
+ var cell = this.firstdayname;
+ var weekend = Calendar._TT["WEEKEND"];
+ for (var i = 0; i < 7; ++i) {
+ cell.className = "day name";
+ var realday = (i + fdow) % 7;
+ if (i) {
+ cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]);
+ cell.navtype = 100;
+ cell.calendar = this;
+ cell.fdow = realday;
+ Calendar._add_evs(cell);
+ }
+ if (weekend.indexOf(realday.toString()) != -1) {
+ Calendar.addClass(cell, "weekend");
+ }
+ cell.innerHTML = Calendar._SDN[(i + fdow) % 7];
+ cell = cell.nextSibling;
+ }
+};
+
+/** Internal function. Hides all combo boxes that might be displayed. */
+Calendar.prototype._hideCombos = function () {
+ this.monthsCombo.style.display = "none";
+ this.yearsCombo.style.display = "none";
+};
+
+/** Internal function. Starts dragging the element. */
+Calendar.prototype._dragStart = function (ev) {
+ if (this.dragging) {
+ return;
+ }
+ this.dragging = true;
+ var posX;
+ var posY;
+ if (Calendar.is_ie) {
+ posY = window.event.clientY + document.body.scrollTop;
+ posX = window.event.clientX + document.body.scrollLeft;
+ } else {
+ posY = ev.clientY + window.scrollY;
+ posX = ev.clientX + window.scrollX;
+ }
+ var st = this.element.style;
+ this.xOffs = posX - parseInt(st.left);
+ this.yOffs = posY - parseInt(st.top);
+ with (Calendar) {
+ addEvent(document, "mousemove", calDragIt);
+ addEvent(document, "mouseup", calDragEnd);
+ }
+};
+
+// BEGIN: DATE OBJECT PATCHES
+
+/** Adds the number of days array to the Date object. */
+Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
+
+/** Constants used for time computations */
+Date.SECOND = 1000 /* milliseconds */;
+Date.MINUTE = 60 * Date.SECOND;
+Date.HOUR = 60 * Date.MINUTE;
+Date.DAY = 24 * Date.HOUR;
+Date.WEEK = 7 * Date.DAY;
+
+Date.parseDate = function(str, fmt) {
+ var today = new Date();
+ var y = 0;
+ var m = -1;
+ var d = 0;
+ var a = str.split(/\W+/);
+ var b = fmt.match(/%./g);
+ var i = 0, j = 0;
+ var hr = 0;
+ var min = 0;
+ for (i = 0; i < a.length; ++i) {
+ if (!a[i])
+ continue;
+ switch (b[i]) {
+ case "%d":
+ case "%e":
+ d = parseInt(a[i], 10);
+ break;
+
+ case "%m":
+ m = parseInt(a[i], 10) - 1;
+ break;
+
+ case "%Y":
+ case "%y":
+ y = parseInt(a[i], 10);
+ (y < 100) && (y += (y > 29) ? 1900 : 2000);
+ break;
+
+ case "%b":
+ case "%B":
+ for (j = 0; j < 12; ++j) {
+ if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }
+ }
+ break;
+
+ case "%H":
+ case "%I":
+ case "%k":
+ case "%l":
+ hr = parseInt(a[i], 10);
+ break;
+
+ case "%P":
+ case "%p":
+ if (/pm/i.test(a[i]) && hr < 12)
+ hr += 12;
+ else if (/am/i.test(a[i]) && hr >= 12)
+ hr -= 12;
+ break;
+
+ case "%M":
+ min = parseInt(a[i], 10);
+ break;
+ }
+ }
+ if (isNaN(y)) y = today.getFullYear();
+ if (isNaN(m)) m = today.getMonth();
+ if (isNaN(d)) d = today.getDate();
+ if (isNaN(hr)) hr = today.getHours();
+ if (isNaN(min)) min = today.getMinutes();
+ if (y != 0 && m != -1 && d != 0)
+ return new Date(y, m, d, hr, min, 0);
+ y = 0; m = -1; d = 0;
+ for (i = 0; i < a.length; ++i) {
+ if (a[i].search(/[a-zA-Z]+/) != -1) {
+ var t = -1;
+ for (j = 0; j < 12; ++j) {
+ if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
+ }
+ if (t != -1) {
+ if (m != -1) {
+ d = m+1;
+ }
+ m = t;
+ }
+ } else if (parseInt(a[i], 10) <= 12 && m == -1) {
+ m = a[i]-1;
+ } else if (parseInt(a[i], 10) > 31 && y == 0) {
+ y = parseInt(a[i], 10);
+ (y < 100) && (y += (y > 29) ? 1900 : 2000);
+ } else if (d == 0) {
+ d = a[i];
+ }
+ }
+ if (y == 0)
+ y = today.getFullYear();
+ if (m != -1 && d != 0)
+ return new Date(y, m, d, hr, min, 0);
+ return today;
+};
+
+/** Returns the number of days in the current month */
+Date.prototype.getMonthDays = function(month) {
+ var year = this.getFullYear();
+ if (typeof month == "undefined") {
+ month = this.getMonth();
+ }
+ if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {
+ return 29;
+ } else {
+ return Date._MD[month];
+ }
+};
+
+/** Returns the number of day in the year. */
+Date.prototype.getDayOfYear = function() {
+ var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
+ var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
+ var time = now - then;
+ return Math.floor(time / Date.DAY);
+};
+
+/** Returns the number of the week in year, as defined in ISO 8601. */
+Date.prototype.getWeekNumber = function() {
+ var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
+ var DoW = d.getDay();
+ d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
+ var ms = d.valueOf(); // GMT
+ d.setMonth(0);
+ d.setDate(4); // Thu in Week 1
+ return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
+};
+
+/** Checks date and time equality */
+Date.prototype.equalsTo = function(date) {
+ return ((this.getFullYear() == date.getFullYear()) &&
+ (this.getMonth() == date.getMonth()) &&
+ (this.getDate() == date.getDate()) &&
+ (this.getHours() == date.getHours()) &&
+ (this.getMinutes() == date.getMinutes()));
+};
+
+/** Set only the year, month, date parts (keep existing time) */
+Date.prototype.setDateOnly = function(date) {
+ var tmp = new Date(date);
+ this.setDate(1);
+ this.setFullYear(tmp.getFullYear());
+ this.setMonth(tmp.getMonth());
+ this.setDate(tmp.getDate());
+};
+
+/** Prints the date in a string according to the given format. */
+Date.prototype.print = function (str) {
+ var m = this.getMonth();
+ var d = this.getDate();
+ var y = this.getFullYear();
+ var wn = this.getWeekNumber();
+ var w = this.getDay();
+ var s = {};
+ var hr = this.getHours();
+ var pm = (hr >= 12);
+ var ir = (pm) ? (hr - 12) : hr;
+ var dy = this.getDayOfYear();
+ if (ir == 0)
+ ir = 12;
+ var min = this.getMinutes();
+ var sec = this.getSeconds();
+ s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N]
+ s["%A"] = Calendar._DN[w]; // full weekday name
+ s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N]
+ s["%B"] = Calendar._MN[m]; // full month name
+ // FIXME: %c : preferred date and time representation for the current locale
+ s["%C"] = 1 + Math.floor(y / 100); // the century number
+ s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
+ s["%e"] = d; // the day of the month (range 1 to 31)
+ // FIXME: %D : american date style: %m/%d/%y
+ // FIXME: %E, %F, %G, %g, %h (man strftime)
+ s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
+ s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
+ s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
+ s["%k"] = hr; // hour, range 0 to 23 (24h format)
+ s["%l"] = ir; // hour, range 1 to 12 (12h format)
+ s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
+ s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
+ s["%n"] = "\n"; // a newline character
+ s["%p"] = pm ? "PM" : "AM";
+ s["%P"] = pm ? "pm" : "am";
+ // FIXME: %r : the time in am/pm notation %I:%M:%S %p
+ // FIXME: %R : the time in 24-hour notation %H:%M
+ s["%s"] = Math.floor(this.getTime() / 1000);
+ s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
+ s["%t"] = "\t"; // a tab character
+ // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
+ s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
+ s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON)
+ s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN)
+ // FIXME: %x : preferred date representation for the current locale without the time
+ // FIXME: %X : preferred time representation for the current locale without the date
+ s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
+ s["%Y"] = y; // year with the century
+ s["%%"] = "%"; // a literal '%' character
+
+ var re = /%./g;
+ if (!Calendar.is_ie5 && !Calendar.is_khtml)
+ return str.replace(re, function (par) { return s[par] || par; });
+
+ var a = str.match(re);
+ for (var i = 0; i < a.length; i++) {
+ var tmp = s[a[i]];
+ if (tmp) {
+ re = new RegExp(a[i], 'g');
+ str = str.replace(re, tmp);
+ }
+ }
+
+ return str;
+};
+
+Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
+Date.prototype.setFullYear = function(y) {
+ var d = new Date(this);
+ d.__msh_oldSetFullYear(y);
+ if (d.getMonth() != this.getMonth())
+ this.setDate(28);
+ this.__msh_oldSetFullYear(y);
+};
+
+// END: DATE OBJECT PATCHES
+
+
+// global object that remembers the calendar
+window._dynarch_popupCalendar = null;
diff --git a/public/javascripts/calendar/lang/calendar-de.js b/public/javascripts/calendar/lang/calendar-de.js
new file mode 100644
index 000000000..59fb983bf
--- /dev/null
+++ b/public/javascripts/calendar/lang/calendar-de.js
@@ -0,0 +1,128 @@
+// ** I18N
+
+// Calendar DE language
+// Author: Jack (tR), <jack@jtr.de>
+// Encoding: any
+// Distributed under the same terms as the calendar itself.
+
+// For translators: please use UTF-8 if possible. We strongly believe that
+// Unicode is the answer to a real internationalized world. Also please
+// include your contact information in the header, as can be seen above.
+
+// full day names
+Calendar._DN = new Array
+("Sonntag",
+ "Montag",
+ "Dienstag",
+ "Mittwoch",
+ "Donnerstag",
+ "Freitag",
+ "Samstag",
+ "Sonntag");
+
+// Please note that the following array of short day names (and the same goes
+// for short month names, _SMN) isn't absolutely necessary. We give it here
+// for exemplification on how one can customize the short day names, but if
+// they are simply the first N letters of the full name you can simply say:
+//
+// Calendar._SDN_len = N; // short day name length
+// Calendar._SMN_len = N; // short month name length
+//
+// If N = 3 then this is not needed either since we assume a value of 3 if not
+// present, to be compatible with translation files that were written before
+// this feature.
+
+// First day of the week. "0" means display Sunday first, "1" means display
+// Monday first, etc.
+Calendar._FD = 1;
+
+// short day names
+Calendar._SDN = new Array
+("So",
+ "Mo",
+ "Di",
+ "Mi",
+ "Do",
+ "Fr",
+ "Sa",
+ "So");
+
+// full month names
+Calendar._MN = new Array
+("Januar",
+ "Februar",
+ "M\u00e4rz",
+ "April",
+ "Mai",
+ "Juni",
+ "Juli",
+ "August",
+ "September",
+ "Oktober",
+ "November",
+ "Dezember");
+
+// short month names
+Calendar._SMN = new Array
+("Jan",
+ "Feb",
+ "M\u00e4r",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Okt",
+ "Nov",
+ "Dez");
+
+// tooltips
+Calendar._TT = {};
+Calendar._TT["INFO"] = "\u00DCber dieses Kalendarmodul";
+
+Calendar._TT["ABOUT"] =
+"DHTML Date/Time Selector\n" +
+"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this ;-)
+"For latest version visit: http://www.dynarch.com/projects/calendar/\n" +
+"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." +
+"\n\n" +
+"Datum ausw\u00e4hlen:\n" +
+"- Benutzen Sie die \xab, \xbb Buttons um das Jahr zu w\u00e4hlen\n" +
+"- Benutzen Sie die " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " Buttons um den Monat zu w\u00e4hlen\n" +
+"- F\u00fcr eine Schnellauswahl halten Sie die Maustaste \u00fcber diesen Buttons fest.";
+Calendar._TT["ABOUT_TIME"] = "\n\n" +
+"Zeit ausw\u00e4hlen:\n" +
+"- Klicken Sie auf die Teile der Uhrzeit, um diese zu erh\u00F6hen\n" +
+"- oder klicken Sie mit festgehaltener Shift-Taste um diese zu verringern\n" +
+"- oder klicken und festhalten f\u00fcr Schnellauswahl.";
+
+Calendar._TT["TOGGLE"] = "Ersten Tag der Woche w\u00e4hlen";
+Calendar._TT["PREV_YEAR"] = "Voriges Jahr (Festhalten f\u00fcr Schnellauswahl)";
+Calendar._TT["PREV_MONTH"] = "Voriger Monat (Festhalten f\u00fcr Schnellauswahl)";
+Calendar._TT["GO_TODAY"] = "Heute ausw\u00e4hlen";
+Calendar._TT["NEXT_MONTH"] = "N\u00e4chst. Monat (Festhalten f\u00fcr Schnellauswahl)";
+Calendar._TT["NEXT_YEAR"] = "N\u00e4chst. Jahr (Festhalten f\u00fcr Schnellauswahl)";
+Calendar._TT["SEL_DATE"] = "Datum ausw\u00e4hlen";
+Calendar._TT["DRAG_TO_MOVE"] = "Zum Bewegen festhalten";
+Calendar._TT["PART_TODAY"] = " (Heute)";
+
+// the following is to inform that "%s" is to be the first day of week
+// %s will be replaced with the day name.
+Calendar._TT["DAY_FIRST"] = "Woche beginnt mit %s ";
+
+// This may be locale-dependent. It specifies the week-end days, as an array
+// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1
+// means Monday, etc.
+Calendar._TT["WEEKEND"] = "0,6";
+
+Calendar._TT["CLOSE"] = "Schlie\u00dfen";
+Calendar._TT["TODAY"] = "Heute";
+Calendar._TT["TIME_PART"] = "(Shift-)Klick oder Festhalten und Ziehen um den Wert zu \u00e4ndern";
+
+// date formats
+Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y";
+Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";
+
+Calendar._TT["WK"] = "wk";
+Calendar._TT["TIME"] = "Zeit:";
diff --git a/public/javascripts/calendar/lang/calendar-en.js b/public/javascripts/calendar/lang/calendar-en.js
new file mode 100644
index 000000000..0dbde793d
--- /dev/null
+++ b/public/javascripts/calendar/lang/calendar-en.js
@@ -0,0 +1,127 @@
+// ** I18N
+
+// Calendar EN language
+// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
+// Encoding: any
+// Distributed under the same terms as the calendar itself.
+
+// For translators: please use UTF-8 if possible. We strongly believe that
+// Unicode is the answer to a real internationalized world. Also please
+// include your contact information in the header, as can be seen above.
+
+// full day names
+Calendar._DN = new Array
+("Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday");
+
+// Please note that the following array of short day names (and the same goes
+// for short month names, _SMN) isn't absolutely necessary. We give it here
+// for exemplification on how one can customize the short day names, but if
+// they are simply the first N letters of the full name you can simply say:
+//
+// Calendar._SDN_len = N; // short day name length
+// Calendar._SMN_len = N; // short month name length
+//
+// If N = 3 then this is not needed either since we assume a value of 3 if not
+// present, to be compatible with translation files that were written before
+// this feature.
+
+// short day names
+Calendar._SDN = new Array
+("Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat",
+ "Sun");
+
+// First day of the week. "0" means display Sunday first, "1" means display
+// Monday first, etc.
+Calendar._FD = 0;
+
+// full month names
+Calendar._MN = new Array
+("January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December");
+
+// short month names
+Calendar._SMN = new Array
+("Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec");
+
+// tooltips
+Calendar._TT = {};
+Calendar._TT["INFO"] = "About the calendar";
+
+Calendar._TT["ABOUT"] =
+"DHTML Date/Time Selector\n" +
+"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
+"For latest version visit: http://www.dynarch.com/projects/calendar/\n" +
+"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." +
+"\n\n" +
+"Date selection:\n" +
+"- Use the \xab, \xbb buttons to select year\n" +
+"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" +
+"- Hold mouse button on any of the above buttons for faster selection.";
+Calendar._TT["ABOUT_TIME"] = "\n\n" +
+"Time selection:\n" +
+"- Click on any of the time parts to increase it\n" +
+"- or Shift-click to decrease it\n" +
+"- or click and drag for faster selection.";
+
+Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)";
+Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)";
+Calendar._TT["GO_TODAY"] = "Go Today";
+Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)";
+Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)";
+Calendar._TT["SEL_DATE"] = "Select date";
+Calendar._TT["DRAG_TO_MOVE"] = "Drag to move";
+Calendar._TT["PART_TODAY"] = " (today)";
+
+// the following is to inform that "%s" is to be the first day of week
+// %s will be replaced with the day name.
+Calendar._TT["DAY_FIRST"] = "Display %s first";
+
+// This may be locale-dependent. It specifies the week-end days, as an array
+// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1
+// means Monday, etc.
+Calendar._TT["WEEKEND"] = "0,6";
+
+Calendar._TT["CLOSE"] = "Close";
+Calendar._TT["TODAY"] = "Today";
+Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value";
+
+// date formats
+Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d";
+Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";
+
+Calendar._TT["WK"] = "wk";
+Calendar._TT["TIME"] = "Time:";
diff --git a/public/javascripts/calendar/lang/calendar-es.js b/public/javascripts/calendar/lang/calendar-es.js
new file mode 100644
index 000000000..11d0b53d5
--- /dev/null
+++ b/public/javascripts/calendar/lang/calendar-es.js
@@ -0,0 +1,129 @@
+// ** I18N
+
+// Calendar ES (spanish) language
+// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
+// Updater: Servilio Afre Puentes <servilios@yahoo.com>
+// Updated: 2004-06-03
+// Encoding: utf-8
+// Distributed under the same terms as the calendar itself.
+
+// For translators: please use UTF-8 if possible. We strongly believe that
+// Unicode is the answer to a real internationalized world. Also please
+// include your contact information in the header, as can be seen above.
+
+// full day names
+Calendar._DN = new Array
+("Domingo",
+ "Lunes",
+ "Martes",
+ "Miércoles",
+ "Jueves",
+ "Viernes",
+ "Sábado",
+ "Domingo");
+
+// Please note that the following array of short day names (and the same goes
+// for short month names, _SMN) isn't absolutely necessary. We give it here
+// for exemplification on how one can customize the short day names, but if
+// they are simply the first N letters of the full name you can simply say:
+//
+// Calendar._SDN_len = N; // short day name length
+// Calendar._SMN_len = N; // short month name length
+//
+// If N = 3 then this is not needed either since we assume a value of 3 if not
+// present, to be compatible with translation files that were written before
+// this feature.
+
+// short day names
+Calendar._SDN = new Array
+("Dom",
+ "Lun",
+ "Mar",
+ "Mié",
+ "Jue",
+ "Vie",
+ "Sáb",
+ "Dom");
+
+// First day of the week. "0" means display Sunday first, "1" means display
+// Monday first, etc.
+Calendar._FD = 1;
+
+// full month names
+Calendar._MN = new Array
+("Enero",
+ "Febrero",
+ "Marzo",
+ "Abril",
+ "Mayo",
+ "Junio",
+ "Julio",
+ "Agosto",
+ "Septiembre",
+ "Octubre",
+ "Noviembre",
+ "Diciembre");
+
+// short month names
+Calendar._SMN = new Array
+("Ene",
+ "Feb",
+ "Mar",
+ "Abr",
+ "May",
+ "Jun",
+ "Jul",
+ "Ago",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dic");
+
+// tooltips
+Calendar._TT = {};
+Calendar._TT["INFO"] = "Acerca del calendario";
+
+Calendar._TT["ABOUT"] =
+"Selector DHTML de Fecha/Hora\n" +
+"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
+"Para conseguir la última versión visite: http://www.dynarch.com/projects/calendar/\n" +
+"Distribuido bajo licencia GNU LGPL. Visite http://gnu.org/licenses/lgpl.html para más detalles." +
+"\n\n" +
+"Selección de fecha:\n" +
+"- Use los botones \xab, \xbb para seleccionar el año\n" +
+"- Use los botones " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionar el mes\n" +
+"- Mantenga pulsado el ratón en cualquiera de estos botones para una selección rápida.";
+Calendar._TT["ABOUT_TIME"] = "\n\n" +
+"Selección de hora:\n" +
+"- Pulse en cualquiera de las partes de la hora para incrementarla\n" +
+"- o pulse las mayúsculas mientras hace clic para decrementarla\n" +
+"- o haga clic y arrastre el ratón para una selección más rápida.";
+
+Calendar._TT["PREV_YEAR"] = "Año anterior (mantener para menú)";
+Calendar._TT["PREV_MONTH"] = "Mes anterior (mantener para menú)";
+Calendar._TT["GO_TODAY"] = "Ir a hoy";
+Calendar._TT["NEXT_MONTH"] = "Mes siguiente (mantener para menú)";
+Calendar._TT["NEXT_YEAR"] = "Año siguiente (mantener para menú)";
+Calendar._TT["SEL_DATE"] = "Seleccionar fecha";
+Calendar._TT["DRAG_TO_MOVE"] = "Arrastrar para mover";
+Calendar._TT["PART_TODAY"] = " (hoy)";
+
+// the following is to inform that "%s" is to be the first day of week
+// %s will be replaced with the day name.
+Calendar._TT["DAY_FIRST"] = "Hacer %s primer día de la semana";
+
+// This may be locale-dependent. It specifies the week-end days, as an array
+// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1
+// means Monday, etc.
+Calendar._TT["WEEKEND"] = "0,6";
+
+Calendar._TT["CLOSE"] = "Cerrar";
+Calendar._TT["TODAY"] = "Hoy";
+Calendar._TT["TIME_PART"] = "(Mayúscula-)Clic o arrastre para cambiar valor";
+
+// date formats
+Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y";
+Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y";
+
+Calendar._TT["WK"] = "sem";
+Calendar._TT["TIME"] = "Hora:";
diff --git a/public/javascripts/calendar/lang/calendar-fr.js b/public/javascripts/calendar/lang/calendar-fr.js
new file mode 100644
index 000000000..fb0cb2380
--- /dev/null
+++ b/public/javascripts/calendar/lang/calendar-fr.js
@@ -0,0 +1,129 @@
+// ** I18N
+
+// Calendar EN language
+// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
+// Encoding: any
+// Distributed under the same terms as the calendar itself.
+
+// For translators: please use UTF-8 if possible. We strongly believe that
+// Unicode is the answer to a real internationalized world. Also please
+// include your contact information in the header, as can be seen above.
+
+// Translator: David Duret, <pilgrim@mala-template.net> from previous french version
+
+// full day names
+Calendar._DN = new Array
+("Dimanche",
+ "Lundi",
+ "Mardi",
+ "Mercredi",
+ "Jeudi",
+ "Vendredi",
+ "Samedi",
+ "Dimanche");
+
+// Please note that the following array of short day names (and the same goes
+// for short month names, _SMN) isn't absolutely necessary. We give it here
+// for exemplification on how one can customize the short day names, but if
+// they are simply the first N letters of the full name you can simply say:
+//
+// Calendar._SDN_len = N; // short day name length
+// Calendar._SMN_len = N; // short month name length
+//
+// If N = 3 then this is not needed either since we assume a value of 3 if not
+// present, to be compatible with translation files that were written before
+// this feature.
+
+// short day names
+Calendar._SDN = new Array
+("Dim",
+ "Lun",
+ "Mar",
+ "Mar",
+ "Jeu",
+ "Ven",
+ "Sam",
+ "Dim");
+
+// First day of the week. "0" means display Sunday first, "1" means display
+// Monday first, etc.
+Calendar._FD = 1;
+
+// full month names
+Calendar._MN = new Array
+("Janvier",
+ "Février",
+ "Mars",
+ "Avril",
+ "Mai",
+ "Juin",
+ "Juillet",
+ "Août",
+ "Septembre",
+ "Octobre",
+ "Novembre",
+ "Décembre");
+
+// short month names
+Calendar._SMN = new Array
+("Jan",
+ "Fev",
+ "Mar",
+ "Avr",
+ "Mai",
+ "Juin",
+ "Juil",
+ "Aout",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec");
+
+// tooltips
+Calendar._TT = {};
+Calendar._TT["INFO"] = "A propos du calendrier";
+
+Calendar._TT["ABOUT"] =
+"DHTML Date/Heure Selecteur\n" +
+"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
+"Pour la derniere version visitez : http://www.dynarch.com/projects/calendar/\n" +
+"Distribué par GNU LGPL. Voir http://gnu.org/licenses/lgpl.html pour les details." +
+"\n\n" +
+"Selection de la date :\n" +
+"- Utiliser les bouttons \xab, \xbb pour selectionner l\'annee\n" +
+"- Utiliser les bouttons " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pour selectionner les mois\n" +
+"- Garder la souris sur n'importe quels boutons pour une selection plus rapide";
+Calendar._TT["ABOUT_TIME"] = "\n\n" +
+"Selection de l\'heure :\n" +
+"- Cliquer sur heures ou minutes pour incrementer\n" +
+"- ou Maj-clic pour decrementer\n" +
+"- ou clic et glisser-deplacer pour une selection plus rapide";
+
+Calendar._TT["PREV_YEAR"] = "Année préc. (maintenir pour menu)";
+Calendar._TT["PREV_MONTH"] = "Mois préc. (maintenir pour menu)";
+Calendar._TT["GO_TODAY"] = "Atteindre la date du jour";
+Calendar._TT["NEXT_MONTH"] = "Mois suiv. (maintenir pour menu)";
+Calendar._TT["NEXT_YEAR"] = "Année suiv. (maintenir pour menu)";
+Calendar._TT["SEL_DATE"] = "Sélectionner une date";
+Calendar._TT["DRAG_TO_MOVE"] = "Déplacer";
+Calendar._TT["PART_TODAY"] = " (Aujourd'hui)";
+
+// the following is to inform that "%s" is to be the first day of week
+// %s will be replaced with the day name.
+Calendar._TT["DAY_FIRST"] = "Afficher %s en premier";
+
+// This may be locale-dependent. It specifies the week-end days, as an array
+// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1
+// means Monday, etc.
+Calendar._TT["WEEKEND"] = "0,6";
+
+Calendar._TT["CLOSE"] = "Fermer";
+Calendar._TT["TODAY"] = "Aujourd'hui";
+Calendar._TT["TIME_PART"] = "(Maj-)Clic ou glisser pour modifier la valeur";
+
+// date formats
+Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y";
+Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";
+
+Calendar._TT["WK"] = "Sem.";
+Calendar._TT["TIME"] = "Heure :";
diff --git a/public/javascripts/controls.js b/public/javascripts/controls.js
new file mode 100644
index 000000000..9742b6918
--- /dev/null
+++ b/public/javascripts/controls.js
@@ -0,0 +1,750 @@
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+// Richard Livsey
+// Rahul Bhargava
+// Rob Wills
+//
+// See scriptaculous.js for full license.
+
+// Autocompleter.Base handles all the autocompletion functionality
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least,
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most
+// useful when one of the tokens is \n (a newline), as it
+// allows smart autocompletion after linebreaks.
+
+var Autocompleter = {}
+Autocompleter.Base = function() {};
+Autocompleter.Base.prototype = {
+ baseInitialize: function(element, update, options) {
+ this.element = $(element);
+ this.update = $(update);
+ this.hasFocus = false;
+ this.changed = false;
+ this.active = false;
+ this.index = 0;
+ this.entryCount = 0;
+
+ if (this.setOptions)
+ this.setOptions(options);
+ else
+ this.options = options || {};
+
+ this.options.paramName = this.options.paramName || this.element.name;
+ this.options.tokens = this.options.tokens || [];
+ this.options.frequency = this.options.frequency || 0.4;
+ this.options.minChars = this.options.minChars || 1;
+ this.options.onShow = this.options.onShow ||
+ function(element, update){
+ if(!update.style.position || update.style.position=='absolute') {
+ update.style.position = 'absolute';
+ Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
+ }
+ Effect.Appear(update,{duration:0.15});
+ };
+ this.options.onHide = this.options.onHide ||
+ function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+
+ if (typeof(this.options.tokens) == 'string')
+ this.options.tokens = new Array(this.options.tokens);
+
+ this.observer = null;
+
+ this.element.setAttribute('autocomplete','off');
+
+ Element.hide(this.update);
+
+ Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
+ Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
+ },
+
+ show: function() {
+ if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
+ if(!this.iefix &&
+ (navigator.appVersion.indexOf('MSIE')>0) &&
+ (navigator.userAgent.indexOf('Opera')<0) &&
+ (Element.getStyle(this.update, 'position')=='absolute')) {
+ new Insertion.After(this.update,
+ '<iframe id="' + this.update.id + '_iefix" '+
+ 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+ 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+ this.iefix = $(this.update.id+'_iefix');
+ }
+ if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
+ },
+
+ fixIEOverlapping: function() {
+ Position.clone(this.update, this.iefix);
+ this.iefix.style.zIndex = 1;
+ this.update.style.zIndex = 2;
+ Element.show(this.iefix);
+ },
+
+ hide: function() {
+ this.stopIndicator();
+ if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
+ if(this.iefix) Element.hide(this.iefix);
+ },
+
+ startIndicator: function() {
+ if(this.options.indicator) Element.show(this.options.indicator);
+ },
+
+ stopIndicator: function() {
+ if(this.options.indicator) Element.hide(this.options.indicator);
+ },
+
+ onKeyPress: function(event) {
+ if(this.active)
+ switch(event.keyCode) {
+ case Event.KEY_TAB:
+ case Event.KEY_RETURN:
+ this.selectEntry();
+ Event.stop(event);
+ case Event.KEY_ESC:
+ this.hide();
+ this.active = false;
+ Event.stop(event);
+ return;
+ case Event.KEY_LEFT:
+ case Event.KEY_RIGHT:
+ return;
+ case Event.KEY_UP:
+ this.markPrevious();
+ this.render();
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+ return;
+ case Event.KEY_DOWN:
+ this.markNext();
+ this.render();
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+ return;
+ }
+ else
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
+ return;
+
+ this.changed = true;
+ this.hasFocus = true;
+
+ if(this.observer) clearTimeout(this.observer);
+ this.observer =
+ setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
+ },
+
+ onHover: function(event) {
+ var element = Event.findElement(event, 'LI');
+ if(this.index != element.autocompleteIndex)
+ {
+ this.index = element.autocompleteIndex;
+ this.render();
+ }
+ Event.stop(event);
+ },
+
+ onClick: function(event) {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ },
+
+ onBlur: function(event) {
+ // needed to make click events working
+ setTimeout(this.hide.bind(this), 250);
+ this.hasFocus = false;
+ this.active = false;
+ },
+
+ render: function() {
+ if(this.entryCount > 0) {
+ for (var i = 0; i < this.entryCount; i++)
+ this.index==i ?
+ Element.addClassName(this.getEntry(i),"selected") :
+ Element.removeClassName(this.getEntry(i),"selected");
+
+ if(this.hasFocus) {
+ this.show();
+ this.active = true;
+ }
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ markPrevious: function() {
+ if(this.index > 0) this.index--
+ else this.index = this.entryCount-1;
+ },
+
+ markNext: function() {
+ if(this.index < this.entryCount-1) this.index++
+ else this.index = 0;
+ },
+
+ getEntry: function(index) {
+ return this.update.firstChild.childNodes[index];
+ },
+
+ getCurrentEntry: function() {
+ return this.getEntry(this.index);
+ },
+
+ selectEntry: function() {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ },
+
+ updateElement: function(selectedElement) {
+ if (this.options.updateElement) {
+ this.options.updateElement(selectedElement);
+ return;
+ }
+
+ var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+ var lastTokenPos = this.findLastToken();
+ if (lastTokenPos != -1) {
+ var newValue = this.element.value.substr(0, lastTokenPos + 1);
+ var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
+ if (whitespace)
+ newValue += whitespace[0];
+ this.element.value = newValue + value;
+ } else {
+ this.element.value = value;
+ }
+ this.element.focus();
+
+ if (this.options.afterUpdateElement)
+ this.options.afterUpdateElement(this.element, selectedElement);
+ },
+
+ updateChoices: function(choices) {
+ if(!this.changed && this.hasFocus) {
+ this.update.innerHTML = choices;
+ Element.cleanWhitespace(this.update);
+ Element.cleanWhitespace(this.update.firstChild);
+
+ if(this.update.firstChild && this.update.firstChild.childNodes) {
+ this.entryCount =
+ this.update.firstChild.childNodes.length;
+ for (var i = 0; i < this.entryCount; i++) {
+ var entry = this.getEntry(i);
+ entry.autocompleteIndex = i;
+ this.addObservers(entry);
+ }
+ } else {
+ this.entryCount = 0;
+ }
+
+ this.stopIndicator();
+
+ this.index = 0;
+ this.render();
+ }
+ },
+
+ addObservers: function(element) {
+ Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+ Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+ },
+
+ onObserverEvent: function() {
+ this.changed = false;
+ if(this.getToken().length>=this.options.minChars) {
+ this.startIndicator();
+ this.getUpdatedChoices();
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ getToken: function() {
+ var tokenPos = this.findLastToken();
+ if (tokenPos != -1)
+ var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
+ else
+ var ret = this.element.value;
+
+ return /\n/.test(ret) ? '' : ret;
+ },
+
+ findLastToken: function() {
+ var lastTokenPos = -1;
+
+ for (var i=0; i<this.options.tokens.length; i++) {
+ var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
+ if (thisTokenPos > lastTokenPos)
+ lastTokenPos = thisTokenPos;
+ }
+ return lastTokenPos;
+ }
+}
+
+Ajax.Autocompleter = Class.create();
+Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
+ initialize: function(element, update, url, options) {
+ this.baseInitialize(element, update, options);
+ this.options.asynchronous = true;
+ this.options.onComplete = this.onComplete.bind(this);
+ this.options.defaultParams = this.options.parameters || null;
+ this.url = url;
+ },
+
+ getUpdatedChoices: function() {
+ entry = encodeURIComponent(this.options.paramName) + '=' +
+ encodeURIComponent(this.getToken());
+
+ this.options.parameters = this.options.callback ?
+ this.options.callback(this.element, entry) : entry;
+
+ if(this.options.defaultParams)
+ this.options.parameters += '&' + this.options.defaultParams;
+
+ new Ajax.Request(this.url, this.options);
+ },
+
+ onComplete: function(request) {
+ this.updateChoices(request.responseText);
+ }
+
+});
+
+// The local array autocompleter. Used when you'd prefer to
+// inject an array of autocompletion options into the page, rather
+// than sending out Ajax queries, which can be quite slow sometimes.
+//
+// The constructor takes four parameters. The first two are, as usual,
+// the id of the monitored textbox, and id of the autocompletion menu.
+// The third is the array you want to autocomplete from, and the fourth
+// is the options block.
+//
+// Extra local autocompletion options:
+// - choices - How many autocompletion choices to offer
+//
+// - partialSearch - If false, the autocompleter will match entered
+// text only at the beginning of strings in the
+// autocomplete array. Defaults to true, which will
+// match text at the beginning of any *word* in the
+// strings in the autocomplete array. If you want to
+// search anywhere in the string, additionally set
+// the option fullSearch to true (default: off).
+//
+// - fullSsearch - Search anywhere in autocomplete array strings.
+//
+// - partialChars - How many characters to enter before triggering
+// a partial match (unlike minChars, which defines
+// how many characters are required to do any match
+// at all). Defaults to 2.
+//
+// - ignoreCase - Whether to ignore case when autocompleting.
+// Defaults to true.
+//
+// It's possible to pass in a custom function as the 'selector'
+// option, if you prefer to write your own autocompletion logic.
+// In that case, the other options above will not apply unless
+// you support them.
+
+Autocompleter.Local = Class.create();
+Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
+ initialize: function(element, update, array, options) {
+ this.baseInitialize(element, update, options);
+ this.options.array = array;
+ },
+
+ getUpdatedChoices: function() {
+ this.updateChoices(this.options.selector(this));
+ },
+
+ setOptions: function(options) {
+ this.options = Object.extend({
+ choices: 10,
+ partialSearch: true,
+ partialChars: 2,
+ ignoreCase: true,
+ fullSearch: false,
+ selector: function(instance) {
+ var ret = []; // Beginning matches
+ var partial = []; // Inside matches
+ var entry = instance.getToken();
+ var count = 0;
+
+ for (var i = 0; i < instance.options.array.length &&
+ ret.length < instance.options.choices ; i++) {
+
+ var elem = instance.options.array[i];
+ var foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase()) :
+ elem.indexOf(entry);
+
+ while (foundPos != -1) {
+ if (foundPos == 0 && elem.length != entry.length) {
+ ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
+ elem.substr(entry.length) + "</li>");
+ break;
+ } else if (entry.length >= instance.options.partialChars &&
+ instance.options.partialSearch && foundPos != -1) {
+ if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
+ partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+ elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
+ foundPos + entry.length) + "</li>");
+ break;
+ }
+ }
+
+ foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
+ elem.indexOf(entry, foundPos + 1);
+
+ }
+ }
+ if (partial.length)
+ ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
+ return "<ul>" + ret.join('') + "</ul>";
+ }
+ }, options || {});
+ }
+});
+
+// AJAX in-place editor
+//
+// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
+
+// Use this if you notice weird scrolling problems on some browsers,
+// the DOM might be a bit confused when this gets called so do this
+// waits 1 ms (with setTimeout) until it does the activation
+Field.scrollFreeActivate = function(field) {
+ setTimeout(function() {
+ Field.activate(field);
+ }, 1);
+}
+
+Ajax.InPlaceEditor = Class.create();
+Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
+Ajax.InPlaceEditor.prototype = {
+ initialize: function(element, url, options) {
+ this.url = url;
+ this.element = $(element);
+
+ this.options = Object.extend({
+ okText: "ok",
+ cancelText: "cancel",
+ savingText: "Saving...",
+ clickToEditText: "Click to edit",
+ okText: "ok",
+ rows: 1,
+ onComplete: function(transport, element) {
+ new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
+ },
+ onFailure: function(transport) {
+ alert("Error communicating with the server: " + transport.responseText.stripTags());
+ },
+ callback: function(form) {
+ return Form.serialize(form);
+ },
+ handleLineBreaks: true,
+ loadingText: 'Loading...',
+ savingClassName: 'inplaceeditor-saving',
+ loadingClassName: 'inplaceeditor-loading',
+ formClassName: 'inplaceeditor-form',
+ highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
+ highlightendcolor: "#FFFFFF",
+ externalControl: null,
+ ajaxOptions: {}
+ }, options || {});
+
+ if(!this.options.formId && this.element.id) {
+ this.options.formId = this.element.id + "-inplaceeditor";
+ if ($(this.options.formId)) {
+ // there's already a form with that name, don't specify an id
+ this.options.formId = null;
+ }
+ }
+
+ if (this.options.externalControl) {
+ this.options.externalControl = $(this.options.externalControl);
+ }
+
+ this.originalBackground = Element.getStyle(this.element, 'background-color');
+ if (!this.originalBackground) {
+ this.originalBackground = "transparent";
+ }
+
+ this.element.title = this.options.clickToEditText;
+
+ this.onclickListener = this.enterEditMode.bindAsEventListener(this);
+ this.mouseoverListener = this.enterHover.bindAsEventListener(this);
+ this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
+ Event.observe(this.element, 'click', this.onclickListener);
+ Event.observe(this.element, 'mouseover', this.mouseoverListener);
+ Event.observe(this.element, 'mouseout', this.mouseoutListener);
+ if (this.options.externalControl) {
+ Event.observe(this.options.externalControl, 'click', this.onclickListener);
+ Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
+ Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
+ }
+ },
+ enterEditMode: function(evt) {
+ if (this.saving) return;
+ if (this.editing) return;
+ this.editing = true;
+ this.onEnterEditMode();
+ if (this.options.externalControl) {
+ Element.hide(this.options.externalControl);
+ }
+ Element.hide(this.element);
+ this.createForm();
+ this.element.parentNode.insertBefore(this.form, this.element);
+ Field.scrollFreeActivate(this.editField);
+ // stop the event to avoid a page refresh in Safari
+ if (evt) {
+ Event.stop(evt);
+ }
+ return false;
+ },
+ createForm: function() {
+ this.form = document.createElement("form");
+ this.form.id = this.options.formId;
+ Element.addClassName(this.form, this.options.formClassName)
+ this.form.onsubmit = this.onSubmit.bind(this);
+
+ this.createEditField();
+
+ if (this.options.textarea) {
+ var br = document.createElement("br");
+ this.form.appendChild(br);
+ }
+
+ okButton = document.createElement("input");
+ okButton.type = "submit";
+ okButton.value = this.options.okText;
+ this.form.appendChild(okButton);
+
+ cancelLink = document.createElement("a");
+ cancelLink.href = "#";
+ cancelLink.appendChild(document.createTextNode(this.options.cancelText));
+ cancelLink.onclick = this.onclickCancel.bind(this);
+ this.form.appendChild(cancelLink);
+ },
+ hasHTMLLineBreaks: function(string) {
+ if (!this.options.handleLineBreaks) return false;
+ return string.match(/<br/i) || string.match(/<p>/i);
+ },
+ convertHTMLLineBreaks: function(string) {
+ return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
+ },
+ createEditField: function() {
+ var text;
+ if(this.options.loadTextURL) {
+ text = this.options.loadingText;
+ } else {
+ text = this.getText();
+ }
+
+ if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
+ this.options.textarea = false;
+ var textField = document.createElement("input");
+ textField.type = "text";
+ textField.name = "value";
+ textField.value = text;
+ textField.style.backgroundColor = this.options.highlightcolor;
+ var size = this.options.size || this.options.cols || 0;
+ if (size != 0) textField.size = size;
+ this.editField = textField;
+ } else {
+ this.options.textarea = true;
+ var textArea = document.createElement("textarea");
+ textArea.name = "value";
+ textArea.value = this.convertHTMLLineBreaks(text);
+ textArea.rows = this.options.rows;
+ textArea.cols = this.options.cols || 40;
+ this.editField = textArea;
+ }
+
+ if(this.options.loadTextURL) {
+ this.loadExternalText();
+ }
+ this.form.appendChild(this.editField);
+ },
+ getText: function() {
+ return this.element.innerHTML;
+ },
+ loadExternalText: function() {
+ Element.addClassName(this.form, this.options.loadingClassName);
+ this.editField.disabled = true;
+ new Ajax.Request(
+ this.options.loadTextURL,
+ Object.extend({
+ asynchronous: true,
+ onComplete: this.onLoadedExternalText.bind(this)
+ }, this.options.ajaxOptions)
+ );
+ },
+ onLoadedExternalText: function(transport) {
+ Element.removeClassName(this.form, this.options.loadingClassName);
+ this.editField.disabled = false;
+ this.editField.value = transport.responseText.stripTags();
+ },
+ onclickCancel: function() {
+ this.onComplete();
+ this.leaveEditMode();
+ return false;
+ },
+ onFailure: function(transport) {
+ this.options.onFailure(transport);
+ if (this.oldInnerHTML) {
+ this.element.innerHTML = this.oldInnerHTML;
+ this.oldInnerHTML = null;
+ }
+ return false;
+ },
+ onSubmit: function() {
+ // onLoading resets these so we need to save them away for the Ajax call
+ var form = this.form;
+ var value = this.editField.value;
+
+ // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
+ // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
+ // to be displayed indefinitely
+ this.onLoading();
+
+ new Ajax.Updater(
+ {
+ success: this.element,
+ // don't update on failure (this could be an option)
+ failure: null
+ },
+ this.url,
+ Object.extend({
+ parameters: this.options.callback(form, value),
+ onComplete: this.onComplete.bind(this),
+ onFailure: this.onFailure.bind(this)
+ }, this.options.ajaxOptions)
+ );
+ // stop the event to avoid a page refresh in Safari
+ if (arguments.length > 1) {
+ Event.stop(arguments[0]);
+ }
+ return false;
+ },
+ onLoading: function() {
+ this.saving = true;
+ this.removeForm();
+ this.leaveHover();
+ this.showSaving();
+ },
+ showSaving: function() {
+ this.oldInnerHTML = this.element.innerHTML;
+ this.element.innerHTML = this.options.savingText;
+ Element.addClassName(this.element, this.options.savingClassName);
+ this.element.style.backgroundColor = this.originalBackground;
+ Element.show(this.element);
+ },
+ removeForm: function() {
+ if(this.form) {
+ if (this.form.parentNode) Element.remove(this.form);
+ this.form = null;
+ }
+ },
+ enterHover: function() {
+ if (this.saving) return;
+ this.element.style.backgroundColor = this.options.highlightcolor;
+ if (this.effect) {
+ this.effect.cancel();
+ }
+ Element.addClassName(this.element, this.options.hoverClassName)
+ },
+ leaveHover: function() {
+ if (this.options.backgroundColor) {
+ this.element.style.backgroundColor = this.oldBackground;
+ }
+ Element.removeClassName(this.element, this.options.hoverClassName)
+ if (this.saving) return;
+ this.effect = new Effect.Highlight(this.element, {
+ startcolor: this.options.highlightcolor,
+ endcolor: this.options.highlightendcolor,
+ restorecolor: this.originalBackground
+ });
+ },
+ leaveEditMode: function() {
+ Element.removeClassName(this.element, this.options.savingClassName);
+ this.removeForm();
+ this.leaveHover();
+ this.element.style.backgroundColor = this.originalBackground;
+ Element.show(this.element);
+ if (this.options.externalControl) {
+ Element.show(this.options.externalControl);
+ }
+ this.editing = false;
+ this.saving = false;
+ this.oldInnerHTML = null;
+ this.onLeaveEditMode();
+ },
+ onComplete: function(transport) {
+ this.leaveEditMode();
+ this.options.onComplete.bind(this)(transport, this.element);
+ },
+ onEnterEditMode: function() {},
+ onLeaveEditMode: function() {},
+ dispose: function() {
+ if (this.oldInnerHTML) {
+ this.element.innerHTML = this.oldInnerHTML;
+ }
+ this.leaveEditMode();
+ Event.stopObserving(this.element, 'click', this.onclickListener);
+ Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
+ Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
+ if (this.options.externalControl) {
+ Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
+ Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
+ Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
+ }
+ }
+};
+
+// Delayed observer, like Form.Element.Observer,
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create();
+Form.Element.DelayedObserver.prototype = {
+ initialize: function(element, delay, callback) {
+ this.delay = delay || 0.5;
+ this.element = $(element);
+ this.callback = callback;
+ this.timer = null;
+ this.lastValue = $F(this.element);
+ Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+ },
+ delayedListener: function(event) {
+ if(this.lastValue == $F(this.element)) return;
+ if(this.timer) clearTimeout(this.timer);
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+ this.lastValue = $F(this.element);
+ },
+ onTimerEvent: function() {
+ this.timer = null;
+ this.callback(this.element, $F(this.element));
+ }
+}; \ No newline at end of file
diff --git a/public/javascripts/dragdrop.js b/public/javascripts/dragdrop.js
new file mode 100644
index 000000000..92d1f7316
--- /dev/null
+++ b/public/javascripts/dragdrop.js
@@ -0,0 +1,584 @@
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// See scriptaculous.js for full license.
+
+/*--------------------------------------------------------------------------*/
+
+var Droppables = {
+ drops: [],
+
+ remove: function(element) {
+ this.drops = this.drops.reject(function(d) { return d.element==$(element) });
+ },
+
+ add: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ greedy: true,
+ hoverclass: null
+ }, arguments[1] || {});
+
+ // cache containers
+ if(options.containment) {
+ options._containers = [];
+ var containment = options.containment;
+ if((typeof containment == 'object') &&
+ (containment.constructor == Array)) {
+ containment.each( function(c) { options._containers.push($(c)) });
+ } else {
+ options._containers.push($(containment));
+ }
+ }
+
+ if(options.accept) options.accept = [options.accept].flatten();
+
+ Element.makePositioned(element); // fix IE
+ options.element = element;
+
+ this.drops.push(options);
+ },
+
+ isContained: function(element, drop) {
+ var parentNode = element.parentNode;
+ return drop._containers.detect(function(c) { return parentNode == c });
+ },
+
+ isAffected: function(point, element, drop) {
+ return (
+ (drop.element!=element) &&
+ ((!drop._containers) ||
+ this.isContained(element, drop)) &&
+ ((!drop.accept) ||
+ (Element.classNames(element).detect(
+ function(v) { return drop.accept.include(v) } ) )) &&
+ Position.within(drop.element, point[0], point[1]) );
+ },
+
+ deactivate: function(drop) {
+ if(drop.hoverclass)
+ Element.removeClassName(drop.element, drop.hoverclass);
+ this.last_active = null;
+ },
+
+ activate: function(drop) {
+ if(drop.hoverclass)
+ Element.addClassName(drop.element, drop.hoverclass);
+ this.last_active = drop;
+ },
+
+ show: function(point, element) {
+ if(!this.drops.length) return;
+
+ if(this.last_active) this.deactivate(this.last_active);
+ this.drops.each( function(drop) {
+ if(Droppables.isAffected(point, element, drop)) {
+ if(drop.onHover)
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+ if(drop.greedy) {
+ Droppables.activate(drop);
+ throw $break;
+ }
+ }
+ });
+ },
+
+ fire: function(event, element) {
+ if(!this.last_active) return;
+ Position.prepare();
+
+ if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
+ if (this.last_active.onDrop)
+ this.last_active.onDrop(element, this.last_active.element, event);
+ },
+
+ reset: function() {
+ if(this.last_active)
+ this.deactivate(this.last_active);
+ }
+}
+
+var Draggables = {
+ drags: [],
+ observers: [],
+
+ register: function(draggable) {
+ if(this.drags.length == 0) {
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
+
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+ Event.observe(document, "keypress", this.eventKeypress);
+ }
+ this.drags.push(draggable);
+ },
+
+ unregister: function(draggable) {
+ this.drags = this.drags.reject(function(d) { return d==draggable });
+ if(this.drags.length == 0) {
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ Event.stopObserving(document, "keypress", this.eventKeypress);
+ }
+ },
+
+ activate: function(draggable) {
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+ this.activeDraggable = draggable;
+ },
+
+ deactivate: function(draggbale) {
+ this.activeDraggable = null;
+ },
+
+ updateDrag: function(event) {
+ if(!this.activeDraggable) return;
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ // Mozilla-based browsers fire successive mousemove events with
+ // the same coordinates, prevent needless redrawing (moz bug?)
+ if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+ this._lastPointer = pointer;
+ this.activeDraggable.updateDrag(event, pointer);
+ },
+
+ endDrag: function(event) {
+ if(!this.activeDraggable) return;
+ this._lastPointer = null;
+ this.activeDraggable.endDrag(event);
+ },
+
+ keyPress: function(event) {
+ if(this.activeDraggable)
+ this.activeDraggable.keyPress(event);
+ },
+
+ addObserver: function(observer) {
+ this.observers.push(observer);
+ this._cacheObserverCallbacks();
+ },
+
+ removeObserver: function(element) { // element instead of observer fixes mem leaks
+ this.observers = this.observers.reject( function(o) { return o.element==element });
+ this._cacheObserverCallbacks();
+ },
+
+ notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
+ if(this[eventName+'Count'] > 0)
+ this.observers.each( function(o) {
+ if(o[eventName]) o[eventName](eventName, draggable, event);
+ });
+ },
+
+ _cacheObserverCallbacks: function() {
+ ['onStart','onEnd','onDrag'].each( function(eventName) {
+ Draggables[eventName+'Count'] = Draggables.observers.select(
+ function(o) { return o[eventName]; }
+ ).length;
+ });
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create();
+Draggable.prototype = {
+ initialize: function(element) {
+ var options = Object.extend({
+ handle: false,
+ starteffect: function(element) {
+ new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
+ },
+ reverteffect: function(element, top_offset, left_offset) {
+ var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+ element._revert = new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur});
+ },
+ endeffect: function(element) {
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
+ },
+ zindex: 1000,
+ revert: false,
+ snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
+ }, arguments[1] || {});
+
+ this.element = $(element);
+
+ if(options.handle && (typeof options.handle == 'string'))
+ this.handle = Element.childrenWithClassName(this.element, options.handle)[0];
+ if(!this.handle) this.handle = $(options.handle);
+ if(!this.handle) this.handle = this.element;
+
+ Element.makePositioned(this.element); // fix IE
+
+ this.delta = this.currentDelta();
+ this.options = options;
+ this.dragging = false;
+
+ this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
+
+ Draggables.register(this);
+ },
+
+ destroy: function() {
+ Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+ Draggables.unregister(this);
+ },
+
+ currentDelta: function() {
+ return([
+ parseInt(this.element.style.left || '0'),
+ parseInt(this.element.style.top || '0')]);
+ },
+
+ initDrag: function(event) {
+ if(Event.isLeftClick(event)) {
+ // abort on form elements, fixes a Firefox issue
+ var src = Event.element(event);
+ if(src.tagName && (
+ src.tagName=='INPUT' ||
+ src.tagName=='SELECT' ||
+ src.tagName=='BUTTON' ||
+ src.tagName=='TEXTAREA')) return;
+
+ if(this.element._revert) {
+ this.element._revert.cancel();
+ this.element._revert = null;
+ }
+
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var pos = Position.cumulativeOffset(this.element);
+ this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+
+ Draggables.activate(this);
+ Event.stop(event);
+ }
+ },
+
+ startDrag: function(event) {
+ this.dragging = true;
+
+ if(this.options.zindex) {
+ this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if(this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ Draggables.notify('onStart', this, event);
+ if(this.options.starteffect) this.options.starteffect(this.element);
+ },
+
+ updateDrag: function(event, pointer) {
+ if(!this.dragging) this.startDrag(event);
+ Position.prepare();
+ Droppables.show(pointer, this.element);
+ Draggables.notify('onDrag', this, event);
+ this.draw(pointer);
+ if(this.options.change) this.options.change(this);
+
+ // fix AppleWebKit rendering
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+ Event.stop(event);
+ },
+
+ finishDrag: function(event, success) {
+ this.dragging = false;
+
+ if(this.options.ghosting) {
+ Position.relativize(this.element);
+ Element.remove(this._clone);
+ this._clone = null;
+ }
+
+ if(success) Droppables.fire(event, this.element);
+ Draggables.notify('onEnd', this, event);
+
+ var revert = this.options.revert;
+ if(revert && typeof revert == 'function') revert = revert(this.element);
+
+ var d = this.currentDelta();
+ if(revert && this.options.reverteffect) {
+ this.options.reverteffect(this.element,
+ d[1]-this.delta[1], d[0]-this.delta[0]);
+ } else {
+ this.delta = d;
+ }
+
+ if(this.options.zindex)
+ this.element.style.zIndex = this.originalZ;
+
+ if(this.options.endeffect)
+ this.options.endeffect(this.element);
+
+ Draggables.deactivate(this);
+ Droppables.reset();
+ },
+
+ keyPress: function(event) {
+ if(!event.keyCode==Event.KEY_ESC) return;
+ this.finishDrag(event, false);
+ Event.stop(event);
+ },
+
+ endDrag: function(event) {
+ if(!this.dragging) return;
+ this.finishDrag(event, true);
+ Event.stop(event);
+ },
+
+ draw: function(point) {
+ var pos = Position.cumulativeOffset(this.element);
+ var d = this.currentDelta();
+ pos[0] -= d[0]; pos[1] -= d[1];
+
+ var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this));
+
+ if(this.options.snap) {
+ if(typeof this.options.snap == 'function') {
+ p = this.options.snap(p[0],p[1]);
+ } else {
+ if(this.options.snap instanceof Array) {
+ p = p.map( function(v, i) {
+ return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
+ } else {
+ p = p.map( function(v) {
+ return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
+ }
+ }}
+
+ var style = this.element.style;
+ if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+ style.left = p[0] + "px";
+ if((!this.options.constraint) || (this.options.constraint=='vertical'))
+ style.top = p[1] + "px";
+ if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create();
+SortableObserver.prototype = {
+ initialize: function(element, observer) {
+ this.element = $(element);
+ this.observer = observer;
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onStart: function() {
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onEnd: function() {
+ Sortable.unmark();
+ if(this.lastValue != Sortable.serialize(this.element))
+ this.observer(this.element)
+ }
+}
+
+var Sortable = {
+ sortables: new Array(),
+
+ options: function(element){
+ element = $(element);
+ return this.sortables.detect(function(s) { return s.element == element });
+ },
+
+ destroy: function(element){
+ element = $(element);
+ this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
+ Draggables.removeObserver(s.element);
+ s.droppables.each(function(d){ Droppables.remove(d) });
+ s.draggables.invoke('destroy');
+ });
+ this.sortables = this.sortables.reject(function(s) { return s.element == element });
+ },
+
+ create: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ element: element,
+ tag: 'li', // assumes li children, override with tag: 'tagname'
+ dropOnEmpty: false,
+ tree: false, // fixme: unimplemented
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
+ containment: element, // also takes array of elements (or id's); or false
+ handle: false, // or a CSS class
+ only: false,
+ hoverclass: null,
+ ghosting: false,
+ format: null,
+ onChange: Prototype.emptyFunction,
+ onUpdate: Prototype.emptyFunction
+ }, arguments[1] || {});
+
+ // clear any old sortable with same element
+ this.destroy(element);
+
+ // build options for the draggables
+ var options_for_draggable = {
+ revert: true,
+ ghosting: options.ghosting,
+ constraint: options.constraint,
+ handle: options.handle };
+
+ if(options.starteffect)
+ options_for_draggable.starteffect = options.starteffect;
+
+ if(options.reverteffect)
+ options_for_draggable.reverteffect = options.reverteffect;
+ else
+ if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+ element.style.top = 0;
+ element.style.left = 0;
+ };
+
+ if(options.endeffect)
+ options_for_draggable.endeffect = options.endeffect;
+
+ if(options.zindex)
+ options_for_draggable.zindex = options.zindex;
+
+ // build options for the droppables
+ var options_for_droppable = {
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass,
+ onHover: Sortable.onHover,
+ greedy: !options.dropOnEmpty
+ }
+
+ // fix for gecko engine
+ Element.cleanWhitespace(element);
+
+ options.draggables = [];
+ options.droppables = [];
+
+ // make it so
+
+ // drop on empty handling
+ if(options.dropOnEmpty) {
+ Droppables.add(element,
+ {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
+ options.droppables.push(element);
+ }
+
+ (this.findElements(element, options) || []).each( function(e) {
+ // handles are per-draggable
+ var handle = options.handle ?
+ Element.childrenWithClassName(e, options.handle)[0] : e;
+ options.draggables.push(
+ new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+ Droppables.add(e, options_for_droppable);
+ options.droppables.push(e);
+ });
+
+ // keep reference
+ this.sortables.push(options);
+
+ // for onupdate
+ Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+ },
+
+ // return all suitable-for-sortable elements in a guaranteed order
+ findElements: function(element, options) {
+ if(!element.hasChildNodes()) return null;
+ var elements = [];
+ $A(element.childNodes).each( function(e) {
+ if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
+ (!options.only || (Element.hasClassName(e, options.only))))
+ elements.push(e);
+ if(options.tree) {
+ var grandchildren = this.findElements(e, options);
+ if(grandchildren) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length>0 ? elements.flatten() : null);
+ },
+
+ onHover: function(element, dropon, overlap) {
+ if(overlap>0.5) {
+ Sortable.mark(dropon, 'before');
+ if(dropon.previousSibling != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, dropon);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ } else {
+ Sortable.mark(dropon, 'after');
+ var nextElement = dropon.nextSibling || null;
+ if(nextElement != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, nextElement);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ }
+ },
+
+ onEmptyHover: function(element, dropon) {
+ if(element.parentNode!=dropon) {
+ var oldParentNode = element.parentNode;
+ dropon.appendChild(element);
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon).onChange(element);
+ }
+ },
+
+ unmark: function() {
+ if(Sortable._marker) Element.hide(Sortable._marker);
+ },
+
+ mark: function(dropon, position) {
+ // mark on ghosting only
+ var sortable = Sortable.options(dropon.parentNode);
+ if(sortable && !sortable.ghosting) return;
+
+ if(!Sortable._marker) {
+ Sortable._marker = $('dropmarker') || document.createElement('DIV');
+ Element.hide(Sortable._marker);
+ Element.addClassName(Sortable._marker, 'dropmarker');
+ Sortable._marker.style.position = 'absolute';
+ document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+ }
+ var offsets = Position.cumulativeOffset(dropon);
+ Sortable._marker.style.left = offsets[0] + 'px';
+ Sortable._marker.style.top = offsets[1] + 'px';
+
+ if(position=='after')
+ if(sortable.overlap == 'horizontal')
+ Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
+ else
+ Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
+
+ Element.show(Sortable._marker);
+ },
+
+ serialize: function(element) {
+ element = $(element);
+ var sortableOptions = this.options(element);
+ var options = Object.extend({
+ tag: sortableOptions.tag,
+ only: sortableOptions.only,
+ name: element.id,
+ format: sortableOptions.format || /^[^_]*_(.*)$/
+ }, arguments[1] || {});
+ return $(this.findElements(element, options) || []).map( function(item) {
+ return (encodeURIComponent(options.name) + "[]=" +
+ encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : ''));
+ }).join("&");
+ }
+} \ No newline at end of file
diff --git a/public/javascripts/effects.js b/public/javascripts/effects.js
new file mode 100644
index 000000000..414398ce4
--- /dev/null
+++ b/public/javascripts/effects.js
@@ -0,0 +1,854 @@
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+// Justin Palmer (http://encytemedia.com/)
+// Mark Pilgrim (http://diveintomark.org/)
+// Martin Bialasinki
+//
+// See scriptaculous.js for full license.
+
+/* ------------- element ext -------------- */
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function() {
+ var color = '#';
+ if(this.slice(0,4) == 'rgb(') {
+ var cols = this.slice(4,this.length-1).split(',');
+ var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
+ } else {
+ if(this.slice(0,1) == '#') {
+ if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+ if(this.length==7) color = this.toLowerCase();
+ }
+ }
+ return(color.length==7 ? color : (arguments[0] || this));
+}
+
+Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
+ var children = $(element).childNodes;
+ var text = '';
+ var classtest = new RegExp('^([^ ]+ )*' + ignoreclass+ '( [^ ]+)*$','i');
+
+ for (var i = 0; i < children.length; i++) {
+ if(children[i].nodeType==3) {
+ text+=children[i].nodeValue;
+ } else {
+ if((!children[i].className.match(classtest)) && children[i].hasChildNodes())
+ text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass);
+ }
+ }
+
+ return text;
+}
+
+Element.setStyle = function(element, style) {
+ element = $(element);
+ for(k in style) element.style[k.camelize()] = style[k];
+}
+
+Element.setContentZoom = function(element, percent) {
+ Element.setStyle(element, {fontSize: (percent/100) + 'em'});
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+}
+
+Element.getOpacity = function(element){
+ var opacity;
+ if (opacity = Element.getStyle(element, 'opacity'))
+ return parseFloat(opacity);
+ if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))
+ if(opacity[1]) return parseFloat(opacity[1]) / 100;
+ return 1.0;
+}
+
+Element.setOpacity = function(element, value){
+ element= $(element);
+ if (value == 1){
+ Element.setStyle(element, { opacity:
+ (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
+ 0.999999 : null });
+ if(/MSIE/.test(navigator.userAgent))
+ Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
+ } else {
+ if(value < 0.00001) value = 0;
+ Element.setStyle(element, {opacity: value});
+ if(/MSIE/.test(navigator.userAgent))
+ Element.setStyle(element,
+ { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
+ 'alpha(opacity='+value*100+')' });
+ }
+}
+
+Element.getInlineOpacity = function(element){
+ return $(element).style.opacity || '';
+}
+
+Element.childrenWithClassName = function(element, className) {
+ return $A($(element).getElementsByTagName('*')).select(
+ function(c) { return Element.hasClassName(c, className) });
+}
+
+Array.prototype.call = function() {
+ var args = arguments;
+ this.each(function(f){ f.apply(this, args) });
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+ tagifyText: function(element) {
+ var tagifyStyle = 'position:relative';
+ if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
+ element = $(element);
+ $A(element.childNodes).each( function(child) {
+ if(child.nodeType==3) {
+ child.nodeValue.toArray().each( function(character) {
+ element.insertBefore(
+ Builder.node('span',{style: tagifyStyle},
+ character == ' ' ? String.fromCharCode(160) : character),
+ child);
+ });
+ Element.remove(child);
+ }
+ });
+ },
+ multiple: function(element, effect) {
+ var elements;
+ if(((typeof element == 'object') ||
+ (typeof element == 'function')) &&
+ (element.length))
+ elements = element;
+ else
+ elements = $(element).childNodes;
+
+ var options = Object.extend({
+ speed: 0.1,
+ delay: 0.0
+ }, arguments[2] || {});
+ var masterDelay = options.delay;
+
+ $A(elements).each( function(element, index) {
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+ });
+ }
+};
+
+var Effect2 = Effect; // deprecated
+
+/* ------------- transitions ------------- */
+
+Effect.Transitions = {}
+
+Effect.Transitions.linear = function(pos) {
+ return pos;
+}
+Effect.Transitions.sinoidal = function(pos) {
+ return (-Math.cos(pos*Math.PI)/2) + 0.5;
+}
+Effect.Transitions.reverse = function(pos) {
+ return 1-pos;
+}
+Effect.Transitions.flicker = function(pos) {
+ return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
+}
+Effect.Transitions.wobble = function(pos) {
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
+}
+Effect.Transitions.pulse = function(pos) {
+ return (Math.floor(pos*10) % 2 == 0 ?
+ (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
+}
+Effect.Transitions.none = function(pos) {
+ return 0;
+}
+Effect.Transitions.full = function(pos) {
+ return 1;
+}
+
+/* ------------- core effects ------------- */
+
+Effect.Queue = {
+ effects: [],
+ _each: function(iterator) {
+ this.effects._each(iterator);
+ },
+ interval: null,
+ add: function(effect) {
+ var timestamp = new Date().getTime();
+
+ switch(effect.options.queue) {
+ case 'front':
+ // move unstarted effects after this effect
+ this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+ e.startOn += effect.finishOn;
+ e.finishOn += effect.finishOn;
+ });
+ break;
+ case 'end':
+ // start effect after last queued effect has finished
+ timestamp = this.effects.pluck('finishOn').max() || timestamp;
+ break;
+ }
+
+ effect.startOn += timestamp;
+ effect.finishOn += timestamp;
+ this.effects.push(effect);
+ if(!this.interval)
+ this.interval = setInterval(this.loop.bind(this), 40);
+ },
+ remove: function(effect) {
+ this.effects = this.effects.reject(function(e) { return e==effect });
+ if(this.effects.length == 0) {
+ clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+ loop: function() {
+ var timePos = new Date().getTime();
+ this.effects.invoke('loop', timePos);
+ }
+}
+Object.extend(Effect.Queue, Enumerable);
+
+Effect.Base = function() {};
+Effect.Base.prototype = {
+ position: null,
+ setOptions: function(options) {
+ this.options = Object.extend({
+ transition: Effect.Transitions.sinoidal,
+ duration: 1.0, // seconds
+ fps: 25.0, // max. 25fps due to Effect.Queue implementation
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
+ }, options || {});
+ },
+ start: function(options) {
+ this.setOptions(options || {});
+ this.currentFrame = 0;
+ this.state = 'idle';
+ this.startOn = this.options.delay*1000;
+ this.finishOn = this.startOn + (this.options.duration*1000);
+ this.event('beforeStart');
+ if(!this.options.sync) Effect.Queue.add(this);
+ },
+ loop: function(timePos) {
+ if(timePos >= this.startOn) {
+ if(timePos >= this.finishOn) {
+ this.render(1.0);
+ this.cancel();
+ this.event('beforeFinish');
+ if(this.finish) this.finish();
+ this.event('afterFinish');
+ return;
+ }
+ var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
+ var frame = Math.round(pos * this.options.fps * this.options.duration);
+ if(frame > this.currentFrame) {
+ this.render(pos);
+ this.currentFrame = frame;
+ }
+ }
+ },
+ render: function(pos) {
+ if(this.state == 'idle') {
+ this.state = 'running';
+ this.event('beforeSetup');
+ if(this.setup) this.setup();
+ this.event('afterSetup');
+ }
+ if(this.state == 'running') {
+ if(this.options.transition) pos = this.options.transition(pos);
+ pos *= (this.options.to-this.options.from);
+ pos += this.options.from;
+ this.position = pos;
+ this.event('beforeUpdate');
+ if(this.update) this.update(pos);
+ this.event('afterUpdate');
+ }
+ },
+ cancel: function() {
+ if(!this.options.sync) Effect.Queue.remove(this);
+ this.state = 'finished';
+ },
+ event: function(eventName) {
+ if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+ if(this.options[eventName]) this.options[eventName](this);
+ },
+ inspect: function() {
+ return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
+ }
+}
+
+Effect.Parallel = Class.create();
+Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
+ initialize: function(effects) {
+ this.effects = effects || [];
+ this.start(arguments[1]);
+ },
+ update: function(position) {
+ this.effects.invoke('render', position);
+ },
+ finish: function(position) {
+ this.effects.each( function(effect) {
+ effect.render(1.0);
+ effect.cancel();
+ effect.event('beforeFinish');
+ if(effect.finish) effect.finish(position);
+ effect.event('afterFinish');
+ });
+ }
+});
+
+Effect.Opacity = Class.create();
+Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
+ initialize: function(element) {
+ this.element = $(element);
+ // make this work on IE on elements without 'layout'
+ if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
+ Element.setStyle(this.element, {zoom: 1});
+ var options = Object.extend({
+ from: Element.getOpacity(this.element) || 0.0,
+ to: 1.0
+ }, arguments[1] || {});
+ this.start(options);
+ },
+ update: function(position) {
+ Element.setOpacity(this.element, position);
+ }
+});
+
+Effect.MoveBy = Class.create();
+Object.extend(Object.extend(Effect.MoveBy.prototype, Effect.Base.prototype), {
+ initialize: function(element, toTop, toLeft) {
+ this.element = $(element);
+ this.toTop = toTop;
+ this.toLeft = toLeft;
+ this.start(arguments[3]);
+ },
+ setup: function() {
+ // Bug in Opera: Opera returns the "real" position of a static element or
+ // relative element that does not have top/left explicitly set.
+ // ==> Always set top and left for position relative elements in your stylesheets
+ // (to 0 if you do not need them)
+ Element.makePositioned(this.element);
+ this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0');
+ this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
+ },
+ update: function(position) {
+ Element.setStyle(this.element, {
+ top: this.toTop * position + this.originalTop + 'px',
+ left: this.toLeft * position + this.originalLeft + 'px'
+ });
+ }
+});
+
+Effect.Scale = Class.create();
+Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
+ initialize: function(element, percent) {
+ this.element = $(element)
+ var options = Object.extend({
+ scaleX: true,
+ scaleY: true,
+ scaleContent: true,
+ scaleFromCenter: false,
+ scaleMode: 'box', // 'box' or 'contents' or {} with provided values
+ scaleFrom: 100.0,
+ scaleTo: percent
+ }, arguments[2] || {});
+ this.start(options);
+ },
+ setup: function() {
+ this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+ this.elementPositioning = Element.getStyle(this.element,'position');
+
+ this.originalStyle = {};
+ ['top','left','width','height','fontSize'].each( function(k) {
+ this.originalStyle[k] = this.element.style[k];
+ }.bind(this));
+
+ this.originalTop = this.element.offsetTop;
+ this.originalLeft = this.element.offsetLeft;
+
+ var fontSize = Element.getStyle(this.element,'font-size') || '100%';
+ ['em','px','%'].each( function(fontSizeType) {
+ if(fontSize.indexOf(fontSizeType)>0) {
+ this.fontSize = parseFloat(fontSize);
+ this.fontSizeType = fontSizeType;
+ }
+ }.bind(this));
+
+ this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+
+ this.dims = null;
+ if(this.options.scaleMode=='box')
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+ if(/^content/.test(this.options.scaleMode))
+ this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+ if(!this.dims)
+ this.dims = [this.options.scaleMode.originalHeight,
+ this.options.scaleMode.originalWidth];
+ },
+ update: function(position) {
+ var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
+ if(this.options.scaleContent && this.fontSize)
+ Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType });
+ this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+ },
+ finish: function(position) {
+ if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle);
+ },
+ setDimensions: function(height, width) {
+ var d = {};
+ if(this.options.scaleX) d.width = width + 'px';
+ if(this.options.scaleY) d.height = height + 'px';
+ if(this.options.scaleFromCenter) {
+ var topd = (height - this.dims[0])/2;
+ var leftd = (width - this.dims[1])/2;
+ if(this.elementPositioning == 'absolute') {
+ if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
+ if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+ } else {
+ if(this.options.scaleY) d.top = -topd + 'px';
+ if(this.options.scaleX) d.left = -leftd + 'px';
+ }
+ }
+ Element.setStyle(this.element, d);
+ }
+});
+
+Effect.Highlight = Class.create();
+Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
+ initialize: function(element) {
+ this.element = $(element);
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
+ this.start(options);
+ },
+ setup: function() {
+ // Prevent executing on elements not in the layout flow
+ if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; }
+ // Disable background image during the effect
+ this.oldStyle = {
+ backgroundImage: Element.getStyle(this.element, 'background-image') };
+ Element.setStyle(this.element, {backgroundImage: 'none'});
+ if(!this.options.endcolor)
+ this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
+ if(!this.options.restorecolor)
+ this.options.restorecolor = Element.getStyle(this.element, 'background-color');
+ // init color calculations
+ this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+ this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
+ },
+ update: function(position) {
+ Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){
+ return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
+ },
+ finish: function() {
+ Element.setStyle(this.element, Object.extend(this.oldStyle, {
+ backgroundColor: this.options.restorecolor
+ }));
+ }
+});
+
+Effect.ScrollTo = Class.create();
+Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
+ initialize: function(element) {
+ this.element = $(element);
+ this.start(arguments[1] || {});
+ },
+ setup: function() {
+ Position.prepare();
+ var offsets = Position.cumulativeOffset(this.element);
+ if(this.options.offset) offsets[1] += this.options.offset;
+ var max = window.innerHeight ?
+ window.height - window.innerHeight :
+ document.body.scrollHeight -
+ (document.documentElement.clientHeight ?
+ document.documentElement.clientHeight : document.body.clientHeight);
+ this.scrollStart = Position.deltaY;
+ this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
+ },
+ update: function(position) {
+ Position.prepare();
+ window.scrollTo(Position.deltaX,
+ this.scrollStart + (position*this.delta));
+ }
+});
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function(element) {
+ var oldOpacity = Element.getInlineOpacity(element);
+ var options = Object.extend({
+ from: Element.getOpacity(element) || 1.0,
+ to: 0.0,
+ afterFinishInternal: function(effect) { with(Element) {
+ if(effect.options.to!=0) return;
+ hide(effect.element);
+ setStyle(effect.element, {opacity: oldOpacity}); }}
+ }, arguments[1] || {});
+ return new Effect.Opacity(element,options);
+}
+
+Effect.Appear = function(element) {
+ var options = Object.extend({
+ from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0),
+ to: 1.0,
+ beforeSetup: function(effect) { with(Element) {
+ setOpacity(effect.element, effect.options.from);
+ show(effect.element); }}
+ }, arguments[1] || {});
+ return new Effect.Opacity(element,options);
+}
+
+Effect.Puff = function(element) {
+ element = $(element);
+ var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') };
+ return new Effect.Parallel(
+ [ new Effect.Scale(element, 200,
+ { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
+ Object.extend({ duration: 1.0,
+ beforeSetupInternal: function(effect) { with(Element) {
+ setStyle(effect.effects[0].element, {position: 'absolute'}); }},
+ afterFinishInternal: function(effect) { with(Element) {
+ hide(effect.effects[0].element);
+ setStyle(effect.effects[0].element, oldStyle); }}
+ }, arguments[1] || {})
+ );
+}
+
+Effect.BlindUp = function(element) {
+ element = $(element);
+ Element.makeClipping(element);
+ return new Effect.Scale(element, 0,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ restoreAfterFinish: true,
+ afterFinishInternal: function(effect) { with(Element) {
+ [hide, undoClipping].call(effect.element); }}
+ }, arguments[1] || {})
+ );
+}
+
+Effect.BlindDown = function(element) {
+ element = $(element);
+ var oldHeight = Element.getStyle(element, 'height');
+ var elementDimensions = Element.getDimensions(element);
+ return new Effect.Scale(element, 100,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) { with(Element) {
+ makeClipping(effect.element);
+ setStyle(effect.element, {height: '0px'});
+ show(effect.element);
+ }},
+ afterFinishInternal: function(effect) { with(Element) {
+ undoClipping(effect.element);
+ setStyle(effect.element, {height: oldHeight});
+ }}
+ }, arguments[1] || {})
+ );
+}
+
+Effect.SwitchOff = function(element) {
+ element = $(element);
+ var oldOpacity = Element.getInlineOpacity(element);
+ return new Effect.Appear(element, {
+ duration: 0.4,
+ from: 0,
+ transition: Effect.Transitions.flicker,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(effect.element, 1, {
+ duration: 0.3, scaleFromCenter: true,
+ scaleX: false, scaleContent: false, restoreAfterFinish: true,
+ beforeSetup: function(effect) { with(Element) {
+ [makePositioned,makeClipping].call(effect.element);
+ }},
+ afterFinishInternal: function(effect) { with(Element) {
+ [hide,undoClipping,undoPositioned].call(effect.element);
+ setStyle(effect.element, {opacity: oldOpacity});
+ }}
+ })
+ }
+ });
+}
+
+Effect.DropOut = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: Element.getStyle(element, 'top'),
+ left: Element.getStyle(element, 'left'),
+ opacity: Element.getInlineOpacity(element) };
+ return new Effect.Parallel(
+ [ new Effect.MoveBy(element, 100, 0, { sync: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
+ Object.extend(
+ { duration: 0.5,
+ beforeSetup: function(effect) { with(Element) {
+ makePositioned(effect.effects[0].element); }},
+ afterFinishInternal: function(effect) { with(Element) {
+ [hide, undoPositioned].call(effect.effects[0].element);
+ setStyle(effect.effects[0].element, oldStyle); }}
+ }, arguments[1] || {}));
+}
+
+Effect.Shake = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: Element.getStyle(element, 'top'),
+ left: Element.getStyle(element, 'left') };
+ return new Effect.MoveBy(element, 0, 20,
+ { duration: 0.05, afterFinishInternal: function(effect) {
+ new Effect.MoveBy(effect.element, 0, -40,
+ { duration: 0.1, afterFinishInternal: function(effect) {
+ new Effect.MoveBy(effect.element, 0, 40,
+ { duration: 0.1, afterFinishInternal: function(effect) {
+ new Effect.MoveBy(effect.element, 0, -40,
+ { duration: 0.1, afterFinishInternal: function(effect) {
+ new Effect.MoveBy(effect.element, 0, 40,
+ { duration: 0.1, afterFinishInternal: function(effect) {
+ new Effect.MoveBy(effect.element, 0, -20,
+ { duration: 0.05, afterFinishInternal: function(effect) { with(Element) {
+ undoPositioned(effect.element);
+ setStyle(effect.element, oldStyle);
+ }}}) }}) }}) }}) }}) }});
+}
+
+Effect.SlideDown = function(element) {
+ element = $(element);
+ Element.cleanWhitespace(element);
+ // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+ var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
+ var elementDimensions = Element.getDimensions(element);
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) { with(Element) {
+ makePositioned(effect.element);
+ makePositioned(effect.element.firstChild);
+ if(window.opera) setStyle(effect.element, {top: ''});
+ makeClipping(effect.element);
+ setStyle(effect.element, {height: '0px'});
+ show(element); }},
+ afterUpdateInternal: function(effect) { with(Element) {
+ setStyle(effect.element.firstChild, {bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
+ afterFinishInternal: function(effect) { with(Element) {
+ undoClipping(effect.element);
+ undoPositioned(effect.element.firstChild);
+ undoPositioned(effect.element);
+ setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
+ }, arguments[1] || {})
+ );
+}
+
+Effect.SlideUp = function(element) {
+ element = $(element);
+ Element.cleanWhitespace(element);
+ var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
+ return new Effect.Scale(element, 0,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ scaleMode: 'box',
+ scaleFrom: 100,
+ restoreAfterFinish: true,
+ beforeStartInternal: function(effect) { with(Element) {
+ makePositioned(effect.element);
+ makePositioned(effect.element.firstChild);
+ if(window.opera) setStyle(effect.element, {top: ''});
+ makeClipping(effect.element);
+ show(element); }},
+ afterUpdateInternal: function(effect) { with(Element) {
+ setStyle(effect.element.firstChild, {bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
+ afterFinishInternal: function(effect) { with(Element) {
+ [hide, undoClipping].call(effect.element);
+ undoPositioned(effect.element.firstChild);
+ undoPositioned(effect.element);
+ setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
+ }, arguments[1] || {})
+ );
+}
+
+// Bug in opera makes the TD containing this element expand for a instance after finish
+Effect.Squish = function(element) {
+ return new Effect.Scale(element, window.opera ? 1 : 0,
+ { restoreAfterFinish: true,
+ beforeSetup: function(effect) { with(Element) {
+ makeClipping(effect.element); }},
+ afterFinishInternal: function(effect) { with(Element) {
+ hide(effect.element);
+ undoClipping(effect.element); }}
+ });
+}
+
+Effect.Grow = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransistion: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.full
+ }, arguments[1] || {});
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: Element.getInlineOpacity(element) };
+
+ var dims = Element.getDimensions(element);
+ var initialMoveX, initialMoveY;
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ initialMoveX = initialMoveY = moveX = moveY = 0;
+ break;
+ case 'top-right':
+ initialMoveX = dims.width;
+ initialMoveY = moveY = 0;
+ moveX = -dims.width;
+ break;
+ case 'bottom-left':
+ initialMoveX = moveX = 0;
+ initialMoveY = dims.height;
+ moveY = -dims.height;
+ break;
+ case 'bottom-right':
+ initialMoveX = dims.width;
+ initialMoveY = dims.height;
+ moveX = -dims.width;
+ moveY = -dims.height;
+ break;
+ case 'center':
+ initialMoveX = dims.width / 2;
+ initialMoveY = dims.height / 2;
+ moveX = -dims.width / 2;
+ moveY = -dims.height / 2;
+ break;
+ }
+
+ return new Effect.MoveBy(element, initialMoveY, initialMoveX, {
+ duration: 0.01,
+ beforeSetup: function(effect) { with(Element) {
+ hide(effect.element);
+ makeClipping(effect.element);
+ makePositioned(effect.element);
+ }},
+ afterFinishInternal: function(effect) {
+ new Effect.Parallel(
+ [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+ new Effect.MoveBy(effect.element, moveY, moveX, { sync: true, transition: options.moveTransition }),
+ new Effect.Scale(effect.element, 100, {
+ scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
+ sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+ ], Object.extend({
+ beforeSetup: function(effect) { with(Element) {
+ setStyle(effect.effects[0].element, {height: '0px'});
+ show(effect.effects[0].element); }},
+ afterFinishInternal: function(effect) { with(Element) {
+ [undoClipping, undoPositioned].call(effect.effects[0].element);
+ setStyle(effect.effects[0].element, oldStyle); }}
+ }, options)
+ )
+ }
+ });
+}
+
+Effect.Shrink = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransistion: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.none
+ }, arguments[1] || {});
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: Element.getInlineOpacity(element) };
+
+ var dims = Element.getDimensions(element);
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ moveX = moveY = 0;
+ break;
+ case 'top-right':
+ moveX = dims.width;
+ moveY = 0;
+ break;
+ case 'bottom-left':
+ moveX = 0;
+ moveY = dims.height;
+ break;
+ case 'bottom-right':
+ moveX = dims.width;
+ moveY = dims.height;
+ break;
+ case 'center':
+ moveX = dims.width / 2;
+ moveY = dims.height / 2;
+ break;
+ }
+
+ return new Effect.Parallel(
+ [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+ new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+ new Effect.MoveBy(element, moveY, moveX, { sync: true, transition: options.moveTransition })
+ ], Object.extend({
+ beforeStartInternal: function(effect) { with(Element) {
+ [makePositioned, makeClipping].call(effect.effects[0].element) }},
+ afterFinishInternal: function(effect) { with(Element) {
+ [hide, undoClipping, undoPositioned].call(effect.effects[0].element);
+ setStyle(effect.effects[0].element, oldStyle); }}
+ }, options)
+ );
+}
+
+Effect.Pulsate = function(element) {
+ element = $(element);
+ var options = arguments[1] || {};
+ var oldOpacity = Element.getInlineOpacity(element);
+ var transition = options.transition || Effect.Transitions.sinoidal;
+ var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
+ reverser.bind(transition);
+ return new Effect.Opacity(element,
+ Object.extend(Object.extend({ duration: 3.0, from: 0,
+ afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); }
+ }, options), {transition: reverser}));
+}
+
+Effect.Fold = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height };
+ Element.makeClipping(element);
+ return new Effect.Scale(element, 5, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(element, 1, {
+ scaleContent: false,
+ scaleY: false,
+ afterFinishInternal: function(effect) { with(Element) {
+ [hide, undoClipping].call(effect.element);
+ setStyle(effect.element, oldStyle);
+ }} });
+ }}, arguments[1] || {}));
+}
diff --git a/public/javascripts/jstoolbar.js b/public/javascripts/jstoolbar.js
new file mode 100644
index 000000000..cf9454619
--- /dev/null
+++ b/public/javascripts/jstoolbar.js
@@ -0,0 +1,440 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * This file is part of DotClear.
+ * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All
+ * rights reserved.
+ *
+ * DotClear is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * DotClear is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DotClear; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ***** END LICENSE BLOCK *****
+*/
+
+/* Modified by JP LANG for textile formatting */
+
+function jsToolBar(textarea) {
+ if (!document.createElement) { return; }
+
+ if (!textarea) { return; }
+
+ if ((typeof(document["selection"]) == "undefined")
+ && (typeof(textarea["setSelectionRange"]) == "undefined")) {
+ return;
+ }
+
+ this.textarea = textarea;
+
+ this.editor = document.createElement('div');
+ this.editor.className = 'jstEditor';
+
+ this.textarea.parentNode.insertBefore(this.editor,this.textarea);
+ this.editor.appendChild(this.textarea);
+
+ this.toolbar = document.createElement("div");
+ this.toolbar.className = 'jstElements';
+ this.editor.parentNode.insertBefore(this.toolbar,this.editor);
+
+ // Dragable resizing (only for gecko)
+ if (this.editor.addEventListener)
+ {
+ this.handle = document.createElement('div');
+ this.handle.className = 'jstHandle';
+ var dragStart = this.resizeDragStart;
+ var This = this;
+ this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false);
+ // fix memory leak in Firefox (bug #241518)
+ window.addEventListener('unload',function() {
+ var del = This.handle.parentNode.removeChild(This.handle);
+ delete(This.handle);
+ },false);
+
+ this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling);
+ }
+
+ this.context = null;
+ this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni
+ // de raccourcis vers les éléments DOM correspondants aux outils.
+}
+
+function jsButton(title, fn, scope, className) {
+ this.title = title || null;
+ this.fn = fn || function(){};
+ this.scope = scope || null;
+ this.className = className || null;
+}
+jsButton.prototype.draw = function() {
+ if (!this.scope) return null;
+
+ var button = document.createElement('button');
+ button.setAttribute('type','button');
+ if (this.className) button.className = this.className;
+ button.title = this.title;
+ var span = document.createElement('span');
+ span.appendChild(document.createTextNode(this.title));
+ button.appendChild(span);
+
+ if (this.icon != undefined) {
+ button.style.backgroundImage = 'url('+this.icon+')';
+ }
+ if (typeof(this.fn) == 'function') {
+ var This = this;
+ button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; };
+ }
+ return button;
+}
+
+function jsSpace(id) {
+ this.id = id || null;
+ this.width = null;
+}
+jsSpace.prototype.draw = function() {
+ var span = document.createElement('span');
+ if (this.id) span.id = this.id;
+ span.appendChild(document.createTextNode(String.fromCharCode(160)));
+ span.className = 'jstSpacer';
+ if (this.width) span.style.marginRight = this.width+'px';
+
+ return span;
+}
+
+function jsCombo(title, options, scope, fn, className) {
+ this.title = title || null;
+ this.options = options || null;
+ this.scope = scope || null;
+ this.fn = fn || function(){};
+ this.className = className || null;
+}
+jsCombo.prototype.draw = function() {
+ if (!this.scope || !this.options) return null;
+
+ var select = document.createElement('select');
+ if (this.className) select.className = className;
+ select.title = this.title;
+
+ for (var o in this.options) {
+ //var opt = this.options[o];
+ var option = document.createElement('option');
+ option.value = o;
+ option.appendChild(document.createTextNode(this.options[o]));
+ select.appendChild(option);
+ }
+
+ var This = this;
+ select.onchange = function() {
+ try {
+ This.fn.call(This.scope, this.value);
+ } catch (e) { alert(e); }
+
+ return false;
+ }
+
+ return select;
+}
+
+
+jsToolBar.prototype = {
+ base_url: '',
+ mode: 'wiki',
+ elements: {},
+
+ getMode: function() {
+ return this.mode;
+ },
+
+ setMode: function(mode) {
+ this.mode = mode || 'wiki';
+ },
+
+ switchMode: function(mode) {
+ mode = mode || 'wiki';
+ this.draw(mode);
+ },
+
+ button: function(toolName) {
+ var tool = this.elements[toolName];
+ if (typeof tool.fn[this.mode] != 'function') return null;
+ var b = new jsButton(tool.title, tool.fn[this.mode], this, 'jstb_'+toolName);
+ if (tool.icon != undefined) b.icon = tool.icon;
+ return b;
+ },
+ space: function(toolName) {
+ var tool = new jsSpace(toolName)
+ if (this.elements[toolName].width !== undefined)
+ tool.width = this.elements[toolName].width;
+ return tool;
+ },
+ combo: function(toolName) {
+ var tool = this.elements[toolName];
+ var length = tool[this.mode].list.length;
+
+ if (typeof tool[this.mode].fn != 'function' || length == 0) {
+ return null;
+ } else {
+ var options = {};
+ for (var i=0; i < length; i++) {
+ var opt = tool[this.mode].list[i];
+ options[opt] = tool.options[opt];
+ }
+ return new jsCombo(tool.title, options, this, tool[this.mode].fn);
+ }
+ },
+ draw: function(mode) {
+ this.setMode(mode);
+
+ // Empty toolbar
+ while (this.toolbar.hasChildNodes()) {
+ this.toolbar.removeChild(this.toolbar.firstChild)
+ }
+ this.toolNodes = {}; // vide les raccourcis DOM/**/
+
+ // Draw toolbar elements
+ var b, tool, newTool;
+
+ for (var i in this.elements) {
+ b = this.elements[i];
+
+ var disabled =
+ b.type == undefined || b.type == ''
+ || (b.disabled != undefined && b.disabled)
+ || (b.context != undefined && b.context != null && b.context != this.context);
+
+ if (!disabled && typeof this[b.type] == 'function') {
+ tool = this[b.type](i);
+ if (tool) newTool = tool.draw();
+ if (newTool) {
+ this.toolNodes[i] = newTool; //mémorise l'accès DOM pour usage éventuel ultérieur
+ this.toolbar.appendChild(newTool);
+ }
+ }
+ }
+ },
+
+ singleTag: function(stag,etag) {
+ stag = stag || null;
+ etag = etag || stag;
+
+ if (!stag || !etag) { return; }
+
+ this.encloseSelection(stag,etag);
+ },
+
+ encloseSelection: function(prefix, suffix, fn) {
+ this.textarea.focus();
+
+ prefix = prefix || '';
+ suffix = suffix || '';
+
+ var start, end, sel, scrollPos, subst, res;
+
+ if (typeof(document["selection"]) != "undefined") {
+ sel = document.selection.createRange().text;
+ } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
+ start = this.textarea.selectionStart;
+ end = this.textarea.selectionEnd;
+ scrollPos = this.textarea.scrollTop;
+ sel = this.textarea.value.substring(start, end);
+ }
+
+ if (sel.match(/ $/)) { // exclude ending space char, if any
+ sel = sel.substring(0, sel.length - 1);
+ suffix = suffix + " ";
+ }
+
+ if (typeof(fn) == 'function') {
+ res = (sel) ? fn.call(this,sel) : fn('');
+ } else {
+ res = (sel) ? sel : '';
+ }
+
+ subst = prefix + res + suffix;
+
+ if (typeof(document["selection"]) != "undefined") {
+ var range = document.selection.createRange().text = subst;
+ this.textarea.caretPos -= suffix.length;
+ } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
+ this.textarea.value = this.textarea.value.substring(0, start) + subst +
+ this.textarea.value.substring(end);
+ if (sel) {
+ this.textarea.setSelectionRange(start + subst.length, start + subst.length);
+ } else {
+ this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
+ }
+ this.textarea.scrollTop = scrollPos;
+ }
+ },
+
+ stripBaseURL: function(url) {
+ if (this.base_url != '') {
+ var pos = url.indexOf(this.base_url);
+ if (pos == 0) {
+ url = url.substr(this.base_url.length);
+ }
+ }
+
+ return url;
+ }
+};
+
+/** Resizer
+-------------------------------------------------------- */
+jsToolBar.prototype.resizeSetStartH = function() {
+ this.dragStartH = this.textarea.offsetHeight + 0;
+};
+jsToolBar.prototype.resizeDragStart = function(event) {
+ var This = this;
+ this.dragStartY = event.clientY;
+ this.resizeSetStartH();
+ document.addEventListener('mousemove', this.dragMoveHdlr=function(event){This.resizeDragMove(event);}, false);
+ document.addEventListener('mouseup', this.dragStopHdlr=function(event){This.resizeDragStop(event);}, false);
+};
+
+jsToolBar.prototype.resizeDragMove = function(event) {
+ this.textarea.style.height = (this.dragStartH+event.clientY-this.dragStartY)+'px';
+};
+
+jsToolBar.prototype.resizeDragStop = function(event) {
+ document.removeEventListener('mousemove', this.dragMoveHdlr, false);
+ document.removeEventListener('mouseup', this.dragStopHdlr, false);
+};
+
+// Elements definition ------------------------------------
+
+// strong
+jsToolBar.prototype.elements.strong = {
+ type: 'button',
+ title: 'Strong emphasis',
+ fn: {
+ wiki: function() { this.singleTag('*') }
+ }
+}
+
+// em
+jsToolBar.prototype.elements.em = {
+ type: 'button',
+ title: 'Emphasis',
+ fn: {
+ wiki: function() { this.singleTag("_") }
+ }
+}
+
+// ins
+jsToolBar.prototype.elements.ins = {
+ type: 'button',
+ title: 'Inserted',
+ fn: {
+ wiki: function() { this.singleTag('+') }
+ }
+}
+
+// del
+jsToolBar.prototype.elements.del = {
+ type: 'button',
+ title: 'Deleted',
+ fn: {
+ wiki: function() { this.singleTag('-') }
+ }
+}
+
+// quote
+//jsToolBar.prototype.elements.quote = {
+// type: 'button',
+// title: 'Inline quote',
+// fn: {
+// wiki: function() { this.singleTag('{{','}}') }
+// }
+//}
+
+// code
+jsToolBar.prototype.elements.code = {
+ type: 'button',
+ title: 'Code',
+ fn: {
+ wiki: function() { this.singleTag('@') }
+ }
+}
+
+// spacer
+//jsToolBar.prototype.elements.space1 = {type: 'space'}
+
+// br
+//jsToolBar.prototype.elements.br = {
+// type: 'button',
+// title: 'Line break',
+// fn: {
+// wiki: function() { this.encloseSelection("%%%\n",'') }
+// }
+//}
+
+// spacer
+jsToolBar.prototype.elements.space2 = {type: 'space'}
+
+// ul
+jsToolBar.prototype.elements.ul = {
+ type: 'button',
+ title: 'Unordered list',
+ fn: {
+ wiki: function() {
+ this.encloseSelection('','',function(str) {
+ str = str.replace(/\r/g,'');
+ return '* '+str.replace(/\n/g,"\n* ");
+ });
+ }
+ }
+}
+
+// ol
+jsToolBar.prototype.elements.ol = {
+ type: 'button',
+ title: 'Ordered list',
+ fn: {
+ wiki: function() {
+ this.encloseSelection('','',function(str) {
+ str = str.replace(/\r/g,'');
+ return '# '+str.replace(/\n/g,"\n# ");
+ });
+ }
+ }
+}
+
+// spacer
+jsToolBar.prototype.elements.space3 = {type: 'space'}
+
+// link
+jsToolBar.prototype.elements.link = {
+ type: 'button',
+ title: 'Link',
+ fn: {},
+ href_prompt: 'Please give page URL:',
+ hreflang_prompt: 'Language of this page:',
+ default_hreflang: '',
+ prompt: function(href,hreflang) {
+ href = href || '';
+ hreflang = hreflang || this.elements.link.default_hreflang;
+
+ href = window.prompt(this.elements.link.href_prompt,href);
+ if (!href) { return false; }
+
+ hreflang = ""
+
+ return { href: this.stripBaseURL(href), hreflang: hreflang };
+ }
+}
+
+jsToolBar.prototype.elements.link.fn.wiki = function() {
+ var link = this.elements.link.prompt.call(this);
+ if (link) {
+ var stag = '"';
+ var etag = '":'+link.href;
+ this.encloseSelection(stag,etag);
+ }
+};
diff --git a/public/javascripts/menu.js b/public/javascripts/menu.js
new file mode 100644
index 000000000..bf5612dd5
--- /dev/null
+++ b/public/javascripts/menu.js
@@ -0,0 +1,556 @@
+//*****************************************************************************
+// Do not remove this notice.
+//
+// Copyright 2000-2004 by Mike Hall.
+// See http://www.brainjar.com for terms of use.
+//*****************************************************************************
+
+//----------------------------------------------------------------------------
+// Emulation de la fonction push pour IE5.0
+//----------------------------------------------------------------------------
+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0;i<arguments.length;i++)this[this.length]=arguments[i];};};
+
+//----------------------------------------------------------------------------
+// Code to determine the browser and version.
+//----------------------------------------------------------------------------
+
+function Browser() {
+
+ var ua, s, i;
+
+ this.isIE = false; // Internet Explorer
+ this.isOP = false; // Opera
+ this.isNS = false; // Netscape
+ this.version = null;
+ //-- debut ajout ci ----
+ this.isIE5mac = false; // Internet Explorer 5 mac
+ //-- fin ajout ci ----
+
+ ua = navigator.userAgent;
+
+ //-- debut ajout ci ----
+ if (ua.indexOf("Opera")==-1 && ua.indexOf("MSIE 5")>-1 && ua.indexOf("Mac")>-1) {
+ this.isIE5mac = true;
+ this.version = "";
+ return;
+ }
+ //-- fin ajout ci ----
+
+ s = "Opera";
+ if ((i = ua.indexOf(s)) >= 0) {
+ this.isOP = true;
+ this.version = parseFloat(ua.substr(i + s.length));
+ return;
+ }
+
+ s = "Netscape6/";
+ if ((i = ua.indexOf(s)) >= 0) {
+ this.isNS = true;
+ this.version = parseFloat(ua.substr(i + s.length));
+ return;
+ }
+
+ // Treat any other "Gecko" browser as Netscape 6.1.
+
+ s = "Gecko";
+ if ((i = ua.indexOf(s)) >= 0) {
+ this.isNS = true;
+ this.version = 6.1;
+ return;
+ }
+
+ s = "MSIE";
+ if ((i = ua.indexOf(s))) {
+ this.isIE = true;
+ this.version = parseFloat(ua.substr(i + s.length));
+ return;
+ }
+}
+
+var browser = new Browser();
+
+//----------------------------------------------------------------------------
+// Code for handling the menu bar and active button.
+//----------------------------------------------------------------------------
+
+var activeButton = null;
+
+
+function buttonClick(event, menuId) {
+
+ var button;
+
+ // Get the target button element.
+
+ if (browser.isIE)
+ button = window.event.srcElement;
+ else
+ button = event.currentTarget;
+
+ // Blur focus from the link to remove that annoying outline.
+
+ button.blur();
+
+ // Associate the named menu to this button if not already done.
+ // Additionally, initialize menu display.
+
+ if (button.menu == null) {
+ button.menu = document.getElementById(menuId);
+ if (button.menu.isInitialized == null)
+ menuInit(button.menu);
+ }
+
+ // Set mouseout event handler for the button, if not already done.
+
+ if (button.onmouseout == null)
+ button.onmouseout = buttonOrMenuMouseout;
+
+ // Exit if this button is the currently active one.
+
+ if (button == activeButton)
+ return false;
+
+ // Reset the currently active button, if any.
+
+ if (activeButton != null)
+ resetButton(activeButton);
+
+ // Activate this button, unless it was the currently active one.
+
+ if (button != activeButton) {
+ depressButton(button);
+ activeButton = button;
+ }
+ else
+ activeButton = null;
+
+ return false;
+}
+
+function buttonMouseover(event, menuId) {
+
+ var button;
+//-- debut ajout ci ----
+ if (!browser.isIE5mac) {
+ //-- fin ajout ci ----
+
+//-- debut ajout ci ----
+ cicacheselect();
+//-- fin ajout ci ----
+
+ // Activates this button's menu if no other is currently active.
+
+ if (activeButton == null) {
+ buttonClick(event, menuId);
+ return;
+ }
+
+ // Find the target button element.
+
+ if (browser.isIE)
+ button = window.event.srcElement;
+ else
+ button = event.currentTarget;
+
+ // If any other button menu is active, make this one active instead.
+
+ if (activeButton != null && activeButton != button)
+ buttonClick(event, menuId);
+ //-- debut ajout ci ----
+ }
+ //-- fin ajout ci ----
+
+}
+
+function depressButton(button) {
+
+ var x, y;
+
+ // Update the button's style class to make it look like it's
+ // depressed.
+
+ button.className += " menuButtonActive";
+
+ // Set mouseout event handler for the button, if not already done.
+
+ if (button.onmouseout == null)
+ button.onmouseout = buttonOrMenuMouseout;
+ if (button.menu.onmouseout == null)
+ button.menu.onmouseout = buttonOrMenuMouseout;
+
+ // Position the associated drop down menu under the button and
+ // show it.
+
+ x = getPageOffsetLeft(button);
+ y = getPageOffsetTop(button) + button.offsetHeight - 1;
+
+ // For IE, adjust position.
+
+ if (browser.isIE) {
+ x += button.offsetParent.clientLeft;
+ y += button.offsetParent.clientTop;
+ }
+
+ button.menu.style.left = x + "px";
+ button.menu.style.top = y + "px";0
+ button.menu.style.visibility = "visible";
+}
+
+function resetButton(button) {
+
+ // Restore the button's style class.
+
+ removeClassName(button, "menuButtonActive");
+
+ // Hide the button's menu, first closing any sub menus.
+
+ if (button.menu != null) {
+ closeSubMenu(button.menu);
+ button.menu.style.visibility = "hidden";
+ }
+}
+
+//----------------------------------------------------------------------------
+// Code to handle the menus and sub menus.
+//----------------------------------------------------------------------------
+
+function menuMouseover(event) {
+
+ var menu;
+ //-- debut ajout ci ----
+ if (!browser.isIE5mac) {
+ //-- fin ajout ci ----
+//-- debut ajout ci ----
+ cicacheselect();
+//-- fin ajout ci ----
+
+ // Find the target menu element.
+ if (browser.isIE)
+ menu = getContainerWith(window.event.srcElement, "DIV", "menu");
+ else
+ menu = event.currentTarget;
+
+ // Close any active sub menu.
+
+ if (menu.activeItem != null)
+ closeSubMenu(menu);
+ //-- debut ajout ci ----
+ }
+ //-- fin ajout ci ----
+}
+
+function menuItemMouseover(event, menuId) {
+
+ var item, menu, x, y;
+//-- debut ajout ci ----
+ cicacheselect();
+//-- fin ajout ci ----
+
+ // Find the target item element and its parent menu element.
+
+ if (browser.isIE)
+ item = getContainerWith(window.event.srcElement, "A", "menuItem");
+ else
+ item = event.currentTarget;
+ menu = getContainerWith(item, "DIV", "menu");
+
+ // Close any active sub menu and mark this one as active.
+
+ if (menu.activeItem != null)
+ closeSubMenu(menu);
+ menu.activeItem = item;
+
+ // Highlight the item element.
+
+ item.className += " menuItemHighlight";
+
+ // Initialize the sub menu, if not already done.
+
+ if (item.subMenu == null) {
+ item.subMenu = document.getElementById(menuId);
+ if (item.subMenu.isInitialized == null)
+ menuInit(item.subMenu);
+ }
+
+ // Set mouseout event handler for the sub menu, if not already done.
+
+ if (item.subMenu.onmouseout == null)
+ item.subMenu.onmouseout = buttonOrMenuMouseout;
+
+ // Get position for submenu based on the menu item.
+
+ x = getPageOffsetLeft(item) + item.offsetWidth;
+ y = getPageOffsetTop(item);
+
+ // Adjust position to fit in view.
+
+ var maxX, maxY;
+
+ if (browser.isIE) {
+ maxX = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) +
+ (document.documentElement.clientWidth != 0 ? document.documentElement.clientWidth : document.body.clientWidth);
+ maxY = Math.max(document.documentElement.scrollTop, document.body.scrollTop) +
+ (document.documentElement.clientHeight != 0 ? document.documentElement.clientHeight : document.body.clientHeight);
+ }
+ if (browser.isOP) {
+ maxX = document.documentElement.scrollLeft + window.innerWidth;
+ maxY = document.documentElement.scrollTop + window.innerHeight;
+ }
+ if (browser.isNS) {
+ maxX = window.scrollX + window.innerWidth;
+ maxY = window.scrollY + window.innerHeight;
+ }
+ maxX -= item.subMenu.offsetWidth;
+ maxY -= item.subMenu.offsetHeight;
+
+ if (x > maxX)
+ x = Math.max(0, x - item.offsetWidth - item.subMenu.offsetWidth
+ + (menu.offsetWidth - item.offsetWidth));
+ y = Math.max(0, Math.min(y, maxY));
+
+ // Position and show the sub menu.
+
+ item.subMenu.style.left = x + "px";
+ item.subMenu.style.top = y + "px";
+ item.subMenu.style.visibility = "visible";
+
+ // Stop the event from bubbling.
+
+ if (browser.isIE)
+ window.event.cancelBubble = true;
+ else
+ event.stopPropagation();
+}
+
+function closeSubMenu(menu) {
+
+ if (menu == null || menu.activeItem == null)
+ return;
+
+ // Recursively close any sub menus.
+
+ if (menu.activeItem.subMenu != null) {
+ closeSubMenu(menu.activeItem.subMenu);
+ menu.activeItem.subMenu.style.visibility = "hidden";
+ menu.activeItem.subMenu = null;
+ }
+ removeClassName(menu.activeItem, "menuItemHighlight");
+ menu.activeItem = null;
+}
+
+
+function buttonOrMenuMouseout(event) {
+
+ var el;
+
+ // If there is no active button, exit.
+
+ if (activeButton == null)
+ return;
+
+ // Find the element the mouse is moving to.
+
+ if (browser.isIE)
+ el = window.event.toElement;
+ else if (event.relatedTarget != null)
+ el = (event.relatedTarget.tagName ? event.relatedTarget : event.relatedTarget.parentNode);
+
+ // If the element is not part of a menu, reset the active button.
+
+ if (getContainerWith(el, "DIV", "menu") == null) {
+ resetButton(activeButton);
+ activeButton = null;
+//-- debut ajout ci ----
+ cimontreselect();
+//-- fin ajout ci ----
+ }
+}
+
+
+//----------------------------------------------------------------------------
+// Code to initialize menus.
+//----------------------------------------------------------------------------
+
+function menuInit(menu) {
+
+ var itemList, spanList;
+ var textEl, arrowEl;
+ var itemWidth;
+ var w, dw;
+ var i, j;
+
+ // For IE, replace arrow characters.
+
+ if (browser.isIE) {
+ menu.style.lineHeight = "2.5ex";
+ spanList = menu.getElementsByTagName("SPAN");
+ for (i = 0; i < spanList.length; i++)
+ if (hasClassName(spanList[i], "menuItemArrow")) {
+ spanList[i].style.fontFamily = "Webdings";
+ spanList[i].firstChild.nodeValue = "4";
+ }
+ }
+
+ // Find the width of a menu item.
+
+ itemList = menu.getElementsByTagName("A");
+ if (itemList.length > 0)
+ itemWidth = itemList[0].offsetWidth;
+ else
+ return;
+
+ // For items with arrows, add padding to item text to make the
+ // arrows flush right.
+
+ for (i = 0; i < itemList.length; i++) {
+ spanList = itemList[i].getElementsByTagName("SPAN");
+ textEl = null;
+ arrowEl = null;
+ for (j = 0; j < spanList.length; j++) {
+ if (hasClassName(spanList[j], "menuItemText"))
+ textEl = spanList[j];
+ if (hasClassName(spanList[j], "menuItemArrow"))
+ arrowEl = spanList[j];
+ }
+ if (textEl != null && arrowEl != null) {
+ textEl.style.paddingRight = (itemWidth
+ - (textEl.offsetWidth + arrowEl.offsetWidth)) + "px";
+ // For Opera, remove the negative right margin to fix a display bug.
+ if (browser.isOP)
+ arrowEl.style.marginRight = "0px";
+ }
+ }
+
+ // Fix IE hover problem by setting an explicit width on first item of
+ // the menu.
+
+ if (browser.isIE) {
+ w = itemList[0].offsetWidth;
+ itemList[0].style.width = w + "px";
+ dw = itemList[0].offsetWidth - w;
+ w -= dw;
+ itemList[0].style.width = w + "px";
+ }
+
+ // Mark menu as initialized.
+
+ menu.isInitialized = true;
+}
+
+//----------------------------------------------------------------------------
+// General utility functions.
+//----------------------------------------------------------------------------
+
+function getContainerWith(node, tagName, className) {
+
+ // Starting with the given node, find the nearest containing element
+ // with the specified tag name and style class.
+
+ while (node != null) {
+ if (node.tagName != null && node.tagName == tagName &&
+ hasClassName(node, className))
+ return node;
+ node = node.parentNode;
+ }
+
+ return node;
+}
+
+function hasClassName(el, name) {
+
+ var i, list;
+
+ // Return true if the given element currently has the given class
+ // name.
+
+ list = el.className.split(" ");
+ for (i = 0; i < list.length; i++)
+ if (list[i] == name)
+ return true;
+
+ return false;
+}
+
+function removeClassName(el, name) {
+
+ var i, curList, newList;
+
+ if (el.className == null)
+ return;
+
+ // Remove the given class name from the element's className property.
+
+ newList = new Array();
+ curList = el.className.split(" ");
+ for (i = 0; i < curList.length; i++)
+ if (curList[i] != name)
+ newList.push(curList[i]);
+ el.className = newList.join(" ");
+}
+
+function getPageOffsetLeft(el) {
+
+ var x;
+
+ // Return the x coordinate of an element relative to the page.
+
+ x = el.offsetLeft;
+ if (el.offsetParent != null)
+ x += getPageOffsetLeft(el.offsetParent);
+
+ return x;
+}
+
+function getPageOffsetTop(el) {
+
+ var y;
+
+ // Return the x coordinate of an element relative to the page.
+
+ y = el.offsetTop;
+ if (el.offsetParent != null)
+ y += getPageOffsetTop(el.offsetParent);
+
+ return y;
+}
+
+//-- debut ajout ci ----
+function cicacheselect(){
+ if (browser.isIE) {
+ oSelects = document.getElementsByTagName('SELECT');
+ if (oSelects.length > 0) {
+ for (i = 0; i < oSelects.length; i++) {
+ oSlt = oSelects[i];
+ if (oSlt.style.visibility != 'hidden') {oSlt.style.visibility = 'hidden';}
+ }
+ }
+ oSelects = document.getElementsByName('masquable');
+ if (oSelects.length > 0) {
+ for (i = 0; i < oSelects.length; i++) {
+ oSlt = oSelects[i];
+ if (oSlt.style.visibility != 'hidden') {oSlt.style.visibility = 'hidden';}
+ }
+ }
+ }
+}
+
+function cimontreselect(){
+ if (browser.isIE) {
+ oSelects = document.getElementsByTagName('SELECT');
+ if (oSelects.length > 0) {
+ for (i = 0; i < oSelects.length; i++) {
+ oSlt = oSelects[i];
+ if (oSlt.style.visibility != 'visible') {oSlt.style.visibility = 'visible';}
+ }
+ }
+ oSelects = document.getElementsByName('masquable');
+ if (oSelects.length > 0) {
+ for (i = 0; i < oSelects.length; i++) {
+ oSlt = oSelects[i];
+ if (oSlt.style.visibility != 'visible') {oSlt.style.visibility = 'visible';}
+ }
+ }
+ }
+}
+
+//-- fin ajout ci ----
diff --git a/public/javascripts/prototype.js b/public/javascripts/prototype.js
new file mode 100644
index 000000000..e9ccd3c88
--- /dev/null
+++ b/public/javascripts/prototype.js
@@ -0,0 +1,1785 @@
+/* Prototype JavaScript framework, version 1.4.0
+ * (c) 2005 Sam Stephenson <sam@conio.net>
+ *
+ * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
+ * against the source tree, available from the Prototype darcs repository.
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ *
+ * For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.4.0',
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+
+ emptyFunction: function() {},
+ K: function(x) {return x}
+}
+
+var Class = {
+ create: function() {
+ return function() {
+ this.initialize.apply(this, arguments);
+ }
+ }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+ for (property in source) {
+ destination[property] = source[property];
+ }
+ return destination;
+}
+
+Object.inspect = function(object) {
+ try {
+ if (object == undefined) return 'undefined';
+ if (object == null) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+}
+
+Function.prototype.bind = function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+ var __method = this;
+ return function(event) {
+ return __method.call(object, event || window.event);
+ }
+}
+
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ var digits = this.toString(16);
+ if (this < 16) return '0' + digits;
+ return digits;
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ }
+});
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) {}
+ }
+
+ return returnValue;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.callback();
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+function $() {
+ var elements = new Array();
+
+ for (var i = 0; i < arguments.length; i++) {
+ var element = arguments[i];
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+
+ if (arguments.length == 1)
+ return element;
+
+ elements.push(element);
+ }
+
+ return elements;
+}
+Object.extend(String.prototype, {
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(eval);
+ },
+
+ escapeHTML: function() {
+ var div = document.createElement('div');
+ var text = document.createTextNode(this);
+ div.appendChild(text);
+ return div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = document.createElement('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
+ },
+
+ toQueryParams: function() {
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
+ return pairs.inject({}, function(params, pairString) {
+ var pair = pairString.split('=');
+ params[pair[0]] = pair[1];
+ return params;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ camelize: function() {
+ var oStringList = this.split('-');
+ if (oStringList.length == 1) return oStringList[0];
+
+ var camelizedString = this.indexOf('-') == 0
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
+ : oStringList[0];
+
+ for (var i = 1, len = oStringList.length; i < len; i++) {
+ var s = oStringList[i];
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+ }
+
+ return camelizedString;
+ },
+
+ inspect: function() {
+ return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
+ }
+});
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var $break = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+ each: function(iterator) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ try {
+ iterator(value, index++);
+ } catch (e) {
+ if (e != $continue) throw e;
+ }
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ },
+
+ all: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ if (result = !!(iterator || Prototype.K)(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ detect: function (iterator) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(pattern, iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ var stringValue = value.toString();
+ if (stringValue.match(pattern))
+ results.push((iterator || Prototype.K)(value, index));
+ })
+ return results;
+ },
+
+ include: function(object) {
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inject: function(memo, iterator) {
+ this.each(function(value, index) {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.collect(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (value >= (result || value))
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (value <= (result || value))
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator) {
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ ((iterator || Prototype.K)(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator) {
+ return this.collect(function(value, index) {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.collect(Prototype.K);
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (typeof args.last() == 'function')
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ iterator(value = collections.pluck(index));
+ return value;
+ });
+ },
+
+ inspect: function() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+}
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) {
+ return iterable.toArray();
+ } else {
+ var results = [];
+ for (var i = 0; i < iterable.length; i++)
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0; i < this.length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != undefined || value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(value.constructor == Array ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ indexOf: function(object) {
+ for (var i = 0; i < this.length; i++)
+ if (this[i] == object) return i;
+ return -1;
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ shift: function() {
+ var result = this[0];
+ for (var i = 0; i < this.length - 1; i++)
+ this[i] = this[i + 1];
+ this.length--;
+ return result;
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+});
+var Hash = {
+ _each: function(iterator) {
+ for (key in this) {
+ var value = this[key];
+ if (typeof value == 'function') continue;
+
+ var pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ merge: function(hash) {
+ return $H(hash).inject($H(this), function(mergedHash, pair) {
+ mergedHash[pair.key] = pair.value;
+ return mergedHash;
+ });
+ },
+
+ toQueryString: function() {
+ return this.map(function(pair) {
+ return pair.map(encodeURIComponent).join('=');
+ }).join('&');
+ },
+
+ inspect: function() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ }
+}
+
+function $H(object) {
+ var hash = Object.extend({}, object || {});
+ Object.extend(hash, Enumerable);
+ Object.extend(hash, Hash);
+ return hash;
+}
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ do {
+ iterator(value);
+ value = value.succ();
+ } while (this.include(value));
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+}
+
+var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')},
+ function() {return new XMLHttpRequest()}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+}
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responderToAdd) {
+ if (!this.include(responderToAdd))
+ this.responders.push(responderToAdd);
+ },
+
+ unregister: function(responderToRemove) {
+ this.responders = this.responders.without(responderToRemove);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (responder[callback] && typeof responder[callback] == 'function') {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) {}
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() {
+ Ajax.activeRequestCount++;
+ },
+
+ onComplete: function() {
+ Ajax.activeRequestCount--;
+ }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+ setOptions: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ parameters: ''
+ }
+ Object.extend(this.options, options || {});
+ },
+
+ responseIsSuccess: function() {
+ return this.transport.status == undefined
+ || this.transport.status == 0
+ || (this.transport.status >= 200 && this.transport.status < 300);
+ },
+
+ responseIsFailure: function() {
+ return !this.responseIsSuccess();
+ }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(url, options) {
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+ this.request(url);
+ },
+
+ request: function(url) {
+ var parameters = this.options.parameters || '';
+ if (parameters.length > 0) parameters += '&_=';
+
+ try {
+ this.url = url;
+ if (this.options.method == 'get' && parameters.length > 0)
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+ this.transport.open(this.options.method, this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) {
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
+ }
+
+ this.setRequestHeaders();
+
+ var body = this.options.postBody ? this.options.postBody : parameters;
+ this.transport.send(this.options.method == 'post' ? body : null);
+
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ setRequestHeaders: function() {
+ var requestHeaders =
+ ['X-Requested-With', 'XMLHttpRequest',
+ 'X-Prototype-Version', Prototype.Version];
+
+ if (this.options.method == 'post') {
+ requestHeaders.push('Content-type',
+ 'application/x-www-form-urlencoded');
+
+ /* Force "Connection: close" for Mozilla browsers to work around
+ * a bug where XMLHttpReqeuest sends an incorrect Content-length
+ * header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType)
+ requestHeaders.push('Connection', 'close');
+ }
+
+ if (this.options.requestHeaders)
+ requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
+
+ for (var i = 0; i < requestHeaders.length; i += 2)
+ this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState != 1)
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ header: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {}
+ },
+
+ evalJSON: function() {
+ try {
+ return eval(this.header('X-JSON'));
+ } catch (e) {}
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ respondToReadyState: function(readyState) {
+ var event = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.evalJSON();
+
+ if (event == 'Complete') {
+ try {
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
+ if (event == 'Complete')
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+ initialize: function(container, url, options) {
+ this.containers = {
+ success: container.success ? $(container.success) : $(container),
+ failure: container.failure ? $(container.failure) :
+ (container.success ? null : $(container))
+ }
+
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
+ this.options.onComplete = (function(transport, object) {
+ this.updateContent();
+ onComplete(transport, object);
+ }).bind(this);
+
+ this.request(url);
+ },
+
+ updateContent: function() {
+ var receiver = this.responseIsSuccess() ?
+ this.containers.success : this.containers.failure;
+ var response = this.transport.responseText;
+
+ if (!this.options.evalScripts)
+ response = response.stripScripts();
+
+ if (receiver) {
+ if (this.options.insertion) {
+ new this.options.insertion(receiver, response);
+ } else {
+ Element.update(receiver, response);
+ }
+ }
+
+ if (this.responseIsSuccess()) {
+ if (this.onComplete)
+ setTimeout(this.onComplete.bind(this), 10);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(container, url, options) {
+ this.setOptions(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = {};
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(request) {
+ if (this.options.decay) {
+ this.decay = (request.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = request.responseText;
+ }
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
+ this.decay * this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+document.getElementsByClassName = function(className, parentElement) {
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
+ return $A(children).inject([], function(elements, child) {
+ if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ elements.push(child);
+ return elements;
+ });
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element) {
+ var Element = new Object();
+}
+
+Object.extend(Element, {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ }
+ },
+
+ hide: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ element.style.display = 'none';
+ }
+ },
+
+ show: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ element.style.display = '';
+ }
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ },
+
+ update: function(element, html) {
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function() {html.evalScripts()}, 10);
+ },
+
+ getHeight: function(element) {
+ element = $(element);
+ return element.offsetHeight;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).include(className);
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).add(className);
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).remove(className);
+ },
+
+ // removes whitespace-only text node children
+ cleanWhitespace: function(element) {
+ element = $(element);
+ for (var i = 0; i < element.childNodes.length; i++) {
+ var node = element.childNodes[i];
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ Element.remove(node);
+ }
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.match(/^\s*$/);
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var x = element.x ? element.x : element.offsetLeft,
+ y = element.y ? element.y : element.offsetTop;
+ window.scrollTo(x, y);
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ var value = element.style[style.camelize()];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style.camelize()];
+ }
+ }
+
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+
+ return value == 'auto' ? null : value;
+ },
+
+ setStyle: function(element, style) {
+ element = $(element);
+ for (name in style)
+ element.style[name.camelize()] = style[name];
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'display') != 'none')
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = '';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = 'none';
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (window.opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return;
+ element._overflow = element.style.overflow;
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+ element.style.overflow = 'hidden';
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return;
+ element.style.overflow = element._overflow;
+ element._overflow = undefined;
+ }
+});
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+ this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+ initialize: function(element, content) {
+ this.element = $(element);
+ this.content = content.stripScripts();
+
+ if (this.adjacency && this.element.insertAdjacentHTML) {
+ try {
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
+ } catch (e) {
+ if (this.element.tagName.toLowerCase() == 'tbody') {
+ this.insertContent(this.contentFromAnonymousTable());
+ } else {
+ throw e;
+ }
+ }
+ } else {
+ this.range = this.element.ownerDocument.createRange();
+ if (this.initializeRange) this.initializeRange();
+ this.insertContent([this.range.createContextualFragment(this.content)]);
+ }
+
+ setTimeout(function() {content.evalScripts()}, 10);
+ },
+
+ contentFromAnonymousTable: function() {
+ var div = document.createElement('div');
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+ return $A(div.childNodes[0].childNodes[0].childNodes);
+ }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+ initializeRange: function() {
+ this.range.setStartBefore(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment, this.element);
+ }).bind(this));
+ }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(true);
+ },
+
+ insertContent: function(fragments) {
+ fragments.reverse(false).each((function(fragment) {
+ this.element.insertBefore(fragment, this.element.firstChild);
+ }).bind(this));
+ }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.appendChild(fragment);
+ }).bind(this));
+ }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+ initializeRange: function() {
+ this.range.setStartAfter(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment,
+ this.element.nextSibling);
+ }).bind(this));
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set(this.toArray().concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set(this.select(function(className) {
+ return className != classNameToRemove;
+ }).join(' '));
+ },
+
+ toString: function() {
+ return this.toArray().join(' ');
+ }
+}
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Field = {
+ clear: function() {
+ for (var i = 0; i < arguments.length; i++)
+ $(arguments[i]).value = '';
+ },
+
+ focus: function(element) {
+ $(element).focus();
+ },
+
+ present: function() {
+ for (var i = 0; i < arguments.length; i++)
+ if ($(arguments[i]).value == '') return false;
+ return true;
+ },
+
+ select: function(element) {
+ $(element).select();
+ },
+
+ activate: function(element) {
+ element = $(element);
+ element.focus();
+ if (element.select)
+ element.select();
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Form = {
+ serialize: function(form) {
+ var elements = Form.getElements($(form));
+ var queryComponents = new Array();
+
+ for (var i = 0; i < elements.length; i++) {
+ var queryComponent = Form.Element.serialize(elements[i]);
+ if (queryComponent)
+ queryComponents.push(queryComponent);
+ }
+
+ return queryComponents.join('&');
+ },
+
+ getElements: function(form) {
+ form = $(form);
+ var elements = new Array();
+
+ for (tagName in Form.Element.Serializers) {
+ var tagElements = form.getElementsByTagName(tagName);
+ for (var j = 0; j < tagElements.length; j++)
+ elements.push(tagElements[j]);
+ }
+ return elements;
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name)
+ return inputs;
+
+ var matchingInputs = new Array();
+ for (var i = 0; i < inputs.length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) ||
+ (name && input.name != name))
+ continue;
+ matchingInputs.push(input);
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ var elements = Form.getElements(form);
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ element.blur();
+ element.disabled = 'true';
+ }
+ },
+
+ enable: function(form) {
+ var elements = Form.getElements(form);
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ element.disabled = '';
+ }
+ },
+
+ findFirstElement: function(form) {
+ return Form.getElements(form).find(function(element) {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ Field.activate(Form.findFirstElement(form));
+ },
+
+ reset: function(form) {
+ $(form).reset();
+ }
+}
+
+Form.Element = {
+ serialize: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if (parameter) {
+ var key = encodeURIComponent(parameter[0]);
+ if (key.length == 0) return;
+
+ if (parameter[1].constructor != Array)
+ parameter[1] = [parameter[1]];
+
+ return parameter[1].map(function(value) {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if (parameter)
+ return parameter[1];
+ }
+}
+
+Form.Element.Serializers = {
+ input: function(element) {
+ switch (element.type.toLowerCase()) {
+ case 'submit':
+ case 'hidden':
+ case 'password':
+ case 'text':
+ return Form.Element.Serializers.textarea(element);
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element);
+ }
+ return false;
+ },
+
+ inputSelector: function(element) {
+ if (element.checked)
+ return [element.name, element.value];
+ },
+
+ textarea: function(element) {
+ return [element.name, element.value];
+ },
+
+ select: function(element) {
+ return Form.Element.Serializers[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ },
+
+ selectOne: function(element) {
+ var value = '', opt, index = element.selectedIndex;
+ if (index >= 0) {
+ opt = element.options[index];
+ value = opt.value;
+ if (!value && !('value' in opt))
+ value = opt.text;
+ }
+ return [element.name, value];
+ },
+
+ selectMany: function(element) {
+ var value = new Array();
+ for (var i = 0; i < element.length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) {
+ var optValue = opt.value;
+ if (!optValue && !('value' in opt))
+ optValue = opt.text;
+ value.push(optValue);
+ }
+ }
+ return [element.name, value];
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+ initialize: function(element, frequency, callback) {
+ this.frequency = frequency;
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ var elements = Form.getElements(this.element);
+ for (var i = 0; i < elements.length; i++)
+ this.registerCallback(elements[i]);
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ case 'password':
+ case 'text':
+ case 'textarea':
+ case 'select-one':
+ case 'select-multiple':
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+if (!window.Event) {
+ var Event = new Object();
+}
+
+Object.extend(Event, {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+
+ element: function(event) {
+ return event.target || event.srcElement;
+ },
+
+ isLeftClick: function(event) {
+ return (((event.which) && (event.which == 1)) ||
+ ((event.button) && (event.button == 1)));
+ },
+
+ pointerX: function(event) {
+ return event.pageX || (event.clientX +
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
+ },
+
+ pointerY: function(event) {
+ return event.pageY || (event.clientY +
+ (document.documentElement.scrollTop || document.body.scrollTop));
+ },
+
+ stop: function(event) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ event.stopPropagation();
+ } else {
+ event.returnValue = false;
+ event.cancelBubble = true;
+ }
+ },
+
+ // find the first node with the given tagName, starting from the
+ // node the event was triggered on; traverses the DOM upwards
+ findElement: function(event, tagName) {
+ var element = Event.element(event);
+ while (element.parentNode && (!element.tagName ||
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
+ element = element.parentNode;
+ return element;
+ },
+
+ observers: false,
+
+ _observeAndCache: function(element, name, observer, useCapture) {
+ if (!this.observers) this.observers = [];
+ if (element.addEventListener) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.addEventListener(name, observer, useCapture);
+ } else if (element.attachEvent) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.attachEvent('on' + name, observer);
+ }
+ },
+
+ unloadCache: function() {
+ if (!Event.observers) return;
+ for (var i = 0; i < Event.observers.length; i++) {
+ Event.stopObserving.apply(this, Event.observers[i]);
+ Event.observers[i][0] = null;
+ }
+ Event.observers = false;
+ },
+
+ observe: function(element, name, observer, useCapture) {
+ var element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.attachEvent))
+ name = 'keydown';
+
+ this._observeAndCache(element, name, observer, useCapture);
+ },
+
+ stopObserving: function(element, name, observer, useCapture) {
+ var element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.detachEvent))
+ name = 'keydown';
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, observer, useCapture);
+ } else if (element.detachEvent) {
+ element.detachEvent('on' + name, observer);
+ }
+ }
+});
+
+/* prevent memory leaks in IE */
+Event.observe(window, 'unload', Event.unloadCache, false);
+var Position = {
+ // set to true if needed, warning: firefox performance problems
+ // NOT neeeded for page scrolling, only if draggable contained in
+ // scrollable elements
+ includeScrollOffsets: false,
+
+ // must be called before calling withinIncludingScrolloffset, every time the
+ // page is scrolled
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ realOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ p = Element.getStyle(element, 'position');
+ if (p == 'relative' || p == 'absolute') break;
+ }
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ offsetParent: function(element) {
+ if (element.offsetParent) return element.offsetParent;
+ if (element == document.body) return element;
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return element;
+
+ return document.body;
+ },
+
+ // caches x/y coordinate pair to use with overlap
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = this.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = this.realOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = this.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ // within must be called directly before
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+ clone: function(source, target) {
+ source = $(source);
+ target = $(target);
+ target.style.position = 'absolute';
+ var offsets = this.cumulativeOffset(source);
+ target.style.top = offsets[1] + 'px';
+ target.style.left = offsets[0] + 'px';
+ target.style.width = source.offsetWidth + 'px';
+ target.style.height = source.offsetHeight + 'px';
+ },
+
+ page: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent==document.body)
+ if (Element.getStyle(element,'position')=='absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ } while (element = element.parentNode);
+
+ return [valueL, valueT];
+ },
+
+ clone: function(source, target) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || {})
+
+ // find page position of source
+ source = $(source);
+ var p = Position.page(source);
+
+ // find coordinate system to use
+ target = $(target);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if (Element.getStyle(target,'position') == 'absolute') {
+ parent = Position.offsetParent(target);
+ delta = Position.page(parent);
+ }
+
+ // correct by body offsets (fixes Safari)
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.style.position == 'absolute') return;
+ Position.prepare();
+
+ var offsets = Position.positionedOffset(element);
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';;
+ element.style.left = left + 'px';;
+ element.style.width = width + 'px';;
+ element.style.height = height + 'px';;
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.style.position == 'relative') return;
+ Position.prepare();
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned. For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ Position.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return [valueL, valueT];
+ }
+} \ No newline at end of file
diff --git a/public/manual/en/ch01.html b/public/manual/en/ch01.html
new file mode 100644
index 000000000..aa86147eb
--- /dev/null
+++ b/public/manual/en/ch01.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter&nbsp;1.&nbsp;Administration</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="index.html" title="RedMine Documentation"><link rel="prev" href="index.html" title="RedMine Documentation"><link rel="next" href="ch01s01.html" title="1.&nbsp;Users"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter&nbsp;1.&nbsp;Administration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s01.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="d0e4"></a>Chapter&nbsp;1.&nbsp;Administration</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="ch01s01.html">1. Users</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s01.html#d0e12">1.1. Users&#8217; List</a></span></dt><dt><span class="section"><a href="ch01s01.html#d0e26">1.2. User Creation or Modification</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s02.html">2. Roles and Permissions</a></span></dt><dt><span class="section"><a href="ch01s03.html">3. Trackers</a></span></dt><dt><span class="section"><a href="ch01s04.html">4. Customized fields</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s04.html#d0e137">4.1. Fields for Projects</a></span></dt><dt><span class="section"><a href="ch01s04.html#d0e148">4.2. Fields for Issues</a></span></dt><dt><span class="section"><a href="ch01s04.html#d0e161">4.3. Field for Users</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s05.html">5. Issue status</a></span></dt><dt><span class="section"><a href="ch01s06.html">6. Workflow</a></span></dt><dt><span class="section"><a href="ch01s07.html">7. Enumerations</a></span></dt><dt><span class="section"><a href="ch01s08.html">8. E-mail notifications</a></span></dt><dt><span class="section"><a href="ch01s09.html">9. Authentication</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s09.html#d0e243">9.1. LDAP statement</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s10.html">10. Information</a></span></dt></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">RedMine Documentation&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;1.&nbsp;Users</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s01.html b/public/manual/en/ch01s01.html
new file mode 100644
index 000000000..9f83e7d3c
--- /dev/null
+++ b/public/manual/en/ch01s01.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>1.&nbsp;Users</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="next" href="ch01s02.html" title="2.&nbsp;Roles and Permissions"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">1.&nbsp;Users</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s02.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e7"></a>1.&nbsp;Users</h2></div></div></div><p>These screens allow you to manage the application users.</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e12"></a>1.1.&nbsp;Users&#8217; List</h3></div></div></div><p></p><div class="screenshot"><div class="mediaobject"><img src="resources/users_list.png"></div></div><p>The Lock/Unlock buttons allow you to lock/unlock the user accounts.</p><p>A user having a locked account cannot log in and access the application.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e26"></a>1.2.&nbsp;User Creation or Modification</h3></div></div></div><p>In modification mode, please leave the Password field blank in order to keep the user&#8217;s password unchanged.</p><p>A user designated as administrator has unrestricted access to the application and to all projects.</p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Administrator</span> : designate the user as the administrator of the application.</p></li><li><p><span class="guilabel">E-mail notifications</span> : activate or de-activate automatic e-mail notifications for this user</p></li><li><p><span class="guilabel">Locked</span> : de-activates the user&#8217;s account</p></li></ul></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&nbsp;1.&nbsp;Administration&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;2.&nbsp;Roles and Permissions</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s02.html b/public/manual/en/ch01s02.html
new file mode 100644
index 000000000..06ba75673
--- /dev/null
+++ b/public/manual/en/ch01s02.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>2.&nbsp;Roles and Permissions</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s01.html" title="1.&nbsp;Users"><link rel="next" href="ch01s03.html" title="3.&nbsp;Trackers"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.&nbsp;Roles and Permissions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s01.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s03.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e50"></a>2.&nbsp;Roles and Permissions</h2></div></div></div><p>Roles organize the permissions of various members of a project. Each member of a project has a one Role in a project. A user can have different roles in different projects.</p><p>On the new or edit Role screen, check off the actions authorized for the Role.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s01.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">1.&nbsp;Users&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;3.&nbsp;Trackers</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s03.html b/public/manual/en/ch01s03.html
new file mode 100644
index 000000000..9253ce104
--- /dev/null
+++ b/public/manual/en/ch01s03.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>3.&nbsp;Trackers</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s02.html" title="2.&nbsp;Roles and Permissions"><link rel="next" href="ch01s04.html" title="4.&nbsp;Customized fields"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.&nbsp;Trackers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s02.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s04.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e57"></a>3.&nbsp;Trackers</h2></div></div></div><p>Trackers allow the sorting of Issues and can define specific workflows.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s02.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.&nbsp;Roles and Permissions&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;4.&nbsp;Customized fields</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s04.html b/public/manual/en/ch01s04.html
new file mode 100644
index 000000000..425e084f3
--- /dev/null
+++ b/public/manual/en/ch01s04.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>4.&nbsp;Customized fields</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s03.html" title="3.&nbsp;Trackers"><link rel="next" href="ch01s05.html" title="5.&nbsp;Issue status"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.&nbsp;Customized fields</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s03.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s05.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e62"></a>4.&nbsp;Customized fields</h2></div></div></div><p>Customized fields allow you to add additional information in Projects, Issues or Users. A customized field can be of one the following types:</p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Integer</span> : positive or negative number</p></li><li><p><span class="guilabel">String</span> : a string of characters - one single line of input.</p></li><li><p><span class="guilabel">Text</span> : a string of characters with multiple lines of input. Differs from String Format by providing multiple lines of input instead of a single line.</p></li><li><p><span class="guilabel">Date</span> : date</p></li><li><p><span class="guilabel">Boolean</span> : true or false (check if necessary)</p></li><li><p><span class="guilabel">List</span> : value to select from a predefined list (aka: scroll list or select box)</p></li></ul></div><p>Validation elements can be defined:</p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Required</span> : A required field must have input in the forms</p></li><li><p><span class="guilabel">For all the projects</span> : field automatically associated to all of the projects</p></li><li><p><span class="guilabel">Min - max length</span> : minimum and maximum length for the input fields (0 means that there is no restriction)</p></li><li><p><span class="guilabel">Regular Expression</span> : regular expressions may provide validation of the input value</p><p>Examples:</p><p><code class="code">^\[A-Z]{4}\d+$</code> : 4 capital letters followed by one or several digits</p><p><code class="code">^[^0-9]*$</code> : characters only - no digits</p></li><li><p><span class="guilabel">Possible values</span> : possible values for the fields of "List" type. Values are separated by the character |</p></li></ul></div><p></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e137"></a>4.1.&nbsp;Fields for Projects</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Required</span> : required field</p></li></ul></div><p></p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e148"></a>4.2.&nbsp;Fields for Issues</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">For all projects</span> : field automatically associated to all project Issues</p><p>If this option is not activated, each project could choose whether or not to use the field for its Issues (please see the project configuration).</p></li></ul></div><p></p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e161"></a>4.3.&nbsp;Field for Users</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Required</span> : required field</p></li></ul></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s03.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">3.&nbsp;Trackers&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;5.&nbsp;Issue status</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s05.html b/public/manual/en/ch01s05.html
new file mode 100644
index 000000000..75a4dd308
--- /dev/null
+++ b/public/manual/en/ch01s05.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>5.&nbsp;Issue status</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s04.html" title="4.&nbsp;Customized fields"><link rel="next" href="ch01s06.html" title="6.&nbsp;Workflow"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5.&nbsp;Issue status</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s04.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s06.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e172"></a>5.&nbsp;Issue status</h2></div></div></div><p>These screens allow you to define the different possible Issue statuses.</p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Closed</span> : indicates Issue is considered as closed</p></li><li><p><span class="guilabel">Default</span> : status applied by default to new Issue requests (only one status can be Default status)</p></li><li><p><span class="guilabel">Color</span> : HTML color code (6 characters) representing the displayed status</p></li></ul></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s04.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.&nbsp;Customized fields&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;6.&nbsp;Workflow</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s06.html b/public/manual/en/ch01s06.html
new file mode 100644
index 000000000..e7d688f33
--- /dev/null
+++ b/public/manual/en/ch01s06.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>6.&nbsp;Workflow</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s05.html" title="5.&nbsp;Issue status"><link rel="next" href="ch01s07.html" title="7.&nbsp;Enumerations"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.&nbsp;Workflow</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s05.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s07.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e194"></a>6.&nbsp;Workflow</h2></div></div></div><p>The workflow allows to define changes the various project members are allowed to make on the Issues, according to their type.</p><p>Select the role and the tracker for which you want to modify the workflow, then click Edit. The screen allows you then to modify the authorized change, for the chosen role and tracker. The Current Status options indicate the initial request status. The "New Statuses allowed" columns stand for the authorized status to apply.</p><p><em><span class="remark">Note: In order for a particular Role to change an Issue status, the authorization must be given to it explicitly, regardless of the workflow configuration.</span></em></p><p></p><div class="screenshot"><div class="mediaobject"><img src="resources/workflow.png"></div></div><p>In the above example, Bug type Issue requests with a New status could be given an Assigned or Resolved status by the Developer role. Those with an Assigned status could get a Resolved status. The status of all the other Bug type requests cannot be modified by the Developer.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s05.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5.&nbsp;Issue status&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;7.&nbsp;Enumerations</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s07.html b/public/manual/en/ch01s07.html
new file mode 100644
index 000000000..7b95d8a63
--- /dev/null
+++ b/public/manual/en/ch01s07.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>7.&nbsp;Enumerations</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s06.html" title="6.&nbsp;Workflow"><link rel="next" href="ch01s08.html" title="8.&nbsp;E-mail notifications"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7.&nbsp;Enumerations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s06.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s08.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e213"></a>7.&nbsp;Enumerations</h2></div></div></div><p>The value lists used by the application can be customized (for example, setting Issue priorities). This screen allows you to define the possible values for each of the following lists:</p><div class="itemizedlist"><ul type="disc"><li><p>Issue Priorities</p></li><li><p>Document Categories</p></li></ul></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s06.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s08.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.&nbsp;Workflow&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;8.&nbsp;E-mail notifications</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s08.html b/public/manual/en/ch01s08.html
new file mode 100644
index 000000000..3a2ecf28d
--- /dev/null
+++ b/public/manual/en/ch01s08.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>8.&nbsp;E-mail notifications</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s07.html" title="7.&nbsp;Enumerations"><link rel="next" href="ch01s09.html" title="9.&nbsp;Authentication"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.&nbsp;E-mail notifications</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s07.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s09.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e226"></a>8.&nbsp;E-mail notifications</h2></div></div></div><p>This screen allows you to select the actions that will generate an e-mail notification for project members.</p><p>Note: E-mail sending must be activated in the application configuration if you want to make any notifications.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s07.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s09.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7.&nbsp;Enumerations&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;9.&nbsp;Authentication</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s09.html b/public/manual/en/ch01s09.html
new file mode 100644
index 000000000..599c6017b
--- /dev/null
+++ b/public/manual/en/ch01s09.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>9.&nbsp;Authentication</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s08.html" title="8.&nbsp;E-mail notifications"><link rel="next" href="ch01s10.html" title="10.&nbsp;Information"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.&nbsp;Authentication</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s08.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s10.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e233"></a>9.&nbsp;Authentication</h2></div></div></div><p>By default, redMine refers to its own database to authenticate users, by a specific password.</p><p>If you already have one or several external user references (like LDAP), you can make them known in order to be used for authentication on redMine. This allows users to access redMine with their usual user names and passwords.</p><p>For each known reference, you can specify if the accounts can be created on the fly on redMine. If needed, the user accounts will be created automatically during the user&#8217;s signing in (without any specific rights on the projects), according to information available in the reference. Otherwise, the administrator must have previously created the user account on redMine.</p><p></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e243"></a>9.1.&nbsp;LDAP statement</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Name</span> : reference display name</p></li><li><p><span class="guilabel">Host</span> : LDAP server host name</p></li><li><p><span class="guilabel">Port</span> : connection port to the LDAP server</p></li><li><p><span class="guilabel">Account</span> : DN of the connection account to LDAP (please leave it blank if the directory authorizes anonymous read access)</p></li><li><p><span class="guilabel">Password</span> : password of the connection account</p></li><li><p><span class="guilabel">Base DN</span> : Basic DN used for user search in the directory</p></li><li><p><span class="guilabel">LDAP screen</span> : User search screen in the directory (optional)</p></li><li><p><span class="guilabel">LDAP features</span> :</p><div class="itemizedlist"><ul type="circle"><li><p><span class="guilabel">Identifier</span> : LDAP feature name used as user identifier (e.g.: uid)</p></li><li><p><span class="guilabel">First name</span> : LDAP feature name including the user&#8217;s first name (ex: givenName)</p></li><li><p><span class="guilabel">Last name</span> : LDAP feature name including the user&#8217;s last name (ex: familyName)</p></li><li><p><span class="guilabel">E-mail</span> : LDAP feature name including the user&#8217;s e-mail address (ex: mail)</p></li></ul></div></li></ul></div><p>The features" <span class="guilabel">First name</span> ", " <span class="guilabel">Last name</span> " and " <span class="guilabel">E-mail</span> " are not used except when the accounts are created on the fly.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s08.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s10.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8.&nbsp;E-mail notifications&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;10.&nbsp;Information</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch01s10.html b/public/manual/en/ch01s10.html
new file mode 100644
index 000000000..5cdb85b9a
--- /dev/null
+++ b/public/manual/en/ch01s10.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>10.&nbsp;Information</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s09.html" title="9.&nbsp;Authentication"><link rel="next" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.&nbsp;Information</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s09.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e320"></a>10.&nbsp;Information</h2></div></div></div><p>Displays application and environment information.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s09.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.&nbsp;Authentication&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;2.&nbsp;Projects</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02.html b/public/manual/en/ch02.html
new file mode 100644
index 000000000..b97b78d9e
--- /dev/null
+++ b/public/manual/en/ch02.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter&nbsp;2.&nbsp;Projects</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="index.html" title="RedMine Documentation"><link rel="prev" href="ch01s10.html" title="10.&nbsp;Information"><link rel="next" href="ch02s01.html" title="1.&nbsp;Project preview"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter&nbsp;2.&nbsp;Projects</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s10.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s01.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="d0e325"></a>Chapter&nbsp;2.&nbsp;Projects</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="ch02s01.html">1. Project preview</a></span></dt><dt><span class="section"><a href="ch02s02.html">2. Issue management</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s02.html#d0e338">2.1. Issue list</a></span></dt></dl></dd><dt><span class="section"><a href="ch02s03.html">3. Reports</a></span></dt><dt><span class="section"><a href="ch02s04.html">4. Change log</a></span></dt><dt><span class="section"><a href="ch02s05.html">5. News</a></span></dt><dt><span class="section"><a href="ch02s06.html">6. Documents</a></span></dt><dt><span class="section"><a href="ch02s07.html">7. Files</a></span></dt><dt><span class="section"><a href="ch02s08.html">8. Settings</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s08.html#d0e382">8.1. Project features</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e398">8.2. Members</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e403">8.3. Versions</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e408">8.4. Request categories</a></span></dt></dl></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s10.html">Prev</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.&nbsp;Information&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;1.&nbsp;Project preview</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02s01.html b/public/manual/en/ch02s01.html
new file mode 100644
index 000000000..63cdde630
--- /dev/null
+++ b/public/manual/en/ch02s01.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>1.&nbsp;Project preview</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="prev" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="next" href="ch02s02.html" title="2.&nbsp;Issue management"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">1.&nbsp;Project preview</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projects</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s02.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e328"></a>1.&nbsp;Project preview</h2></div></div></div><p>The preview presents the general project information, its main members, the latest announcements, as well as an synthesis of Issue requests open by tracker.</p><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&nbsp;2.&nbsp;Projects&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;2.&nbsp;Issue management</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02s02.html b/public/manual/en/ch02s02.html
new file mode 100644
index 000000000..4354ce4c8
--- /dev/null
+++ b/public/manual/en/ch02s02.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>2.&nbsp;Issue management</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="prev" href="ch02s01.html" title="1.&nbsp;Project preview"><link rel="next" href="ch02s03.html" title="3.&nbsp;Reports"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.&nbsp;Issue management</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s01.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projects</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s03.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e334"></a>2.&nbsp;Issue management</h2></div></div></div><p></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e338"></a>2.1.&nbsp;Issue list</h3></div></div></div><p>By default, the entire list of the project open Issues are displayed. Various screens allow you to select the Issues to be displayed. If the project has sub-projects, you have the possibility to display the sub-project's Issues as well (not displayed by default).</p><p>Once applied, a screen is valid during the entire session. You can re-define it or delete it by clicking Cancel.</p><p></p><div class="screenshot"><div class="mediaobject"><img src="resources/issues_list.png"></div></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s01.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">1.&nbsp;Project preview&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;3.&nbsp;Reports</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02s03.html b/public/manual/en/ch02s03.html
new file mode 100644
index 000000000..351e1c916
--- /dev/null
+++ b/public/manual/en/ch02s03.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>3.&nbsp;Reports</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="prev" href="ch02s02.html" title="2.&nbsp;Issue management"><link rel="next" href="ch02s04.html" title="4.&nbsp;Change log"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.&nbsp;Reports</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s02.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projects</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s04.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e353"></a>3.&nbsp;Reports</h2></div></div></div><p>This screen presents the number of Issues and Issue status synthesis according to various criteria (tracker, priority, category). Direct links allow for access to the detailed Issue list for each criterion.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s02.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.&nbsp;Issue management&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;4.&nbsp;Change log</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02s04.html b/public/manual/en/ch02s04.html
new file mode 100644
index 000000000..14da5dc73
--- /dev/null
+++ b/public/manual/en/ch02s04.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>4.&nbsp;Change log</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="prev" href="ch02s03.html" title="3.&nbsp;Reports"><link rel="next" href="ch02s05.html" title="5.&nbsp;News"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.&nbsp;Change log</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s03.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projects</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s05.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e358"></a>4.&nbsp;Change log</h2></div></div></div><p>This page presents the entire list of the resolved Issues for each version of the project. Certain types of Issues can be excluded from this display.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s03.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">3.&nbsp;Reports&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;5.&nbsp;News</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02s05.html b/public/manual/en/ch02s05.html
new file mode 100644
index 000000000..3a8334df2
--- /dev/null
+++ b/public/manual/en/ch02s05.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>5.&nbsp;News</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="prev" href="ch02s04.html" title="4.&nbsp;Change log"><link rel="next" href="ch02s06.html" title="6.&nbsp;Documents"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5.&nbsp;News</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s04.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projects</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s06.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e363"></a>5.&nbsp;News</h2></div></div></div><p>Allows you to inform users on project activity.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s04.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.&nbsp;Change log&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;6.&nbsp;Documents</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02s06.html b/public/manual/en/ch02s06.html
new file mode 100644
index 000000000..71ced3400
--- /dev/null
+++ b/public/manual/en/ch02s06.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>6.&nbsp;Documents</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="prev" href="ch02s05.html" title="5.&nbsp;News"><link rel="next" href="ch02s07.html" title="7.&nbsp;Files"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.&nbsp;Documents</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s05.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projects</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s07.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e368"></a>6.&nbsp;Documents</h2></div></div></div><p>Documents are grouped by categories (see Value Lists). A document can contain several files (for example: revisions or successive versions).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s05.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5.&nbsp;News&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;7.&nbsp;Files</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02s07.html b/public/manual/en/ch02s07.html
new file mode 100644
index 000000000..b7eacb6a3
--- /dev/null
+++ b/public/manual/en/ch02s07.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>7.&nbsp;Files</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="prev" href="ch02s06.html" title="6.&nbsp;Documents"><link rel="next" href="ch02s08.html" title="8.&nbsp;Settings"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7.&nbsp;Files</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s06.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projects</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s08.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e373"></a>7.&nbsp;Files</h2></div></div></div><p>This module allows you to display various folders (sources, binaires, ...) for each version of the application.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s06.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s08.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.&nbsp;Documents&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;8.&nbsp;Settings</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/ch02s08.html b/public/manual/en/ch02s08.html
new file mode 100644
index 000000000..f9d19e8ce
--- /dev/null
+++ b/public/manual/en/ch02s08.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>8.&nbsp;Settings</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projects"><link rel="prev" href="ch02s07.html" title="7.&nbsp;Files"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.&nbsp;Settings</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s07.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projects</th><td width="20%" align="right">&nbsp;</td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e378"></a>8.&nbsp;Settings</h2></div></div></div><p></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e382"></a>8.1.&nbsp;Project features</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Public</span> : if it&#8217;s a public project, it can be viewed (request consultation, documents consultation, ...) for all the users, including those who are not project members. If it&#8217;s not a public project, only the project members have access to it, according to their role.</p></li><li><p><span class="guilabel">Customized fields</span> : Select the customized fields that you want to use. Only the administrator can define new customized fields.</p></li></ul></div><p></p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e398"></a>8.2.&nbsp;Members</h3></div></div></div><p>This screen allows you to define the project members as well as their corresponding roles. A user can have only one role in a given project. The role of a member determines the permissions they have in a project.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e403"></a>8.3.&nbsp;Versions</h3></div></div></div><p>Versions allow you to follow the changes made during all the project. For instance, at the close of an Issue, you can indicate which version takes it into account. You can display the various versions of the application (see Files).</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e408"></a>8.4.&nbsp;Request categories</h3></div></div></div><p>Issue categories allow you to organize Issues. Categories can correspond to different project modules.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s07.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;</td></tr><tr><td width="40%" align="left" valign="top">7.&nbsp;Files&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/html.css b/public/manual/en/html.css
new file mode 100644
index 000000000..c1b2a6fca
--- /dev/null
+++ b/public/manual/en/html.css
@@ -0,0 +1,55 @@
+body {
+ background: #FFFFFF;
+ font: 0.8em Verdana,Tahoma,Arial,sans-serif;
+}
+
+h1, h2, h3, h4, h5 {
+ color: #800000;
+ font-family: sans-serif;
+}
+
+table {
+ font-size: 1em;
+}
+
+a{
+color:#467aa7;
+font-weight:bold;
+text-decoration:none;
+background-color:inherit;
+}
+
+a:hover{
+ color: #800000;
+ text-decoration:underline;
+ background-color:inherit;
+}
+
+a img{border:none;}
+
+.screenshot {
+ text-align: center;
+}
+
+.guilabel {
+ font-weight: bold;
+}
+
+span.term {
+ font-weight: bold;
+}
+
+div.sidebar {
+ background: #F0F0F0;
+ border: 1px solid gray;
+ padding: 5px;
+ margin: 20px;
+}
+
+pre.programlisting {
+ background: #F0F0F0;
+ border: 1px solid gray;
+ padding: 2px;
+ font-size: 10pt;
+ white-space: pre;
+}
diff --git a/public/manual/en/index.html b/public/manual/en/index.html
new file mode 100644
index 000000000..f1f64aa45
--- /dev/null
+++ b/public/manual/en/index.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>RedMine Documentation</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="RedMine Documentation"><link rel="next" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"></head><body><a href="http://redmine.rubyforge.org/">redMine home</a><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">RedMine Documentation</th></tr><tr><td width="20%" align="left">&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Next</a></td></tr></table><hr></div><div class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="d0e1"></a>RedMine Documentation</h1></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="ch01.html">1. Administration</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s01.html">1. Users</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s01.html#d0e12">1.1. Users&#8217; List</a></span></dt><dt><span class="section"><a href="ch01s01.html#d0e26">1.2. User Creation or Modification</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s02.html">2. Roles and Permissions</a></span></dt><dt><span class="section"><a href="ch01s03.html">3. Trackers</a></span></dt><dt><span class="section"><a href="ch01s04.html">4. Customized fields</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s04.html#d0e137">4.1. Fields for Projects</a></span></dt><dt><span class="section"><a href="ch01s04.html#d0e148">4.2. Fields for Issues</a></span></dt><dt><span class="section"><a href="ch01s04.html#d0e161">4.3. Field for Users</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s05.html">5. Issue status</a></span></dt><dt><span class="section"><a href="ch01s06.html">6. Workflow</a></span></dt><dt><span class="section"><a href="ch01s07.html">7. Enumerations</a></span></dt><dt><span class="section"><a href="ch01s08.html">8. E-mail notifications</a></span></dt><dt><span class="section"><a href="ch01s09.html">9. Authentication</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s09.html#d0e243">9.1. LDAP statement</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s10.html">10. Information</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch02.html">2. Projects</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s01.html">1. Project preview</a></span></dt><dt><span class="section"><a href="ch02s02.html">2. Issue management</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s02.html#d0e338">2.1. Issue list</a></span></dt></dl></dd><dt><span class="section"><a href="ch02s03.html">3. Reports</a></span></dt><dt><span class="section"><a href="ch02s04.html">4. Change log</a></span></dt><dt><span class="section"><a href="ch02s05.html">5. News</a></span></dt><dt><span class="section"><a href="ch02s06.html">6. Documents</a></span></dt><dt><span class="section"><a href="ch02s07.html">7. Files</a></span></dt><dt><span class="section"><a href="ch02s08.html">8. Settings</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s08.html#d0e382">8.1. Project features</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e398">8.2. Members</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e403">8.3. Versions</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e408">8.4. Request categories</a></span></dt></dl></dd></dl></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left">&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;1.&nbsp;Administration</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/en/resources/issues_list.png b/public/manual/en/resources/issues_list.png
new file mode 100644
index 000000000..47eab0fca
--- /dev/null
+++ b/public/manual/en/resources/issues_list.png
Binary files differ
diff --git a/public/manual/en/resources/users_list.png b/public/manual/en/resources/users_list.png
new file mode 100644
index 000000000..0c9ef86ec
--- /dev/null
+++ b/public/manual/en/resources/users_list.png
Binary files differ
diff --git a/public/manual/en/resources/workflow.png b/public/manual/en/resources/workflow.png
new file mode 100644
index 000000000..04e79d61e
--- /dev/null
+++ b/public/manual/en/resources/workflow.png
Binary files differ
diff --git a/public/manual/fr/ch01.html b/public/manual/fr/ch01.html
new file mode 100644
index 000000000..567c5368a
--- /dev/null
+++ b/public/manual/fr/ch01.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter&nbsp;1.&nbsp;Administration</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="index.html" title="Documentation redMine"><link rel="prev" href="index.html" title="Documentation redMine"><link rel="next" href="ch01s01.html" title="1.&nbsp;Utilisateurs"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter&nbsp;1.&nbsp;Administration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s01.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="d0e4"></a>Chapter&nbsp;1.&nbsp;Administration</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="ch01s01.html">1. Utilisateurs</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s01.html#d0e12">1.1. Liste des utilisateurs</a></span></dt><dt><span class="section"><a href="ch01s01.html#d0e26">1.2. Cr&eacute;ation ou modification d'un utilisateur</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s02.html">2. R&ocirc;les et permissions</a></span></dt><dt><span class="section"><a href="ch01s03.html">3. Trackers</a></span></dt><dt><span class="section"><a href="ch01s04.html">4. Champs personnalis&eacute;s</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s04.html#d0e132">4.1. Champs pour les projets</a></span></dt><dt><span class="section"><a href="ch01s04.html#d0e143">4.2. Champs pour les demandes</a></span></dt><dt><span class="section"><a href="ch01s04.html#d0e156">4.3. Champs pour les utilisateurs</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s05.html">5. Statut des demandes</a></span></dt><dt><span class="section"><a href="ch01s06.html">6. Workflow</a></span></dt><dt><span class="section"><a href="ch01s07.html">7. Listes de valeurs</a></span></dt><dt><span class="section"><a href="ch01s08.html">8. Notifications par mail</a></span></dt><dt><span class="section"><a href="ch01s09.html">9. Authentification</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s09.html#d0e238">9.1. D&eacute;claration d'un annuaire LDAP</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s10.html">10. Informations</a></span></dt></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Documentation redMine&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;1.&nbsp;Utilisateurs</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s01.html b/public/manual/fr/ch01s01.html
new file mode 100644
index 000000000..c08192b8b
--- /dev/null
+++ b/public/manual/fr/ch01s01.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>1.&nbsp;Utilisateurs</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="next" href="ch01s02.html" title="2.&nbsp;R&ocirc;les et permissions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">1.&nbsp;Utilisateurs</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s02.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e7"></a>1.&nbsp;Utilisateurs</h2></div></div></div><p>Ces &eacute;crans vous permettent de g&eacute;rer les utilisateurs de l'application.</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e12"></a>1.1.&nbsp;Liste des utilisateurs</h3></div></div></div><p></p><div class="screenshot"><div class="mediaobject"><img src="resources/users_list.png"></div></div><p>Les boutons Lock/Unlock vous permettent de v&eacute;rouiller/d&eacute;v&eacute;rouiller les comptes utilisateurs.</p><p>Un utilisateur dont le compte est v&eacute;rouill&eacute; ne peut plus s'identifier pour acc&eacute;der &agrave; l'application.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e26"></a>1.2.&nbsp;Cr&eacute;ation ou modification d'un utilisateur</h3></div></div></div><p>En mode modification, laissez le champ Password vide pour laisser le mot de passe de l'utilisateur inchang&eacute;.</p><p>Un utilisateur d&eacute;clar&eacute; comme administrateur dispose de toutes les permissions sur l'application et sur tous les projets.</p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Administrateur</span>: d&eacute;clare l'utilisateur comme administrateur de l'application.</p></li><li><p><span class="guilabel">Notifications par mail</span>: permet d'activer ou non l'envoi automatique de notifications par mail pour cet utilisateur</p></li><li><p><span class="guilabel">V&eacute;rouill&eacute;</span>: d&eacute;sactive le compte de l'utilisateur</p></li></ul></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&nbsp;1.&nbsp;Administration&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;2.&nbsp;R&ocirc;les et permissions</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s02.html b/public/manual/fr/ch01s02.html
new file mode 100644
index 000000000..2b448d1a8
--- /dev/null
+++ b/public/manual/fr/ch01s02.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>2.&nbsp;R&ocirc;les et permissions</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s01.html" title="1.&nbsp;Utilisateurs"><link rel="next" href="ch01s03.html" title="3.&nbsp;Trackers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.&nbsp;R&ocirc;les et permissions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s01.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s03.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e50"></a>2.&nbsp;R&ocirc;les et permissions</h2></div></div></div><p>Les r&ocirc;les permettent de d&eacute;finir les permissions des diff&eacute;rents membres d'un projet. Chaque membre d'un projet dispose d'un r&ocirc;le unique au sein d'un projet. Un utilisateur peut avoir diff&eacute;rents r&ocirc;les au sein de diff&eacute;rents projets.</p><p>Sur l'&eacute;cran d'&eacute;dition du r&ocirc;le, cochez les actions que vous souhaitez autoriser pour le r&ocirc;le.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s01.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">1.&nbsp;Utilisateurs&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;3.&nbsp;Trackers</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s03.html b/public/manual/fr/ch01s03.html
new file mode 100644
index 000000000..4e03eed49
--- /dev/null
+++ b/public/manual/fr/ch01s03.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>3.&nbsp;Trackers</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s02.html" title="2.&nbsp;R&ocirc;les et permissions"><link rel="next" href="ch01s04.html" title="4.&nbsp;Champs personnalis&eacute;s"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.&nbsp;Trackers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s02.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s04.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e57"></a>3.&nbsp;Trackers</h2></div></div></div><p>Les trackers permettent de typer les demandes et de d&eacute;finir des workflows sp&eacute;cifiques pour chacun de ces types.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s02.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.&nbsp;R&ocirc;les et permissions&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;4.&nbsp;Champs personnalis&eacute;s</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s04.html b/public/manual/fr/ch01s04.html
new file mode 100644
index 000000000..53fae1e24
--- /dev/null
+++ b/public/manual/fr/ch01s04.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>4.&nbsp;Champs personnalis&eacute;s</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s03.html" title="3.&nbsp;Trackers"><link rel="next" href="ch01s05.html" title="5.&nbsp;Statut des demandes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.&nbsp;Champs personnalis&eacute;s</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s03.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s05.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e62"></a>4.&nbsp;Champs personnalis&eacute;s</h2></div></div></div><p>Les champs personnalis&eacute;s vous permettent d'ajouter des informations suppl&eacute;mentaires sur les projets, les demandes ou les utilisateurs. Un champ personnalis&eacute; peut &ecirc;tre de l'un des types suivants:</p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Entier</span>: entier positif ou n&eacute;gatif</p></li><li><p><span class="guilabel">Cha&icirc;ne</span>: cha&icirc;ne de caract&egrave;re</p></li><li><p><span class="guilabel">Date</span>: date</p></li><li><p><span class="guilabel">Bool&eacute;en</span>: bool&eacute;en (case &agrave; cocher)</p></li><li><p><span class="guilabel">Liste</span>: valeur &agrave; s&eacute;lectionn&eacute;e parmi une liste pr&eacute;d&eacute;finie (liste d&eacute;roulante)</p></li></ul></div><p>Des &eacute;l&eacute;ments de validation peuvent &ecirc;tre d&eacute;finis:</p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Obligatoire</span>: champ dont la saisie est obligatoire sur les demandes</p></li><li><p><span class="guilabel">Pour tous les projects</span>: champ automatiquement associ&eacute; &agrave; l'ensemble des projets</p></li><li><p><span class="guilabel">Min - max length</span>: longueurs minimales et maximales pour les champs en saisie libre (0 signifie qu'il n'y a pas de restriction)</p></li><li><p><span class="guilabel">Expression r&eacute;guli&egrave;re</span>: expression r&eacute;guli&egrave;re permettant de valider la valeur saisie</p><p>Exemples:</p><p><code class="code">^\[A-Z]{4}\d+$</code> : 4 lettres majuscules suivies d'un ou plusieurs chiffres</p><p><code class="code">^[^0-9]*$</code> : cha&icirc;ne ne comportant pas de chiffres</p></li><li><p><span class="guilabel">Valeurs possibles</span>: valeurs possibles pour les champs de type "Liste". Les valeurs sont s&eacute;par&eacute;es par le caract&egrave;re |</p></li></ul></div><p></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e132"></a>4.1.&nbsp;Champs pour les projets</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Obligatoire</span>: champ dont la saisie est obligatoire</p></li></ul></div><p></p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e143"></a>4.2.&nbsp;Champs pour les demandes</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Pour tous les projects</span>: champ automatiquement associ&eacute; aux demandes de l'ensemble des projets</p><p>Si cette option n'est pas activ&eacute;e, chaque projet pourra choisir d'utiliser ou non le champ pour ses demandes (voir configuration du projet).</p></li></ul></div><p></p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e156"></a>4.3.&nbsp;Champs pour les utilisateurs</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Obligatoire</span>: champ dont la saisie est obligatoire</p></li></ul></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s03.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">3.&nbsp;Trackers&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;5.&nbsp;Statut des demandes</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s05.html b/public/manual/fr/ch01s05.html
new file mode 100644
index 000000000..67212eb4e
--- /dev/null
+++ b/public/manual/fr/ch01s05.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>5.&nbsp;Statut des demandes</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s04.html" title="4.&nbsp;Champs personnalis&eacute;s"><link rel="next" href="ch01s06.html" title="6.&nbsp;Workflow"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5.&nbsp;Statut des demandes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s04.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s06.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e167"></a>5.&nbsp;Statut des demandes</h2></div></div></div><p>Ces &eacute;crans vous permettent de d&eacute;finir les diff&eacute;rents statuts possibles des demandes.</p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Demande ferm&eacute;e</span>: indique que le statut correspond &agrave; une demande consid&eacute;r&eacute;e comme ferm&eacute;e</p></li><li><p><span class="guilabel">Statut par d&eacute;faut</span>: statut appliqu&eacute; par d&eacute;faut aux nouvelles demandes (seul un statut peut &ecirc;tre d&eacute;clar&eacute; comme statut par d&eacute;faut)</p></li><li><p><span class="guilabel">Couleur</span>: code couleur HTML (6 caract&egrave;res) repr&eacute;sentant le statut &agrave; l'affichage</p></li></ul></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s04.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.&nbsp;Champs personnalis&eacute;s&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;6.&nbsp;Workflow</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s06.html b/public/manual/fr/ch01s06.html
new file mode 100644
index 000000000..335d27aba
--- /dev/null
+++ b/public/manual/fr/ch01s06.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>6.&nbsp;Workflow</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s05.html" title="5.&nbsp;Statut des demandes"><link rel="next" href="ch01s07.html" title="7.&nbsp;Listes de valeurs"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.&nbsp;Workflow</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s05.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s07.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e189"></a>6.&nbsp;Workflow</h2></div></div></div><p>Le workflow permet de d&eacute;finir les changements que les diff&eacute;rents membres d'un projet sont autoris&eacute;s &agrave; effectuer sur les demandes, en fonction de leur type.</p><p>S&eacute;lectionnez le r&ocirc;le et le tracker pour lesquels vous souhaitez modifier le workflow, puis cliquez sur Edit. L'&eacute;cran vous permet alors de modifier, pour le r&ocirc;le et le tracker choisi, les changements autoris&eacute;s. Les lignes repr&eacute;sentent les statuts initiaux des demandes. Les colonnes repr&eacute;sentent les statuts autoris&eacute;s &agrave; &ecirc;tre appliqu&eacute;s.</p><p><em><span class="remark">Remarque: pour qu'un r&ocirc;le puisse changer le statut des demandes, la permission doit lui &ecirc;tre explicitement donn&eacute;e ind&eacute;pendemment de la configuration du workflow.</span></em></p><p></p><div class="screenshot"><div class="mediaobject"><img src="resources/workflow.png"></div></div><p>Dans l'exemple ci-dessus, les demandes de type Bug au statut Nouveau pourront &ecirc;tre pass&eacute;es au statut Assign&eacute;e ou R&eacute;solue par le r&ocirc;le D&eacute;veloppeur. Celles au statut Assign&eacute;e pourront &ecirc;tre pass&eacute;es au statut R&eacute;solue. Le statut de toutes les autres demandes de type Bug ne pourra pas &ecirc;tre modifi&eacute; par le D&eacute;veloppeur.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s05.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5.&nbsp;Statut des demandes&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;7.&nbsp;Listes de valeurs</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s07.html b/public/manual/fr/ch01s07.html
new file mode 100644
index 000000000..4b8be47d3
--- /dev/null
+++ b/public/manual/fr/ch01s07.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>7.&nbsp;Listes de valeurs</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s06.html" title="6.&nbsp;Workflow"><link rel="next" href="ch01s08.html" title="8.&nbsp;Notifications par mail"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7.&nbsp;Listes de valeurs</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s06.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s08.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e208"></a>7.&nbsp;Listes de valeurs</h2></div></div></div><p>Les listes de valeurs utilis&eacute;es par l'application (exemple: les priorit&eacute;s des demandes) peuvent &ecirc;tre personnalis&eacute;es. Cet &eacute;cran vous permet de d&eacute;finir les valeurs possibles pour chacune des listes suivantes:</p><div class="itemizedlist"><ul type="disc"><li><p>Priorit&eacute;s des demandes</p></li><li><p>Cat&eacute;gories de documents</p></li></ul></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s06.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s08.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.&nbsp;Workflow&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;8.&nbsp;Notifications par mail</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s08.html b/public/manual/fr/ch01s08.html
new file mode 100644
index 000000000..db3133c68
--- /dev/null
+++ b/public/manual/fr/ch01s08.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>8.&nbsp;Notifications par mail</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s07.html" title="7.&nbsp;Listes de valeurs"><link rel="next" href="ch01s09.html" title="9.&nbsp;Authentification"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.&nbsp;Notifications par mail</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s07.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s09.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e221"></a>8.&nbsp;Notifications par mail</h2></div></div></div><p>Cet &eacute;cran vous permet de s&eacute;lectionner les actions qui donneront lieu &agrave; une notification par mail aux membres du projet.</p><p>Remarque: l'envoi de mails doit &ecirc;tre activ&eacute; dans la configuration de l'application si souhaitez effectuer des notifications.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s07.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s09.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7.&nbsp;Listes de valeurs&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;9.&nbsp;Authentification</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s09.html b/public/manual/fr/ch01s09.html
new file mode 100644
index 000000000..7fb82b2a1
--- /dev/null
+++ b/public/manual/fr/ch01s09.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>9.&nbsp;Authentification</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s08.html" title="8.&nbsp;Notifications par mail"><link rel="next" href="ch01s10.html" title="10.&nbsp;Informations"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.&nbsp;Authentification</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s08.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01s10.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e228"></a>9.&nbsp;Authentification</h2></div></div></div><p>Par d&eacute;faut, redMine s'appuie sur sa propre base de donn&eacute;es pour authentifier les utilisateurs, &agrave; l'aide d'un mot de passe sp&eacute;cifique.</p><p>Si vous disposez d&eacute;j&agrave; d'un ou plusieurs r&eacute;f&eacute;rentiels externes d'utilisateurs (annuaires LDAP), vous pouvez les d&eacute;clarer afin qu'ils soient utilis&eacute;s pour l'authentification sur redMine. Cela permet aux utilisateurs d'acc&eacute;der &agrave; redMine avec leurs identifiants et mots de passe habituels.</p><p>Pour chaque r&eacute;f&eacute;rentiel d&eacute;clar&eacute;, vous pouvez sp&eacute;cifier si les comptes peuvent &ecirc;tre cr&eacute;&eacute;s &agrave; la vol&eacute;e dans redMine. Si c'est le cas, les comptes utilisateurs sont automatiquement cr&eacute;&eacute;s &agrave; la premi&egrave;re connexion de l'utilisateur (sans droits sp&eacute;cifiques sur les projets), &agrave; partir des informations disponibles dans le r&eacute;f&eacute;rentiel. Sinon, l'administrateur doit au pr&eacute;alable cr&eacute;er le compte de l'utilisateur dans redMine.</p><p></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e238"></a>9.1.&nbsp;D&eacute;claration d'un annuaire LDAP</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Nom</span>: nom d'affichage du r&eacute;f&eacute;rentiel</p></li><li><p><span class="guilabel">H&ocirc;te</span>: nom d'h&ocirc;te du serveur LDAP</p></li><li><p><span class="guilabel">Port</span>: port de connexion au serveur LDAP</p></li><li><p><span class="guilabel">Compte</span>: DN du compte de connexion au LDAP (laisser vide si l'annuaire autorise l'acc&egrave;s anonyme en lecture)</p></li><li><p><span class="guilabel">Mot de passe</span>: mot de passe du compte de connexion</p></li><li><p><span class="guilabel">Base DN</span>: DN de base utilis&eacute; pour la recherche des utilisateur dans l'annuaire</p></li><li><p><span class="guilabel">Filtre LDAP</span>: Filtre de recherche des utilisateurs dans l'annuaire (optionnel)</p></li><li><p><span class="guilabel">Attributs LDAP</span>:</p><div class="itemizedlist"><ul type="circle"><li><p><span class="guilabel">Identifiant</span>: nom de l'attribut LDAP utilis&eacute; comme identifiant de l'utilisateur (ex: uid)</p></li><li><p><span class="guilabel">Pr&eacute;nom</span>: nom de l'attribut LDAP contenant le pr&eacute;nom de l'utilisateur (ex: givenName)</p></li><li><p><span class="guilabel">Nom</span>: nom de l'attribut LDAP contenant le nom de l'utilisateur (ex: sn)</p></li><li><p><span class="guilabel">Email</span>: nom de l'attribut LDAP contenant l'adresse mail de l'utilisateur (ex: mail)</p></li></ul></div></li></ul></div><p>Les attributs "<span class="guilabel">Pr&eacute;nom</span>", "<span class="guilabel">Nom</span>" et "<span class="guilabel">Email</span>" ne sont utilis&eacute;s que lorsque les comptes sont cr&eacute;&eacute;s &agrave; la vol&eacute;e.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s08.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01s10.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8.&nbsp;Notifications par mail&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;10.&nbsp;Informations</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch01s10.html b/public/manual/fr/ch01s10.html
new file mode 100644
index 000000000..ab1cd4540
--- /dev/null
+++ b/public/manual/fr/ch01s10.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>10.&nbsp;Informations</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"><link rel="prev" href="ch01s09.html" title="9.&nbsp;Authentification"><link rel="next" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.&nbsp;Informations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s09.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;1.&nbsp;Administration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e315"></a>10.&nbsp;Informations</h2></div></div></div><p>Affiche des informations relatives &agrave; l'application et &agrave; son environnement.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s09.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch01.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.&nbsp;Authentification&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;2.&nbsp;Projets</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02.html b/public/manual/fr/ch02.html
new file mode 100644
index 000000000..1fbca1b09
--- /dev/null
+++ b/public/manual/fr/ch02.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter&nbsp;2.&nbsp;Projets</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="index.html" title="Documentation redMine"><link rel="prev" href="ch01s10.html" title="10.&nbsp;Informations"><link rel="next" href="ch02s01.html" title="1.&nbsp;Aper&ccedil;u du projet"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter&nbsp;2.&nbsp;Projets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01s10.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s01.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="d0e320"></a>Chapter&nbsp;2.&nbsp;Projets</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="ch02s01.html">1. Aper&ccedil;u du projet</a></span></dt><dt><span class="section"><a href="ch02s02.html">2. Gestion des demandes</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s02.html#d0e333">2.1. Liste des demandes</a></span></dt></dl></dd><dt><span class="section"><a href="ch02s03.html">3. Rapports</a></span></dt><dt><span class="section"><a href="ch02s04.html">4. Historique</a></span></dt><dt><span class="section"><a href="ch02s05.html">5. Annonces</a></span></dt><dt><span class="section"><a href="ch02s06.html">6. Documents</a></span></dt><dt><span class="section"><a href="ch02s07.html">7. Fichiers</a></span></dt><dt><span class="section"><a href="ch02s08.html">8. Configuration du projet</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s08.html#d0e377">8.1. Propri&eacute;t&eacute;s du projet</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e393">8.2. Membres</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e398">8.3. Versions</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e403">8.4. Cat&eacute;gories des demandes</a></span></dt></dl></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01s10.html">Prev</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.&nbsp;Informations&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;1.&nbsp;Aper&ccedil;u du projet</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02s01.html b/public/manual/fr/ch02s01.html
new file mode 100644
index 000000000..8509f6dea
--- /dev/null
+++ b/public/manual/fr/ch02s01.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>1.&nbsp;Aper&ccedil;u du projet</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="prev" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="next" href="ch02s02.html" title="2.&nbsp;Gestion des demandes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">1.&nbsp;Aper&ccedil;u du projet</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projets</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s02.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e323"></a>1.&nbsp;Aper&ccedil;u du projet</h2></div></div></div><p>L'aper&ccedil;u vous pr&eacute;sente les informations g&eacute;n&eacute;rales relatives au projet, les principaux membres, les derni&egrave;res annonces, ainsi qu'une synth&egrave;se du nombre de demandes ouvertes par tracker.</p><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&nbsp;2.&nbsp;Projets&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;2.&nbsp;Gestion des demandes</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02s02.html b/public/manual/fr/ch02s02.html
new file mode 100644
index 000000000..ba79d555f
--- /dev/null
+++ b/public/manual/fr/ch02s02.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>2.&nbsp;Gestion des demandes</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="prev" href="ch02s01.html" title="1.&nbsp;Aper&ccedil;u du projet"><link rel="next" href="ch02s03.html" title="3.&nbsp;Rapports"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.&nbsp;Gestion des demandes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s01.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projets</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s03.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e329"></a>2.&nbsp;Gestion des demandes</h2></div></div></div><p></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e333"></a>2.1.&nbsp;Liste des demandes</h3></div></div></div><p>Par d&eacute;faut, l'ensemble des demandes ouvertes du projet sont affich&eacute;es. Diff&eacute;rents filtres vous permettent de s&eacute;lectionner les demandes &agrave; afficher. Si le projet comporte des sous-projets, vous avez la possibilit&eacute; d'afficher &eacute;galement les demandes relatives aux sous-projets (non affich&eacute;es par d&eacute;faut).</p><p>Une fois appliqu&eacute;, un filtre reste valable durant toute votre session. Vous pouvez le red&eacute;finir, ou le supprimer en cliquant sur Annuler.</p><p></p><div class="screenshot"><div class="mediaobject"><img src="resources/issues_list.png"></div></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s01.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">1.&nbsp;Aper&ccedil;u du projet&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;3.&nbsp;Rapports</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02s03.html b/public/manual/fr/ch02s03.html
new file mode 100644
index 000000000..1e3aa8906
--- /dev/null
+++ b/public/manual/fr/ch02s03.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>3.&nbsp;Rapports</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="prev" href="ch02s02.html" title="2.&nbsp;Gestion des demandes"><link rel="next" href="ch02s04.html" title="4.&nbsp;Historique"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.&nbsp;Rapports</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s02.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projets</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s04.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e348"></a>3.&nbsp;Rapports</h2></div></div></div><p>Cet &eacute;cran pr&eacute;sente la synth&egrave;se du nombre de demandes par statut et selon diff&eacute;rents crit&egrave;res (tracker, priorit&eacute;, cat&eacute;gorie). Des liens directs permettent d'acc&eacute;der &agrave; la liste d&eacute;taill&eacute;e des demandes pour chaque crit&egrave;re.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s02.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.&nbsp;Gestion des demandes&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;4.&nbsp;Historique</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02s04.html b/public/manual/fr/ch02s04.html
new file mode 100644
index 000000000..d75c67318
--- /dev/null
+++ b/public/manual/fr/ch02s04.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>4.&nbsp;Historique</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="prev" href="ch02s03.html" title="3.&nbsp;Rapports"><link rel="next" href="ch02s05.html" title="5.&nbsp;Annonces"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.&nbsp;Historique</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s03.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projets</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s05.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e353"></a>4.&nbsp;Historique</h2></div></div></div><p>Cette page pr&eacute;sente l'ensemble des demandes r&eacute;solues dans chacune des versions du projet. Certains types de demande peuvent &ecirc;tre exclus de cet affichage.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s03.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">3.&nbsp;Rapports&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;5.&nbsp;Annonces</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02s05.html b/public/manual/fr/ch02s05.html
new file mode 100644
index 000000000..b3b39eacf
--- /dev/null
+++ b/public/manual/fr/ch02s05.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>5.&nbsp;Annonces</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="prev" href="ch02s04.html" title="4.&nbsp;Historique"><link rel="next" href="ch02s06.html" title="6.&nbsp;Documents"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5.&nbsp;Annonces</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s04.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projets</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s06.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e358"></a>5.&nbsp;Annonces</h2></div></div></div><p>Les nouvelles vous permettent d'informer les utilisateurs sur l'activit&eacute; du projet.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s04.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.&nbsp;Historique&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;6.&nbsp;Documents</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02s06.html b/public/manual/fr/ch02s06.html
new file mode 100644
index 000000000..9a78b9f31
--- /dev/null
+++ b/public/manual/fr/ch02s06.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>6.&nbsp;Documents</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="prev" href="ch02s05.html" title="5.&nbsp;Annonces"><link rel="next" href="ch02s07.html" title="7.&nbsp;Fichiers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.&nbsp;Documents</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s05.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projets</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s07.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e363"></a>6.&nbsp;Documents</h2></div></div></div><p>Les documents sont group&eacute;s par cat&eacute;gories (voir Listes de valeurs). Un document peut contenir plusieurs fichiers (exemple: r&eacute;visions ou versions successives).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s05.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5.&nbsp;Annonces&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;7.&nbsp;Fichiers</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02s07.html b/public/manual/fr/ch02s07.html
new file mode 100644
index 000000000..38f0a0400
--- /dev/null
+++ b/public/manual/fr/ch02s07.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>7.&nbsp;Fichiers</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="prev" href="ch02s06.html" title="6.&nbsp;Documents"><link rel="next" href="ch02s08.html" title="8.&nbsp;Configuration du projet"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7.&nbsp;Fichiers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s06.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projets</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s08.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e368"></a>7.&nbsp;Fichiers</h2></div></div></div><p>Ce module vous permet de publier les diff&eacute;rents fichiers (sources, binaires, ...) pour chaque version de l'application.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s06.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s08.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.&nbsp;Documents&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;8.&nbsp;Configuration du projet</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/ch02s08.html b/public/manual/fr/ch02s08.html
new file mode 100644
index 000000000..67d12305a
--- /dev/null
+++ b/public/manual/fr/ch02s08.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>8.&nbsp;Configuration du projet</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="up" href="ch02.html" title="Chapter&nbsp;2.&nbsp;Projets"><link rel="prev" href="ch02s07.html" title="7.&nbsp;Fichiers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.&nbsp;Configuration du projet</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s07.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;2.&nbsp;Projets</th><td width="20%" align="right">&nbsp;</td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e373"></a>8.&nbsp;Configuration du projet</h2></div></div></div><p></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e377"></a>8.1.&nbsp;Propri&eacute;t&eacute;s du projet</h3></div></div></div><p></p><div class="itemizedlist"><ul type="disc"><li><p><span class="guilabel">Public</span>: si le projet est public, il sera visible (consultation des demandes, des documents, ...) pour l'ensemble des utilisateurs, y compris ceux qui ne sont pas membres du projet. Si le projet n'est pas public, seuls les membres du projet y ont acc&egrave;s, en fonction de leur r&ocirc;le.</p></li><li><p><span class="guilabel">Champs personnalis&eacute;s</span>: s&eacute;lectionner les champs personnalis&eacute;s que vous souhaitez utiliser pour les demandes du projet. Seul l'administrateur peut d&eacute;finir de nouveaux champs personnalis&eacute;s.</p></li></ul></div><p></p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e393"></a>8.2.&nbsp;Membres</h3></div></div></div><p>Cet &eacute;cran vous permet de d&eacute;finir les membres du projet ainsi que leurs r&ocirc;les respectifs. Un utilisateur ne peut avoir qu'un r&ocirc;le au sein d'un projet donn&eacute;. Le r&ocirc;le d'un membre d&eacute;termine les permissions dont il b&eacute;n&eacute;ficie sur le projet.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e398"></a>8.3.&nbsp;Versions</h3></div></div></div><p>Les versions vous permettent de suivre les changements survenus tout au long du projet. A la fermeture d'une demande, vous pouvez par exemple indiquer quelle version la prend en compte. Vous pouvez par ailleurs publier les diff&eacute;rentes versions de l'application (voir Fichiers).</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e403"></a>8.4.&nbsp;Cat&eacute;gories des demandes</h3></div></div></div><p>Les cat&eacute;gories de demande vous permettent de typer les demandes. Les cat&eacute;gories peuvent par exemple correspondre aux diff&eacute;rents modules du projet.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s07.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right">&nbsp;</td></tr><tr><td width="40%" align="left" valign="top">7.&nbsp;Fichiers&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/html.css b/public/manual/fr/html.css
new file mode 100644
index 000000000..c1b2a6fca
--- /dev/null
+++ b/public/manual/fr/html.css
@@ -0,0 +1,55 @@
+body {
+ background: #FFFFFF;
+ font: 0.8em Verdana,Tahoma,Arial,sans-serif;
+}
+
+h1, h2, h3, h4, h5 {
+ color: #800000;
+ font-family: sans-serif;
+}
+
+table {
+ font-size: 1em;
+}
+
+a{
+color:#467aa7;
+font-weight:bold;
+text-decoration:none;
+background-color:inherit;
+}
+
+a:hover{
+ color: #800000;
+ text-decoration:underline;
+ background-color:inherit;
+}
+
+a img{border:none;}
+
+.screenshot {
+ text-align: center;
+}
+
+.guilabel {
+ font-weight: bold;
+}
+
+span.term {
+ font-weight: bold;
+}
+
+div.sidebar {
+ background: #F0F0F0;
+ border: 1px solid gray;
+ padding: 5px;
+ margin: 20px;
+}
+
+pre.programlisting {
+ background: #F0F0F0;
+ border: 1px solid gray;
+ padding: 2px;
+ font-size: 10pt;
+ white-space: pre;
+}
diff --git a/public/manual/fr/index.html b/public/manual/fr/index.html
new file mode 100644
index 000000000..8d69ced1a
--- /dev/null
+++ b/public/manual/fr/index.html
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Documentation redMine</title><link rel="stylesheet" href="html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.70.1"><link rel="start" href="index.html" title="Documentation redMine"><link rel="next" href="ch01.html" title="Chapter&nbsp;1.&nbsp;Administration"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Documentation redMine</th></tr><tr><td width="20%" align="left">&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Next</a></td></tr></table><hr></div><div class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="d0e1"></a>Documentation redMine</h1></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="ch01.html">1. Administration</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s01.html">1. Utilisateurs</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s01.html#d0e12">1.1. Liste des utilisateurs</a></span></dt><dt><span class="section"><a href="ch01s01.html#d0e26">1.2. Cr&eacute;ation ou modification d'un utilisateur</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s02.html">2. R&ocirc;les et permissions</a></span></dt><dt><span class="section"><a href="ch01s03.html">3. Trackers</a></span></dt><dt><span class="section"><a href="ch01s04.html">4. Champs personnalis&eacute;s</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s04.html#d0e132">4.1. Champs pour les projets</a></span></dt><dt><span class="section"><a href="ch01s04.html#d0e143">4.2. Champs pour les demandes</a></span></dt><dt><span class="section"><a href="ch01s04.html#d0e156">4.3. Champs pour les utilisateurs</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s05.html">5. Statut des demandes</a></span></dt><dt><span class="section"><a href="ch01s06.html">6. Workflow</a></span></dt><dt><span class="section"><a href="ch01s07.html">7. Listes de valeurs</a></span></dt><dt><span class="section"><a href="ch01s08.html">8. Notifications par mail</a></span></dt><dt><span class="section"><a href="ch01s09.html">9. Authentification</a></span></dt><dd><dl><dt><span class="section"><a href="ch01s09.html#d0e238">9.1. D&eacute;claration d'un annuaire LDAP</a></span></dt></dl></dd><dt><span class="section"><a href="ch01s10.html">10. Informations</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch02.html">2. Projets</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s01.html">1. Aper&ccedil;u du projet</a></span></dt><dt><span class="section"><a href="ch02s02.html">2. Gestion des demandes</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s02.html#d0e333">2.1. Liste des demandes</a></span></dt></dl></dd><dt><span class="section"><a href="ch02s03.html">3. Rapports</a></span></dt><dt><span class="section"><a href="ch02s04.html">4. Historique</a></span></dt><dt><span class="section"><a href="ch02s05.html">5. Annonces</a></span></dt><dt><span class="section"><a href="ch02s06.html">6. Documents</a></span></dt><dt><span class="section"><a href="ch02s07.html">7. Fichiers</a></span></dt><dt><span class="section"><a href="ch02s08.html">8. Configuration du projet</a></span></dt><dd><dl><dt><span class="section"><a href="ch02s08.html#d0e377">8.1. Propri&eacute;t&eacute;s du projet</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e393">8.2. Membres</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e398">8.3. Versions</a></span></dt><dt><span class="section"><a href="ch02s08.html#d0e403">8.4. Cat&eacute;gories des demandes</a></span></dt></dl></dd></dl></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left">&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;1.&nbsp;Administration</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/public/manual/fr/resources/issues_list.png b/public/manual/fr/resources/issues_list.png
new file mode 100644
index 000000000..47eab0fca
--- /dev/null
+++ b/public/manual/fr/resources/issues_list.png
Binary files differ
diff --git a/public/manual/fr/resources/users_list.png b/public/manual/fr/resources/users_list.png
new file mode 100644
index 000000000..0c9ef86ec
--- /dev/null
+++ b/public/manual/fr/resources/users_list.png
Binary files differ
diff --git a/public/manual/fr/resources/workflow.png b/public/manual/fr/resources/workflow.png
new file mode 100644
index 000000000..04e79d61e
--- /dev/null
+++ b/public/manual/fr/resources/workflow.png
Binary files differ
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 000000000..4ab9e89fe
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1 @@
+# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file \ No newline at end of file
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
new file mode 100644
index 000000000..13c1f6e34
--- /dev/null
+++ b/public/stylesheets/application.css
@@ -0,0 +1,484 @@
+/* andreas08 - an open source xhtml/css website layout by Andreas Viklund - http://andreasviklund.com . Free to use in any way and for any purpose as long as the proper credits are given to the original designer. Version: 1.0, November 28, 2005 */
+/* Edited by Jean-Philippe Lang *>
+/**************** Body and tag styles ****************/
+
+
+#header * {margin:0; padding:0;}
+p, ul, ol, li {margin:0; padding:0;}
+
+
+body{
+font:76% Verdana,Tahoma,Arial,sans-serif;
+line-height:1.4em;
+text-align:center;
+color:#303030;
+background:#e8eaec;
+margin:0;
+}
+
+
+a{
+color:#467aa7;
+font-weight:bold;
+text-decoration:none;
+background-color:inherit;
+}
+
+a:hover{color:#2a5a8a; text-decoration:none; background-color:inherit;}
+a img{border:none;}
+
+p{padding:0 0 1em 0;}
+p form{margin-top:0; margin-bottom:20px;}
+
+img.left,img.center,img.right{padding:4px; border:1px solid #a0a0a0;}
+img.left{float:left; margin:0 12px 5px 0;}
+img.center{display:block; margin:0 auto 5px auto;}
+img.right{float:right; margin:0 0 5px 12px;}
+
+/**************** Header and navigation styles ****************/
+
+#container{
+width:100%;
+min-width: 800px;
+margin:0;
+padding:0;
+text-align:left;
+background:#ffffff;
+color:#303030;
+}
+
+#header{
+height:4.5em;
+/*width:758px;*/
+margin:0;
+background:#467aa7;
+color:#ffffff;
+margin-bottom:1px;
+}
+
+#header h1{
+padding:10px 0 0 20px;
+font-size:2em;
+background-color:inherit;
+color:#fff; /*rgb(152, 26, 33);*/
+letter-spacing:-1px;
+font-weight:bold;
+font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
+}
+
+#header h2{
+margin:3px 0 0 40px;
+font-size:1.5em;
+background-color:inherit;
+color:#f0f2f4;
+letter-spacing:-1px;
+font-weight:normal;
+font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
+}
+
+#navigation{
+height:2.2em;
+line-height:2.2em;
+/*width:758px;*/
+margin:0;
+background:#578bb8;
+color:#ffffff;
+}
+
+#navigation li{
+float:left;
+list-style-type:none;
+border-right:1px solid #ffffff;
+white-space:nowrap;
+}
+
+#navigation li.right {
+ float:right;
+list-style-type:none;
+border-right:0;
+border-left:1px solid #ffffff;
+white-space:nowrap;
+}
+
+#navigation li a{
+display:block;
+padding:0px 10px 0px 22px;
+font-size:0.8em;
+font-weight:normal;
+/*text-transform:uppercase;*/
+text-decoration:none;
+background-color:inherit;
+color: #ffffff;
+}
+
+* html #navigation a {width:1%;}
+
+#navigation .selected,#navigation a:hover{
+color:#ffffff;
+text-decoration:none;
+background-color: #80b0da;
+}
+
+/**************** Icons links *******************/
+.picHome { background: url(../images/home.png) no-repeat 4px 50%; }
+.picUser { background: url(../images/user.png) no-repeat 4px 50%; }
+.picUserPage { background: url(../images/user_page.png) no-repeat 4px 50%; }
+.picAdmin { background: url(../images/admin.png) no-repeat 4px 50%; }
+.picProject { background: url(../images/projects.png) no-repeat 4px 50%; }
+.picLogout { background: url(../images/logout.png) no-repeat 4px 50%; }
+.picHelp { background: url(../images/help.png) no-repeat 4px 50%; }
+
+/**************** Content styles ****************/
+
+html>body #content {
+height: auto;
+min-height: 500px;
+}
+
+#content{
+/*float:right;*/
+/*width:530px;*/
+width: auto;
+height:500px;
+font-size:0.9em;
+padding:20px 10px 10px 20px;
+/*position: absolute;*/
+margin-left: 120px;
+border-left: 1px dashed #c0c0c0;
+
+}
+
+#content h2{
+display:block;
+margin:0 0 16px 0;
+font-size:1.7em;
+font-weight:normal;
+letter-spacing:-1px;
+color:#606060;
+background-color:inherit;
+font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
+}
+
+#content h2 a{font-weight:normal;}
+#content h3{margin:0 0 12px 0; font-size:1.4em;color:#707070;font-family: Trebuchet MS,Georgia,"Times New Roman",serif;}
+#content a:hover,#subcontent a:hover{text-decoration:underline;}
+#content ul,#content ol{margin:0 5px 16px 35px;}
+#content dl{margin:0 5px 10px 25px;}
+#content dt{font-weight:bold; margin-bottom:5px;}
+#content dd{margin:0 0 10px 15px;}
+
+
+/***********************************************/
+
+/*
+form{
+ padding:15px;
+ margin:0 0 20px 0;
+ border:1px solid #c0c0c0;
+ background-color:#CEE1ED;
+ width:600px;
+}
+*/
+
+form {
+ display: inline;
+}
+
+.noborder {
+ border:0px;
+ background-color:#fff;
+ width:100%;
+}
+
+textarea {
+ padding:0;
+ margin:0;
+}
+
+input {
+ vertical-align: middle;
+}
+
+input.button-small
+{
+ font-size: 0.8em;
+}
+
+select {
+ vertical-align: middle;
+}
+
+select.select-small
+{
+ border: 1px solid #7F9DB9;
+ padding: 1px;
+ font-size: 0.8em;
+}
+
+.active-filter
+{
+ background-color: #F9FA9E;
+
+}
+
+label {
+ font-weight: bold;
+ font-size: 1em;
+}
+
+fieldset {
+ border:1px solid #7F9DB9;
+ padding: 6px;
+}
+
+legend {
+ color: #505050;
+
+}
+
+.required {
+ color: #bb0000;
+}
+
+table.listTableContent {
+ border:1px solid #578bb8;
+ width:99%;
+ border-collapse: collapse;
+}
+
+table.listTableContent td {
+ padding:2px;
+}
+
+tr.ListHead {
+ background-color:#467aa7;
+ color:#FFFFFF;
+ text-align:center;
+}
+
+tr.ListHead a {
+ color:#FFFFFF;
+ text-decoration:underline;
+}
+
+.odd {
+ background-color:#f0f1f2;
+}
+.even {
+ background-color: #fff;
+}
+
+table.reportTableContent {
+ border:1px solid #c0c0c0;
+ width:99%;
+ border-collapse: collapse;
+}
+
+table.reportTableContent td {
+ padding:2px;
+}
+
+table.calenderTable {
+ border:1px solid #578bb8;
+ width:99%;
+ border-collapse: collapse;
+}
+
+table.calenderTable td {
+ border:1px solid #578bb8;
+}
+
+hr { border:none; border-bottom: dotted 1px #c0c0c0; }
+
+
+/**************** Sidebar styles ****************/
+
+#subcontent{
+position: absolute;
+left: 0px;
+width:110px;
+padding:20px 20px 10px 5px;
+}
+
+#subcontent h2{
+display:block;
+margin:0 0 5px 0;
+font-size:1.0em;
+font-weight:bold;
+text-align:left;
+color:#606060;
+background-color:inherit;
+font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
+}
+
+#subcontent p{margin:0 0 16px 0; font-size:0.9em;}
+
+/**************** Menublock styles ****************/
+
+.menublock{margin:0 0 20px 8px; font-size:0.8em;}
+.menublock li{list-style:none; display:block; padding:1px; margin-bottom:0px;}
+.menublock li a{font-weight:bold; text-decoration:none;}
+.menublock li a:hover{text-decoration:none;}
+.menublock li ul{margin:0; font-size:1em; font-weight:normal;}
+.menublock li ul li{margin-bottom:0;}
+.menublock li ul a{font-weight:normal;}
+
+/**************** Searchbar styles ****************/
+
+#searchbar{margin:0 0 20px 0;}
+#searchbar form fieldset{margin-left:10px; border:0 solid;}
+
+#searchbar #s{
+height:1.2em;
+width:110px;
+margin:0 5px 0 0;
+border:1px solid #a0a0a0;
+}
+
+#searchbar #searchbutton{
+width:auto;
+padding:0 1px;
+border:1px solid #808080;
+font-size:0.9em;
+text-align:center;
+}
+
+/**************** Footer styles ****************/
+
+#footer{
+clear:both;
+/*width:758px;*/
+padding:5px 0;
+margin:0;
+font-size:0.9em;
+color:#f0f0f0;
+background:#467aa7;
+}
+
+#footer p{padding:0; margin:0; text-align:center;}
+#footer a{color:#f0f0f0; background-color:inherit; font-weight:bold;}
+#footer a:hover{color:#ffffff; background-color:inherit; text-decoration: underline;}
+
+/**************** Misc classes and styles ****************/
+
+.splitcontentleft{float:left; width:49%;}
+.splitcontentright{float:right; width:49%;}
+.clear{clear:both;}
+.small{font-size:0.8em;line-height:1.4em;padding:0 0 0 0;}
+.hide{display:none;}
+.textcenter{text-align:center;}
+.textright{text-align:right;}
+.important{color:#f02025; background-color:inherit; font-weight:bold;}
+
+.box{
+margin:0 0 20px 0;
+padding:10px;
+border:1px solid #c0c0c0;
+background-color:#fafbfc;
+color:#505050;
+line-height:1.5em;
+}
+
+a.close-icon {
+display:block;
+margin-top:3px;
+overflow:hidden;
+width:12px;
+height:12px;
+background-repeat: no-repeat;
+cursor:hand;
+cursor:pointer;
+background-image:url('../images/close.png');
+}
+
+a.close-icon:hover {
+background-image:url('../images/close_hl.png');
+}
+
+.rightbox{
+background: #fafbfc;
+border: 1px solid #c0c0c0;
+float: right;
+padding: 8px;
+position: relative;
+margin: 0 5px 5px;
+}
+
+.layout-active {
+background: #ECF3E1;
+}
+
+.block-receiver {
+border:1px dashed #c0c0c0;
+margin-bottom: 20px;
+padding: 15px 0 15px 0;
+}
+
+.mypage-box {
+margin:0 0 20px 0;
+color:#505050;
+line-height:1.5em;
+}
+
+.blocks {
+cursor: move;
+}
+
+.topright{
+position: absolute;
+right: 25px;
+top: 100px;
+}
+
+.login {
+width: 50%;
+text-align: left;
+}
+
+img.calendar-trigger {
+ cursor: pointer;
+ vertical-align: middle;
+ margin-left: 4px;
+}
+
+#history h4 {
+ font-size: 1em;
+ margin-bottom: 12px;
+ margin-top: 20px;
+ font-weight: normal;
+ border-bottom: dotted 1px #c0c0c0;
+}
+
+#history p {
+ margin-left: 34px;
+}
+
+/***** CSS FORM ******/
+.tabular p{
+margin: 0;
+padding: 5px 0 8px 0;
+padding-left: 180px; /*width of left column containing the label elements*/
+height: 1%;
+}
+
+.tabular label{
+font-weight: bold;
+float: left;
+margin-left: -180px; /*width of left column*/
+width: 175px; /*width of labels. Should be smaller than left column to create some right
+margin*/
+}
+
+.error {
+color: #cc0000;
+}
+
+
+/*.threepxfix class below:
+Targets IE6- ONLY. Adds 3 pixel indent for multi-line form contents.
+to account for 3 pixel bug: http://www.positioniseverything.net/explorer/threepxtest.html
+*/
+
+* html .threepxfix{
+margin-left: 3px;
+} \ No newline at end of file
diff --git a/public/stylesheets/calendar.css b/public/stylesheets/calendar.css
new file mode 100644
index 000000000..f460d5cb0
--- /dev/null
+++ b/public/stylesheets/calendar.css
@@ -0,0 +1,231 @@
+/* The main calendar widget. DIV containing a table. */
+
+div.calendar { position: relative; }
+
+.calendar, .calendar table {
+ border: 1px solid #556;
+ font-size: 11px;
+ color: #000;
+ cursor: default;
+ background: #fafbfc;
+ font-family: tahoma,verdana,sans-serif;
+}
+
+/* Header part -- contains navigation buttons and day names. */
+
+.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */
+ text-align: center; /* They are the navigation buttons */
+ padding: 2px; /* Make the buttons seem like they're pressing */
+}
+
+.calendar .nav {
+ background: #467aa7 url(menuarrow.gif) no-repeat 100% 100%;
+}
+
+.calendar thead .title { /* This holds the current "month, year" */
+ font-weight: bold; /* Pressing it will take you to the current date */
+ text-align: center;
+ background: #fff;
+ color: #000;
+ padding: 2px;
+}
+
+.calendar thead .headrow { /* Row <TR> containing navigation buttons */
+ background: #467aa7;
+ color: #fff;
+}
+
+.calendar thead .daynames { /* Row <TR> containing the day names */
+ background: #bdf;
+}
+
+.calendar thead .name { /* Cells <TD> containing the day names */
+ border-bottom: 1px solid #556;
+ padding: 2px;
+ text-align: center;
+ color: #000;
+}
+
+.calendar thead .weekend { /* How a weekend day name shows in header */
+ color: #a66;
+}
+
+.calendar thead .hilite { /* How do the buttons in header appear when hover */
+ background-color: #80b0da;
+ color: #000;
+ padding: 1px;
+}
+
+.calendar thead .active { /* Active (pressed) buttons in header */
+ background-color: #77c;
+ padding: 2px 0px 0px 2px;
+}
+
+/* The body part -- contains all the days in month. */
+
+.calendar tbody .day { /* Cells <TD> containing month days dates */
+ width: 2em;
+ color: #456;
+ text-align: right;
+ padding: 2px 4px 2px 2px;
+}
+.calendar tbody .day.othermonth {
+ font-size: 80%;
+ color: #bbb;
+}
+.calendar tbody .day.othermonth.oweekend {
+ color: #fbb;
+}
+
+.calendar table .wn {
+ padding: 2px 3px 2px 2px;
+ border-right: 1px solid #000;
+ background: #bdf;
+}
+
+.calendar tbody .rowhilite td {
+ background: #def;
+}
+
+.calendar tbody .rowhilite td.wn {
+ background: #80b0da;
+}
+
+.calendar tbody td.hilite { /* Hovered cells <TD> */
+ background: #80b0da;
+ padding: 1px 3px 1px 1px;
+ border: 1px solid #bbb;
+}
+
+.calendar tbody td.active { /* Active (pressed) cells <TD> */
+ background: #cde;
+ padding: 2px 2px 0px 2px;
+}
+
+.calendar tbody td.selected { /* Cell showing today date */
+ font-weight: bold;
+ border: 1px solid #000;
+ padding: 1px 3px 1px 1px;
+ background: #fff;
+ color: #000;
+}
+
+.calendar tbody td.weekend { /* Cells showing weekend days */
+ color: #a66;
+}
+
+.calendar tbody td.today { /* Cell showing selected date */
+ font-weight: bold;
+ color: #f00;
+}
+
+.calendar tbody .disabled { color: #999; }
+
+.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */
+ visibility: hidden;
+}
+
+.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */
+ display: none;
+}
+
+/* The footer part -- status bar and "Close" button */
+
+.calendar tfoot .footrow { /* The <TR> in footer (only one right now) */
+ text-align: center;
+ background: #556;
+ color: #fff;
+}
+
+.calendar tfoot .ttip { /* Tooltip (status bar) cell <TD> */
+ background: #fff;
+ color: #445;
+ border-top: 1px solid #556;
+ padding: 1px;
+}
+
+.calendar tfoot .hilite { /* Hover style for buttons in footer */
+ background: #aaf;
+ border: 1px solid #04f;
+ color: #000;
+ padding: 1px;
+}
+
+.calendar tfoot .active { /* Active (pressed) style for buttons in footer */
+ background: #77c;
+ padding: 2px 0px 0px 2px;
+}
+
+/* Combo boxes (menus that display months/years for direct selection) */
+
+.calendar .combo {
+ position: absolute;
+ display: none;
+ top: 0px;
+ left: 0px;
+ width: 4em;
+ cursor: default;
+ border: 1px solid #655;
+ background: #def;
+ color: #000;
+ font-size: 90%;
+ z-index: 100;
+}
+
+.calendar .combo .label,
+.calendar .combo .label-IEfix {
+ text-align: center;
+ padding: 1px;
+}
+
+.calendar .combo .label-IEfix {
+ width: 4em;
+}
+
+.calendar .combo .hilite {
+ background: #acf;
+}
+
+.calendar .combo .active {
+ border-top: 1px solid #46a;
+ border-bottom: 1px solid #46a;
+ background: #eef;
+ font-weight: bold;
+}
+
+.calendar td.time {
+ border-top: 1px solid #000;
+ padding: 1px 0px;
+ text-align: center;
+ background-color: #f4f0e8;
+}
+
+.calendar td.time .hour,
+.calendar td.time .minute,
+.calendar td.time .ampm {
+ padding: 0px 3px 0px 4px;
+ border: 1px solid #889;
+ font-weight: bold;
+ background-color: #fff;
+}
+
+.calendar td.time .ampm {
+ text-align: center;
+}
+
+.calendar td.time .colon {
+ padding: 0px 2px 0px 3px;
+ font-weight: bold;
+}
+
+.calendar td.time span.hilite {
+ border-color: #000;
+ background-color: #667;
+ color: #fff;
+}
+
+.calendar td.time span.active {
+ border-color: #f00;
+ background-color: #000;
+ color: #0f0;
+}
diff --git a/public/stylesheets/jstoolbar.css b/public/stylesheets/jstoolbar.css
new file mode 100644
index 000000000..efdf3d264
--- /dev/null
+++ b/public/stylesheets/jstoolbar.css
@@ -0,0 +1,79 @@
+.jstEditor {
+ padding-left: 0px;
+}
+.jstEditor textarea, .jstEditor iframe {
+ margin: 0;
+ border: 1;
+}
+
+.jstHandle {
+ height: 16px;
+ font-size: 0.1em;
+ cursor: s-resize;
+ background: transparent url(img/resizer.png) no-repeat 45% 50%;
+}
+
+.jstElements {
+ padding: 3px 3px;
+}
+
+.jstElements button {
+ margin-right : 6px;
+ width : 24px;
+ height: 24px;
+ padding: 4px;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #ddd;
+ background-color : #f7f7f7;
+ background-position : 50% 50%;
+ background-repeat: no-repeat;
+}
+.jstElements button:hover {
+ border-color : #000;
+}
+.jstElements button span {
+ display : none;
+}
+.jstElements span {
+ display : inline;
+}
+
+.jstSpacer {
+ width : 0px;
+ font-size: 1px;
+ margin-right: 4px;
+}
+
+/* Buttons
+-------------------------------------------------------- */
+.jstb_strong {
+ background-image: url(../images/jstoolbar/bt_strong.png);
+}
+.jstb_em {
+ background-image: url(../images/jstoolbar/bt_em.png);
+}
+.jstb_ins {
+ background-image: url(../images/jstoolbar/bt_ins.png);
+}
+.jstb_del {
+ background-image: url(../images/jstoolbar/bt_del.png);
+}
+.jstb_quote {
+ background-image: url(../images/jstoolbar/bt_quote.png);
+}
+.jstb_code {
+ background-image: url(../images/jstoolbar/bt_code.png);
+}
+.jstb_br {
+ background-image: url(../images/jstoolbar/bt_br.png);
+}
+.jstb_ul {
+ background-image: url(../images/jstoolbar/bt_ul.png);
+}
+.jstb_ol {
+ background-image: url(../images/jstoolbar/bt_ol.png);
+}
+.jstb_link {
+ background-image: url(../images/jstoolbar/bt_link.png);
+}
diff --git a/public/stylesheets/menu.css b/public/stylesheets/menu.css
new file mode 100644
index 000000000..b7084c2e7
--- /dev/null
+++ b/public/stylesheets/menu.css
@@ -0,0 +1,39 @@
+/*========== Drop down menu ==============*/
+div.menu {
+ background-color: #FFFFFF;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #7F9DB9;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ padding: 0;
+ visibility: hidden;
+ z-index: 101;
+}
+
+div.menu a.menuItem {
+ font-size: 10px;
+ font-weight: normal;
+ line-height: 2em;
+ color: #000000;
+ background-color: #FFFFFF;
+ cursor: default;
+ display: block;
+ padding: 0 1em;
+ margin: 0;
+ border: 0;
+ text-decoration: none;
+ white-space: nowrap;
+}
+
+div.menu a.menuItem:hover, div.menu a.menuItemHighlight {
+ background-color: #80b0da;
+ color: #ffffff;
+}
+
+div.menu a.menuItem span.menuItemText {}
+
+div.menu a.menuItem span.menuItemArrow {
+ margin-right: -.75em;
+}
diff --git a/public/stylesheets/rails.css b/public/stylesheets/rails.css
new file mode 100644
index 000000000..3f7b6ca41
--- /dev/null
+++ b/public/stylesheets/rails.css
@@ -0,0 +1,57 @@
+
+.fieldWithErrors {
+ padding: 2px;
+ margin: 0px;
+ background-color: red;
+ display: table;
+}
+
+#errorExplanation {
+ width: 400px;
+ border: 0;
+ padding: 7px;
+ padding-bottom: 3px;
+ margin-bottom: 0px;
+ /*background-color: #f0f0f0;*/
+}
+
+#errorExplanation h2 {
+ text-align: left;
+ font-weight: bold;
+ padding: 5px 5px 10px 26px;
+ font-size: 1em;
+ margin: -7px;
+ background: url(../images/alert.png) no-repeat 6px 6px;
+}
+
+#errorExplanation p {
+ color: #333;
+ margin-bottom: 0;
+ padding: 5px;
+}
+
+#errorExplanation ul li {
+ font-size: 1em;
+ list-style: none;
+ margin-left: -16px;
+}
+
+div.uploadStatus {
+ margin: 5px;
+}
+
+div.progressBar {
+ margin: 5px;
+}
+
+div.progressBar div.border {
+ background-color: #fff;
+ border: 1px solid grey;
+ width: 100%;
+}
+
+div.progressBar div.background {
+ background-color: #333;
+ height: 18px;
+ width: 0%;
+}