From 96f83cc8f0f032554f771a59da22303cd473b878 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Tue, 5 Dec 2006 20:45:04 +0000 Subject: trunk moved from /trunk/redmine to /trunk git-svn-id: http://redmine.rubyforge.org/svn/trunk@67 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- Rakefile | 10 + app/controllers/account_controller.rb | 131 ++ app/controllers/admin_controller.rb | 56 + app/controllers/application.rb | 126 ++ app/controllers/auth_sources_controller.rb | 83 + app/controllers/custom_fields_controller.rb | 71 + app/controllers/documents_controller.rb | 68 + app/controllers/enumerations_controller.rb | 70 + app/controllers/help_controller.rb | 47 + app/controllers/issue_categories_controller.rb | 42 + app/controllers/issue_statuses_controller.rb | 69 + app/controllers/issues_controller.rb | 145 ++ app/controllers/members_controller.rb | 41 + app/controllers/my_controller.rb | 131 ++ app/controllers/news_controller.rb | 42 + app/controllers/projects_controller.rb | 469 +++++ app/controllers/reports_controller.rb | 164 ++ app/controllers/roles_controller.rb | 84 + app/controllers/trackers_controller.rb | 61 + app/controllers/users_controller.rb | 92 + app/controllers/versions_controller.rb | 57 + app/controllers/welcome_controller.rb | 25 + app/helpers/account_helper.rb | 19 + app/helpers/admin_helper.rb | 19 + app/helpers/application_helper.rb | 179 ++ app/helpers/auth_sources_helper.rb | 19 + app/helpers/custom_fields_helper.rb | 77 + app/helpers/documents_helper.rb | 19 + app/helpers/enumerations_helper.rb | 19 + app/helpers/help_helper.rb | 19 + app/helpers/ifpdf_helper.rb | 48 + app/helpers/issue_categories_helper.rb | 19 + app/helpers/issue_statuses_helper.rb | 19 + app/helpers/issues_helper.rb | 74 + app/helpers/members_helper.rb | 19 + app/helpers/my_helper.rb | 19 + app/helpers/news_helper.rb | 19 + app/helpers/projects_helper.rb | 19 + app/helpers/reports_helper.rb | 32 + app/helpers/roles_helper.rb | 19 + app/helpers/search_filter_helper.rb | 106 ++ app/helpers/sort_helper.rb | 160 ++ app/helpers/trackers_helper.rb | 19 + app/helpers/users_helper.rb | 19 + app/helpers/versions_helper.rb | 19 + app/helpers/welcome_helper.rb | 19 + app/models/attachment.rb | 81 + app/models/auth_source.rb | 47 + app/models/auth_source_ldap.rb | 79 + app/models/custom_field.rb | 42 + app/models/custom_value.rb | 38 + app/models/document.rb | 24 + app/models/enumeration.rb | 46 + app/models/issue.rb | 103 ++ app/models/issue_category.rb | 29 + app/models/issue_custom_field.rb | 27 + app/models/issue_history.rb | 24 + app/models/issue_status.rb | 49 + app/models/journal.rb | 22 + app/models/journal_detail.rb | 20 + app/models/mailer.rb | 53 + app/models/member.rb | 29 + app/models/news.rb | 28 + app/models/permission.rb | 63 + app/models/project.rb | 57 + app/models/project_custom_field.rb | 22 + app/models/role.rb | 31 + app/models/token.rb | 44 + app/models/tracker.rb | 31 + app/models/user.rb | 129 ++ app/models/user_custom_field.rb | 23 + app/models/user_preference.rb | 44 + app/models/version.rb | 32 + app/models/workflow.rb | 24 + app/views/account/login.rhtml | 18 + app/views/account/lost_password.rhtml | 14 + app/views/account/password_recovery.rhtml | 21 + app/views/account/register.rhtml | 39 + app/views/account/show.rhtml | 26 + app/views/admin/index.rhtml | 50 + app/views/admin/info.rhtml | 10 + app/views/admin/mail_options.rhtml | 24 + app/views/admin/projects.rhtml | 30 + app/views/auth_sources/_form.rhtml | 45 + app/views/auth_sources/edit.rhtml | 7 + app/views/auth_sources/list.rhtml | 30 + app/views/auth_sources/new.rhtml | 6 + app/views/custom_fields/_form.rhtml | 52 + app/views/custom_fields/edit.rhtml | 6 + app/views/custom_fields/list.rhtml | 36 + app/views/custom_fields/new.rhtml | 8 + app/views/documents/_form.rhtml | 29 + app/views/documents/edit.rhtml | 8 + app/views/documents/show.rhtml | 48 + app/views/enumerations/_form.rhtml | 9 + app/views/enumerations/edit.rhtml | 10 + app/views/enumerations/list.rhtml | 21 + app/views/enumerations/new.rhtml | 6 + app/views/issue_categories/_form.rhtml | 7 + app/views/issue_categories/edit.rhtml | 6 + app/views/issue_statuses/_form.rhtml | 18 + app/views/issue_statuses/edit.rhtml | 6 + app/views/issue_statuses/list.rhtml | 28 + app/views/issue_statuses/new.rhtml | 6 + app/views/issues/_history.rhtml | 11 + app/views/issues/_list_simple.rhtml | 28 + app/views/issues/_pdf.rfpdf | 100 ++ app/views/issues/change_status.rhtml | 37 + app/views/issues/edit.rhtml | 49 + app/views/issues/export_pdf.rfpdf | 9 + app/views/issues/history.rhtml | 6 + app/views/issues/show.rhtml | 133 ++ app/views/layouts/base.rhtml | 142 ++ app/views/mailer/_issue.rhtml | 7 + app/views/mailer/issue_add_de.rhtml | 3 + app/views/mailer/issue_add_en.rhtml | 3 + app/views/mailer/issue_add_es.rhtml | 3 + app/views/mailer/issue_add_fr.rhtml | 3 + app/views/mailer/issue_edit_de.rhtml | 8 + app/views/mailer/issue_edit_en.rhtml | 8 + app/views/mailer/issue_edit_es.rhtml | 8 + app/views/mailer/issue_edit_fr.rhtml | 8 + app/views/mailer/lost_password_de.rhtml | 3 + app/views/mailer/lost_password_en.rhtml | 3 + app/views/mailer/lost_password_es.rhtml | 3 + app/views/mailer/lost_password_fr.rhtml | 3 + app/views/mailer/register_de.rhtml | 3 + app/views/mailer/register_en.rhtml | 3 + app/views/mailer/register_es.rhtml | 3 + app/views/mailer/register_fr.rhtml | 3 + app/views/my/_block.rhtml | 16 + app/views/my/account.rhtml | 47 + app/views/my/blocks/_calendar.rhtml | 45 + app/views/my/blocks/_documents.rhtml | 15 + app/views/my/blocks/_issues_assigned_to_me.rhtml | 10 + app/views/my/blocks/_issues_reported_by_me.rhtml | 10 + app/views/my/blocks/_latest_news.rhtml | 13 + app/views/my/page.rhtml | 30 + app/views/my/page_layout.rhtml | 121 ++ app/views/news/_form.rhtml | 20 + app/views/news/edit.rhtml | 6 + app/views/news/show.rhtml | 16 + app/views/projects/_form.rhtml | 26 + app/views/projects/activity.rhtml | 41 + app/views/projects/add.rhtml | 6 + app/views/projects/add_document.rhtml | 14 + app/views/projects/add_file.rhtml | 14 + app/views/projects/add_issue.rhtml | 50 + app/views/projects/add_news.rhtml | 6 + app/views/projects/add_version.rhtml | 6 + app/views/projects/calendar.rhtml | 75 + app/views/projects/changelog.rhtml | 28 + app/views/projects/destroy.rhtml | 14 + app/views/projects/export_issues_pdf.rfpdf | 11 + app/views/projects/gantt.rfpdf | 168 ++ app/views/projects/gantt.rhtml | 241 +++ app/views/projects/list.rhtml | 20 + app/views/projects/list_documents.rhtml | 23 + app/views/projects/list_files.rhtml | 46 + app/views/projects/list_issues.rhtml | 76 + app/views/projects/list_members.rhtml | 11 + app/views/projects/list_news.rhtml | 18 + app/views/projects/move_issues.rhtml | 24 + app/views/projects/settings.rhtml | 118 ++ app/views/projects/show.rhtml | 72 + app/views/reports/_details.rhtml | 47 + app/views/reports/_simple.rhtml | 36 + app/views/reports/issue_report.rhtml | 20 + app/views/reports/issue_report_details.rhtml | 7 + app/views/roles/_form.rhtml | 20 + app/views/roles/edit.rhtml | 6 + app/views/roles/list.rhtml | 21 + app/views/roles/new.rhtml | 6 + app/views/roles/workflow.rhtml | 71 + app/views/trackers/_form.rhtml | 7 + app/views/trackers/edit.rhtml | 6 + app/views/trackers/list.rhtml | 22 + app/views/trackers/new.rhtml | 6 + app/views/users/_form.rhtml | 30 + app/views/users/add.rhtml | 6 + app/views/users/edit.rhtml | 6 + app/views/users/list.rhtml | 46 + app/views/versions/_form.rhtml | 9 + app/views/versions/edit.rhtml | 7 + app/views/welcome/index.rhtml | 30 + config/boot.rb | 19 + config/config_custom.example.rb | 65 + config/database.yml | 69 + config/environment.rb | 140 ++ config/environments/demo.rb | 21 + config/environments/development.rb | 19 + config/environments/development_oracle.rb | 19 + config/environments/development_pgsql.rb | 19 + config/environments/development_sqlserver.rb | 19 + config/environments/production.rb | 20 + config/environments/test.rb | 16 + config/environments/test_oracle.rb | 16 + config/environments/test_pgsql.rb | 16 + config/environments/test_sqlserver.rb | 16 + config/help.yml | 63 + config/routes.rb | 24 + db/migrate/001_setup.rb | 317 ++++ db/migrate/002_issue_move.rb | 9 + db/migrate/003_issue_add_note.rb | 9 + db/migrate/004_export_pdf.rb | 11 + db/migrate/005_issue_start_date.rb | 11 + db/migrate/006_calendar_and_activity.rb | 13 + db/migrate/007_create_journals.rb | 54 + db/migrate/008_create_user_preferences.rb | 12 + db/migrate/009_add_hide_mail_pref.rb | 9 + doc/CHANGELOG | 96 ++ doc/COPYING | 339 ++++ doc/INSTALL | 74 + doc/README | 58 + doc/docbook/en/redmine-userdoc-en.xml | 429 +++++ doc/docbook/fr/redmine-userdoc-fr.xml | 553 ++++++ files/delete.me | 1 + lang/de.yml | 320 ++++ lang/en.yml | 320 ++++ lang/es.yml | 320 ++++ lang/fr.yml | 321 ++++ lib/tasks/extract_fixtures.rake | 24 + lib/tasks/load_default_data.rake | 88 + log/delete.me | 1 + public/.htaccess | 40 + public/404.html | 23 + public/500.html | 24 + public/dispatch.cgi | 10 + public/dispatch.fcgi | 24 + public/dispatch.rb | 10 + public/favicon.ico | 0 public/images/add.png | Bin 0 -> 336 bytes public/images/admin.png | Bin 0 -> 716 bytes public/images/alert.png | Bin 0 -> 483 bytes public/images/arrow_bw.png | Bin 0 -> 997 bytes public/images/arrow_from.png | Bin 0 -> 994 bytes public/images/arrow_to.png | Bin 0 -> 991 bytes public/images/attachment.png | Bin 0 -> 259 bytes public/images/bulletgreen.png | Bin 0 -> 193 bytes public/images/bulletred.png | Bin 0 -> 193 bytes public/images/calendar.png | Bin 0 -> 196 bytes public/images/close.png | Bin 0 -> 200 bytes public/images/close_hl.png | Bin 0 -> 199 bytes public/images/delete.png | Bin 0 -> 320 bytes public/images/details.png | Bin 0 -> 224 bytes public/images/dir.png | Bin 0 -> 314 bytes public/images/dir_new.png | Bin 0 -> 321 bytes public/images/dir_open.png | Bin 0 -> 1030 bytes public/images/document.png | Bin 0 -> 1014 bytes public/images/edit_small.png | Bin 0 -> 238 bytes public/images/file_new.png | Bin 0 -> 253 bytes public/images/gantt.png | Bin 0 -> 218 bytes public/images/help.png | Bin 0 -> 1079 bytes public/images/home.png | Bin 0 -> 301 bytes public/images/issues.png | Bin 0 -> 356 bytes public/images/jstoolbar/bt_br.png | Bin 0 -> 244 bytes public/images/jstoolbar/bt_code.png | Bin 0 -> 338 bytes public/images/jstoolbar/bt_del.png | Bin 0 -> 368 bytes public/images/jstoolbar/bt_em.png | Bin 0 -> 311 bytes public/images/jstoolbar/bt_ins.png | Bin 0 -> 322 bytes public/images/jstoolbar/bt_link.png | Bin 0 -> 900 bytes public/images/jstoolbar/bt_ol.png | Bin 0 -> 249 bytes public/images/jstoolbar/bt_quote.png | Bin 0 -> 323 bytes public/images/jstoolbar/bt_strong.png | Bin 0 -> 355 bytes public/images/jstoolbar/bt_ul.png | Bin 0 -> 239 bytes public/images/loading.gif | Bin 0 -> 1553 bytes public/images/locked.png | Bin 0 -> 437 bytes public/images/login.png | Bin 0 -> 1082 bytes public/images/mailer.png | Bin 0 -> 294 bytes public/images/notes.png | Bin 0 -> 996 bytes public/images/options.png | Bin 0 -> 1005 bytes public/images/package.png | Bin 0 -> 298 bytes public/images/projects.png | Bin 0 -> 299 bytes public/images/rails.png | Bin 0 -> 1787 bytes public/images/rails_powered.png | Bin 0 -> 262 bytes public/images/rails_small.png | Bin 0 -> 1140 bytes public/images/role.png | Bin 0 -> 293 bytes public/images/rss.png | Bin 0 -> 256 bytes public/images/sort_asc.png | Bin 0 -> 215 bytes public/images/sort_desc.png | Bin 0 -> 217 bytes public/images/tracker.png | Bin 0 -> 356 bytes public/images/true.png | Bin 0 -> 183 bytes public/images/user.png | Bin 0 -> 236 bytes public/images/user_new.png | Bin 0 -> 215 bytes public/images/user_page.png | Bin 0 -> 292 bytes public/images/users.png | Bin 0 -> 242 bytes public/images/workflow.png | Bin 0 -> 285 bytes public/images/zoom_in.png | Bin 0 -> 593 bytes public/images/zoom_in_g.png | Bin 0 -> 312 bytes public/images/zoom_out.png | Bin 0 -> 588 bytes public/images/zoom_out_g.png | Bin 0 -> 311 bytes public/javascripts/application.js | 20 + public/javascripts/calendar/calendar-setup.js | 200 +++ public/javascripts/calendar/calendar.js | 1806 ++++++++++++++++++++ public/javascripts/calendar/lang/calendar-de.js | 128 ++ public/javascripts/calendar/lang/calendar-en.js | 127 ++ public/javascripts/calendar/lang/calendar-es.js | 129 ++ public/javascripts/calendar/lang/calendar-fr.js | 129 ++ public/javascripts/controls.js | 750 ++++++++ public/javascripts/dragdrop.js | 584 +++++++ public/javascripts/effects.js | 854 +++++++++ public/javascripts/jstoolbar.js | 440 +++++ public/javascripts/menu.js | 556 ++++++ public/javascripts/prototype.js | 1785 +++++++++++++++++++ public/manual/en/ch01.html | 3 + public/manual/en/ch01s01.html | 3 + public/manual/en/ch01s02.html | 3 + public/manual/en/ch01s03.html | 3 + public/manual/en/ch01s04.html | 3 + public/manual/en/ch01s05.html | 3 + public/manual/en/ch01s06.html | 3 + public/manual/en/ch01s07.html | 3 + public/manual/en/ch01s08.html | 3 + public/manual/en/ch01s09.html | 3 + public/manual/en/ch01s10.html | 3 + public/manual/en/ch02.html | 3 + public/manual/en/ch02s01.html | 3 + public/manual/en/ch02s02.html | 3 + public/manual/en/ch02s03.html | 3 + public/manual/en/ch02s04.html | 3 + public/manual/en/ch02s05.html | 3 + public/manual/en/ch02s06.html | 3 + public/manual/en/ch02s07.html | 3 + public/manual/en/ch02s08.html | 3 + public/manual/en/html.css | 55 + public/manual/en/index.html | 3 + public/manual/en/resources/issues_list.png | Bin 0 -> 8233 bytes public/manual/en/resources/users_list.png | Bin 0 -> 6502 bytes public/manual/en/resources/workflow.png | Bin 0 -> 6503 bytes public/manual/fr/ch01.html | 3 + public/manual/fr/ch01s01.html | 3 + public/manual/fr/ch01s02.html | 3 + public/manual/fr/ch01s03.html | 3 + public/manual/fr/ch01s04.html | 3 + public/manual/fr/ch01s05.html | 3 + public/manual/fr/ch01s06.html | 3 + public/manual/fr/ch01s07.html | 3 + public/manual/fr/ch01s08.html | 3 + public/manual/fr/ch01s09.html | 3 + public/manual/fr/ch01s10.html | 3 + public/manual/fr/ch02.html | 3 + public/manual/fr/ch02s01.html | 3 + public/manual/fr/ch02s02.html | 3 + public/manual/fr/ch02s03.html | 3 + public/manual/fr/ch02s04.html | 3 + public/manual/fr/ch02s05.html | 3 + public/manual/fr/ch02s06.html | 3 + public/manual/fr/ch02s07.html | 3 + public/manual/fr/ch02s08.html | 3 + public/manual/fr/html.css | 55 + public/manual/fr/index.html | 3 + public/manual/fr/resources/issues_list.png | Bin 0 -> 8233 bytes public/manual/fr/resources/users_list.png | Bin 0 -> 6502 bytes public/manual/fr/resources/workflow.png | Bin 0 -> 6503 bytes public/robots.txt | 1 + public/stylesheets/application.css | 484 ++++++ public/stylesheets/calendar.css | 231 +++ public/stylesheets/jstoolbar.css | 79 + public/stylesheets/menu.css | 39 + public/stylesheets/rails.css | 57 + redmine/Rakefile | 10 - redmine/app/controllers/account_controller.rb | 131 -- redmine/app/controllers/admin_controller.rb | 56 - redmine/app/controllers/application.rb | 126 -- redmine/app/controllers/auth_sources_controller.rb | 83 - .../app/controllers/custom_fields_controller.rb | 71 - redmine/app/controllers/documents_controller.rb | 68 - redmine/app/controllers/enumerations_controller.rb | 70 - redmine/app/controllers/help_controller.rb | 47 - .../app/controllers/issue_categories_controller.rb | 42 - .../app/controllers/issue_statuses_controller.rb | 69 - redmine/app/controllers/issues_controller.rb | 145 -- redmine/app/controllers/members_controller.rb | 41 - redmine/app/controllers/my_controller.rb | 131 -- redmine/app/controllers/news_controller.rb | 42 - redmine/app/controllers/projects_controller.rb | 469 ----- redmine/app/controllers/reports_controller.rb | 164 -- redmine/app/controllers/roles_controller.rb | 84 - redmine/app/controllers/trackers_controller.rb | 61 - redmine/app/controllers/users_controller.rb | 92 - redmine/app/controllers/versions_controller.rb | 57 - redmine/app/controllers/welcome_controller.rb | 25 - redmine/app/helpers/account_helper.rb | 19 - redmine/app/helpers/admin_helper.rb | 19 - redmine/app/helpers/application_helper.rb | 179 -- redmine/app/helpers/auth_sources_helper.rb | 19 - redmine/app/helpers/custom_fields_helper.rb | 77 - redmine/app/helpers/documents_helper.rb | 19 - redmine/app/helpers/enumerations_helper.rb | 19 - redmine/app/helpers/help_helper.rb | 19 - redmine/app/helpers/ifpdf_helper.rb | 48 - redmine/app/helpers/issue_categories_helper.rb | 19 - redmine/app/helpers/issue_statuses_helper.rb | 19 - redmine/app/helpers/issues_helper.rb | 74 - redmine/app/helpers/members_helper.rb | 19 - redmine/app/helpers/my_helper.rb | 19 - redmine/app/helpers/news_helper.rb | 19 - redmine/app/helpers/projects_helper.rb | 19 - redmine/app/helpers/reports_helper.rb | 32 - redmine/app/helpers/roles_helper.rb | 19 - redmine/app/helpers/search_filter_helper.rb | 106 -- redmine/app/helpers/sort_helper.rb | 160 -- redmine/app/helpers/trackers_helper.rb | 19 - redmine/app/helpers/users_helper.rb | 19 - redmine/app/helpers/versions_helper.rb | 19 - redmine/app/helpers/welcome_helper.rb | 19 - redmine/app/models/attachment.rb | 81 - redmine/app/models/auth_source.rb | 47 - redmine/app/models/auth_source_ldap.rb | 79 - redmine/app/models/custom_field.rb | 42 - redmine/app/models/custom_value.rb | 38 - redmine/app/models/document.rb | 24 - redmine/app/models/enumeration.rb | 46 - redmine/app/models/issue.rb | 103 -- redmine/app/models/issue_category.rb | 29 - redmine/app/models/issue_custom_field.rb | 27 - redmine/app/models/issue_history.rb | 24 - redmine/app/models/issue_status.rb | 49 - redmine/app/models/journal.rb | 22 - redmine/app/models/journal_detail.rb | 20 - redmine/app/models/mailer.rb | 53 - redmine/app/models/member.rb | 29 - redmine/app/models/news.rb | 28 - redmine/app/models/permission.rb | 63 - redmine/app/models/project.rb | 57 - redmine/app/models/project_custom_field.rb | 22 - redmine/app/models/role.rb | 31 - redmine/app/models/token.rb | 44 - redmine/app/models/tracker.rb | 31 - redmine/app/models/user.rb | 129 -- redmine/app/models/user_custom_field.rb | 23 - redmine/app/models/user_preference.rb | 44 - redmine/app/models/version.rb | 32 - redmine/app/models/workflow.rb | 24 - redmine/app/views/account/login.rhtml | 18 - redmine/app/views/account/lost_password.rhtml | 14 - redmine/app/views/account/password_recovery.rhtml | 21 - redmine/app/views/account/register.rhtml | 39 - redmine/app/views/account/show.rhtml | 26 - redmine/app/views/admin/index.rhtml | 50 - redmine/app/views/admin/info.rhtml | 10 - redmine/app/views/admin/mail_options.rhtml | 24 - redmine/app/views/admin/projects.rhtml | 30 - redmine/app/views/auth_sources/_form.rhtml | 45 - redmine/app/views/auth_sources/edit.rhtml | 7 - redmine/app/views/auth_sources/list.rhtml | 30 - redmine/app/views/auth_sources/new.rhtml | 6 - redmine/app/views/custom_fields/_form.rhtml | 52 - redmine/app/views/custom_fields/edit.rhtml | 6 - redmine/app/views/custom_fields/list.rhtml | 36 - redmine/app/views/custom_fields/new.rhtml | 8 - redmine/app/views/documents/_form.rhtml | 29 - redmine/app/views/documents/edit.rhtml | 8 - redmine/app/views/documents/show.rhtml | 48 - redmine/app/views/enumerations/_form.rhtml | 9 - redmine/app/views/enumerations/edit.rhtml | 10 - redmine/app/views/enumerations/list.rhtml | 21 - redmine/app/views/enumerations/new.rhtml | 6 - redmine/app/views/issue_categories/_form.rhtml | 7 - redmine/app/views/issue_categories/edit.rhtml | 6 - redmine/app/views/issue_statuses/_form.rhtml | 18 - redmine/app/views/issue_statuses/edit.rhtml | 6 - redmine/app/views/issue_statuses/list.rhtml | 28 - redmine/app/views/issue_statuses/new.rhtml | 6 - redmine/app/views/issues/_history.rhtml | 11 - redmine/app/views/issues/_list_simple.rhtml | 28 - redmine/app/views/issues/_pdf.rfpdf | 100 -- redmine/app/views/issues/change_status.rhtml | 37 - redmine/app/views/issues/edit.rhtml | 49 - redmine/app/views/issues/export_pdf.rfpdf | 9 - redmine/app/views/issues/history.rhtml | 6 - redmine/app/views/issues/show.rhtml | 133 -- redmine/app/views/layouts/base.rhtml | 142 -- redmine/app/views/mailer/_issue.rhtml | 7 - redmine/app/views/mailer/issue_add_de.rhtml | 3 - redmine/app/views/mailer/issue_add_en.rhtml | 3 - redmine/app/views/mailer/issue_add_es.rhtml | 3 - redmine/app/views/mailer/issue_add_fr.rhtml | 3 - redmine/app/views/mailer/issue_edit_de.rhtml | 8 - redmine/app/views/mailer/issue_edit_en.rhtml | 8 - redmine/app/views/mailer/issue_edit_es.rhtml | 8 - redmine/app/views/mailer/issue_edit_fr.rhtml | 8 - redmine/app/views/mailer/lost_password_de.rhtml | 3 - redmine/app/views/mailer/lost_password_en.rhtml | 3 - redmine/app/views/mailer/lost_password_es.rhtml | 3 - redmine/app/views/mailer/lost_password_fr.rhtml | 3 - redmine/app/views/mailer/register_de.rhtml | 3 - redmine/app/views/mailer/register_en.rhtml | 3 - redmine/app/views/mailer/register_es.rhtml | 3 - redmine/app/views/mailer/register_fr.rhtml | 3 - redmine/app/views/my/_block.rhtml | 16 - redmine/app/views/my/account.rhtml | 47 - redmine/app/views/my/blocks/_calendar.rhtml | 45 - redmine/app/views/my/blocks/_documents.rhtml | 15 - .../views/my/blocks/_issues_assigned_to_me.rhtml | 10 - .../views/my/blocks/_issues_reported_by_me.rhtml | 10 - redmine/app/views/my/blocks/_latest_news.rhtml | 13 - redmine/app/views/my/page.rhtml | 30 - redmine/app/views/my/page_layout.rhtml | 121 -- redmine/app/views/news/_form.rhtml | 20 - redmine/app/views/news/edit.rhtml | 6 - redmine/app/views/news/show.rhtml | 16 - redmine/app/views/projects/_form.rhtml | 26 - redmine/app/views/projects/activity.rhtml | 41 - redmine/app/views/projects/add.rhtml | 6 - redmine/app/views/projects/add_document.rhtml | 14 - redmine/app/views/projects/add_file.rhtml | 14 - redmine/app/views/projects/add_issue.rhtml | 50 - redmine/app/views/projects/add_news.rhtml | 6 - redmine/app/views/projects/add_version.rhtml | 6 - redmine/app/views/projects/calendar.rhtml | 75 - redmine/app/views/projects/changelog.rhtml | 28 - redmine/app/views/projects/destroy.rhtml | 14 - redmine/app/views/projects/export_issues_pdf.rfpdf | 11 - redmine/app/views/projects/gantt.rfpdf | 168 -- redmine/app/views/projects/gantt.rhtml | 241 --- redmine/app/views/projects/list.rhtml | 20 - redmine/app/views/projects/list_documents.rhtml | 23 - redmine/app/views/projects/list_files.rhtml | 46 - redmine/app/views/projects/list_issues.rhtml | 76 - redmine/app/views/projects/list_members.rhtml | 11 - redmine/app/views/projects/list_news.rhtml | 18 - redmine/app/views/projects/move_issues.rhtml | 24 - redmine/app/views/projects/settings.rhtml | 118 -- redmine/app/views/projects/show.rhtml | 72 - redmine/app/views/reports/_details.rhtml | 47 - redmine/app/views/reports/_simple.rhtml | 36 - redmine/app/views/reports/issue_report.rhtml | 20 - .../app/views/reports/issue_report_details.rhtml | 7 - redmine/app/views/roles/_form.rhtml | 20 - redmine/app/views/roles/edit.rhtml | 6 - redmine/app/views/roles/list.rhtml | 21 - redmine/app/views/roles/new.rhtml | 6 - redmine/app/views/roles/workflow.rhtml | 71 - redmine/app/views/trackers/_form.rhtml | 7 - redmine/app/views/trackers/edit.rhtml | 6 - redmine/app/views/trackers/list.rhtml | 22 - redmine/app/views/trackers/new.rhtml | 6 - redmine/app/views/users/_form.rhtml | 30 - redmine/app/views/users/add.rhtml | 6 - redmine/app/views/users/edit.rhtml | 6 - redmine/app/views/users/list.rhtml | 46 - redmine/app/views/versions/_form.rhtml | 9 - redmine/app/views/versions/edit.rhtml | 7 - redmine/app/views/welcome/index.rhtml | 30 - redmine/config/boot.rb | 19 - redmine/config/config_custom.example.rb | 65 - redmine/config/database.yml | 69 - redmine/config/environment.rb | 140 -- redmine/config/environments/demo.rb | 21 - redmine/config/environments/development.rb | 19 - redmine/config/environments/development_oracle.rb | 19 - redmine/config/environments/development_pgsql.rb | 19 - .../config/environments/development_sqlserver.rb | 19 - redmine/config/environments/production.rb | 20 - redmine/config/environments/test.rb | 16 - redmine/config/environments/test_oracle.rb | 16 - redmine/config/environments/test_pgsql.rb | 16 - redmine/config/environments/test_sqlserver.rb | 16 - redmine/config/help.yml | 63 - redmine/config/routes.rb | 24 - redmine/db/migrate/001_setup.rb | 317 ---- redmine/db/migrate/002_issue_move.rb | 9 - redmine/db/migrate/003_issue_add_note.rb | 9 - redmine/db/migrate/004_export_pdf.rb | 11 - redmine/db/migrate/005_issue_start_date.rb | 11 - redmine/db/migrate/006_calendar_and_activity.rb | 13 - redmine/db/migrate/007_create_journals.rb | 54 - redmine/db/migrate/008_create_user_preferences.rb | 12 - redmine/db/migrate/009_add_hide_mail_pref.rb | 9 - redmine/doc/CHANGELOG | 96 -- redmine/doc/COPYING | 339 ---- redmine/doc/INSTALL | 74 - redmine/doc/README | 58 - redmine/doc/docbook/en/redmine-userdoc-en.xml | 429 ----- redmine/doc/docbook/fr/redmine-userdoc-fr.xml | 553 ------ redmine/files/delete.me | 1 - redmine/lang/de.yml | 320 ---- redmine/lang/en.yml | 320 ---- redmine/lang/es.yml | 320 ---- redmine/lang/fr.yml | 321 ---- redmine/lib/tasks/extract_fixtures.rake | 24 - redmine/lib/tasks/load_default_data.rake | 88 - redmine/log/delete.me | 1 - redmine/public/.htaccess | 40 - redmine/public/404.html | 23 - redmine/public/500.html | 24 - redmine/public/dispatch.cgi | 10 - redmine/public/dispatch.fcgi | 24 - redmine/public/dispatch.rb | 10 - redmine/public/favicon.ico | 0 redmine/public/images/add.png | Bin 336 -> 0 bytes redmine/public/images/admin.png | Bin 716 -> 0 bytes redmine/public/images/alert.png | Bin 483 -> 0 bytes redmine/public/images/arrow_bw.png | Bin 997 -> 0 bytes redmine/public/images/arrow_from.png | Bin 994 -> 0 bytes redmine/public/images/arrow_to.png | Bin 991 -> 0 bytes redmine/public/images/attachment.png | Bin 259 -> 0 bytes redmine/public/images/bulletgreen.png | Bin 193 -> 0 bytes redmine/public/images/bulletred.png | Bin 193 -> 0 bytes redmine/public/images/calendar.png | Bin 196 -> 0 bytes redmine/public/images/close.png | Bin 200 -> 0 bytes redmine/public/images/close_hl.png | Bin 199 -> 0 bytes redmine/public/images/delete.png | Bin 320 -> 0 bytes redmine/public/images/details.png | Bin 224 -> 0 bytes redmine/public/images/dir.png | Bin 314 -> 0 bytes redmine/public/images/dir_new.png | Bin 321 -> 0 bytes redmine/public/images/dir_open.png | Bin 1030 -> 0 bytes redmine/public/images/document.png | Bin 1014 -> 0 bytes redmine/public/images/edit_small.png | Bin 238 -> 0 bytes redmine/public/images/file_new.png | Bin 253 -> 0 bytes redmine/public/images/gantt.png | Bin 218 -> 0 bytes redmine/public/images/help.png | Bin 1079 -> 0 bytes redmine/public/images/home.png | Bin 301 -> 0 bytes redmine/public/images/issues.png | Bin 356 -> 0 bytes redmine/public/images/jstoolbar/bt_br.png | Bin 244 -> 0 bytes redmine/public/images/jstoolbar/bt_code.png | Bin 338 -> 0 bytes redmine/public/images/jstoolbar/bt_del.png | Bin 368 -> 0 bytes redmine/public/images/jstoolbar/bt_em.png | Bin 311 -> 0 bytes redmine/public/images/jstoolbar/bt_ins.png | Bin 322 -> 0 bytes redmine/public/images/jstoolbar/bt_link.png | Bin 900 -> 0 bytes redmine/public/images/jstoolbar/bt_ol.png | Bin 249 -> 0 bytes redmine/public/images/jstoolbar/bt_quote.png | Bin 323 -> 0 bytes redmine/public/images/jstoolbar/bt_strong.png | Bin 355 -> 0 bytes redmine/public/images/jstoolbar/bt_ul.png | Bin 239 -> 0 bytes redmine/public/images/loading.gif | Bin 1553 -> 0 bytes redmine/public/images/locked.png | Bin 437 -> 0 bytes redmine/public/images/login.png | Bin 1082 -> 0 bytes redmine/public/images/mailer.png | Bin 294 -> 0 bytes redmine/public/images/notes.png | Bin 996 -> 0 bytes redmine/public/images/options.png | Bin 1005 -> 0 bytes redmine/public/images/package.png | Bin 298 -> 0 bytes redmine/public/images/projects.png | Bin 299 -> 0 bytes redmine/public/images/rails.png | Bin 1787 -> 0 bytes redmine/public/images/rails_powered.png | Bin 262 -> 0 bytes redmine/public/images/rails_small.png | Bin 1140 -> 0 bytes redmine/public/images/role.png | Bin 293 -> 0 bytes redmine/public/images/rss.png | Bin 256 -> 0 bytes redmine/public/images/sort_asc.png | Bin 215 -> 0 bytes redmine/public/images/sort_desc.png | Bin 217 -> 0 bytes redmine/public/images/tracker.png | Bin 356 -> 0 bytes redmine/public/images/true.png | Bin 183 -> 0 bytes redmine/public/images/user.png | Bin 236 -> 0 bytes redmine/public/images/user_new.png | Bin 215 -> 0 bytes redmine/public/images/user_page.png | Bin 292 -> 0 bytes redmine/public/images/users.png | Bin 242 -> 0 bytes redmine/public/images/workflow.png | Bin 285 -> 0 bytes redmine/public/images/zoom_in.png | Bin 593 -> 0 bytes redmine/public/images/zoom_in_g.png | Bin 312 -> 0 bytes redmine/public/images/zoom_out.png | Bin 588 -> 0 bytes redmine/public/images/zoom_out_g.png | Bin 311 -> 0 bytes redmine/public/javascripts/application.js | 20 - .../public/javascripts/calendar/calendar-setup.js | 200 --- redmine/public/javascripts/calendar/calendar.js | 1806 -------------------- .../javascripts/calendar/lang/calendar-de.js | 128 -- .../javascripts/calendar/lang/calendar-en.js | 127 -- .../javascripts/calendar/lang/calendar-es.js | 129 -- .../javascripts/calendar/lang/calendar-fr.js | 129 -- redmine/public/javascripts/controls.js | 750 -------- redmine/public/javascripts/dragdrop.js | 584 ------- redmine/public/javascripts/effects.js | 854 --------- redmine/public/javascripts/jstoolbar.js | 440 ----- redmine/public/javascripts/menu.js | 556 ------ redmine/public/javascripts/prototype.js | 1785 ------------------- redmine/public/manual/en/ch01.html | 3 - redmine/public/manual/en/ch01s01.html | 3 - redmine/public/manual/en/ch01s02.html | 3 - redmine/public/manual/en/ch01s03.html | 3 - redmine/public/manual/en/ch01s04.html | 3 - redmine/public/manual/en/ch01s05.html | 3 - redmine/public/manual/en/ch01s06.html | 3 - redmine/public/manual/en/ch01s07.html | 3 - redmine/public/manual/en/ch01s08.html | 3 - redmine/public/manual/en/ch01s09.html | 3 - redmine/public/manual/en/ch01s10.html | 3 - redmine/public/manual/en/ch02.html | 3 - redmine/public/manual/en/ch02s01.html | 3 - redmine/public/manual/en/ch02s02.html | 3 - redmine/public/manual/en/ch02s03.html | 3 - redmine/public/manual/en/ch02s04.html | 3 - redmine/public/manual/en/ch02s05.html | 3 - redmine/public/manual/en/ch02s06.html | 3 - redmine/public/manual/en/ch02s07.html | 3 - redmine/public/manual/en/ch02s08.html | 3 - redmine/public/manual/en/html.css | 55 - redmine/public/manual/en/index.html | 3 - redmine/public/manual/en/resources/issues_list.png | Bin 8233 -> 0 bytes redmine/public/manual/en/resources/users_list.png | Bin 6502 -> 0 bytes redmine/public/manual/en/resources/workflow.png | Bin 6503 -> 0 bytes redmine/public/manual/fr/ch01.html | 3 - redmine/public/manual/fr/ch01s01.html | 3 - redmine/public/manual/fr/ch01s02.html | 3 - redmine/public/manual/fr/ch01s03.html | 3 - redmine/public/manual/fr/ch01s04.html | 3 - redmine/public/manual/fr/ch01s05.html | 3 - redmine/public/manual/fr/ch01s06.html | 3 - redmine/public/manual/fr/ch01s07.html | 3 - redmine/public/manual/fr/ch01s08.html | 3 - redmine/public/manual/fr/ch01s09.html | 3 - redmine/public/manual/fr/ch01s10.html | 3 - redmine/public/manual/fr/ch02.html | 3 - redmine/public/manual/fr/ch02s01.html | 3 - redmine/public/manual/fr/ch02s02.html | 3 - redmine/public/manual/fr/ch02s03.html | 3 - redmine/public/manual/fr/ch02s04.html | 3 - redmine/public/manual/fr/ch02s05.html | 3 - redmine/public/manual/fr/ch02s06.html | 3 - redmine/public/manual/fr/ch02s07.html | 3 - redmine/public/manual/fr/ch02s08.html | 3 - redmine/public/manual/fr/html.css | 55 - redmine/public/manual/fr/index.html | 3 - redmine/public/manual/fr/resources/issues_list.png | Bin 8233 -> 0 bytes redmine/public/manual/fr/resources/users_list.png | Bin 6502 -> 0 bytes redmine/public/manual/fr/resources/workflow.png | Bin 6503 -> 0 bytes redmine/public/robots.txt | 1 - redmine/public/stylesheets/application.css | 484 ------ redmine/public/stylesheets/calendar.css | 231 --- redmine/public/stylesheets/jstoolbar.css | 79 - redmine/public/stylesheets/menu.css | 39 - redmine/public/stylesheets/rails.css | 57 - redmine/script/about | 3 - redmine/script/breakpointer | 3 - redmine/script/console | 3 - redmine/script/destroy | 3 - redmine/script/generate | 3 - redmine/script/performance/benchmarker | 3 - redmine/script/performance/profiler | 3 - redmine/script/plugin | 3 - redmine/script/process/reaper | 3 - redmine/script/process/spawner | 3 - redmine/script/process/spinner | 3 - redmine/script/runner | 3 - redmine/script/server | 3 - redmine/test/fixtures/attachments.yml | 13 - redmine/test/fixtures/auth_sources.yml | 2 - redmine/test/fixtures/custom_fields.yml | 45 - redmine/test/fixtures/custom_fields_projects.yml | 2 - redmine/test/fixtures/custom_fields_trackers.yml | 10 - redmine/test/fixtures/custom_values.yml | 43 - redmine/test/fixtures/documents.yml | 2 - redmine/test/fixtures/enumerations.yml | 33 - redmine/test/fixtures/issue_categories.yml | 9 - redmine/test/fixtures/issue_statuses.yml | 37 - redmine/test/fixtures/issues.yml | 43 - redmine/test/fixtures/members.yml | 13 - redmine/test/fixtures/news.yml | 20 - redmine/test/fixtures/permissions.yml | 379 ---- redmine/test/fixtures/permissions_roles.yml | 379 ---- redmine/test/fixtures/projects.yml | 41 - redmine/test/fixtures/roles.yml | 10 - redmine/test/fixtures/tokens.yml | 1 - redmine/test/fixtures/trackers.yml | 13 - redmine/test/fixtures/user_preferences.yml | 5 - redmine/test/fixtures/users.yml | 61 - redmine/test/fixtures/versions.yml | 17 - redmine/test/fixtures/workflows.yml | 1621 ------------------ redmine/test/functional/my_controller_test.rb | 18 - .../test/functional/projects_controller_test.rb | 114 -- redmine/test/integration/account_test.rb | 100 -- redmine/test/integration/admin_test.rb | 61 - redmine/test/test_helper.rb | 55 - redmine/test/unit/member_test.rb | 51 - redmine/test/unit/project_test.rb | 79 - redmine/test/unit/token_test.rb | 10 - redmine/test/unit/user_preference_test.rb | 10 - redmine/test/unit/user_test.rb | 88 - redmine/vendor/plugins/gloc-1.1.0/CHANGELOG | 19 - redmine/vendor/plugins/gloc-1.1.0/MIT-LICENSE | 19 - redmine/vendor/plugins/gloc-1.1.0/README | 208 --- redmine/vendor/plugins/gloc-1.1.0/Rakefile | 15 - .../ActionController/Filters/ClassMethods.html | 230 --- .../gloc-1.1.0/doc/classes/ActionMailer/Base.html | 140 -- .../gloc-1.1.0/doc/classes/ActionView/Base.html | 174 -- .../doc/classes/ActionView/Helpers/DateHelper.html | 348 ---- .../classes/ActionView/Helpers/InstanceTag.html | 167 -- .../doc/classes/ActiveRecord/Errors.html | 215 --- .../ActiveRecord/Validations/ClassMethods.html | 217 --- .../plugins/gloc-1.1.0/doc/classes/GLoc.html | 774 --------- .../gloc-1.1.0/doc/classes/GLoc/ClassMethods.html | 160 -- .../gloc-1.1.0/doc/classes/GLoc/Helpers.html | 323 ---- .../doc/classes/GLoc/InstanceMethods.html | 364 ---- redmine/vendor/plugins/gloc-1.1.0/doc/created.rid | 1 - .../plugins/gloc-1.1.0/doc/files/CHANGELOG.html | 153 -- .../plugins/gloc-1.1.0/doc/files/README.html | 480 ------ .../gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html | 107 -- .../gloc-1.1.0/doc/files/lib/gloc-internal_rb.html | 115 -- .../doc/files/lib/gloc-rails-text_rb.html | 114 -- .../gloc-1.1.0/doc/files/lib/gloc-rails_rb.html | 114 -- .../gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html | 107 -- .../gloc-1.1.0/doc/files/lib/gloc-version_rb.html | 101 -- .../plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html | 116 -- .../plugins/gloc-1.1.0/doc/fr_class_index.html | 37 - .../plugins/gloc-1.1.0/doc/fr_file_index.html | 35 - .../plugins/gloc-1.1.0/doc/fr_method_index.html | 72 - redmine/vendor/plugins/gloc-1.1.0/doc/index.html | 24 - .../vendor/plugins/gloc-1.1.0/doc/rdoc-style.css | 208 --- redmine/vendor/plugins/gloc-1.1.0/init.rb | 11 - .../vendor/plugins/gloc-1.1.0/lib/gloc-config.rb | 16 - redmine/vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb | 97 -- .../vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb | 20 - .../vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb | 134 -- .../plugins/gloc-1.1.0/lib/gloc-rails-text.rb | 137 -- .../vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb | 230 --- redmine/vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb | 7 - .../vendor/plugins/gloc-1.1.0/lib/gloc-version.rb | 12 - redmine/vendor/plugins/gloc-1.1.0/lib/gloc.rb | 294 ---- redmine/vendor/plugins/gloc-1.1.0/tasks/gloc.rake | 30 - .../plugins/gloc-1.1.0/test/gloc_rails_test.rb | 118 -- .../vendor/plugins/gloc-1.1.0/test/gloc_test.rb | 433 ----- .../vendor/plugins/gloc-1.1.0/test/lang/en.yaml | 2 - .../vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml | 2 - redmine/vendor/plugins/gloc-1.1.0/test/lang/ja.yml | 2 - .../vendor/plugins/gloc-1.1.0/test/lang2/en.yml | 2 - .../vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml | 2 - .../gloc-1.1.0/test/lib/rails-string_ext.rb | 23 - .../plugins/gloc-1.1.0/test/lib/rails-time_ext.rb | 76 - redmine/vendor/plugins/rfpdf/CHANGELOG | 13 - redmine/vendor/plugins/rfpdf/MIT-LICENSE | 20 - redmine/vendor/plugins/rfpdf/README | 99 -- redmine/vendor/plugins/rfpdf/init.rb | 3 - redmine/vendor/plugins/rfpdf/lib/rfpdf.rb | 31 - redmine/vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb | 99 -- redmine/vendor/plugins/rfpdf/lib/rfpdf/chinese.rb | 473 ----- redmine/vendor/plugins/rfpdf/lib/rfpdf/errors.rb | 4 - redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb | 1550 ----------------- redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb | 139 -- redmine/vendor/plugins/rfpdf/lib/rfpdf/japanese.rb | 468 ----- redmine/vendor/plugins/rfpdf/lib/rfpdf/korean.rb | 436 ----- redmine/vendor/plugins/rfpdf/lib/rfpdf/makefont.rb | 1787 ------------------- redmine/vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb | 346 ---- redmine/vendor/plugins/rfpdf/lib/rfpdf/view.rb | 75 - redmine/vendor/plugins/rfpdf/test/test_helper.rb | 1 - script/about | 3 + script/breakpointer | 3 + script/console | 3 + script/destroy | 3 + script/generate | 3 + script/performance/benchmarker | 3 + script/performance/profiler | 3 + script/plugin | 3 + script/process/reaper | 3 + script/process/spawner | 3 + script/process/spinner | 3 + script/runner | 3 + script/server | 3 + test/fixtures/attachments.yml | 13 + test/fixtures/auth_sources.yml | 2 + test/fixtures/custom_fields.yml | 45 + test/fixtures/custom_fields_projects.yml | 2 + test/fixtures/custom_fields_trackers.yml | 10 + test/fixtures/custom_values.yml | 43 + test/fixtures/documents.yml | 2 + test/fixtures/enumerations.yml | 33 + test/fixtures/issue_categories.yml | 9 + test/fixtures/issue_statuses.yml | 37 + test/fixtures/issues.yml | 43 + test/fixtures/members.yml | 13 + test/fixtures/news.yml | 20 + test/fixtures/permissions.yml | 379 ++++ test/fixtures/permissions_roles.yml | 379 ++++ test/fixtures/projects.yml | 41 + test/fixtures/roles.yml | 10 + test/fixtures/tokens.yml | 1 + test/fixtures/trackers.yml | 13 + test/fixtures/user_preferences.yml | 5 + test/fixtures/users.yml | 61 + test/fixtures/versions.yml | 17 + test/fixtures/workflows.yml | 1621 ++++++++++++++++++ test/functional/my_controller_test.rb | 18 + test/functional/projects_controller_test.rb | 114 ++ test/integration/account_test.rb | 100 ++ test/integration/admin_test.rb | 61 + test/test_helper.rb | 55 + test/unit/member_test.rb | 51 + test/unit/project_test.rb | 79 + test/unit/token_test.rb | 10 + test/unit/user_preference_test.rb | 10 + test/unit/user_test.rb | 88 + vendor/plugins/gloc-1.1.0/CHANGELOG | 19 + vendor/plugins/gloc-1.1.0/MIT-LICENSE | 19 + vendor/plugins/gloc-1.1.0/README | 208 +++ vendor/plugins/gloc-1.1.0/Rakefile | 15 + .../ActionController/Filters/ClassMethods.html | 230 +++ .../gloc-1.1.0/doc/classes/ActionMailer/Base.html | 140 ++ .../gloc-1.1.0/doc/classes/ActionView/Base.html | 174 ++ .../doc/classes/ActionView/Helpers/DateHelper.html | 348 ++++ .../classes/ActionView/Helpers/InstanceTag.html | 167 ++ .../doc/classes/ActiveRecord/Errors.html | 215 +++ .../ActiveRecord/Validations/ClassMethods.html | 217 +++ vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html | 774 +++++++++ .../gloc-1.1.0/doc/classes/GLoc/ClassMethods.html | 160 ++ .../gloc-1.1.0/doc/classes/GLoc/Helpers.html | 323 ++++ .../doc/classes/GLoc/InstanceMethods.html | 364 ++++ vendor/plugins/gloc-1.1.0/doc/created.rid | 1 + vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html | 153 ++ vendor/plugins/gloc-1.1.0/doc/files/README.html | 480 ++++++ .../gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html | 107 ++ .../gloc-1.1.0/doc/files/lib/gloc-internal_rb.html | 115 ++ .../doc/files/lib/gloc-rails-text_rb.html | 114 ++ .../gloc-1.1.0/doc/files/lib/gloc-rails_rb.html | 114 ++ .../gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html | 107 ++ .../gloc-1.1.0/doc/files/lib/gloc-version_rb.html | 101 ++ .../plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html | 116 ++ vendor/plugins/gloc-1.1.0/doc/fr_class_index.html | 37 + vendor/plugins/gloc-1.1.0/doc/fr_file_index.html | 35 + vendor/plugins/gloc-1.1.0/doc/fr_method_index.html | 72 + vendor/plugins/gloc-1.1.0/doc/index.html | 24 + vendor/plugins/gloc-1.1.0/doc/rdoc-style.css | 208 +++ vendor/plugins/gloc-1.1.0/init.rb | 11 + vendor/plugins/gloc-1.1.0/lib/gloc-config.rb | 16 + vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb | 97 ++ vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb | 20 + vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb | 134 ++ vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb | 137 ++ vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb | 230 +++ vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb | 7 + vendor/plugins/gloc-1.1.0/lib/gloc-version.rb | 12 + vendor/plugins/gloc-1.1.0/lib/gloc.rb | 294 ++++ vendor/plugins/gloc-1.1.0/tasks/gloc.rake | 30 + vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb | 118 ++ vendor/plugins/gloc-1.1.0/test/gloc_test.rb | 433 +++++ vendor/plugins/gloc-1.1.0/test/lang/en.yaml | 2 + vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml | 2 + vendor/plugins/gloc-1.1.0/test/lang/ja.yml | 2 + vendor/plugins/gloc-1.1.0/test/lang2/en.yml | 2 + vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml | 2 + .../gloc-1.1.0/test/lib/rails-string_ext.rb | 23 + .../plugins/gloc-1.1.0/test/lib/rails-time_ext.rb | 76 + vendor/plugins/rfpdf/CHANGELOG | 13 + vendor/plugins/rfpdf/MIT-LICENSE | 20 + vendor/plugins/rfpdf/README | 99 ++ vendor/plugins/rfpdf/init.rb | 3 + vendor/plugins/rfpdf/lib/rfpdf.rb | 31 + vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb | 99 ++ vendor/plugins/rfpdf/lib/rfpdf/chinese.rb | 473 +++++ vendor/plugins/rfpdf/lib/rfpdf/errors.rb | 4 + vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb | 1550 +++++++++++++++++ vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb | 139 ++ vendor/plugins/rfpdf/lib/rfpdf/japanese.rb | 468 +++++ vendor/plugins/rfpdf/lib/rfpdf/korean.rb | 436 +++++ vendor/plugins/rfpdf/lib/rfpdf/makefont.rb | 1787 +++++++++++++++++++ vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb | 346 ++++ vendor/plugins/rfpdf/lib/rfpdf/view.rb | 75 + vendor/plugins/rfpdf/test/test_helper.rb | 1 + 944 files changed, 35893 insertions(+), 35893 deletions(-) create mode 100644 Rakefile create mode 100644 app/controllers/account_controller.rb create mode 100644 app/controllers/admin_controller.rb create mode 100644 app/controllers/application.rb create mode 100644 app/controllers/auth_sources_controller.rb create mode 100644 app/controllers/custom_fields_controller.rb create mode 100644 app/controllers/documents_controller.rb create mode 100644 app/controllers/enumerations_controller.rb create mode 100644 app/controllers/help_controller.rb create mode 100644 app/controllers/issue_categories_controller.rb create mode 100644 app/controllers/issue_statuses_controller.rb create mode 100644 app/controllers/issues_controller.rb create mode 100644 app/controllers/members_controller.rb create mode 100644 app/controllers/my_controller.rb create mode 100644 app/controllers/news_controller.rb create mode 100644 app/controllers/projects_controller.rb create mode 100644 app/controllers/reports_controller.rb create mode 100644 app/controllers/roles_controller.rb create mode 100644 app/controllers/trackers_controller.rb create mode 100644 app/controllers/users_controller.rb create mode 100644 app/controllers/versions_controller.rb create mode 100644 app/controllers/welcome_controller.rb create mode 100644 app/helpers/account_helper.rb create mode 100644 app/helpers/admin_helper.rb create mode 100644 app/helpers/application_helper.rb create mode 100644 app/helpers/auth_sources_helper.rb create mode 100644 app/helpers/custom_fields_helper.rb create mode 100644 app/helpers/documents_helper.rb create mode 100644 app/helpers/enumerations_helper.rb create mode 100644 app/helpers/help_helper.rb create mode 100644 app/helpers/ifpdf_helper.rb create mode 100644 app/helpers/issue_categories_helper.rb create mode 100644 app/helpers/issue_statuses_helper.rb create mode 100644 app/helpers/issues_helper.rb create mode 100644 app/helpers/members_helper.rb create mode 100644 app/helpers/my_helper.rb create mode 100644 app/helpers/news_helper.rb create mode 100644 app/helpers/projects_helper.rb create mode 100644 app/helpers/reports_helper.rb create mode 100644 app/helpers/roles_helper.rb create mode 100644 app/helpers/search_filter_helper.rb create mode 100644 app/helpers/sort_helper.rb create mode 100644 app/helpers/trackers_helper.rb create mode 100644 app/helpers/users_helper.rb create mode 100644 app/helpers/versions_helper.rb create mode 100644 app/helpers/welcome_helper.rb create mode 100644 app/models/attachment.rb create mode 100644 app/models/auth_source.rb create mode 100644 app/models/auth_source_ldap.rb create mode 100644 app/models/custom_field.rb create mode 100644 app/models/custom_value.rb create mode 100644 app/models/document.rb create mode 100644 app/models/enumeration.rb create mode 100644 app/models/issue.rb create mode 100644 app/models/issue_category.rb create mode 100644 app/models/issue_custom_field.rb create mode 100644 app/models/issue_history.rb create mode 100644 app/models/issue_status.rb create mode 100644 app/models/journal.rb create mode 100644 app/models/journal_detail.rb create mode 100644 app/models/mailer.rb create mode 100644 app/models/member.rb create mode 100644 app/models/news.rb create mode 100644 app/models/permission.rb create mode 100644 app/models/project.rb create mode 100644 app/models/project_custom_field.rb create mode 100644 app/models/role.rb create mode 100644 app/models/token.rb create mode 100644 app/models/tracker.rb create mode 100644 app/models/user.rb create mode 100644 app/models/user_custom_field.rb create mode 100644 app/models/user_preference.rb create mode 100644 app/models/version.rb create mode 100644 app/models/workflow.rb create mode 100644 app/views/account/login.rhtml create mode 100644 app/views/account/lost_password.rhtml create mode 100644 app/views/account/password_recovery.rhtml create mode 100644 app/views/account/register.rhtml create mode 100644 app/views/account/show.rhtml create mode 100644 app/views/admin/index.rhtml create mode 100644 app/views/admin/info.rhtml create mode 100644 app/views/admin/mail_options.rhtml create mode 100644 app/views/admin/projects.rhtml create mode 100644 app/views/auth_sources/_form.rhtml create mode 100644 app/views/auth_sources/edit.rhtml create mode 100644 app/views/auth_sources/list.rhtml create mode 100644 app/views/auth_sources/new.rhtml create mode 100644 app/views/custom_fields/_form.rhtml create mode 100644 app/views/custom_fields/edit.rhtml create mode 100644 app/views/custom_fields/list.rhtml create mode 100644 app/views/custom_fields/new.rhtml create mode 100644 app/views/documents/_form.rhtml create mode 100644 app/views/documents/edit.rhtml create mode 100644 app/views/documents/show.rhtml create mode 100644 app/views/enumerations/_form.rhtml create mode 100644 app/views/enumerations/edit.rhtml create mode 100644 app/views/enumerations/list.rhtml create mode 100644 app/views/enumerations/new.rhtml create mode 100644 app/views/issue_categories/_form.rhtml create mode 100644 app/views/issue_categories/edit.rhtml create mode 100644 app/views/issue_statuses/_form.rhtml create mode 100644 app/views/issue_statuses/edit.rhtml create mode 100644 app/views/issue_statuses/list.rhtml create mode 100644 app/views/issue_statuses/new.rhtml create mode 100644 app/views/issues/_history.rhtml create mode 100644 app/views/issues/_list_simple.rhtml create mode 100644 app/views/issues/_pdf.rfpdf create mode 100644 app/views/issues/change_status.rhtml create mode 100644 app/views/issues/edit.rhtml create mode 100644 app/views/issues/export_pdf.rfpdf create mode 100644 app/views/issues/history.rhtml create mode 100644 app/views/issues/show.rhtml create mode 100644 app/views/layouts/base.rhtml create mode 100644 app/views/mailer/_issue.rhtml create mode 100644 app/views/mailer/issue_add_de.rhtml create mode 100644 app/views/mailer/issue_add_en.rhtml create mode 100644 app/views/mailer/issue_add_es.rhtml create mode 100644 app/views/mailer/issue_add_fr.rhtml create mode 100644 app/views/mailer/issue_edit_de.rhtml create mode 100644 app/views/mailer/issue_edit_en.rhtml create mode 100644 app/views/mailer/issue_edit_es.rhtml create mode 100644 app/views/mailer/issue_edit_fr.rhtml create mode 100644 app/views/mailer/lost_password_de.rhtml create mode 100644 app/views/mailer/lost_password_en.rhtml create mode 100644 app/views/mailer/lost_password_es.rhtml create mode 100644 app/views/mailer/lost_password_fr.rhtml create mode 100644 app/views/mailer/register_de.rhtml create mode 100644 app/views/mailer/register_en.rhtml create mode 100644 app/views/mailer/register_es.rhtml create mode 100644 app/views/mailer/register_fr.rhtml create mode 100644 app/views/my/_block.rhtml create mode 100644 app/views/my/account.rhtml create mode 100644 app/views/my/blocks/_calendar.rhtml create mode 100644 app/views/my/blocks/_documents.rhtml create mode 100644 app/views/my/blocks/_issues_assigned_to_me.rhtml create mode 100644 app/views/my/blocks/_issues_reported_by_me.rhtml create mode 100644 app/views/my/blocks/_latest_news.rhtml create mode 100644 app/views/my/page.rhtml create mode 100644 app/views/my/page_layout.rhtml create mode 100644 app/views/news/_form.rhtml create mode 100644 app/views/news/edit.rhtml create mode 100644 app/views/news/show.rhtml create mode 100644 app/views/projects/_form.rhtml create mode 100644 app/views/projects/activity.rhtml create mode 100644 app/views/projects/add.rhtml create mode 100644 app/views/projects/add_document.rhtml create mode 100644 app/views/projects/add_file.rhtml create mode 100644 app/views/projects/add_issue.rhtml create mode 100644 app/views/projects/add_news.rhtml create mode 100644 app/views/projects/add_version.rhtml create mode 100644 app/views/projects/calendar.rhtml create mode 100644 app/views/projects/changelog.rhtml create mode 100644 app/views/projects/destroy.rhtml create mode 100644 app/views/projects/export_issues_pdf.rfpdf create mode 100644 app/views/projects/gantt.rfpdf create mode 100644 app/views/projects/gantt.rhtml create mode 100644 app/views/projects/list.rhtml create mode 100644 app/views/projects/list_documents.rhtml create mode 100644 app/views/projects/list_files.rhtml create mode 100644 app/views/projects/list_issues.rhtml create mode 100644 app/views/projects/list_members.rhtml create mode 100644 app/views/projects/list_news.rhtml create mode 100644 app/views/projects/move_issues.rhtml create mode 100644 app/views/projects/settings.rhtml create mode 100644 app/views/projects/show.rhtml create mode 100644 app/views/reports/_details.rhtml create mode 100644 app/views/reports/_simple.rhtml create mode 100644 app/views/reports/issue_report.rhtml create mode 100644 app/views/reports/issue_report_details.rhtml create mode 100644 app/views/roles/_form.rhtml create mode 100644 app/views/roles/edit.rhtml create mode 100644 app/views/roles/list.rhtml create mode 100644 app/views/roles/new.rhtml create mode 100644 app/views/roles/workflow.rhtml create mode 100644 app/views/trackers/_form.rhtml create mode 100644 app/views/trackers/edit.rhtml create mode 100644 app/views/trackers/list.rhtml create mode 100644 app/views/trackers/new.rhtml create mode 100644 app/views/users/_form.rhtml create mode 100644 app/views/users/add.rhtml create mode 100644 app/views/users/edit.rhtml create mode 100644 app/views/users/list.rhtml create mode 100644 app/views/versions/_form.rhtml create mode 100644 app/views/versions/edit.rhtml create mode 100644 app/views/welcome/index.rhtml create mode 100644 config/boot.rb create mode 100644 config/config_custom.example.rb create mode 100644 config/database.yml create mode 100644 config/environment.rb create mode 100644 config/environments/demo.rb create mode 100644 config/environments/development.rb create mode 100644 config/environments/development_oracle.rb create mode 100644 config/environments/development_pgsql.rb create mode 100644 config/environments/development_sqlserver.rb create mode 100644 config/environments/production.rb create mode 100644 config/environments/test.rb create mode 100644 config/environments/test_oracle.rb create mode 100644 config/environments/test_pgsql.rb create mode 100644 config/environments/test_sqlserver.rb create mode 100644 config/help.yml create mode 100644 config/routes.rb create mode 100644 db/migrate/001_setup.rb create mode 100644 db/migrate/002_issue_move.rb create mode 100644 db/migrate/003_issue_add_note.rb create mode 100644 db/migrate/004_export_pdf.rb create mode 100644 db/migrate/005_issue_start_date.rb create mode 100644 db/migrate/006_calendar_and_activity.rb create mode 100644 db/migrate/007_create_journals.rb create mode 100644 db/migrate/008_create_user_preferences.rb create mode 100644 db/migrate/009_add_hide_mail_pref.rb create mode 100644 doc/CHANGELOG create mode 100644 doc/COPYING create mode 100644 doc/INSTALL create mode 100644 doc/README create mode 100644 doc/docbook/en/redmine-userdoc-en.xml create mode 100644 doc/docbook/fr/redmine-userdoc-fr.xml create mode 100644 files/delete.me create mode 100644 lang/de.yml create mode 100644 lang/en.yml create mode 100644 lang/es.yml create mode 100644 lang/fr.yml create mode 100644 lib/tasks/extract_fixtures.rake create mode 100644 lib/tasks/load_default_data.rake create mode 100644 log/delete.me create mode 100644 public/.htaccess create mode 100644 public/404.html create mode 100644 public/500.html create mode 100644 public/dispatch.cgi create mode 100644 public/dispatch.fcgi create mode 100644 public/dispatch.rb create mode 100644 public/favicon.ico create mode 100644 public/images/add.png create mode 100644 public/images/admin.png create mode 100644 public/images/alert.png create mode 100644 public/images/arrow_bw.png create mode 100644 public/images/arrow_from.png create mode 100644 public/images/arrow_to.png create mode 100644 public/images/attachment.png create mode 100644 public/images/bulletgreen.png create mode 100644 public/images/bulletred.png create mode 100644 public/images/calendar.png create mode 100644 public/images/close.png create mode 100644 public/images/close_hl.png create mode 100644 public/images/delete.png create mode 100644 public/images/details.png create mode 100644 public/images/dir.png create mode 100644 public/images/dir_new.png create mode 100644 public/images/dir_open.png create mode 100644 public/images/document.png create mode 100644 public/images/edit_small.png create mode 100644 public/images/file_new.png create mode 100644 public/images/gantt.png create mode 100644 public/images/help.png create mode 100644 public/images/home.png create mode 100644 public/images/issues.png create mode 100644 public/images/jstoolbar/bt_br.png create mode 100644 public/images/jstoolbar/bt_code.png create mode 100644 public/images/jstoolbar/bt_del.png create mode 100644 public/images/jstoolbar/bt_em.png create mode 100644 public/images/jstoolbar/bt_ins.png create mode 100644 public/images/jstoolbar/bt_link.png create mode 100644 public/images/jstoolbar/bt_ol.png create mode 100644 public/images/jstoolbar/bt_quote.png create mode 100644 public/images/jstoolbar/bt_strong.png create mode 100644 public/images/jstoolbar/bt_ul.png create mode 100644 public/images/loading.gif create mode 100644 public/images/locked.png create mode 100644 public/images/login.png create mode 100644 public/images/mailer.png create mode 100644 public/images/notes.png create mode 100644 public/images/options.png create mode 100644 public/images/package.png create mode 100644 public/images/projects.png create mode 100644 public/images/rails.png create mode 100644 public/images/rails_powered.png create mode 100644 public/images/rails_small.png create mode 100644 public/images/role.png create mode 100644 public/images/rss.png create mode 100644 public/images/sort_asc.png create mode 100644 public/images/sort_desc.png create mode 100644 public/images/tracker.png create mode 100644 public/images/true.png create mode 100644 public/images/user.png create mode 100644 public/images/user_new.png create mode 100644 public/images/user_page.png create mode 100644 public/images/users.png create mode 100644 public/images/workflow.png create mode 100644 public/images/zoom_in.png create mode 100644 public/images/zoom_in_g.png create mode 100644 public/images/zoom_out.png create mode 100644 public/images/zoom_out_g.png create mode 100644 public/javascripts/application.js create mode 100644 public/javascripts/calendar/calendar-setup.js create mode 100644 public/javascripts/calendar/calendar.js create mode 100644 public/javascripts/calendar/lang/calendar-de.js create mode 100644 public/javascripts/calendar/lang/calendar-en.js create mode 100644 public/javascripts/calendar/lang/calendar-es.js create mode 100644 public/javascripts/calendar/lang/calendar-fr.js create mode 100644 public/javascripts/controls.js create mode 100644 public/javascripts/dragdrop.js create mode 100644 public/javascripts/effects.js create mode 100644 public/javascripts/jstoolbar.js create mode 100644 public/javascripts/menu.js create mode 100644 public/javascripts/prototype.js create mode 100644 public/manual/en/ch01.html create mode 100644 public/manual/en/ch01s01.html create mode 100644 public/manual/en/ch01s02.html create mode 100644 public/manual/en/ch01s03.html create mode 100644 public/manual/en/ch01s04.html create mode 100644 public/manual/en/ch01s05.html create mode 100644 public/manual/en/ch01s06.html create mode 100644 public/manual/en/ch01s07.html create mode 100644 public/manual/en/ch01s08.html create mode 100644 public/manual/en/ch01s09.html create mode 100644 public/manual/en/ch01s10.html create mode 100644 public/manual/en/ch02.html create mode 100644 public/manual/en/ch02s01.html create mode 100644 public/manual/en/ch02s02.html create mode 100644 public/manual/en/ch02s03.html create mode 100644 public/manual/en/ch02s04.html create mode 100644 public/manual/en/ch02s05.html create mode 100644 public/manual/en/ch02s06.html create mode 100644 public/manual/en/ch02s07.html create mode 100644 public/manual/en/ch02s08.html create mode 100644 public/manual/en/html.css create mode 100644 public/manual/en/index.html create mode 100644 public/manual/en/resources/issues_list.png create mode 100644 public/manual/en/resources/users_list.png create mode 100644 public/manual/en/resources/workflow.png create mode 100644 public/manual/fr/ch01.html create mode 100644 public/manual/fr/ch01s01.html create mode 100644 public/manual/fr/ch01s02.html create mode 100644 public/manual/fr/ch01s03.html create mode 100644 public/manual/fr/ch01s04.html create mode 100644 public/manual/fr/ch01s05.html create mode 100644 public/manual/fr/ch01s06.html create mode 100644 public/manual/fr/ch01s07.html create mode 100644 public/manual/fr/ch01s08.html create mode 100644 public/manual/fr/ch01s09.html create mode 100644 public/manual/fr/ch01s10.html create mode 100644 public/manual/fr/ch02.html create mode 100644 public/manual/fr/ch02s01.html create mode 100644 public/manual/fr/ch02s02.html create mode 100644 public/manual/fr/ch02s03.html create mode 100644 public/manual/fr/ch02s04.html create mode 100644 public/manual/fr/ch02s05.html create mode 100644 public/manual/fr/ch02s06.html create mode 100644 public/manual/fr/ch02s07.html create mode 100644 public/manual/fr/ch02s08.html create mode 100644 public/manual/fr/html.css create mode 100644 public/manual/fr/index.html create mode 100644 public/manual/fr/resources/issues_list.png create mode 100644 public/manual/fr/resources/users_list.png create mode 100644 public/manual/fr/resources/workflow.png create mode 100644 public/robots.txt create mode 100644 public/stylesheets/application.css create mode 100644 public/stylesheets/calendar.css create mode 100644 public/stylesheets/jstoolbar.css create mode 100644 public/stylesheets/menu.css create mode 100644 public/stylesheets/rails.css delete mode 100644 redmine/Rakefile delete mode 100644 redmine/app/controllers/account_controller.rb delete mode 100644 redmine/app/controllers/admin_controller.rb delete mode 100644 redmine/app/controllers/application.rb delete mode 100644 redmine/app/controllers/auth_sources_controller.rb delete mode 100644 redmine/app/controllers/custom_fields_controller.rb delete mode 100644 redmine/app/controllers/documents_controller.rb delete mode 100644 redmine/app/controllers/enumerations_controller.rb delete mode 100644 redmine/app/controllers/help_controller.rb delete mode 100644 redmine/app/controllers/issue_categories_controller.rb delete mode 100644 redmine/app/controllers/issue_statuses_controller.rb delete mode 100644 redmine/app/controllers/issues_controller.rb delete mode 100644 redmine/app/controllers/members_controller.rb delete mode 100644 redmine/app/controllers/my_controller.rb delete mode 100644 redmine/app/controllers/news_controller.rb delete mode 100644 redmine/app/controllers/projects_controller.rb delete mode 100644 redmine/app/controllers/reports_controller.rb delete mode 100644 redmine/app/controllers/roles_controller.rb delete mode 100644 redmine/app/controllers/trackers_controller.rb delete mode 100644 redmine/app/controllers/users_controller.rb delete mode 100644 redmine/app/controllers/versions_controller.rb delete mode 100644 redmine/app/controllers/welcome_controller.rb delete mode 100644 redmine/app/helpers/account_helper.rb delete mode 100644 redmine/app/helpers/admin_helper.rb delete mode 100644 redmine/app/helpers/application_helper.rb delete mode 100644 redmine/app/helpers/auth_sources_helper.rb delete mode 100644 redmine/app/helpers/custom_fields_helper.rb delete mode 100644 redmine/app/helpers/documents_helper.rb delete mode 100644 redmine/app/helpers/enumerations_helper.rb delete mode 100644 redmine/app/helpers/help_helper.rb delete mode 100644 redmine/app/helpers/ifpdf_helper.rb delete mode 100644 redmine/app/helpers/issue_categories_helper.rb delete mode 100644 redmine/app/helpers/issue_statuses_helper.rb delete mode 100644 redmine/app/helpers/issues_helper.rb delete mode 100644 redmine/app/helpers/members_helper.rb delete mode 100644 redmine/app/helpers/my_helper.rb delete mode 100644 redmine/app/helpers/news_helper.rb delete mode 100644 redmine/app/helpers/projects_helper.rb delete mode 100644 redmine/app/helpers/reports_helper.rb delete mode 100644 redmine/app/helpers/roles_helper.rb delete mode 100644 redmine/app/helpers/search_filter_helper.rb delete mode 100644 redmine/app/helpers/sort_helper.rb delete mode 100644 redmine/app/helpers/trackers_helper.rb delete mode 100644 redmine/app/helpers/users_helper.rb delete mode 100644 redmine/app/helpers/versions_helper.rb delete mode 100644 redmine/app/helpers/welcome_helper.rb delete mode 100644 redmine/app/models/attachment.rb delete mode 100644 redmine/app/models/auth_source.rb delete mode 100644 redmine/app/models/auth_source_ldap.rb delete mode 100644 redmine/app/models/custom_field.rb delete mode 100644 redmine/app/models/custom_value.rb delete mode 100644 redmine/app/models/document.rb delete mode 100644 redmine/app/models/enumeration.rb delete mode 100644 redmine/app/models/issue.rb delete mode 100644 redmine/app/models/issue_category.rb delete mode 100644 redmine/app/models/issue_custom_field.rb delete mode 100644 redmine/app/models/issue_history.rb delete mode 100644 redmine/app/models/issue_status.rb delete mode 100644 redmine/app/models/journal.rb delete mode 100644 redmine/app/models/journal_detail.rb delete mode 100644 redmine/app/models/mailer.rb delete mode 100644 redmine/app/models/member.rb delete mode 100644 redmine/app/models/news.rb delete mode 100644 redmine/app/models/permission.rb delete mode 100644 redmine/app/models/project.rb delete mode 100644 redmine/app/models/project_custom_field.rb delete mode 100644 redmine/app/models/role.rb delete mode 100644 redmine/app/models/token.rb delete mode 100644 redmine/app/models/tracker.rb delete mode 100644 redmine/app/models/user.rb delete mode 100644 redmine/app/models/user_custom_field.rb delete mode 100644 redmine/app/models/user_preference.rb delete mode 100644 redmine/app/models/version.rb delete mode 100644 redmine/app/models/workflow.rb delete mode 100644 redmine/app/views/account/login.rhtml delete mode 100644 redmine/app/views/account/lost_password.rhtml delete mode 100644 redmine/app/views/account/password_recovery.rhtml delete mode 100644 redmine/app/views/account/register.rhtml delete mode 100644 redmine/app/views/account/show.rhtml delete mode 100644 redmine/app/views/admin/index.rhtml delete mode 100644 redmine/app/views/admin/info.rhtml delete mode 100644 redmine/app/views/admin/mail_options.rhtml delete mode 100644 redmine/app/views/admin/projects.rhtml delete mode 100644 redmine/app/views/auth_sources/_form.rhtml delete mode 100644 redmine/app/views/auth_sources/edit.rhtml delete mode 100644 redmine/app/views/auth_sources/list.rhtml delete mode 100644 redmine/app/views/auth_sources/new.rhtml delete mode 100644 redmine/app/views/custom_fields/_form.rhtml delete mode 100644 redmine/app/views/custom_fields/edit.rhtml delete mode 100644 redmine/app/views/custom_fields/list.rhtml delete mode 100644 redmine/app/views/custom_fields/new.rhtml delete mode 100644 redmine/app/views/documents/_form.rhtml delete mode 100644 redmine/app/views/documents/edit.rhtml delete mode 100644 redmine/app/views/documents/show.rhtml delete mode 100644 redmine/app/views/enumerations/_form.rhtml delete mode 100644 redmine/app/views/enumerations/edit.rhtml delete mode 100644 redmine/app/views/enumerations/list.rhtml delete mode 100644 redmine/app/views/enumerations/new.rhtml delete mode 100644 redmine/app/views/issue_categories/_form.rhtml delete mode 100644 redmine/app/views/issue_categories/edit.rhtml delete mode 100644 redmine/app/views/issue_statuses/_form.rhtml delete mode 100644 redmine/app/views/issue_statuses/edit.rhtml delete mode 100644 redmine/app/views/issue_statuses/list.rhtml delete mode 100644 redmine/app/views/issue_statuses/new.rhtml delete mode 100644 redmine/app/views/issues/_history.rhtml delete mode 100644 redmine/app/views/issues/_list_simple.rhtml delete mode 100644 redmine/app/views/issues/_pdf.rfpdf delete mode 100644 redmine/app/views/issues/change_status.rhtml delete mode 100644 redmine/app/views/issues/edit.rhtml delete mode 100644 redmine/app/views/issues/export_pdf.rfpdf delete mode 100644 redmine/app/views/issues/history.rhtml delete mode 100644 redmine/app/views/issues/show.rhtml delete mode 100644 redmine/app/views/layouts/base.rhtml delete mode 100644 redmine/app/views/mailer/_issue.rhtml delete mode 100644 redmine/app/views/mailer/issue_add_de.rhtml delete mode 100644 redmine/app/views/mailer/issue_add_en.rhtml delete mode 100644 redmine/app/views/mailer/issue_add_es.rhtml delete mode 100644 redmine/app/views/mailer/issue_add_fr.rhtml delete mode 100644 redmine/app/views/mailer/issue_edit_de.rhtml delete mode 100644 redmine/app/views/mailer/issue_edit_en.rhtml delete mode 100644 redmine/app/views/mailer/issue_edit_es.rhtml delete mode 100644 redmine/app/views/mailer/issue_edit_fr.rhtml delete mode 100644 redmine/app/views/mailer/lost_password_de.rhtml delete mode 100644 redmine/app/views/mailer/lost_password_en.rhtml delete mode 100644 redmine/app/views/mailer/lost_password_es.rhtml delete mode 100644 redmine/app/views/mailer/lost_password_fr.rhtml delete mode 100644 redmine/app/views/mailer/register_de.rhtml delete mode 100644 redmine/app/views/mailer/register_en.rhtml delete mode 100644 redmine/app/views/mailer/register_es.rhtml delete mode 100644 redmine/app/views/mailer/register_fr.rhtml delete mode 100644 redmine/app/views/my/_block.rhtml delete mode 100644 redmine/app/views/my/account.rhtml delete mode 100644 redmine/app/views/my/blocks/_calendar.rhtml delete mode 100644 redmine/app/views/my/blocks/_documents.rhtml delete mode 100644 redmine/app/views/my/blocks/_issues_assigned_to_me.rhtml delete mode 100644 redmine/app/views/my/blocks/_issues_reported_by_me.rhtml delete mode 100644 redmine/app/views/my/blocks/_latest_news.rhtml delete mode 100644 redmine/app/views/my/page.rhtml delete mode 100644 redmine/app/views/my/page_layout.rhtml delete mode 100644 redmine/app/views/news/_form.rhtml delete mode 100644 redmine/app/views/news/edit.rhtml delete mode 100644 redmine/app/views/news/show.rhtml delete mode 100644 redmine/app/views/projects/_form.rhtml delete mode 100644 redmine/app/views/projects/activity.rhtml delete mode 100644 redmine/app/views/projects/add.rhtml delete mode 100644 redmine/app/views/projects/add_document.rhtml delete mode 100644 redmine/app/views/projects/add_file.rhtml delete mode 100644 redmine/app/views/projects/add_issue.rhtml delete mode 100644 redmine/app/views/projects/add_news.rhtml delete mode 100644 redmine/app/views/projects/add_version.rhtml delete mode 100644 redmine/app/views/projects/calendar.rhtml delete mode 100644 redmine/app/views/projects/changelog.rhtml delete mode 100644 redmine/app/views/projects/destroy.rhtml delete mode 100644 redmine/app/views/projects/export_issues_pdf.rfpdf delete mode 100644 redmine/app/views/projects/gantt.rfpdf delete mode 100644 redmine/app/views/projects/gantt.rhtml delete mode 100644 redmine/app/views/projects/list.rhtml delete mode 100644 redmine/app/views/projects/list_documents.rhtml delete mode 100644 redmine/app/views/projects/list_files.rhtml delete mode 100644 redmine/app/views/projects/list_issues.rhtml delete mode 100644 redmine/app/views/projects/list_members.rhtml delete mode 100644 redmine/app/views/projects/list_news.rhtml delete mode 100644 redmine/app/views/projects/move_issues.rhtml delete mode 100644 redmine/app/views/projects/settings.rhtml delete mode 100644 redmine/app/views/projects/show.rhtml delete mode 100644 redmine/app/views/reports/_details.rhtml delete mode 100644 redmine/app/views/reports/_simple.rhtml delete mode 100644 redmine/app/views/reports/issue_report.rhtml delete mode 100644 redmine/app/views/reports/issue_report_details.rhtml delete mode 100644 redmine/app/views/roles/_form.rhtml delete mode 100644 redmine/app/views/roles/edit.rhtml delete mode 100644 redmine/app/views/roles/list.rhtml delete mode 100644 redmine/app/views/roles/new.rhtml delete mode 100644 redmine/app/views/roles/workflow.rhtml delete mode 100644 redmine/app/views/trackers/_form.rhtml delete mode 100644 redmine/app/views/trackers/edit.rhtml delete mode 100644 redmine/app/views/trackers/list.rhtml delete mode 100644 redmine/app/views/trackers/new.rhtml delete mode 100644 redmine/app/views/users/_form.rhtml delete mode 100644 redmine/app/views/users/add.rhtml delete mode 100644 redmine/app/views/users/edit.rhtml delete mode 100644 redmine/app/views/users/list.rhtml delete mode 100644 redmine/app/views/versions/_form.rhtml delete mode 100644 redmine/app/views/versions/edit.rhtml delete mode 100644 redmine/app/views/welcome/index.rhtml delete mode 100644 redmine/config/boot.rb delete mode 100644 redmine/config/config_custom.example.rb delete mode 100644 redmine/config/database.yml delete mode 100644 redmine/config/environment.rb delete mode 100644 redmine/config/environments/demo.rb delete mode 100644 redmine/config/environments/development.rb delete mode 100644 redmine/config/environments/development_oracle.rb delete mode 100644 redmine/config/environments/development_pgsql.rb delete mode 100644 redmine/config/environments/development_sqlserver.rb delete mode 100644 redmine/config/environments/production.rb delete mode 100644 redmine/config/environments/test.rb delete mode 100644 redmine/config/environments/test_oracle.rb delete mode 100644 redmine/config/environments/test_pgsql.rb delete mode 100644 redmine/config/environments/test_sqlserver.rb delete mode 100644 redmine/config/help.yml delete mode 100644 redmine/config/routes.rb delete mode 100644 redmine/db/migrate/001_setup.rb delete mode 100644 redmine/db/migrate/002_issue_move.rb delete mode 100644 redmine/db/migrate/003_issue_add_note.rb delete mode 100644 redmine/db/migrate/004_export_pdf.rb delete mode 100644 redmine/db/migrate/005_issue_start_date.rb delete mode 100644 redmine/db/migrate/006_calendar_and_activity.rb delete mode 100644 redmine/db/migrate/007_create_journals.rb delete mode 100644 redmine/db/migrate/008_create_user_preferences.rb delete mode 100644 redmine/db/migrate/009_add_hide_mail_pref.rb delete mode 100644 redmine/doc/CHANGELOG delete mode 100644 redmine/doc/COPYING delete mode 100644 redmine/doc/INSTALL delete mode 100644 redmine/doc/README delete mode 100644 redmine/doc/docbook/en/redmine-userdoc-en.xml delete mode 100644 redmine/doc/docbook/fr/redmine-userdoc-fr.xml delete mode 100644 redmine/files/delete.me delete mode 100644 redmine/lang/de.yml delete mode 100644 redmine/lang/en.yml delete mode 100644 redmine/lang/es.yml delete mode 100644 redmine/lang/fr.yml delete mode 100644 redmine/lib/tasks/extract_fixtures.rake delete mode 100644 redmine/lib/tasks/load_default_data.rake delete mode 100644 redmine/log/delete.me delete mode 100644 redmine/public/.htaccess delete mode 100644 redmine/public/404.html delete mode 100644 redmine/public/500.html delete mode 100644 redmine/public/dispatch.cgi delete mode 100644 redmine/public/dispatch.fcgi delete mode 100644 redmine/public/dispatch.rb delete mode 100644 redmine/public/favicon.ico delete mode 100644 redmine/public/images/add.png delete mode 100644 redmine/public/images/admin.png delete mode 100644 redmine/public/images/alert.png delete mode 100644 redmine/public/images/arrow_bw.png delete mode 100644 redmine/public/images/arrow_from.png delete mode 100644 redmine/public/images/arrow_to.png delete mode 100644 redmine/public/images/attachment.png delete mode 100644 redmine/public/images/bulletgreen.png delete mode 100644 redmine/public/images/bulletred.png delete mode 100644 redmine/public/images/calendar.png delete mode 100644 redmine/public/images/close.png delete mode 100644 redmine/public/images/close_hl.png delete mode 100644 redmine/public/images/delete.png delete mode 100644 redmine/public/images/details.png delete mode 100644 redmine/public/images/dir.png delete mode 100644 redmine/public/images/dir_new.png delete mode 100644 redmine/public/images/dir_open.png delete mode 100644 redmine/public/images/document.png delete mode 100644 redmine/public/images/edit_small.png delete mode 100644 redmine/public/images/file_new.png delete mode 100644 redmine/public/images/gantt.png delete mode 100644 redmine/public/images/help.png delete mode 100644 redmine/public/images/home.png delete mode 100644 redmine/public/images/issues.png delete mode 100644 redmine/public/images/jstoolbar/bt_br.png delete mode 100644 redmine/public/images/jstoolbar/bt_code.png delete mode 100644 redmine/public/images/jstoolbar/bt_del.png delete mode 100644 redmine/public/images/jstoolbar/bt_em.png delete mode 100644 redmine/public/images/jstoolbar/bt_ins.png delete mode 100644 redmine/public/images/jstoolbar/bt_link.png delete mode 100644 redmine/public/images/jstoolbar/bt_ol.png delete mode 100644 redmine/public/images/jstoolbar/bt_quote.png delete mode 100644 redmine/public/images/jstoolbar/bt_strong.png delete mode 100644 redmine/public/images/jstoolbar/bt_ul.png delete mode 100644 redmine/public/images/loading.gif delete mode 100644 redmine/public/images/locked.png delete mode 100644 redmine/public/images/login.png delete mode 100644 redmine/public/images/mailer.png delete mode 100644 redmine/public/images/notes.png delete mode 100644 redmine/public/images/options.png delete mode 100644 redmine/public/images/package.png delete mode 100644 redmine/public/images/projects.png delete mode 100644 redmine/public/images/rails.png delete mode 100644 redmine/public/images/rails_powered.png delete mode 100644 redmine/public/images/rails_small.png delete mode 100644 redmine/public/images/role.png delete mode 100644 redmine/public/images/rss.png delete mode 100644 redmine/public/images/sort_asc.png delete mode 100644 redmine/public/images/sort_desc.png delete mode 100644 redmine/public/images/tracker.png delete mode 100644 redmine/public/images/true.png delete mode 100644 redmine/public/images/user.png delete mode 100644 redmine/public/images/user_new.png delete mode 100644 redmine/public/images/user_page.png delete mode 100644 redmine/public/images/users.png delete mode 100644 redmine/public/images/workflow.png delete mode 100644 redmine/public/images/zoom_in.png delete mode 100644 redmine/public/images/zoom_in_g.png delete mode 100644 redmine/public/images/zoom_out.png delete mode 100644 redmine/public/images/zoom_out_g.png delete mode 100644 redmine/public/javascripts/application.js delete mode 100644 redmine/public/javascripts/calendar/calendar-setup.js delete mode 100644 redmine/public/javascripts/calendar/calendar.js delete mode 100644 redmine/public/javascripts/calendar/lang/calendar-de.js delete mode 100644 redmine/public/javascripts/calendar/lang/calendar-en.js delete mode 100644 redmine/public/javascripts/calendar/lang/calendar-es.js delete mode 100644 redmine/public/javascripts/calendar/lang/calendar-fr.js delete mode 100644 redmine/public/javascripts/controls.js delete mode 100644 redmine/public/javascripts/dragdrop.js delete mode 100644 redmine/public/javascripts/effects.js delete mode 100644 redmine/public/javascripts/jstoolbar.js delete mode 100644 redmine/public/javascripts/menu.js delete mode 100644 redmine/public/javascripts/prototype.js delete mode 100644 redmine/public/manual/en/ch01.html delete mode 100644 redmine/public/manual/en/ch01s01.html delete mode 100644 redmine/public/manual/en/ch01s02.html delete mode 100644 redmine/public/manual/en/ch01s03.html delete mode 100644 redmine/public/manual/en/ch01s04.html delete mode 100644 redmine/public/manual/en/ch01s05.html delete mode 100644 redmine/public/manual/en/ch01s06.html delete mode 100644 redmine/public/manual/en/ch01s07.html delete mode 100644 redmine/public/manual/en/ch01s08.html delete mode 100644 redmine/public/manual/en/ch01s09.html delete mode 100644 redmine/public/manual/en/ch01s10.html delete mode 100644 redmine/public/manual/en/ch02.html delete mode 100644 redmine/public/manual/en/ch02s01.html delete mode 100644 redmine/public/manual/en/ch02s02.html delete mode 100644 redmine/public/manual/en/ch02s03.html delete mode 100644 redmine/public/manual/en/ch02s04.html delete mode 100644 redmine/public/manual/en/ch02s05.html delete mode 100644 redmine/public/manual/en/ch02s06.html delete mode 100644 redmine/public/manual/en/ch02s07.html delete mode 100644 redmine/public/manual/en/ch02s08.html delete mode 100644 redmine/public/manual/en/html.css delete mode 100644 redmine/public/manual/en/index.html delete mode 100644 redmine/public/manual/en/resources/issues_list.png delete mode 100644 redmine/public/manual/en/resources/users_list.png delete mode 100644 redmine/public/manual/en/resources/workflow.png delete mode 100644 redmine/public/manual/fr/ch01.html delete mode 100644 redmine/public/manual/fr/ch01s01.html delete mode 100644 redmine/public/manual/fr/ch01s02.html delete mode 100644 redmine/public/manual/fr/ch01s03.html delete mode 100644 redmine/public/manual/fr/ch01s04.html delete mode 100644 redmine/public/manual/fr/ch01s05.html delete mode 100644 redmine/public/manual/fr/ch01s06.html delete mode 100644 redmine/public/manual/fr/ch01s07.html delete mode 100644 redmine/public/manual/fr/ch01s08.html delete mode 100644 redmine/public/manual/fr/ch01s09.html delete mode 100644 redmine/public/manual/fr/ch01s10.html delete mode 100644 redmine/public/manual/fr/ch02.html delete mode 100644 redmine/public/manual/fr/ch02s01.html delete mode 100644 redmine/public/manual/fr/ch02s02.html delete mode 100644 redmine/public/manual/fr/ch02s03.html delete mode 100644 redmine/public/manual/fr/ch02s04.html delete mode 100644 redmine/public/manual/fr/ch02s05.html delete mode 100644 redmine/public/manual/fr/ch02s06.html delete mode 100644 redmine/public/manual/fr/ch02s07.html delete mode 100644 redmine/public/manual/fr/ch02s08.html delete mode 100644 redmine/public/manual/fr/html.css delete mode 100644 redmine/public/manual/fr/index.html delete mode 100644 redmine/public/manual/fr/resources/issues_list.png delete mode 100644 redmine/public/manual/fr/resources/users_list.png delete mode 100644 redmine/public/manual/fr/resources/workflow.png delete mode 100644 redmine/public/robots.txt delete mode 100644 redmine/public/stylesheets/application.css delete mode 100644 redmine/public/stylesheets/calendar.css delete mode 100644 redmine/public/stylesheets/jstoolbar.css delete mode 100644 redmine/public/stylesheets/menu.css delete mode 100644 redmine/public/stylesheets/rails.css delete mode 100644 redmine/script/about delete mode 100644 redmine/script/breakpointer delete mode 100644 redmine/script/console delete mode 100644 redmine/script/destroy delete mode 100644 redmine/script/generate delete mode 100644 redmine/script/performance/benchmarker delete mode 100644 redmine/script/performance/profiler delete mode 100644 redmine/script/plugin delete mode 100644 redmine/script/process/reaper delete mode 100644 redmine/script/process/spawner delete mode 100644 redmine/script/process/spinner delete mode 100644 redmine/script/runner delete mode 100644 redmine/script/server delete mode 100644 redmine/test/fixtures/attachments.yml delete mode 100644 redmine/test/fixtures/auth_sources.yml delete mode 100644 redmine/test/fixtures/custom_fields.yml delete mode 100644 redmine/test/fixtures/custom_fields_projects.yml delete mode 100644 redmine/test/fixtures/custom_fields_trackers.yml delete mode 100644 redmine/test/fixtures/custom_values.yml delete mode 100644 redmine/test/fixtures/documents.yml delete mode 100644 redmine/test/fixtures/enumerations.yml delete mode 100644 redmine/test/fixtures/issue_categories.yml delete mode 100644 redmine/test/fixtures/issue_statuses.yml delete mode 100644 redmine/test/fixtures/issues.yml delete mode 100644 redmine/test/fixtures/members.yml delete mode 100644 redmine/test/fixtures/news.yml delete mode 100644 redmine/test/fixtures/permissions.yml delete mode 100644 redmine/test/fixtures/permissions_roles.yml delete mode 100644 redmine/test/fixtures/projects.yml delete mode 100644 redmine/test/fixtures/roles.yml delete mode 100644 redmine/test/fixtures/tokens.yml delete mode 100644 redmine/test/fixtures/trackers.yml delete mode 100644 redmine/test/fixtures/user_preferences.yml delete mode 100644 redmine/test/fixtures/users.yml delete mode 100644 redmine/test/fixtures/versions.yml delete mode 100644 redmine/test/fixtures/workflows.yml delete mode 100644 redmine/test/functional/my_controller_test.rb delete mode 100644 redmine/test/functional/projects_controller_test.rb delete mode 100644 redmine/test/integration/account_test.rb delete mode 100644 redmine/test/integration/admin_test.rb delete mode 100644 redmine/test/test_helper.rb delete mode 100644 redmine/test/unit/member_test.rb delete mode 100644 redmine/test/unit/project_test.rb delete mode 100644 redmine/test/unit/token_test.rb delete mode 100644 redmine/test/unit/user_preference_test.rb delete mode 100644 redmine/test/unit/user_test.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/CHANGELOG delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/MIT-LICENSE delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/README delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/Rakefile delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionController/Filters/ClassMethods.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionMailer/Base.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Base.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/DateHelper.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/InstanceTag.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Errors.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Validations/ClassMethods.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/ClassMethods.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/Helpers.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/InstanceMethods.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/created.rid delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/README.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-internal_rb.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails-text_rb.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails_rb.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-version_rb.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/fr_class_index.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/fr_file_index.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/fr_method_index.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/index.html delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/doc/rdoc-style.css delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/init.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc-config.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc-version.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/lib/gloc.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/tasks/gloc.rake delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/gloc_test.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/lang/en.yaml delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/lang/ja.yml delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/lang2/en.yml delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/lib/rails-string_ext.rb delete mode 100644 redmine/vendor/plugins/gloc-1.1.0/test/lib/rails-time_ext.rb delete mode 100644 redmine/vendor/plugins/rfpdf/CHANGELOG delete mode 100644 redmine/vendor/plugins/rfpdf/MIT-LICENSE delete mode 100644 redmine/vendor/plugins/rfpdf/README delete mode 100644 redmine/vendor/plugins/rfpdf/init.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/chinese.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/errors.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/japanese.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/korean.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/makefont.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb delete mode 100644 redmine/vendor/plugins/rfpdf/lib/rfpdf/view.rb delete mode 100644 redmine/vendor/plugins/rfpdf/test/test_helper.rb create mode 100644 script/about create mode 100644 script/breakpointer create mode 100644 script/console create mode 100644 script/destroy create mode 100644 script/generate create mode 100644 script/performance/benchmarker create mode 100644 script/performance/profiler create mode 100644 script/plugin create mode 100644 script/process/reaper create mode 100644 script/process/spawner create mode 100644 script/process/spinner create mode 100644 script/runner create mode 100644 script/server create mode 100644 test/fixtures/attachments.yml create mode 100644 test/fixtures/auth_sources.yml create mode 100644 test/fixtures/custom_fields.yml create mode 100644 test/fixtures/custom_fields_projects.yml create mode 100644 test/fixtures/custom_fields_trackers.yml create mode 100644 test/fixtures/custom_values.yml create mode 100644 test/fixtures/documents.yml create mode 100644 test/fixtures/enumerations.yml create mode 100644 test/fixtures/issue_categories.yml create mode 100644 test/fixtures/issue_statuses.yml create mode 100644 test/fixtures/issues.yml create mode 100644 test/fixtures/members.yml create mode 100644 test/fixtures/news.yml create mode 100644 test/fixtures/permissions.yml create mode 100644 test/fixtures/permissions_roles.yml create mode 100644 test/fixtures/projects.yml create mode 100644 test/fixtures/roles.yml create mode 100644 test/fixtures/tokens.yml create mode 100644 test/fixtures/trackers.yml create mode 100644 test/fixtures/user_preferences.yml create mode 100644 test/fixtures/users.yml create mode 100644 test/fixtures/versions.yml create mode 100644 test/fixtures/workflows.yml create mode 100644 test/functional/my_controller_test.rb create mode 100644 test/functional/projects_controller_test.rb create mode 100644 test/integration/account_test.rb create mode 100644 test/integration/admin_test.rb create mode 100644 test/test_helper.rb create mode 100644 test/unit/member_test.rb create mode 100644 test/unit/project_test.rb create mode 100644 test/unit/token_test.rb create mode 100644 test/unit/user_preference_test.rb create mode 100644 test/unit/user_test.rb create mode 100644 vendor/plugins/gloc-1.1.0/CHANGELOG create mode 100644 vendor/plugins/gloc-1.1.0/MIT-LICENSE create mode 100644 vendor/plugins/gloc-1.1.0/README create mode 100644 vendor/plugins/gloc-1.1.0/Rakefile create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/ActionController/Filters/ClassMethods.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/ActionMailer/Base.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Base.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/DateHelper.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/InstanceTag.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Errors.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Validations/ClassMethods.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/GLoc/ClassMethods.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/GLoc/Helpers.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/classes/GLoc/InstanceMethods.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/created.rid create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/README.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-internal_rb.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails-text_rb.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails_rb.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-version_rb.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/fr_class_index.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/fr_file_index.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/fr_method_index.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/index.html create mode 100644 vendor/plugins/gloc-1.1.0/doc/rdoc-style.css create mode 100644 vendor/plugins/gloc-1.1.0/init.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc-config.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc-version.rb create mode 100644 vendor/plugins/gloc-1.1.0/lib/gloc.rb create mode 100644 vendor/plugins/gloc-1.1.0/tasks/gloc.rake create mode 100644 vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb create mode 100644 vendor/plugins/gloc-1.1.0/test/gloc_test.rb create mode 100644 vendor/plugins/gloc-1.1.0/test/lang/en.yaml create mode 100644 vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml create mode 100644 vendor/plugins/gloc-1.1.0/test/lang/ja.yml create mode 100644 vendor/plugins/gloc-1.1.0/test/lang2/en.yml create mode 100644 vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml create mode 100644 vendor/plugins/gloc-1.1.0/test/lib/rails-string_ext.rb create mode 100644 vendor/plugins/gloc-1.1.0/test/lib/rails-time_ext.rb create mode 100644 vendor/plugins/rfpdf/CHANGELOG create mode 100644 vendor/plugins/rfpdf/MIT-LICENSE create mode 100644 vendor/plugins/rfpdf/README create mode 100644 vendor/plugins/rfpdf/init.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/chinese.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/errors.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/japanese.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/korean.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/makefont.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb create mode 100644 vendor/plugins/rfpdf/lib/rfpdf/view.rb create mode 100644 vendor/plugins/rfpdf/test/test_helper.rb diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..cffd19f0c --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake. + +require(File.join(File.dirname(__FILE__), 'config', 'boot')) + +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +require 'tasks/rails' \ No newline at end of file diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb new file mode 100644 index 000000000..ffd2419b3 --- /dev/null +++ b/app/controllers/account_controller.rb @@ -0,0 +1,131 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AccountController < ApplicationController + layout 'base' + helper :custom_fields + include CustomFieldsHelper + + # prevents login action to be filtered by check_if_login_required application scope filter + skip_before_filter :check_if_login_required, :only => [:login, :lost_password, :register] + before_filter :require_login, :except => [:show, :login, :lost_password, :register] + + # Show user's account + def show + @user = User.find(params[:id]) + @custom_values = @user.custom_values.find(:all, :include => :custom_field) + end + + # Login request and validation + def login + if request.get? + # Logout user + self.logged_in_user = nil + else + # Authenticate user + user = User.try_to_login(params[:login], params[:password]) + if user + self.logged_in_user = user + redirect_back_or_default :controller => 'my', :action => 'page' + else + flash.now[:notice] = l(:notice_account_invalid_creditentials) + end + end + end + + # Log out current user and redirect to welcome page + def logout + self.logged_in_user = nil + redirect_to :controller => '' + end + + # Enable user to choose a new password + def lost_password + if params[:token] + @token = Token.find_by_action_and_value("recovery", params[:token]) + redirect_to :controller => '' and return unless @token and !@token.expired? + @user = @token.user + if request.post? + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + if @user.save + @token.destroy + flash[:notice] = l(:notice_account_password_updated) + redirect_to :action => 'login' + return + end + end + render :template => "account/password_recovery" + return + else + if request.post? + user = User.find_by_mail(params[:mail]) + # user not found in db + flash.now[:notice] = l(:notice_account_unknown_email) and return unless user + # user uses an external authentification + flash.now[:notice] = l(:notice_can_t_change_password) and return if user.auth_source_id + # create a new token for password recovery + token = Token.new(:user => user, :action => "recovery") + if token.save + # send token to user via email + Mailer.set_language_if_valid(user.language) + Mailer.deliver_lost_password(token) + flash[:notice] = l(:notice_account_lost_email_sent) + redirect_to :action => 'login' + return + end + end + end + end + + # User self-registration + def register + redirect_to :controller => '' and return if $RDM_SELF_REGISTRATION == false + if params[:token] + token = Token.find_by_action_and_value("register", params[:token]) + redirect_to :controller => '' and return unless token and !token.expired? + user = token.user + redirect_to :controller => '' and return unless user.status == User::STATUS_REGISTERED + user.status = User::STATUS_ACTIVE + if user.save + token.destroy + flash[:notice] = l(:notice_account_activated) + redirect_to :action => 'login' + return + end + else + if request.get? + @user = User.new(:language => $RDM_DEFAULT_LANG) + @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) } + else + @user = User.new(params[:user]) + @user.admin = false + @user.login = params[:user][:login] + @user.status = User::STATUS_REGISTERED + @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] + @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) } + @user.custom_values = @custom_values + token = Token.new(:user => @user, :action => "register") + if @user.save and token.save + Mailer.set_language_if_valid(@user.language) + Mailer.deliver_register(token) + flash[:notice] = l(:notice_account_register_done) + redirect_to :controller => '' + end + end + end + end +end diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb new file mode 100644 index 000000000..2c9f67586 --- /dev/null +++ b/app/controllers/admin_controller.rb @@ -0,0 +1,56 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AdminController < ApplicationController + layout 'base' + before_filter :require_admin + + helper :sort + include SortHelper + + def index + end + + def projects + sort_init 'name', 'asc' + sort_update + @project_count = Project.count + @project_pages = Paginator.new self, @project_count, + 15, + @params['page'] + @projects = Project.find :all, :order => sort_clause, + :limit => @project_pages.items_per_page, + :offset => @project_pages.current.offset + + render :action => "projects", :layout => false if request.xhr? + end + + def mail_options + @actions = Permission.find(:all, :conditions => ["mail_option=?", true]) || [] + if request.post? + @actions.each { |a| + a.mail_enabled = (params[:action_ids] || []).include? a.id.to_s + a.save + } + flash.now[:notice] = l(:notice_successful_update) + end + end + + def info + @adapter_name = ActiveRecord::Base.connection.adapter_name + end +end diff --git a/app/controllers/application.rb b/app/controllers/application.rb new file mode 100644 index 000000000..3bebf4de5 --- /dev/null +++ b/app/controllers/application.rb @@ -0,0 +1,126 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ApplicationController < ActionController::Base + before_filter :check_if_login_required, :set_localization + + def logged_in_user=(user) + @logged_in_user = user + session[:user_id] = (user ? user.id : nil) + end + + def logged_in_user + if session[:user_id] + @logged_in_user ||= User.find(session[:user_id], :include => :memberships) + else + nil + end + end + + # check if login is globally required to access the application + def check_if_login_required + require_login if $RDM_LOGIN_REQUIRED + end + + def set_localization + lang = begin + if self.logged_in_user and self.logged_in_user.language and !self.logged_in_user.language.empty? and GLoc.valid_languages.include? self.logged_in_user.language.to_sym + self.logged_in_user.language + elsif request.env['HTTP_ACCEPT_LANGUAGE'] + accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first + if accept_lang and !accept_lang.empty? and GLoc.valid_languages.include? accept_lang.to_sym + accept_lang + end + end + rescue + nil + end || $RDM_DEFAULT_LANG + set_language_if_valid(lang) + end + + def require_login + unless self.logged_in_user + store_location + redirect_to :controller => "account", :action => "login" + return false + end + true + end + + def require_admin + return unless require_login + unless self.logged_in_user.admin? + render :nothing => true, :status => 403 + return false + end + true + end + + # authorizes the user for the requested action. + def authorize + # check if action is allowed on public projects + if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ @params[:controller], @params[:action] ] + return true + end + # if action is not public, force login + return unless require_login + # admin is always authorized + return true if self.logged_in_user.admin? + # if not admin, check membership permission + @user_membership ||= Member.find(:first, :conditions => ["user_id=? and project_id=?", self.logged_in_user.id, @project.id]) + if @user_membership and Permission.allowed_to_role( "%s/%s" % [ @params[:controller], @params[:action] ], @user_membership.role_id ) + return true + end + render :nothing => true, :status => 403 + false + end + + # store current uri in session. + # return to this location by calling redirect_back_or_default + def store_location + session[:return_to] = @request.request_uri + end + + # move to the last store_location call or to the passed default one + def redirect_back_or_default(default) + if session[:return_to].nil? + redirect_to default + else + redirect_to_url session[:return_to] + session[:return_to] = nil + end + end + + # qvalues http header parser + # code taken from webrick + def parse_qvalues(value) + tmp = [] + if value + parts = value.split(/,\s*/) + parts.each {|part| + if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) + val = m[1] + q = (m[2] or 1).to_f + tmp.push([val, q]) + end + } + tmp = tmp.sort_by{|val, q| -q} + tmp.collect!{|val, q| val} + end + return tmp + end +end \ No newline at end of file diff --git a/app/controllers/auth_sources_controller.rb b/app/controllers/auth_sources_controller.rb new file mode 100644 index 000000000..86b58d365 --- /dev/null +++ b/app/controllers/auth_sources_controller.rb @@ -0,0 +1,83 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AuthSourcesController < ApplicationController + layout 'base' + before_filter :require_admin + + def index + list + render :action => 'list' unless request.xhr? + end + + # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) + verify :method => :post, :only => [ :destroy, :create, :update ], + :redirect_to => { :action => :list } + + def list + @auth_source_pages, @auth_sources = paginate :auth_sources, :per_page => 10 + render :action => "list", :layout => false if request.xhr? + end + + def new + @auth_source = AuthSourceLdap.new + end + + def create + @auth_source = AuthSourceLdap.new(params[:auth_source]) + if @auth_source.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list' + else + render :action => 'new' + end + end + + def edit + @auth_source = AuthSource.find(params[:id]) + end + + def update + @auth_source = AuthSource.find(params[:id]) + if @auth_source.update_attributes(params[:auth_source]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'list' + else + render :action => 'edit' + end + end + + def test_connection + @auth_method = AuthSource.find(params[:id]) + begin + @auth_method.test_connection + rescue => text + flash[:notice] = text + end + flash[:notice] ||= l(:notice_successful_connection) + redirect_to :action => 'list' + end + + def destroy + @auth_source = AuthSource.find(params[:id]) + unless @auth_source.users.find(:first) + @auth_source.destroy + flash[:notice] = l(:notice_successful_delete) + end + redirect_to :action => 'list' + end +end diff --git a/app/controllers/custom_fields_controller.rb b/app/controllers/custom_fields_controller.rb new file mode 100644 index 000000000..bfa152fd1 --- /dev/null +++ b/app/controllers/custom_fields_controller.rb @@ -0,0 +1,71 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CustomFieldsController < ApplicationController + layout 'base' + before_filter :require_admin + + def index + list + render :action => 'list' unless request.xhr? + end + + def list + @custom_field_pages, @custom_fields = paginate :custom_fields, :per_page => 15 + render :action => "list", :layout => false if request.xhr? + end + + def new + case params[:type] + when "IssueCustomField" + @custom_field = IssueCustomField.new(params[:custom_field]) + @custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids] + when "UserCustomField" + @custom_field = UserCustomField.new(params[:custom_field]) + when "ProjectCustomField" + @custom_field = ProjectCustomField.new(params[:custom_field]) + else + redirect_to :action => 'list' + return + end + if request.post? and @custom_field.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list' + end + @trackers = Tracker.find(:all) + end + + def edit + @custom_field = CustomField.find(params[:id]) + if request.post? and @custom_field.update_attributes(params[:custom_field]) + if @custom_field.is_a? IssueCustomField + @custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : [] + end + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'list' + end + @trackers = Tracker.find(:all) + end + + def destroy + CustomField.find(params[:id]).destroy + redirect_to :action => 'list' + rescue + flash[:notice] = "Unable to delete custom field" + redirect_to :action => 'list' + end +end diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb new file mode 100644 index 000000000..3107b3ed1 --- /dev/null +++ b/app/controllers/documents_controller.rb @@ -0,0 +1,68 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class DocumentsController < ApplicationController + layout 'base' + before_filter :find_project, :authorize + + def show + @attachments = @document.attachments.find(:all, :order => "created_on DESC") + end + + def edit + @categories = Enumeration::get_values('DCAT') + if request.post? and @document.update_attributes(params[:document]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'show', :id => @document + end + end + + def destroy + @document.destroy + redirect_to :controller => 'projects', :action => 'list_documents', :id => @project + end + + def download + @attachment = @document.attachments.find(params[:attachment_id]) + @attachment.increment_download + send_file @attachment.diskfile, :filename => @attachment.filename + rescue + flash.now[:notice] = l(:notice_file_not_found) + render :text => "", :layout => true, :status => 404 + end + + def add_attachment + # Save the attachment + if params[:attachment][:file].size > 0 + @attachment = @document.attachments.build(params[:attachment]) + @attachment.author_id = self.logged_in_user.id if self.logged_in_user + @attachment.save + end + redirect_to :action => 'show', :id => @document + end + + def destroy_attachment + @document.attachments.find(params[:attachment_id]).destroy + redirect_to :action => 'show', :id => @document + end + +private + def find_project + @document = Document.find(params[:id]) + @project = @document.project + end +end diff --git a/app/controllers/enumerations_controller.rb b/app/controllers/enumerations_controller.rb new file mode 100644 index 000000000..8e5be0a20 --- /dev/null +++ b/app/controllers/enumerations_controller.rb @@ -0,0 +1,70 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class EnumerationsController < ApplicationController + layout 'base' + before_filter :require_admin + + def index + list + render :action => 'list' + end + + # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) + verify :method => :post, :only => [ :destroy, :create, :update ], + :redirect_to => { :action => :list } + + def list + end + + def new + @enumeration = Enumeration.new(:opt => params[:opt]) + end + + def create + @enumeration = Enumeration.new(params[:enumeration]) + if @enumeration.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list', :opt => @enumeration.opt + else + render :action => 'new' + end + end + + def edit + @enumeration = Enumeration.find(params[:id]) + end + + def update + @enumeration = Enumeration.find(params[:id]) + if @enumeration.update_attributes(params[:enumeration]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'list', :opt => @enumeration.opt + else + render :action => 'edit' + end + end + + def destroy + Enumeration.find(params[:id]).destroy + flash[:notice] = l(:notice_successful_delete) + redirect_to :action => 'list' + rescue + flash[:notice] = "Unable to delete enumeration" + redirect_to :action => 'list' + end +end diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb new file mode 100644 index 000000000..32d822993 --- /dev/null +++ b/app/controllers/help_controller.rb @@ -0,0 +1,47 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class HelpController < ApplicationController + + skip_before_filter :check_if_login_required + before_filter :load_help_config + + # displays help page for the requested controller/action + def index + # select help page to display + if @params[:ctrl] and @help_config['pages'][@params[:ctrl]] + if @params[:page] and @help_config['pages'][@params[:ctrl]][@params[:page]] + template = @help_config['pages'][@params[:ctrl]][@params[:page]] + else + template = @help_config['pages'][@params[:ctrl]]['index'] + end + end + # choose language according to available help translations + lang = (@help_config['langs'].include? current_language.to_s) ? current_language.to_s : @help_config['langs'].first + + if template + redirect_to "/manual/#{lang}/#{template}" + else + redirect_to "/manual/#{lang}/" + end + end + +private + def load_help_config + @help_config = YAML::load(File.open("#{RAILS_ROOT}/config/help.yml")) + end +end diff --git a/app/controllers/issue_categories_controller.rb b/app/controllers/issue_categories_controller.rb new file mode 100644 index 000000000..965a15e78 --- /dev/null +++ b/app/controllers/issue_categories_controller.rb @@ -0,0 +1,42 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueCategoriesController < ApplicationController + layout 'base' + before_filter :find_project, :authorize + + def edit + if request.post? and @category.update_attributes(params[:category]) + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'projects', :action => 'settings', :id => @project + end + end + + def destroy + @category.destroy + redirect_to :controller => 'projects', :action => 'settings', :id => @project + rescue + flash[:notice] = "Categorie can't be deleted" + redirect_to :controller => 'projects', :action => 'settings', :id => @project + end + +private + def find_project + @category = IssueCategory.find(params[:id]) + @project = @category.project + end +end diff --git a/app/controllers/issue_statuses_controller.rb b/app/controllers/issue_statuses_controller.rb new file mode 100644 index 000000000..18ca9c76d --- /dev/null +++ b/app/controllers/issue_statuses_controller.rb @@ -0,0 +1,69 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueStatusesController < ApplicationController + layout 'base' + before_filter :require_admin + + def index + list + render :action => 'list' unless request.xhr? + end + + def list + @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 10 + render :action => "list", :layout => false if request.xhr? + end + + def new + @issue_status = IssueStatus.new + end + + def create + @issue_status = IssueStatus.new(params[:issue_status]) + if @issue_status.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list' + else + render :action => 'new' + end + end + + def edit + @issue_status = IssueStatus.find(params[:id]) + end + + def update + @issue_status = IssueStatus.find(params[:id]) + if @issue_status.update_attributes(params[:issue_status]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'list' + else + render :action => 'edit' + end + end + + def destroy + IssueStatus.find(params[:id]).destroy + redirect_to :action => 'list' + rescue + flash[:notice] = "Unable to delete issue status" + redirect_to :action => 'list' + end + + +end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb new file mode 100644 index 000000000..94e036ab3 --- /dev/null +++ b/app/controllers/issues_controller.rb @@ -0,0 +1,145 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssuesController < ApplicationController + layout 'base', :except => :export_pdf + before_filter :find_project, :authorize + + helper :custom_fields + include CustomFieldsHelper + helper :ifpdf + include IfpdfHelper + + def show + @status_options = @issue.status.workflows.find(:all, :include => :new_status, :conditions => ["role_id=? and tracker_id=?", self.logged_in_user.role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if self.logged_in_user + @custom_values = @issue.custom_values.find(:all, :include => :custom_field) + @journals_count = @issue.journals.count + @journals = @issue.journals.find(:all, :include => [:user, :details], :limit => 15, :order => "journals.created_on desc") + end + + def history + @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "journals.created_on desc") + @journals_count = @journals.length + end + + def export_pdf + @custom_values = @issue.custom_values.find(:all, :include => :custom_field) + @options_for_rfpdf ||= {} + @options_for_rfpdf[:file_name] = "#{@project.name}_#{@issue.long_id}.pdf" + end + + def edit + @priorities = Enumeration::get_values('IPRI') + if request.get? + @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) } + else + begin + @issue.init_journal(self.logged_in_user) + # Retrieve custom fields and values + @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) } + @issue.custom_values = @custom_values + @issue.attributes = params[:issue] + if @issue.save + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'show', :id => @issue + end + rescue ActiveRecord::StaleObjectError + # Optimistic locking exception + flash[:notice] = l(:notice_locking_conflict) + end + end + end + + def add_note + unless params[:notes].empty? + journal = @issue.init_journal(self.logged_in_user, params[:notes]) + #@history = @issue.histories.build(params[:history]) + #@history.author_id = self.logged_in_user.id if self.logged_in_user + #@history.status = @issue.status + if @issue.save + flash[:notice] = l(:notice_successful_update) + Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled? + redirect_to :action => 'show', :id => @issue + return + end + end + show + render :action => 'show' + end + + def change_status + #@history = @issue.histories.build(params[:history]) + @status_options = @issue.status.workflows.find(:all, :conditions => ["role_id=? and tracker_id=?", self.logged_in_user.role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if self.logged_in_user + @new_status = IssueStatus.find(params[:new_status_id]) + if params[:confirm] + begin + #@history.author_id = self.logged_in_user.id if self.logged_in_user + #@issue.status = @history.status + #@issue.fixed_version_id = (params[:issue][:fixed_version_id]) + #@issue.assigned_to_id = (params[:issue][:assigned_to_id]) + #@issue.done_ratio = (params[:issue][:done_ratio]) + #@issue.lock_version = (params[:issue][:lock_version]) + journal = @issue.init_journal(self.logged_in_user, params[:notes]) + @issue.status = @new_status + if @issue.update_attributes(params[:issue]) + flash[:notice] = l(:notice_successful_update) + Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled? + redirect_to :action => 'show', :id => @issue + end + rescue ActiveRecord::StaleObjectError + # Optimistic locking exception + flash[:notice] = l(:notice_locking_conflict) + end + end + @assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user } + end + + def destroy + @issue.destroy + redirect_to :controller => 'projects', :action => 'list_issues', :id => @project + end + + def add_attachment + # Save the attachments + params[:attachments].each { |a| + @attachment = @issue.attachments.build(:file => a, :author => self.logged_in_user) unless a.size == 0 + @attachment.save + } if params[:attachments] and params[:attachments].is_a? Array + redirect_to :action => 'show', :id => @issue + end + + def destroy_attachment + @issue.attachments.find(params[:attachment_id]).destroy + redirect_to :action => 'show', :id => @issue + end + + # Send the file in stream mode + def download + @attachment = @issue.attachments.find(params[:attachment_id]) + send_file @attachment.diskfile, :filename => @attachment.filename + rescue + flash.now[:notice] = l(:notice_file_not_found) + render :text => "", :layout => true, :status => 404 + end + +private + def find_project + @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) + @project = @issue.project + @html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}" + end +end diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb new file mode 100644 index 000000000..be3f717d1 --- /dev/null +++ b/app/controllers/members_controller.rb @@ -0,0 +1,41 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MembersController < ApplicationController + layout 'base' + before_filter :find_project, :authorize + + def edit + if request.post? and @member.update_attributes(params[:member]) + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'projects', :action => 'settings', :id => @project + end + end + + def destroy + @member.destroy + flash[:notice] = l(:notice_successful_delete) + redirect_to :controller => 'projects', :action => 'settings', :id => @project + end + +private + def find_project + @member = Member.find(params[:id]) + @project = @member.project + end + +end diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb new file mode 100644 index 000000000..ff12b74d7 --- /dev/null +++ b/app/controllers/my_controller.rb @@ -0,0 +1,131 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MyController < ApplicationController + layout 'base' + before_filter :require_login + + BLOCKS = { 'issues_assigned_to_me' => :label_assigned_to_me_issues, + 'issues_reported_by_me' => :label_reported_issues, + 'latest_news' => :label_news_latest, + 'calendar' => :label_calendar, + 'documents' => :label_document_plural + }.freeze + + verify :xhr => true, + :session => :page_layout, + :only => [:add_block, :remove_block, :order_blocks] + + def index + page + render :action => 'page' + end + + # Show user's page + def page + @user = self.logged_in_user + @blocks = @user.pref[:my_page_layout] || { 'left' => ['issues_assigned_to_me'], 'right' => ['issues_reported_by_me'] } + end + + # Edit user's account + def account + @user = self.logged_in_user + @pref = @user.pref + @user.attributes = params[:user] + @user.pref.attributes = params[:pref] + if request.post? and @user.save + set_localization + flash.now[:notice] = l(:notice_account_updated) + self.logged_in_user.reload + end + end + + # Change user's password + def change_password + @user = self.logged_in_user + flash[:notice] = l(:notice_can_t_change_password) and redirect_to :action => 'account' and return if @user.auth_source_id + if @user.check_password?(@params[:password]) + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + if @user.save + flash[:notice] = l(:notice_account_password_updated) + else + render :action => 'account' + return + end + else + flash[:notice] = l(:notice_account_wrong_password) + end + redirect_to :action => 'account' + end + + # User's page layout configuration + def page_layout + @user = self.logged_in_user + @blocks = @user.pref[:my_page_layout] || { 'left' => ['issues_assigned_to_me'], 'right' => ['issues_reported_by_me'] } + session[:page_layout] = @blocks + %w(top left right).each {|f| session[:page_layout][f] ||= [] } + @block_options = [] + BLOCKS.each {|k, v| @block_options << [l(v), k]} + end + + # Add a block to user's page + # The block is added on top of the page + # params[:block] : id of the block to add + def add_block + @user = self.logged_in_user + block = params[:block] + # remove if already present in a group + %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block } + # add it on top + session[:page_layout]['top'].unshift block + render :partial => "block", :locals => {:user => @user, :block_name => block} + end + + # Remove a block to user's page + # params[:block] : id of the block to remove + def remove_block + block = params[:block] + # remove block in all groups + %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block } + render :nothing => true + end + + # Change blocks order on user's page + # params[:group] : group to order (top, left or right) + # params[:list-(top|left|right)] : array of block ids of the group + def order_blocks + group = params[:group] + group_items = params["list-#{group}"] + if group_items and group_items.is_a? Array + # remove group blocks if they are presents in other groups + %w(top left right).each {|f| + session[:page_layout][f] = (session[:page_layout][f] || []) - group_items + } + session[:page_layout][group] = group_items + end + render :nothing => true + end + + # Save user's page layout + def page_layout_save + @user = self.logged_in_user + @user.pref[:my_page_layout] = session[:page_layout] if session[:page_layout] + @user.pref.save + session[:page_layout] = nil + redirect_to :action => 'page' + end +end diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb new file mode 100644 index 000000000..b50b59dc0 --- /dev/null +++ b/app/controllers/news_controller.rb @@ -0,0 +1,42 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class NewsController < ApplicationController + layout 'base' + before_filter :find_project, :authorize + + def show + end + + def edit + if request.post? and @news.update_attributes(params[:news]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'show', :id => @news + end + end + + def destroy + @news.destroy + redirect_to :controller => 'projects', :action => 'list_news', :id => @project + end + +private + def find_project + @news = News.find(params[:id]) + @project = @news.project + end +end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb new file mode 100644 index 000000000..c968800c3 --- /dev/null +++ b/app/controllers/projects_controller.rb @@ -0,0 +1,469 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ProjectsController < ApplicationController + layout 'base', :except => :export_issues_pdf + before_filter :find_project, :authorize, :except => [ :index, :list, :add ] + before_filter :require_admin, :only => [ :add, :destroy ] + + helper :sort + include SortHelper + helper :search_filter + include SearchFilterHelper + helper :custom_fields + include CustomFieldsHelper + helper :ifpdf + include IfpdfHelper + helper IssuesHelper + + def index + list + render :action => 'list' unless request.xhr? + end + + # Lists public projects + def list + sort_init 'name', 'asc' + sort_update + @project_count = Project.count(["is_public=?", true]) + @project_pages = Paginator.new self, @project_count, + 15, + @params['page'] + @projects = Project.find :all, :order => sort_clause, + :conditions => ["is_public=?", true], + :limit => @project_pages.items_per_page, + :offset => @project_pages.current.offset + + render :action => "list", :layout => false if request.xhr? + end + + # Add a new project + def add + @custom_fields = IssueCustomField.find(:all) + @root_projects = Project.find(:all, :conditions => "parent_id is null") + @project = Project.new(params[:project]) + if request.get? + @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project) } + else + @project.custom_fields = CustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids] + @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) } + @project.custom_values = @custom_values + if @project.save + flash[:notice] = l(:notice_successful_create) + redirect_to :controller => 'admin', :action => 'projects' + end + end + end + + # Show @project + def show + @custom_values = @project.custom_values.find(:all, :include => :custom_field) + @members = @project.members.find(:all, :include => [:user, :role]) + @subprojects = @project.children if @project.children_count > 0 + @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC") + @trackers = Tracker.find(:all) + end + + def settings + @root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id]) + @custom_fields = IssueCustomField::find_all + @issue_category ||= IssueCategory.new + @member ||= @project.members.new + @roles = Role.find_all + @users = User.find_all - @project.members.find(:all, :include => :user).collect{|m| m.user } + @custom_values ||= ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) } + end + + # Edit @project + def edit + if request.post? + @project.custom_fields = IssueCustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids] + if params[:custom_fields] + @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) } + @project.custom_values = @custom_values + end + if @project.update_attributes(params[:project]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'settings', :id => @project + else + settings + render :action => 'settings' + end + end + end + + # Delete @project + def destroy + if request.post? and params[:confirm] + @project.destroy + redirect_to :controller => 'admin', :action => 'projects' + end + end + + # Add a new issue category to @project + def add_issue_category + if request.post? + @issue_category = @project.issue_categories.build(params[:issue_category]) + if @issue_category.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'settings', :id => @project + else + settings + render :action => 'settings' + end + end + end + + # Add a new version to @project + def add_version + @version = @project.versions.build(params[:version]) + if request.post? and @version.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'settings', :id => @project + end + end + + # Add a new member to @project + def add_member + @member = @project.members.build(params[:member]) + if request.post? + if @member.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'settings', :id => @project + else + settings + render :action => 'settings' + end + end + end + + # Show members list of @project + def list_members + @members = @project.members + end + + # Add a new document to @project + def add_document + @categories = Enumeration::get_values('DCAT') + @document = @project.documents.build(params[:document]) + if request.post? + # Save the attachment + if params[:attachment][:file].size > 0 + @attachment = @document.attachments.build(params[:attachment]) + @attachment.author_id = self.logged_in_user.id if self.logged_in_user + end + if @document.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list_documents', :id => @project + end + end + end + + # Show documents list of @project + def list_documents + @documents = @project.documents + end + + # Add a new issue to @project + def add_issue + @tracker = Tracker.find(params[:tracker_id]) + @priorities = Enumeration::get_values('IPRI') + @issue = Issue.new(:project => @project, :tracker => @tracker) + if request.get? + @issue.start_date = Date.today + @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) } + else + @issue.attributes = params[:issue] + @issue.author_id = self.logged_in_user.id if self.logged_in_user + # Multiple file upload + params[:attachments].each { |a| + @attachment = @issue.attachments.build(:file => a, :author => self.logged_in_user) unless a.size == 0 + } if params[:attachments] and params[:attachments].is_a? Array + @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) } + @issue.custom_values = @custom_values + if @issue.save + flash[:notice] = l(:notice_successful_create) + Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled? + redirect_to :action => 'list_issues', :id => @project + end + end + end + + # Show filtered/sorted issues list of @project + def list_issues + sort_init 'issues.id', 'desc' + sort_update + + search_filter_init_list_issues + search_filter_update if params[:set_filter] + + @results_per_page_options = [ 15, 25, 50, 100 ] + if params[:per_page] and @results_per_page_options.include? params[:per_page].to_i + @results_per_page = params[:per_page].to_i + session[:results_per_page] = @results_per_page + else + @results_per_page = session[:results_per_page] || 25 + end + + @issue_count = Issue.count(:include => [:status, :project], :conditions => search_filter_clause) + @issue_pages = Paginator.new self, @issue_count, @results_per_page, @params['page'] + @issues = Issue.find :all, :order => sort_clause, + :include => [ :author, :status, :tracker, :project ], + :conditions => search_filter_clause, + :limit => @issue_pages.items_per_page, + :offset => @issue_pages.current.offset + + render :layout => false if request.xhr? + end + + # Export filtered/sorted issues list to CSV + def export_issues_csv + sort_init 'issues.id', 'desc' + sort_update + + search_filter_init_list_issues + + @issues = Issue.find :all, :order => sort_clause, + :include => [ :author, :status, :tracker, :project, :custom_values ], + :conditions => search_filter_clause + + ic = Iconv.new('ISO-8859-1', 'UTF-8') + export = StringIO.new + CSV::Writer.generate(export, l(:general_csv_separator)) do |csv| + # csv header fields + headers = [ "#", l(:field_status), l(:field_tracker), l(:field_subject), l(:field_author), l(:field_created_on), l(:field_updated_on) ] + for custom_field in @project.all_custom_fields + headers << custom_field.name + end + csv << headers.collect {|c| ic.iconv(c) } + # csv lines + @issues.each do |issue| + fields = [issue.id, issue.status.name, issue.tracker.name, issue.subject, issue.author.display_name, l_datetime(issue.created_on), l_datetime(issue.updated_on)] + for custom_field in @project.all_custom_fields + fields << (show_value issue.custom_value_for(custom_field)) + end + csv << fields.collect {|c| ic.iconv(c.to_s) } + end + end + export.rewind + send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv') + end + + # Export filtered/sorted issues to PDF + def export_issues_pdf + sort_init 'issues.id', 'desc' + sort_update + + search_filter_init_list_issues + + @issues = Issue.find :all, :order => sort_clause, + :include => [ :author, :status, :tracker, :project, :custom_values ], + :conditions => search_filter_clause + + @options_for_rfpdf ||= {} + @options_for_rfpdf[:file_name] = "export.pdf" + end + + def move_issues + @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids] + redirect_to :action => 'list_issues', :id => @project and return unless @issues + @projects = [] + # find projects to which the user is allowed to move the issue + @logged_in_user.memberships.each {|m| @projects << m.project if Permission.allowed_to_role("projects/move_issues", m.role_id)} + # issue can be moved to any tracker + @trackers = Tracker.find(:all) + if request.post? and params[:new_project_id] and params[:new_tracker_id] + new_project = Project.find(params[:new_project_id]) + new_tracker = Tracker.find(params[:new_tracker_id]) + @issues.each { |i| + # category is project dependent + i.category = nil unless i.project_id == new_project.id + # move the issue + i.project = new_project + i.tracker = new_tracker + i.save + } + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'list_issues', :id => @project + end + end + + # Add a news to @project + def add_news + @news = News.new(:project => @project) + if request.post? + @news.attributes = params[:news] + @news.author_id = self.logged_in_user.id if self.logged_in_user + if @news.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list_news', :id => @project + end + end + end + + # Show news list of @project + def list_news + @news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "news.created_on DESC" + render :action => "list_news", :layout => false if request.xhr? + end + + def add_file + if request.post? + # Save the attachment + if params[:attachment][:file].size > 0 + @attachment = @project.versions.find(params[:version_id]).attachments.build(params[:attachment]) + @attachment.author_id = self.logged_in_user.id if self.logged_in_user + if @attachment.save + flash[:notice] = l(:notice_successful_create) + redirect_to :controller => 'projects', :action => 'list_files', :id => @project + end + end + end + @versions = @project.versions + end + + def list_files + @versions = @project.versions + end + + # Show changelog for @project + def changelog + @trackers = Tracker.find(:all, :conditions => ["is_in_chlog=?", true]) + if request.get? + @selected_tracker_ids = @trackers.collect {|t| t.id.to_s } + else + @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array + end + @selected_tracker_ids ||= [] + @fixed_issues = @project.issues.find(:all, + :include => [ :fixed_version, :status, :tracker ], + :conditions => [ "issue_statuses.is_closed=? and issues.tracker_id in (#{@selected_tracker_ids.join(',')}) and issues.fixed_version_id is not null", true], + :order => "versions.effective_date DESC, issues.id DESC" + ) unless @selected_tracker_ids.empty? + @fixed_issues ||= [] + end + + def activity + if params[:year] and params[:year].to_i > 1900 + @year = params[:year].to_i + if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 + @month = params[:month].to_i + end + end + @year ||= Date.today.year + @month ||= Date.today.month + + @date_from = Date.civil(@year, @month, 1) + @date_to = (@date_from >> 1)-1 + + @events_by_day = {} + + unless params[:show_issues] == "0" + @project.issues.find(:all, :include => [:author, :status], :conditions => ["issues.created_on>=? and issues.created_on<=?", @date_from, @date_to] ).each { |i| + @events_by_day[i.created_on.to_date] ||= [] + @events_by_day[i.created_on.to_date] << i + } + @show_issues = 1 + end + + unless params[:show_news] == "0" + @project.news.find(:all, :conditions => ["news.created_on>=? and news.created_on<=?", @date_from, @date_to] ).each { |i| + @events_by_day[i.created_on.to_date] ||= [] + @events_by_day[i.created_on.to_date] << i + } + @show_news = 1 + end + + unless params[:show_files] == "0" + Attachment.find(:all, :joins => "LEFT JOIN versions ON versions.id = attachments.container_id", :conditions => ["attachments.container_type='Version' and versions.project_id=? and attachments.created_on>=? and attachments.created_on<=?", @project.id, @date_from, @date_to] ).each { |i| + @events_by_day[i.created_on.to_date] ||= [] + @events_by_day[i.created_on.to_date] << i + } + @show_files = 1 + end + + unless params[:show_documents] == "0" + Attachment.find(:all, :joins => "LEFT JOIN documents ON documents.id = attachments.container_id", :conditions => ["attachments.container_type='Document' and documents.project_id=? and attachments.created_on>=? and attachments.created_on<=?", @project.id, @date_from, @date_to] ).each { |i| + @events_by_day[i.created_on.to_date] ||= [] + @events_by_day[i.created_on.to_date] << i + } + @show_documents = 1 + end + + end + + def calendar + if params[:year] and params[:year].to_i > 1900 + @year = params[:year].to_i + if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 + @month = params[:month].to_i + end + end + @year ||= Date.today.year + @month ||= Date.today.month + + @date_from = Date.civil(@year, @month, 1) + @date_to = (@date_from >> 1)-1 + # start on monday + @date_from = @date_from - (@date_from.cwday-1) + # finish on sunday + @date_to = @date_to + (7-@date_to.cwday) + + @issues = @project.issues.find(:all, :include => :tracker, :conditions => ["((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", @date_from, @date_to, @date_from, @date_to]) + render :layout => false if request.xhr? + end + + def gantt + if params[:year] and params[:year].to_i >0 + @year_from = params[:year].to_i + if params[:month] and params[:month].to_i >=1 and params[:month].to_i <= 12 + @month_from = params[:month].to_i + else + @month_from = 1 + end + else + @month_from ||= (Date.today << 1).month + @year_from ||= (Date.today << 1).year + end + + @zoom = (params[:zoom].to_i > 0 and params[:zoom].to_i < 5) ? params[:zoom].to_i : 2 + @months = (params[:months].to_i > 0 and params[:months].to_i < 25) ? params[:months].to_i : 6 + + @date_from = Date.civil(@year_from, @month_from, 1) + @date_to = (@date_from >> @months) - 1 + @issues = @project.issues.find(:all, :order => "start_date, due_date", :conditions => ["(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date?)) and start_date is not null and due_date is not null)", @date_from, @date_to, @date_from, @date_to, @date_from, @date_to]) + + if params[:output]=='pdf' + @options_for_rfpdf ||= {} + @options_for_rfpdf[:file_name] = "gantt.pdf" + render :template => "projects/gantt.rfpdf", :layout => false + else + render :template => "projects/gantt.rhtml" + end + end + +private + # Find project of id params[:id] + # if not found, redirect to project list + # Used as a before_filter + def find_project + @project = Project.find(params[:id]) + @html_title = @project.name + rescue + redirect_to :action => 'list' + end +end diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb new file mode 100644 index 000000000..985c937fc --- /dev/null +++ b/app/controllers/reports_controller.rb @@ -0,0 +1,164 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ReportsController < ApplicationController + layout 'base' + before_filter :find_project, :authorize + + def issue_report + @statuses = IssueStatus.find_all + + case params[:detail] + when "tracker" + @field = "tracker_id" + @rows = Tracker.find_all + @data = issues_by_tracker + @report_title = l(:field_tracker) + render :template => "reports/issue_report_details" + when "priority" + @field = "priority_id" + @rows = Enumeration::get_values('IPRI') + @data = issues_by_priority + @report_title = l(:field_priority) + render :template => "reports/issue_report_details" + when "category" + @field = "category_id" + @rows = @project.issue_categories + @data = issues_by_category + @report_title = l(:field_category) + render :template => "reports/issue_report_details" + when "author" + @field = "author_id" + @rows = @project.members.collect { |m| m.user } + @data = issues_by_author + @report_title = l(:field_author) + render :template => "reports/issue_report_details" + else + @trackers = Tracker.find(:all) + @priorities = Enumeration::get_values('IPRI') + @categories = @project.issue_categories + @authors = @project.members.collect { |m| m.user } + issues_by_tracker + issues_by_priority + issues_by_category + issues_by_author + render :template => "reports/issue_report" + end + end + + def delays + @trackers = Tracker.find(:all) + if request.get? + @selected_tracker_ids = @trackers.collect {|t| t.id.to_s } + else + @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array + end + @selected_tracker_ids ||= [] + @raw = + ActiveRecord::Base.connection.select_all("SELECT datediff( a.created_on, b.created_on ) as delay, count(a.id) as total + FROM issue_histories a, issue_histories b, issues i + WHERE a.status_id =5 + AND a.issue_id = b.issue_id + AND a.issue_id = i.id + AND i.tracker_id in (#{@selected_tracker_ids.join(',')}) + AND b.id = ( + SELECT min( c.id ) + FROM issue_histories c + WHERE b.issue_id = c.issue_id ) + GROUP BY delay") unless @selected_tracker_ids.empty? + @raw ||=[] + + @x_from = 0 + @x_to = 0 + @y_from = 0 + @y_to = 0 + @sum_total = 0 + @sum_delay = 0 + @raw.each do |r| + @x_to = [r['delay'].to_i, @x_to].max + @y_to = [r['total'].to_i, @y_to].max + @sum_total = @sum_total + r['total'].to_i + @sum_delay = @sum_delay + r['total'].to_i * r['delay'].to_i + end + end + +private + # Find project of id params[:id] + def find_project + @project = Project.find(params[:id]) + end + + def issues_by_tracker + @issues_by_tracker ||= + ActiveRecord::Base.connection.select_all("select s.id as status_id, + s.is_closed as closed, + t.id as tracker_id, + count(i.id) as total + from + issues i, issue_statuses s, trackers t + where + i.status_id=s.id + and i.tracker_id=t.id + and i.project_id=#{@project.id} + group by s.id, s.is_closed, t.id") + end + + def issues_by_priority + @issues_by_priority ||= + ActiveRecord::Base.connection.select_all("select s.id as status_id, + s.is_closed as closed, + p.id as priority_id, + count(i.id) as total + from + issues i, issue_statuses s, enumerations p + where + i.status_id=s.id + and i.priority_id=p.id + and i.project_id=#{@project.id} + group by s.id, s.is_closed, p.id") + end + + def issues_by_category + @issues_by_category ||= + ActiveRecord::Base.connection.select_all("select s.id as status_id, + s.is_closed as closed, + c.id as category_id, + count(i.id) as total + from + issues i, issue_statuses s, issue_categories c + where + i.status_id=s.id + and i.category_id=c.id + and i.project_id=#{@project.id} + group by s.id, s.is_closed, c.id") + end + + def issues_by_author + @issues_by_author ||= + ActiveRecord::Base.connection.select_all("select s.id as status_id, + s.is_closed as closed, + a.id as author_id, + count(i.id) as total + from + issues i, issue_statuses s, users a + where + i.status_id=s.id + and i.author_id=a.id + and i.project_id=#{@project.id} + group by s.id, s.is_closed, a.id") + end +end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb new file mode 100644 index 000000000..e16127b61 --- /dev/null +++ b/app/controllers/roles_controller.rb @@ -0,0 +1,84 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class RolesController < ApplicationController + layout 'base' + before_filter :require_admin + + def index + list + render :action => 'list' unless request.xhr? + end + + def list + @role_pages, @roles = paginate :roles, :per_page => 10 + render :action => "list", :layout => false if request.xhr? + end + + def new + @role = Role.new(params[:role]) + if request.post? + @role.permissions = Permission.find(@params[:permission_ids]) if @params[:permission_ids] + if @role.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list' + end + end + @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC') + end + + def edit + @role = Role.find(params[:id]) + if request.post? and @role.update_attributes(params[:role]) + @role.permissions = Permission.find(@params[:permission_ids] || []) + Permission.allowed_to_role_expired + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'list' + end + @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC') + end + + def destroy + @role = Role.find(params[:id]) + unless @role.members.empty? + flash[:notice] = 'Some members have this role. Can\'t delete it.' + else + @role.destroy + end + redirect_to :action => 'list' + end + + def workflow + @role = Role.find_by_id(params[:role_id]) + @tracker = Tracker.find_by_id(params[:tracker_id]) + + if request.post? + Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) + (params[:issue_status] || []).each { |old, news| + news.each { |new| + @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new) + } + } + if @role.save + flash[:notice] = l(:notice_successful_update) + end + end + @roles = Role.find_all + @trackers = Tracker.find_all + @statuses = IssueStatus.find(:all, :include => :workflows) + end +end diff --git a/app/controllers/trackers_controller.rb b/app/controllers/trackers_controller.rb new file mode 100644 index 000000000..bbfb4f48b --- /dev/null +++ b/app/controllers/trackers_controller.rb @@ -0,0 +1,61 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TrackersController < ApplicationController + layout 'base' + before_filter :require_admin + + def index + list + render :action => 'list' unless request.xhr? + end + + # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) + verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :list } + + def list + @tracker_pages, @trackers = paginate :trackers, :per_page => 10 + render :action => "list", :layout => false if request.xhr? + end + + def new + @tracker = Tracker.new(params[:tracker]) + if request.post? and @tracker.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list' + end + end + + def edit + @tracker = Tracker.find(params[:id]) + if request.post? and @tracker.update_attributes(params[:tracker]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'list' + end + end + + def destroy + @tracker = Tracker.find(params[:id]) + unless @tracker.issues.empty? + flash[:notice] = "This tracker contains issues and can\'t be deleted." + else + @tracker.destroy + end + redirect_to :action => 'list' + end + +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 000000000..47d0e51c9 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,92 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class UsersController < ApplicationController + layout 'base' + before_filter :require_admin + + helper :sort + include SortHelper + helper :custom_fields + include CustomFieldsHelper + + def index + list + render :action => 'list' unless request.xhr? + end + + def list + sort_init 'login', 'asc' + sort_update + @user_count = User.count + @user_pages = Paginator.new self, @user_count, + 15, + @params['page'] + @users = User.find :all,:order => sort_clause, + :limit => @user_pages.items_per_page, + :offset => @user_pages.current.offset + + render :action => "list", :layout => false if request.xhr? + end + + def add + if request.get? + @user = User.new(:language => $RDM_DEFAULT_LANG) + @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) } + else + @user = User.new(params[:user]) + @user.admin = params[:user][:admin] || false + @user.login = params[:user][:login] + @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id + @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) } + @user.custom_values = @custom_values + if @user.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'list' + end + end + @auth_sources = AuthSource.find(:all) + end + + def edit + @user = User.find(params[:id]) + if request.get? + @custom_values = UserCustomField.find(:all).collect { |x| @user.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) } + else + @user.admin = params[:user][:admin] if params[:user][:admin] + @user.login = params[:user][:login] if params[:user][:login] + @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty? or @user.auth_source_id + if params[:custom_fields] + @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) } + @user.custom_values = @custom_values + end + if @user.update_attributes(params[:user]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'list' + end + end + @auth_sources = AuthSource.find(:all) + end + + def destroy + User.find(params[:id]).destroy + redirect_to :action => 'list' + rescue + flash[:notice] = "Unable to delete user" + redirect_to :action => 'list' + end +end diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb new file mode 100644 index 000000000..d1980d74f --- /dev/null +++ b/app/controllers/versions_controller.rb @@ -0,0 +1,57 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class VersionsController < ApplicationController + layout 'base' + before_filter :find_project, :authorize + + def edit + if request.post? and @version.update_attributes(params[:version]) + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'projects', :action => 'settings', :id => @project + end + end + + def destroy + @version.destroy + redirect_to :controller => 'projects', :action => 'settings', :id => @project + rescue + flash[:notice] = "Unable to delete version" + redirect_to :controller => 'projects', :action => 'settings', :id => @project + end + + def download + @attachment = @version.attachments.find(params[:attachment_id]) + @attachment.increment_download + send_file @attachment.diskfile, :filename => @attachment.filename + rescue + flash.now[:notice] = l(:notice_file_not_found) + render :text => "", :layout => true, :status => 404 + end + + def destroy_file + @version.attachments.find(params[:attachment_id]).destroy + flash[:notice] = l(:notice_successful_delete) + redirect_to :controller => 'projects', :action => 'list_files', :id => @project + end + +private + def find_project + @version = Version.find(params[:id]) + @project = @version.project + end +end diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb new file mode 100644 index 000000000..c47198d51 --- /dev/null +++ b/app/controllers/welcome_controller.rb @@ -0,0 +1,25 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WelcomeController < ApplicationController + layout 'base' + + def index + @news = News.latest + @projects = Project.latest + end +end diff --git a/app/helpers/account_helper.rb b/app/helpers/account_helper.rb new file mode 100644 index 000000000..e18ab6ff4 --- /dev/null +++ b/app/helpers/account_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module AccountHelper +end diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb new file mode 100644 index 000000000..db2777392 --- /dev/null +++ b/app/helpers/admin_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module AdminHelper +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 000000000..0f0deeb30 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,179 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ApplicationHelper + + # Return current logged in user or nil + def loggedin? + @logged_in_user + end + + # Return true if user is logged in and is admin, otherwise false + def admin_loggedin? + @logged_in_user and @logged_in_user.admin? + end + + # Return true if user is authorized for controller/action, otherwise false + def authorize_for(controller, action) + # check if action is allowed on public projects + if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ controller, action ] + return true + end + # check if user is authorized + if @logged_in_user and (@logged_in_user.admin? or Permission.allowed_to_role( "%s/%s" % [ controller, action ], @logged_in_user.role_for_project(@project.id) ) ) + return true + end + return false + end + + # Display a link if user is authorized + def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) + link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller], options[:action]) + end + + # Display a link to user's account page + def link_to_user(user) + link_to user.display_name, :controller => 'account', :action => 'show', :id => user + end + + def format_date(date) + l_date(date) if date + end + + def format_time(time) + l_datetime(time) if time + end + + def day_name(day) + l(:general_day_names).split(',')[day-1] + end + + def pagination_links_full(paginator, options={}, html_options={}) + html = '' + html << link_to_remote(('« ' + l(:label_previous)), + {:update => "content", :url => { :page => paginator.current.previous }}, + {:href => url_for(:action => 'list', :params => @params.merge({:page => paginator.current.previous}))}) + ' ' if paginator.current.previous + + html << (pagination_links_each(paginator, options) do |n| + link_to_remote(n.to_s, + {:url => {:action => 'list', :params => @params.merge({:page => n})}, :update => 'content'}, + {:href => url_for(:action => 'list', :params => @params.merge({:page => n}))}) + end || '') + + html << ' ' + link_to_remote((l(:label_next) + ' »'), + {:update => "content", :url => { :page => paginator.current.next }}, + {:href => url_for(:action => 'list', :params => @params.merge({:page => paginator.current.next}))}) if paginator.current.next + html + end + + def textilizable(text) + $RDM_TEXTILE_DISABLED ? text : RedCloth.new(text).to_html + end + + def error_messages_for(object_name, options = {}) + options = options.symbolize_keys + object = instance_variable_get("@#{object_name}") + if object && !object.errors.empty? + # build full_messages here with controller current language + full_messages = [] + object.errors.each do |attr, msg| + next if msg.nil? + if attr == "base" + full_messages << l(msg) + else + full_messages << "« " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " » " + l(msg) unless attr == "custom_values" + end + end + # retrieve custom values error messages + if object.errors[:custom_values] + object.custom_values.each do |v| + v.errors.each do |attr, msg| + next if msg.nil? + full_messages << "« " + v.custom_field.name + " » " + l(msg) + end + end + end + content_tag("div", + content_tag( + options[:header_tag] || "h2", lwr(:gui_validation_error, full_messages.length) + " :" + ) + + content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }), + "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation" + ) + else + "" + end + end + + def lang_options_for_select + (GLoc.valid_languages.sort {|x,y| x.to_s <=> y.to_s }).collect {|lang| [ l_lang_name(lang.to_s, lang), lang.to_s]} + end + + def label_tag_for(name, option_tags = nil, options = {}) + label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") + content_tag("label", label_text) + end + + def labelled_tabular_form_for(name, object, options, &proc) + options[:html] ||= {} + options[:html].store :class, "tabular" + form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc) + end + + def check_all_links(form_name) + link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + + " | " + + link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") + end + + def calendar_for(field_id) + image_tag("calendar", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) + + javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });") + end +end + +class TabularFormBuilder < ActionView::Helpers::FormBuilder + include GLoc + + def initialize(object_name, object, template, options, proc) + set_language_if_valid options.delete(:lang) + @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc + end + + (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector| + src = <<-END_SRC + def #{selector}(field, options = {}) + label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") + label = @template.content_tag("label", label_text, + :class => (@object.errors[field] ? "error" : nil), + :for => (@object_name.to_s + "_" + field.to_s)) + label + super + end + END_SRC + class_eval src, __FILE__, __LINE__ + end + + def select(field, choices, options = {}) + label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") + label = @template.content_tag("label", label_text, + :class => (@object.errors[field] ? "error" : nil), + :for => (@object_name.to_s + "_" + field.to_s)) + label + super + end + +end + diff --git a/app/helpers/auth_sources_helper.rb b/app/helpers/auth_sources_helper.rb new file mode 100644 index 000000000..d47e9856a --- /dev/null +++ b/app/helpers/auth_sources_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module AuthSourcesHelper +end diff --git a/app/helpers/custom_fields_helper.rb b/app/helpers/custom_fields_helper.rb new file mode 100644 index 000000000..9df5c50a3 --- /dev/null +++ b/app/helpers/custom_fields_helper.rb @@ -0,0 +1,77 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module CustomFieldsHelper + + # Return custom field html tag corresponding to its format + def custom_field_tag(custom_value) + custom_field = custom_value.custom_field + field_name = "custom_fields[#{custom_field.id}]" + field_id = "custom_fields_#{custom_field.id}" + + case custom_field.field_format + when "string", "int" + text_field 'custom_value', 'value', :name => field_name, :id => field_id + when "date" + text_field('custom_value', 'value', :name => field_name, :id => field_id, :size => 10) + + calendar_for(field_id) + when "text" + text_area 'custom_value', 'value', :name => field_name, :id => field_id, :cols => 60, :rows => 3 + when "bool" + check_box 'custom_value', 'value', :name => field_name, :id => field_id + when "list" + select 'custom_value', 'value', custom_field.possible_values.split('|'), { :include_blank => true }, :name => field_name, :id => field_id + end + end + + # Return custom field label tag + def custom_field_label_tag(custom_value) + content_tag "label", custom_value.custom_field.name + + (custom_value.custom_field.is_required? ? " *" : ""), + :for => "custom_fields_#{custom_value.custom_field.id}", + :class => (custom_value.errors.empty? ? nil : "error" ) + end + + # Return custom field tag with its label tag + def custom_field_tag_with_label(custom_value) + custom_field_label_tag(custom_value) + custom_field_tag(custom_value) + end + + # Return a string used to display a custom value + def show_value(custom_value) + return "" unless custom_value + format_value(custom_value.value, custom_value.custom_field.field_format) + end + + # Return a string used to display a custom value + def format_value(value, field_format) + return "" unless value + case field_format + when "date" + value.empty? ? "" : l_date(value.to_date) + when "bool" + l_YesNo(value == "1") + else + value + end + end + + # Return an array of custom field formats which can be used in select_tag + def custom_field_formats_for_select + CustomField::FIELD_FORMATS.keys.collect { |k| [ l(CustomField::FIELD_FORMATS[k]), k ] } + end +end diff --git a/app/helpers/documents_helper.rb b/app/helpers/documents_helper.rb new file mode 100644 index 000000000..c9897647d --- /dev/null +++ b/app/helpers/documents_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module DocumentsHelper +end diff --git a/app/helpers/enumerations_helper.rb b/app/helpers/enumerations_helper.rb new file mode 100644 index 000000000..11a216a82 --- /dev/null +++ b/app/helpers/enumerations_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module EnumerationsHelper +end diff --git a/app/helpers/help_helper.rb b/app/helpers/help_helper.rb new file mode 100644 index 000000000..bb629316c --- /dev/null +++ b/app/helpers/help_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module HelpHelper +end diff --git a/app/helpers/ifpdf_helper.rb b/app/helpers/ifpdf_helper.rb new file mode 100644 index 000000000..a0dab0f94 --- /dev/null +++ b/app/helpers/ifpdf_helper.rb @@ -0,0 +1,48 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'iconv' + +module IfpdfHelper + + class IFPDF < FPDF + + attr_accessor :footer_date + + def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='') + @ic ||= Iconv.new('ISO-8859-1', 'UTF-8') + txt = begin + @ic.iconv(txt) + rescue + txt + end + super w,h,txt,border,ln,align,fill,link + end + + def Footer + SetFont('Helvetica', 'I', 8) + SetY(-15) + SetX(15) + Cell(0, 5, @footer_date, 0, 0, 'L') + SetY(-15) + SetX(-30) + Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C') + end + + end + +end diff --git a/app/helpers/issue_categories_helper.rb b/app/helpers/issue_categories_helper.rb new file mode 100644 index 000000000..997d830d7 --- /dev/null +++ b/app/helpers/issue_categories_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module IssueCategoriesHelper +end diff --git a/app/helpers/issue_statuses_helper.rb b/app/helpers/issue_statuses_helper.rb new file mode 100644 index 000000000..17704b7ba --- /dev/null +++ b/app/helpers/issue_statuses_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module IssueStatusesHelper +end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb new file mode 100644 index 000000000..93bd6c050 --- /dev/null +++ b/app/helpers/issues_helper.rb @@ -0,0 +1,74 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module IssuesHelper + + def show_detail(detail, no_html=false) + case detail.property + when 'attr' + label = l(("field_" + detail.prop_key.to_s.gsub(/\_id$/, "")).to_sym) + case detail.prop_key + when 'due_date', 'start_date' + value = format_date(detail.value.to_date) if detail.value + old_value = format_date(detail.old_value.to_date) if detail.old_value + when 'status_id' + s = IssueStatus.find_by_id(detail.value) and value = s.name if detail.value + s = IssueStatus.find_by_id(detail.old_value) and old_value = s.name if detail.old_value + when 'assigned_to_id' + u = User.find_by_id(detail.value) and value = u.name if detail.value + u = User.find_by_id(detail.old_value) and old_value = u.name if detail.old_value + when 'priority_id' + e = Enumeration.find_by_id(detail.value) and value = e.name if detail.value + e = Enumeration.find_by_id(detail.old_value) and old_value = e.name if detail.old_value + when 'category_id' + c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value + c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value + when 'fixed_version_id' + v = Version.find_by_id(detail.value) and value = v.name if detail.value + v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value + end + when 'cf' + custom_field = CustomField.find_by_id(detail.prop_key) + if custom_field + label = custom_field.name + value = format_value(detail.value, custom_field.field_format) if detail.value + old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value + end + end + + label ||= detail.prop_key + value ||= detail.value + old_value ||= detail.old_value + + unless no_html + label = content_tag('strong', label) + old_value = content_tag("i", old_value) if old_value + old_value = content_tag("strike", old_value) if old_value and !value + value = content_tag("i", value) if value + end + + if value + if old_value + label + " " + l(:text_journal_changed, old_value, value) + else + label + " " + l(:text_journal_set_to, value) + end + else + label + " " + l(:text_journal_deleted) + " (#{old_value})" + end + end +end diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb new file mode 100644 index 000000000..8bf90913d --- /dev/null +++ b/app/helpers/members_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module MembersHelper +end diff --git a/app/helpers/my_helper.rb b/app/helpers/my_helper.rb new file mode 100644 index 000000000..9098f67bc --- /dev/null +++ b/app/helpers/my_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module MyHelper +end diff --git a/app/helpers/news_helper.rb b/app/helpers/news_helper.rb new file mode 100644 index 000000000..f4a633f4b --- /dev/null +++ b/app/helpers/news_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module NewsHelper +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb new file mode 100644 index 000000000..0c85ce24c --- /dev/null +++ b/app/helpers/projects_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ProjectsHelper +end diff --git a/app/helpers/reports_helper.rb b/app/helpers/reports_helper.rb new file mode 100644 index 000000000..ed7fd7884 --- /dev/null +++ b/app/helpers/reports_helper.rb @@ -0,0 +1,32 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ReportsHelper + + def aggregate(data, criteria) + a = 0 + data.each { |row| + match = 1 + criteria.each { |k, v| + match = 0 unless row[k].to_s == v.to_s + } unless criteria.nil? + a = a + row["total"].to_i if match == 1 + } unless data.nil? + a + end + +end diff --git a/app/helpers/roles_helper.rb b/app/helpers/roles_helper.rb new file mode 100644 index 000000000..8ae339053 --- /dev/null +++ b/app/helpers/roles_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module RolesHelper +end diff --git a/app/helpers/search_filter_helper.rb b/app/helpers/search_filter_helper.rb new file mode 100644 index 000000000..f17ffeebf --- /dev/null +++ b/app/helpers/search_filter_helper.rb @@ -0,0 +1,106 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module SearchFilterHelper + + def search_filter_criteria(name, options = {}) + @search_filter ||= {} + @search_filter[name] ||= {} + @search_filter[name][:options] = [] + @search_filter[name][:conditions] = {} + yield.each { |c| + @search_filter[name][:options] << [c[0], c[1].to_s] + @search_filter[name][:conditions].store(c[1].to_s, c[2]) + } + end + + def search_filter_update + session[:search_filter] ||= {} + @search_filter.each_key {|field| session[:search_filter][field] = params[field] } + end + + def search_filter_clause + session[:search_filter] ||= {} + clause = ["1=1"] + @search_filter.each { |k, v| + filter_value = session[:search_filter][k] || v[:options][0][1] + if v[:conditions][filter_value] + clause[0] = clause[0] + " AND " + v[:conditions][filter_value].first + clause += v[:conditions][filter_value][1..-1] + end + } + clause + end + + def search_filter_tag(criteria, options = {}) + session[:search_filter] ||= {} + options[:name] = criteria + options[:class] += " active-filter" if session[:search_filter][criteria] and session[:search_filter][criteria] != @search_filter[criteria][:options][0][1] + content_tag("select", + options_for_select(@search_filter[criteria][:options], session[:search_filter][criteria]), + options + ) + end + + def search_filter_init_list_issues + search_filter_criteria('status_id') { + [ [('['+l(:label_open_issues_plural)+']'), "O", ["issue_statuses.is_closed=?", false]], + [('['+l(:label_closed_issues_plural)+']'), "C", ["issue_statuses.is_closed=?", true]], + [('['+l(:label_all)+']'), "A", nil] + ] + IssueStatus.find(:all).collect {|s| [s.name, s.id, ["issues.status_id=?", s.id]] } + } + + search_filter_criteria('tracker_id') { + [ [('['+l(:label_all)+']'), "A", nil] + ] + Tracker.find(:all).collect {|s| [s.name, s.id, ["issues.tracker_id=?", s.id]] } + } + + search_filter_criteria('priority_id') { + [ [('['+l(:label_all)+']'), "A", nil] + ] + Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect {|s| [s.name, s.id, ["issues.priority_id=?", s.id]] } + } + + search_filter_criteria('category_id') { + [ [('['+l(:label_all)+']'), "A", nil], + [('['+l(:label_none)+']'), "N", ["issues.category_id is null"]] + ] + @project.issue_categories.find(:all).collect {|s| [s.name, s.id, ["issues.category_id=?", s.id]] } + } + + search_filter_criteria('fixed_version_id') { + [ [('['+l(:label_all)+']'), "A", nil], + [('['+l(:label_none)+']'), "N", ["issues.fixed_version_id is null"]] + ] + @project.versions.collect {|s| [s.name, s.id, ["issues.fixed_version_id=?", s.id]] } + } + + search_filter_criteria('author_id') { + [ [('['+l(:label_all)+']'), "A", nil], + ] + @project.users.collect {|s| [s.display_name, s.id, ["issues.author_id=?", s.id]] } + } + + search_filter_criteria('assigned_to_id') { + [ [('['+l(:label_all)+']'), "A", nil], + [('['+l(:label_none)+']'), "N", ["issues.assigned_to_id is null"]] + ] + @project.users.collect {|s| [s.display_name, s.id, ["issues.assigned_to_id=?", s.id]] } + } + + search_filter_criteria('subproject_id') { + [ [('['+l(:label_none)+']'), "N", ["issues.project_id=?", @project.id]], + [('['+l(:label_all)+']'), "A", ["(issues.project_id=? or projects.parent_id=?)", @project.id, @project.id]] + ] + } + end +end \ No newline at end of file diff --git a/app/helpers/sort_helper.rb b/app/helpers/sort_helper.rb new file mode 100644 index 000000000..04a84c8e4 --- /dev/null +++ b/app/helpers/sort_helper.rb @@ -0,0 +1,160 @@ +# Helpers to sort tables using clickable column headers. +# +# Author: Stuart Rackham , March 2005. +# License: This source code is released under the MIT license. +# +# - Consecutive clicks toggle the column's sort order. +# - Sort state is maintained by a session hash entry. +# - Icon image identifies sort column and state. +# - Typically used in conjunction with the Pagination module. +# +# Example code snippets: +# +# Controller: +# +# helper :sort +# include SortHelper +# +# def list +# sort_init 'last_name' +# sort_update +# @items = Contact.find_all nil, sort_clause +# end +# +# Controller (using Pagination module): +# +# helper :sort +# include SortHelper +# +# def list +# sort_init 'last_name' +# sort_update +# @contact_pages, @items = paginate :contacts, +# :order_by => sort_clause, +# :per_page => 10 +# end +# +# View (table header in list.rhtml): +# +# +# +# <%= sort_header_tag('id', :title => 'Sort by contact ID') %> +# <%= sort_header_tag('last_name', :caption => 'Name') %> +# <%= sort_header_tag('phone') %> +# <%= sort_header_tag('address', :width => 200) %> +# +# +# +# - The ascending and descending sort icon images are sort_asc.png and +# sort_desc.png and reside in the application's images directory. +# - Introduces instance variables: @sort_name, @sort_default. +# - Introduces params :sort_key and :sort_order. +# +module SortHelper + + # Initializes the default sort column (default_key) and sort order + # (default_order). + # + # - default_key is a column attribute name. + # - default_order is 'asc' or 'desc'. + # - name is the name of the session hash entry that stores the sort state, + # defaults to '_sort'. + # + def sort_init(default_key, default_order='asc', name=nil) + @sort_name = name || @params[:controller] + @params[:action] + '_sort' + @sort_default = {:key => default_key, :order => default_order} + end + + # Updates the sort state. Call this in the controller prior to calling + # sort_clause. + # + def sort_update() + if @params[:sort_key] + sort = {:key => @params[:sort_key], :order => @params[:sort_order]} + elsif @session[@sort_name] + sort = @session[@sort_name] # Previous sort. + else + sort = @sort_default + end + @session[@sort_name] = sort + end + + # Returns an SQL sort clause corresponding to the current sort state. + # Use this to sort the controller's table items collection. + # + def sort_clause() + @session[@sort_name][:key] + ' ' + @session[@sort_name][:order] + end + + # Returns a link which sorts by the named column. + # + # - column is the name of an attribute in the sorted record collection. + # - The optional caption explicitly specifies the displayed link text. + # - A sort icon image is positioned to the right of the sort link. + # + def sort_link(column, caption=nil) + key, order = @session[@sort_name][:key], @session[@sort_name][:order] + if key == column + if order.downcase == 'asc' + icon = 'sort_asc' + order = 'desc' + else + icon = 'sort_desc' + order = 'asc' + end + else + icon = nil + order = 'desc' # changed for desc order by default + end + caption = titleize(Inflector::humanize(column)) unless caption + params = {:params => {:sort_key => column, :sort_order => order}} + link_to_remote(caption, + {:update => "content", :url => { :sort_key => column, :sort_order => order}}, + {:href => url_for(:params => { :sort_key => column, :sort_order => order})}) + + (icon ? nbsp(2) + image_tag(icon) : '') + end + + # Returns a table header tag with a sort link for the named column + # attribute. + # + # Options: + # :caption The displayed link name (defaults to titleized column name). + # :title The tag's 'title' attribute (defaults to 'Sort by :caption'). + # + # Other options hash entries generate additional table header tag attributes. + # + # Example: + # + # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %> + # + # Renders: + # + # + # Id + #   Sort_asc + # + # + def sort_header_tag(column, options = {}) + if options[:caption] + caption = options[:caption] + options.delete(:caption) + else + caption = titleize(Inflector::humanize(column)) + end + options[:title]= "Sort by #{caption}" unless options[:title] + content_tag('th', sort_link(column, caption), options) + end + + private + + # Return n non-breaking spaces. + def nbsp(n) + ' ' * n + end + + # Return capitalized title. + def titleize(title) + title.split.map {|w| w.capitalize }.join(' ') + end + +end diff --git a/app/helpers/trackers_helper.rb b/app/helpers/trackers_helper.rb new file mode 100644 index 000000000..839327efe --- /dev/null +++ b/app/helpers/trackers_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module TrackersHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 000000000..035db3d00 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module UsersHelper +end diff --git a/app/helpers/versions_helper.rb b/app/helpers/versions_helper.rb new file mode 100644 index 000000000..e2724fe84 --- /dev/null +++ b/app/helpers/versions_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module VersionsHelper +end diff --git a/app/helpers/welcome_helper.rb b/app/helpers/welcome_helper.rb new file mode 100644 index 000000000..cace5f542 --- /dev/null +++ b/app/helpers/welcome_helper.rb @@ -0,0 +1,19 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module WelcomeHelper +end diff --git a/app/models/attachment.rb b/app/models/attachment.rb new file mode 100644 index 000000000..2e1e9b156 --- /dev/null +++ b/app/models/attachment.rb @@ -0,0 +1,81 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "digest/md5" + +class Attachment < ActiveRecord::Base + belongs_to :container, :polymorphic => true + belongs_to :author, :class_name => "User", :foreign_key => "author_id" + + validates_presence_of :filename + + def file=(incomming_file) + unless incomming_file.nil? + @temp_file = incomming_file + if @temp_file.size > 0 + self.filename = sanitize_filename(@temp_file.original_filename) + self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename + self.content_type = @temp_file.content_type + self.filesize = @temp_file.size + end + end + end + + # Copy temp file to its final location + def before_save + if @temp_file && (@temp_file.size > 0) + logger.debug("saving '#{self.diskfile}'") + File.open(diskfile, "wb") do |f| + f.write(@temp_file.read) + end + self.digest = Digest::MD5.hexdigest(File.read(diskfile)) + end + end + + # Deletes file on the disk + def after_destroy + if self.filename? + File.delete(diskfile) if File.exist?(diskfile) + end + end + + # Returns file's location on disk + def diskfile + "#{$RDM_STORAGE_PATH}/#{self.disk_filename}" + end + + def increment_download + increment!(:downloads) + end + + # returns last created projects + def self.most_downloaded + find(:all, :limit => 5, :order => "downloads DESC") + end + +private + def sanitize_filename(value) + # get only the filename, not the whole path + just_filename = value.gsub(/^.*(\\|\/)/, '') + # NOTE: File.basename doesn't work right with Windows paths on Unix + # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/')) + + # Finally, replace all non alphanumeric, underscore or periods with underscore + @filename = just_filename.gsub(/[^\w\.\-]/,'_') + end + +end diff --git a/app/models/auth_source.rb b/app/models/auth_source.rb new file mode 100644 index 000000000..47eec106d --- /dev/null +++ b/app/models/auth_source.rb @@ -0,0 +1,47 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AuthSource < ActiveRecord::Base + has_many :users + + validates_presence_of :name + validates_uniqueness_of :name + + def authenticate(login, password) + end + + def test_connection + end + + def auth_method_name + "Abstract" + end + + # Try to authenticate a user not yet registered against available sources + def self.authenticate(login, password) + AuthSource.find(:all, :conditions => ["onthefly_register=?", true]).each do |source| + begin + logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug? + attrs = source.authenticate(login, password) + rescue + attrs = nil + end + return attrs if attrs + end + return nil + end +end diff --git a/app/models/auth_source_ldap.rb b/app/models/auth_source_ldap.rb new file mode 100644 index 000000000..895cf1c63 --- /dev/null +++ b/app/models/auth_source_ldap.rb @@ -0,0 +1,79 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'net/ldap' +require 'iconv' + +class AuthSourceLdap < AuthSource + validates_presence_of :host, :port, :attr_login + + def after_initialize + self.port = 389 if self.port == 0 + end + + def authenticate(login, password) + attrs = [] + # get user's DN + ldap_con = initialize_ldap_con(self.account, self.account_password) + login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) + object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) + dn = String.new + ldap_con.search( :base => self.base_dn, + :filter => object_filter & login_filter, + :attributes=> ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]) do |entry| + dn = entry.dn + attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname), + :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname), + :mail => AuthSourceLdap.get_attr(entry, self.attr_mail), + :auth_source_id => self.id ] + end + return nil if dn.empty? + logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug? + # authenticate user + ldap_con = initialize_ldap_con(dn, password) + return nil unless ldap_con.bind + # return user's attributes + logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? + attrs + rescue Net::LDAP::LdapError => text + raise "LdapError: " + text + end + + # test the connection to the LDAP + def test_connection + ldap_con = initialize_ldap_con(self.account, self.account_password) + ldap_con.open { } + rescue Net::LDAP::LdapError => text + raise "LdapError: " + text + end + + def auth_method_name + "LDAP" + end + +private + def initialize_ldap_con(ldap_user, ldap_password) + Net::LDAP.new( {:host => self.host, + :port => self.port, + :auth => { :method => :simple, :username => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_user), :password => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_password) }} + ) + end + + def self.get_attr(entry, attr_name) + entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] + end +end diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb new file mode 100644 index 000000000..924a874a3 --- /dev/null +++ b/app/models/custom_field.rb @@ -0,0 +1,42 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CustomField < ActiveRecord::Base + has_many :custom_values, :dependent => true + + FIELD_FORMATS = { "list" => :label_list, + "date" => :label_date, + "bool" => :label_boolean, + "int" => :label_integer, + "string" => :label_string, + "text" => :label_text + }.freeze + + validates_presence_of :name, :field_format + validates_uniqueness_of :name + validates_inclusion_of :field_format, :in => FIELD_FORMATS.keys + validates_presence_of :possible_values, :if => Proc.new { |field| field.field_format == "list" } + + # to move in project_custom_field + def self.for_all + find(:all, :conditions => ["is_for_all=?", true]) + end + + def type_name + nil + end +end diff --git a/app/models/custom_value.rb b/app/models/custom_value.rb new file mode 100644 index 000000000..015ccd244 --- /dev/null +++ b/app/models/custom_value.rb @@ -0,0 +1,38 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CustomValue < ActiveRecord::Base + belongs_to :custom_field + belongs_to :customized, :polymorphic => true + +protected + def validate + errors.add(:value, :activerecord_error_blank) and return if custom_field.is_required? and value.empty? + errors.add(:value, :activerecord_error_invalid) unless custom_field.regexp.empty? or value =~ Regexp.new(custom_field.regexp) + errors.add(:value, :activerecord_error_too_short) if custom_field.min_length > 0 and value.length < custom_field.min_length and value.length > 0 + errors.add(:value, :activerecord_error_too_long) if custom_field.max_length > 0 and value.length > custom_field.max_length + case custom_field.field_format + when "int" + errors.add(:value, :activerecord_error_not_a_number) unless value =~ /^[0-9]*$/ + when "date" + errors.add(:value, :activerecord_error_not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ or value.empty? + when "list" + errors.add(:value, :activerecord_error_inclusion) unless custom_field.possible_values.split('|').include? value or value.empty? + end + end +end + diff --git a/app/models/document.rb b/app/models/document.rb new file mode 100644 index 000000000..08e0ef607 --- /dev/null +++ b/app/models/document.rb @@ -0,0 +1,24 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Document < ActiveRecord::Base + belongs_to :project + belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id" + has_many :attachments, :as => :container, :dependent => true + + validates_presence_of :project, :title, :category +end diff --git a/app/models/enumeration.rb b/app/models/enumeration.rb new file mode 100644 index 000000000..b5c8ed6e7 --- /dev/null +++ b/app/models/enumeration.rb @@ -0,0 +1,46 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Enumeration < ActiveRecord::Base + before_destroy :check_integrity + + validates_presence_of :opt, :name + validates_uniqueness_of :name, :scope => [:opt] + + OPTIONS = { + "IPRI" => :enumeration_issue_priorities, + "DCAT" => :enumeration_doc_categories + }.freeze + + def self.get_values(option) + find(:all, :conditions => ['opt=?', option]) + end + + def option_name + OPTIONS[self.opt] + end + +private + def check_integrity + case self.opt + when "IPRI" + raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id]) + when "DCAT" + raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id]) + end + end +end diff --git a/app/models/issue.rb b/app/models/issue.rb new file mode 100644 index 000000000..f00eb7a9c --- /dev/null +++ b/app/models/issue.rb @@ -0,0 +1,103 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Issue < ActiveRecord::Base + + belongs_to :project + belongs_to :tracker + belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' + belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' + belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id' + belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' + + #has_many :histories, :class_name => 'IssueHistory', :dependent => true, :order => "issue_histories.created_on DESC", :include => :status + has_many :journals, :as => :journalized, :dependent => true + has_many :attachments, :as => :container, :dependent => true + + has_many :custom_values, :dependent => true, :as => :customized + has_many :custom_fields, :through => :custom_values + + validates_presence_of :subject, :description, :priority, :tracker, :author, :status + validates_inclusion_of :done_ratio, :in => 0..100 + validates_associated :custom_values, :on => :update + + # set default status for new issues + def before_validation + self.status = IssueStatus.default if new_record? + end + + def validate + if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty? + errors.add :due_date, :activerecord_error_not_a_date + end + + if self.due_date and self.start_date and self.due_date < self.start_date + errors.add :due_date, :activerecord_error_greater_than_start_date + end + end + + #def before_create + # build_history + #end + + def before_save + if @current_journal + # attributes changes + (Issue.column_names - %w(id description)).each {|c| + @current_journal.details << JournalDetail.new(:property => 'attr', + :prop_key => c, + :old_value => @issue_before_change.send(c), + :value => send(c)) unless send(c)==@issue_before_change.send(c) + } + # custom fields changes + custom_values.each {|c| + @current_journal.details << JournalDetail.new(:property => 'cf', + :prop_key => c.custom_field_id, + :old_value => @custom_values_before_change[c.custom_field_id], + :value => c.value) unless @custom_values_before_change[c.custom_field_id]==c.value + } + @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty? + end + end + + def long_id + "%05d" % self.id + end + + def custom_value_for(custom_field) + self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id } + return nil + end + + def init_journal(user, notes = "") + @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) + @issue_before_change = self.clone + @custom_values_before_change = {} + self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } + @current_journal + end + +private + # Creates an history for the issue + #def build_history + # @history = self.histories.build + # @history.status = self.status + # @history.author = self.author + #end +end diff --git a/app/models/issue_category.rb b/app/models/issue_category.rb new file mode 100644 index 000000000..74adb8f52 --- /dev/null +++ b/app/models/issue_category.rb @@ -0,0 +1,29 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueCategory < ActiveRecord::Base + before_destroy :check_integrity + belongs_to :project + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:project_id] + +private + def check_integrity + raise "Can't delete category" if Issue.find(:first, :conditions => ["category_id=?", self.id]) + end +end diff --git a/app/models/issue_custom_field.rb b/app/models/issue_custom_field.rb new file mode 100644 index 000000000..209ae206b --- /dev/null +++ b/app/models/issue_custom_field.rb @@ -0,0 +1,27 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueCustomField < CustomField + has_and_belongs_to_many :projects, :join_table => "custom_fields_projects", :foreign_key => "custom_field_id" + has_and_belongs_to_many :trackers, :join_table => "custom_fields_trackers", :foreign_key => "custom_field_id" + has_many :issues, :through => :issue_custom_values + + def type_name + :label_issue_plural + end +end + diff --git a/app/models/issue_history.rb b/app/models/issue_history.rb new file mode 100644 index 000000000..4b6682600 --- /dev/null +++ b/app/models/issue_history.rb @@ -0,0 +1,24 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueHistory < ActiveRecord::Base + belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + belongs_to :issue + + validates_presence_of :status +end diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb new file mode 100644 index 000000000..c8a40d330 --- /dev/null +++ b/app/models/issue_status.rb @@ -0,0 +1,49 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueStatus < ActiveRecord::Base + before_destroy :check_integrity + has_many :workflows, :foreign_key => "old_status_id" + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :html_color, :is => 6 + validates_format_of :html_color, :with => /^[a-f0-9]*$/i + + def before_save + IssueStatus.update_all "is_default=false" if self.is_default? + end + + # Returns the default status for new issues + def self.default + find(:first, :conditions =>["is_default=?", true]) + end + + # Returns an array of all statuses the given role can switch to + def new_statuses_allowed_to(role, tracker) + statuses = [] + for workflow in self.workflows + statuses << workflow.new_status if workflow.role_id == role.id and workflow.tracker_id == tracker.id + end unless role.nil? or tracker.nil? + statuses + end + +private + def check_integrity + raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id]) or IssueHistory.find(:first, :conditions => ["status_id=?", self.id]) + end +end diff --git a/app/models/journal.rb b/app/models/journal.rb new file mode 100644 index 000000000..9d173552f --- /dev/null +++ b/app/models/journal.rb @@ -0,0 +1,22 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Journal < ActiveRecord::Base + belongs_to :journalized, :polymorphic => true + belongs_to :user + has_many :details, :class_name => "JournalDetail", :dependent => true +end diff --git a/app/models/journal_detail.rb b/app/models/journal_detail.rb new file mode 100644 index 000000000..784e98bf7 --- /dev/null +++ b/app/models/journal_detail.rb @@ -0,0 +1,20 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class JournalDetail < ActiveRecord::Base + belongs_to :journal +end diff --git a/app/models/mailer.rb b/app/models/mailer.rb new file mode 100644 index 000000000..07047c594 --- /dev/null +++ b/app/models/mailer.rb @@ -0,0 +1,53 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Mailer < ActionMailer::Base + + helper IssuesHelper + + def issue_add(issue) + # Sends to all project members + @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification } + @from = $RDM_MAIL_FROM + @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" + @body['issue'] = issue + end + + def issue_edit(journal) + # Sends to all project members + issue = journal.journalized + @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification } + @from = $RDM_MAIL_FROM + @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" + @body['issue'] = issue + @body['journal']= journal + end + + def lost_password(token) + @recipients = token.user.mail + @from = $RDM_MAIL_FROM + @subject = l(:mail_subject_lost_password) + @body['token'] = token + end + + def register(token) + @recipients = token.user.mail + @from = $RDM_MAIL_FROM + @subject = l(:mail_subject_register) + @body['token'] = token + end +end diff --git a/app/models/member.rb b/app/models/member.rb new file mode 100644 index 000000000..1214b6443 --- /dev/null +++ b/app/models/member.rb @@ -0,0 +1,29 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Member < ActiveRecord::Base + belongs_to :user + belongs_to :role + belongs_to :project + + validates_presence_of :role, :user, :project + validates_uniqueness_of :user_id, :scope => :project_id + + def name + self.user.display_name + end +end diff --git a/app/models/news.rb b/app/models/news.rb new file mode 100644 index 000000000..faafa7eef --- /dev/null +++ b/app/models/news.rb @@ -0,0 +1,28 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class News < ActiveRecord::Base + belongs_to :project + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + + validates_presence_of :title, :description + + # returns last created news + def self.latest + find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC") + end +end diff --git a/app/models/permission.rb b/app/models/permission.rb new file mode 100644 index 000000000..620974608 --- /dev/null +++ b/app/models/permission.rb @@ -0,0 +1,63 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Permission < ActiveRecord::Base + has_and_belongs_to_many :roles + + validates_presence_of :controller, :action, :description + + GROUPS = { + 100 => :label_project, + 200 => :label_member_plural, + 300 => :label_version_plural, + 400 => :label_issue_category_plural, + 1000 => :label_issue_plural, + 1100 => :label_news_plural, + 1200 => :label_document_plural, + 1300 => :label_attachment_plural, + }.freeze + + @@cached_perms_for_public = nil + @@cached_perms_for_roles = nil + + def name + self.controller + "/" + self.action + end + + def group_id + (self.sort / 100)*100 + end + + def self.allowed_to_public(action) + @@cached_perms_for_public ||= find(:all, :conditions => ["is_public=?", true]).collect {|p| "#{p.controller}/#{p.action}"} + @@cached_perms_for_public.include? action + end + + def self.allowed_to_role(action, role) + @@cached_perms_for_roles ||= + begin + perms = {} + find(:all, :include => :roles).each {|p| perms.store "#{p.controller}/#{p.action}", p.roles.collect {|r| r.id } } + perms + end + @@cached_perms_for_roles[action] and @@cached_perms_for_roles[action].include? role + end + + def self.allowed_to_role_expired + @@cached_perms_for_roles = nil + end +end diff --git a/app/models/project.rb b/app/models/project.rb new file mode 100644 index 000000000..ae7436910 --- /dev/null +++ b/app/models/project.rb @@ -0,0 +1,57 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Project < ActiveRecord::Base + has_many :versions, :dependent => true, :order => "versions.effective_date DESC, versions.name DESC" + has_many :members, :dependent => true + has_many :users, :through => :members + has_many :custom_values, :dependent => true, :as => :customized + has_many :issues, :dependent => true, :order => "issues.created_on DESC", :include => :status + has_many :documents, :dependent => true + has_many :news, :dependent => true, :include => :author + has_many :issue_categories, :dependent => true, :order => "issue_categories.name" + has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_projects', :association_foreign_key => 'custom_field_id' + acts_as_tree :order => "name", :counter_cache => true + + validates_presence_of :name, :description + validates_uniqueness_of :name + validates_associated :custom_values, :on => :update + + # returns 5 last created projects + def self.latest + find(:all, :limit => 5, :order => "created_on DESC") + end + + # Returns an array of all custom fields enabled for project issues + # (explictly associated custom fields and custom fields enabled for all projects) + def custom_fields_for_issues(tracker) + tracker.custom_fields.find(:all, :include => :projects, + :conditions => ["is_for_all=? or project_id=?", true, self.id]) + #(CustomField.for_all + custom_fields).uniq + end + + def all_custom_fields + @all_custom_fields ||= IssueCustomField.find(:all, :include => :projects, + :conditions => ["is_for_all=? or project_id=?", true, self.id]) + end + +protected + def validate + errors.add(parent_id, " must be a root project") if parent and parent.parent + errors.add_to_base("A project with subprojects can't be a subproject") if parent and projects_count > 0 + end +end diff --git a/app/models/project_custom_field.rb b/app/models/project_custom_field.rb new file mode 100644 index 000000000..baa533812 --- /dev/null +++ b/app/models/project_custom_field.rb @@ -0,0 +1,22 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ProjectCustomField < CustomField + def type_name + :label_project_plural + end +end diff --git a/app/models/role.rb b/app/models/role.rb new file mode 100644 index 000000000..6908095e9 --- /dev/null +++ b/app/models/role.rb @@ -0,0 +1,31 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Role < ActiveRecord::Base + before_destroy :check_integrity + has_and_belongs_to_many :permissions + has_many :workflows, :dependent => true + has_many :members + + validates_presence_of :name + validates_uniqueness_of :name + +private + def check_integrity + raise "Can't delete role" if Member.find(:first, :conditions =>["role_id=?", self.id]) + end +end diff --git a/app/models/token.rb b/app/models/token.rb new file mode 100644 index 000000000..98745d29e --- /dev/null +++ b/app/models/token.rb @@ -0,0 +1,44 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Token < ActiveRecord::Base + belongs_to :user + + @@validity_time = 1.day + + def before_create + self.value = Token.generate_token_value + end + + # Return true if token has expired + def expired? + return Time.now > self.created_on + @@validity_time + end + + # Delete all expired tokens + def self.destroy_expired + Token.delete_all ["created_on < ?", Time.now - @@validity_time] + end + +private + def self.generate_token_value + chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + token_value = '' + 40.times { |i| token_value << chars[rand(chars.size-1)] } + token_value + end +end diff --git a/app/models/tracker.rb b/app/models/tracker.rb new file mode 100644 index 000000000..a4376a351 --- /dev/null +++ b/app/models/tracker.rb @@ -0,0 +1,31 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Tracker < ActiveRecord::Base + before_destroy :check_integrity + has_many :issues + has_many :workflows, :dependent => true + has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_trackers', :association_foreign_key => 'custom_field_id' + + validates_presence_of :name + validates_uniqueness_of :name + +private + def check_integrity + raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id]) + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 000000000..a82c98a88 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,129 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "digest/sha1" + +class User < ActiveRecord::Base + has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => true + has_many :projects, :through => :memberships + has_many :custom_values, :dependent => true, :as => :customized + has_one :preference, :dependent => true, :class_name => 'UserPreference' + belongs_to :auth_source + + attr_accessor :password, :password_confirmation + attr_accessor :last_before_login_on + # Prevents unauthorized assignments + attr_protected :login, :admin, :password, :password_confirmation, :hashed_password + + validates_presence_of :login, :firstname, :lastname, :mail + validates_uniqueness_of :login, :mail + # Login must contain lettres, numbers, underscores only + validates_format_of :login, :with => /^[a-z0-9_]+$/i + validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i + # Password length between 4 and 12 + validates_length_of :password, :in => 4..12, :allow_nil => true + validates_confirmation_of :password, :allow_nil => true + validates_associated :custom_values, :on => :update + + # Account statuses + STATUS_ACTIVE = 1 + STATUS_REGISTERED = 2 + STATUS_LOCKED = 3 + + def before_save + # update hashed_password if password was set + self.hashed_password = User.hash_password(self.password) if self.password + end + + # Returns the user that matches provided login and password, or nil + def self.try_to_login(login, password) + user = find(:first, :conditions => ["login=?", login]) + if user + # user is already in local database + return nil if !user.active? + if user.auth_source + # user has an external authentication method + return nil unless user.auth_source.authenticate(login, password) + else + # authentication with local password + return nil unless User.hash_password(password) == user.hashed_password + end + else + # user is not yet registered, try to authenticate with available sources + attrs = AuthSource.authenticate(login, password) + if attrs + onthefly = new(*attrs) + onthefly.login = login + onthefly.language = $RDM_DEFAULT_LANG + if onthefly.save + user = find(:first, :conditions => ["login=?", login]) + logger.info("User '#{user.login}' created on the fly.") if logger + end + end + end + user.update_attribute(:last_login_on, Time.now) if user + user + + rescue => text + raise text + end + + # Return user's full name for display + def display_name + firstname + " " + lastname + end + + def name + display_name + end + + def active? + self.status == STATUS_ACTIVE + end + + def registered? + self.status == STATUS_REGISTERED + end + + def locked? + self.status == STATUS_LOCKED + end + + def check_password?(clear_password) + User.hash_password(clear_password) == self.hashed_password + end + + def role_for_project(project_id) + @role_for_projects ||= + begin + roles = {} + self.memberships.each { |m| roles.store m.project_id, m.role_id } + roles + end + @role_for_projects[project_id] + end + + def pref + self.preference ||= UserPreference.new(:user => self) + end + +private + # Return password digest + def self.hash_password(clear_password) + Digest::SHA1.hexdigest(clear_password || "") + end +end diff --git a/app/models/user_custom_field.rb b/app/models/user_custom_field.rb new file mode 100644 index 000000000..866234a7f --- /dev/null +++ b/app/models/user_custom_field.rb @@ -0,0 +1,23 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class UserCustomField < CustomField + def type_name + :label_user_plural + end +end + diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb new file mode 100644 index 000000000..5240c9757 --- /dev/null +++ b/app/models/user_preference.rb @@ -0,0 +1,44 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class UserPreference < ActiveRecord::Base + belongs_to :user + serialize :others, Hash + + attr_protected :others + + def initialize(attributes = nil) + super + self.others ||= {} + end + + def [](attr_name) + if attribute_present? attr_name + super + else + others[attr_name] + end + end + + def []=(attr_name, value) + if attribute_present? attr_name + super + else + others.store attr_name, value + end + end +end diff --git a/app/models/version.rb b/app/models/version.rb new file mode 100644 index 000000000..0ae1edda8 --- /dev/null +++ b/app/models/version.rb @@ -0,0 +1,32 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Version < ActiveRecord::Base + before_destroy :check_integrity + belongs_to :project + has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id' + has_many :attachments, :as => :container, :dependent => true + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:project_id] + validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date + +private + def check_integrity + raise "Can't delete version" if self.fixed_issues.find(:first) + end +end diff --git a/app/models/workflow.rb b/app/models/workflow.rb new file mode 100644 index 000000000..22c873fc7 --- /dev/null +++ b/app/models/workflow.rb @@ -0,0 +1,24 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Workflow < ActiveRecord::Base + belongs_to :role + belongs_to :old_status, :class_name => 'IssueStatus', :foreign_key => 'old_status_id' + belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id' + + validates_presence_of :role, :old_status, :new_status +end diff --git a/app/views/account/login.rhtml b/app/views/account/login.rhtml new file mode 100644 index 000000000..74c075516 --- /dev/null +++ b/app/views/account/login.rhtml @@ -0,0 +1,18 @@ +
+ +
\ No newline at end of file diff --git a/app/views/account/lost_password.rhtml b/app/views/account/lost_password.rhtml new file mode 100644 index 000000000..3f32e7153 --- /dev/null +++ b/app/views/account/lost_password.rhtml @@ -0,0 +1,14 @@ +
+ +
\ No newline at end of file diff --git a/app/views/account/password_recovery.rhtml b/app/views/account/password_recovery.rhtml new file mode 100644 index 000000000..39a8071a9 --- /dev/null +++ b/app/views/account/password_recovery.rhtml @@ -0,0 +1,21 @@ +
+ +
\ No newline at end of file diff --git a/app/views/account/register.rhtml b/app/views/account/register.rhtml new file mode 100644 index 000000000..b34aff79c --- /dev/null +++ b/app/views/account/register.rhtml @@ -0,0 +1,39 @@ +

<%=l(:label_register)%>

+ +<%= start_form_tag({:action => 'register'}, :class => "tabular") %> +<%= error_messages_for 'user' %> + +
+ +

+<%= text_field 'user', 'login', :size => 25 %>

+ +

+<%= password_field_tag 'password', nil, :size => 25 %>

+ +

+<%= password_field_tag 'password_confirmation', nil, :size => 25 %>

+ +

+<%= text_field 'user', 'firstname' %>

+ +

+<%= text_field 'user', 'lastname' %>

+ +

+<%= text_field 'user', 'mail' %>

+ +

+<%= select("user", "language", lang_options_for_select) %>

+ +<% for @custom_value in @custom_values %> +

<%= custom_field_tag_with_label @custom_value %>

+<% end %> + +

+<%= check_box 'user', 'mail_notification' %>

+ +
+ +<%= submit_tag l(:button_submit) %> +<%= end_form_tag %> diff --git a/app/views/account/show.rhtml b/app/views/account/show.rhtml new file mode 100644 index 000000000..985238951 --- /dev/null +++ b/app/views/account/show.rhtml @@ -0,0 +1,26 @@ +

<%= @user.display_name %>

+ +

+<%= mail_to @user.mail unless @user.pref.hide_mail %> +

    +
  • <%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %>
  • +<% for custom_value in @custom_values %> +<% if !custom_value.value.empty? %> +
  • <%= custom_value.custom_field.name%>: <%= show_value(custom_value) %>
  • +<% end %> +<% end %> +
+

+ +

<%=l(:label_project_plural)%>

+

+<% for membership in @user.memberships %> + <%= membership.project.name %> (<%= membership.role.name %>, <%= format_date(membership.created_on) %>) +
+<% end %> +

+ +

<%=l(:label_activity)%>

+

+<%=l(:label_reported_issues)%>: <%= Issue.count(["author_id=?", @user.id]) %> +

\ No newline at end of file diff --git a/app/views/admin/index.rhtml b/app/views/admin/index.rhtml new file mode 100644 index 000000000..d937e287c --- /dev/null +++ b/app/views/admin/index.rhtml @@ -0,0 +1,50 @@ +

<%=l(:label_administration)%>

+ +

+<%= image_tag "projects" %> +<%= link_to l(:label_project_plural), :controller => 'admin', :action => 'projects' %> | +<%= link_to l(:label_new), :controller => 'projects', :action => 'add' %> +

+ +

+<%= image_tag "users" %> +<%= link_to l(:label_user_plural), :controller => 'users' %> | +<%= link_to l(:label_new), :controller => 'users', :action => 'add' %> +

+ +

+<%= image_tag "role" %> +<%= link_to l(:label_role_and_permissions), :controller => 'roles' %> +

+ +

+<%= image_tag "tracker" %> +<%= link_to l(:label_tracker_plural), :controller => 'trackers' %> | +<%= link_to l(:label_custom_field_plural), :controller => 'custom_fields' %> +

+ +

+<%= image_tag "workflow" %> +<%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses' %> | +<%= link_to l(:label_workflow), :controller => 'roles', :action => 'workflow' %> +

+ +

+<%= image_tag "options" %> +<%= link_to l(:label_enumerations), :controller => 'enumerations' %> +

+ +

+<%= image_tag "mailer" %> +<%= link_to l(:field_mail_notification), :controller => 'admin', :action => 'mail_options' %> +

+ +

+<%= image_tag "login" %> +<%= link_to l(:label_authentication), :controller => 'auth_sources' %> +

+ +

+<%= image_tag "help" %> +<%= link_to l(:label_information_plural), :controller => 'admin', :action => 'info' %> +

\ No newline at end of file diff --git a/app/views/admin/info.rhtml b/app/views/admin/info.rhtml new file mode 100644 index 000000000..4777a151e --- /dev/null +++ b/app/views/admin/info.rhtml @@ -0,0 +1,10 @@ +

<%=l(:label_information_plural)%>

+ +

<%=l(:field_version)%>: <%= RDM_APP_NAME %> <%= RDM_APP_VERSION %>

+ +<%=l(:label_environment)%>: +
    +<% Rails::Info.properties.each do |name, value| %> +
  • <%= name %>: <%= value %>
  • +<% end %> +
\ No newline at end of file diff --git a/app/views/admin/mail_options.rhtml b/app/views/admin/mail_options.rhtml new file mode 100644 index 000000000..54e2daf3e --- /dev/null +++ b/app/views/admin/mail_options.rhtml @@ -0,0 +1,24 @@ +

<%=l(:field_mail_notification)%>

+ +<%= start_form_tag ({}, :id => 'mail_options_form')%> + +
+

<%=l(:text_select_mail_notifications)%>

+ +<% actions = @actions.group_by {|p| p.group_id } %> +<% actions.keys.sort.each do |group_id| %> +
<%= l(Permission::GROUPS[group_id]) %> +<% actions[group_id].each do |p| %> +
<%= check_box_tag "action_ids[]", p.id, p.mail_enabled? %> + <%= l(p.description.to_sym) %> +
+<% end %> +
+<% end %> + +
+

<%= check_all_links 'mail_options_form' %>

+
+ +<%= submit_tag l(:button_save) %> +<%= end_form_tag %> diff --git a/app/views/admin/projects.rhtml b/app/views/admin/projects.rhtml new file mode 100644 index 000000000..39e4d9bf7 --- /dev/null +++ b/app/views/admin/projects.rhtml @@ -0,0 +1,30 @@ +

<%=l(:label_project_plural)%>

+ + + + <%= sort_header_tag('name', :caption => l(:label_project)) %> + + + + <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> + + + +<% for project in @projects %> + "> + + +<% end %> +
<%=l(:field_description)%><%=l(:field_is_public)%><%=l(:label_subproject_plural)%>
<%= link_to project.name, :controller => 'projects', :action => 'settings', :id => project %> + <%= project.description %> + <%= image_tag 'true' if project.is_public? %> + <%= project.projects_count %> + <%= format_date(project.created_on) %> + + <%= button_to l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => "button-small" %> +
+ +

<%= pagination_links_full @project_pages %> +[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ]

+ +

<%= link_to ('» ' + l(:label_project_new)), :controller => 'projects', :action => 'add' %>

\ No newline at end of file diff --git a/app/views/auth_sources/_form.rhtml b/app/views/auth_sources/_form.rhtml new file mode 100644 index 000000000..b6365dce5 --- /dev/null +++ b/app/views/auth_sources/_form.rhtml @@ -0,0 +1,45 @@ +<%= error_messages_for 'auth_source' %> + +
+ +

+<%= text_field 'auth_source', 'name' %>

+ +

+<%= text_field 'auth_source', 'host' %>

+ +

+<%= text_field 'auth_source', 'port', :size => 6 %>

+ +

+<%= text_field 'auth_source', 'account' %>

+ +

+<%= password_field 'auth_source', 'account_password' %>

+ +

+<%= text_field 'auth_source', 'base_dn', :size => 60 %>

+
+ +
+

+<%= check_box 'auth_source', 'onthefly_register' %>

+ +

+

<%=l(:label_attribute_plural)%> +

+<%= text_field 'auth_source', 'attr_login', :size => 20 %>

+ +

+<%= text_field 'auth_source', 'attr_firstname', :size => 20 %>

+ +

+<%= text_field 'auth_source', 'attr_lastname', :size => 20 %>

+ +

+<%= text_field 'auth_source', 'attr_mail', :size => 20 %>

+
+

+
+ + diff --git a/app/views/auth_sources/edit.rhtml b/app/views/auth_sources/edit.rhtml new file mode 100644 index 000000000..149463e7f --- /dev/null +++ b/app/views/auth_sources/edit.rhtml @@ -0,0 +1,7 @@ +

<%=l(:label_auth_source)%> (<%= @auth_source.auth_method_name %>)

+ +<%= start_form_tag({:action => 'update', :id => @auth_source}, :class => "tabular") %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<%= end_form_tag %> + diff --git a/app/views/auth_sources/list.rhtml b/app/views/auth_sources/list.rhtml new file mode 100644 index 000000000..47cbeeaff --- /dev/null +++ b/app/views/auth_sources/list.rhtml @@ -0,0 +1,30 @@ +

<%=l(:label_auth_source_plural)%>

+ + + + + + + + + + +<% for source in @auth_sources %> + "> + + + + + + +<% end %> +
<%=l(:field_name)%><%=l(:field_type)%><%=l(:field_host)%>
<%= link_to source.name, :action => 'edit', :id => source%><%= source.auth_method_name %><%= source.host %> + <%= link_to l(:button_test), :action => 'test_connection', :id => source %> + + <%= button_to l(:button_delete), { :action => 'destroy', :id => source }, :confirm => l(:text_are_you_sure), :class => "button-small" %> +
+ +<%= pagination_links_full @auth_source_pages %> +
+<%= link_to '» ' + l(:label_auth_source_new), :action => 'new' %> + diff --git a/app/views/auth_sources/new.rhtml b/app/views/auth_sources/new.rhtml new file mode 100644 index 000000000..29d66327b --- /dev/null +++ b/app/views/auth_sources/new.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_auth_source_new)%> (<%= @auth_source.auth_method_name %>)

+ +<%= start_form_tag({:action => 'create'}, :class => "tabular") %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> +<%= end_form_tag %> diff --git a/app/views/custom_fields/_form.rhtml b/app/views/custom_fields/_form.rhtml new file mode 100644 index 000000000..f7f968e33 --- /dev/null +++ b/app/views/custom_fields/_form.rhtml @@ -0,0 +1,52 @@ +<%= error_messages_for 'custom_field' %> + + +
+

+<%= text_field 'custom_field', 'name' %>

+ +

+<%= select("custom_field", "field_format", custom_field_formats_for_select) %>

+ +

+<%= text_field 'custom_field', 'min_length', :size => 5 %> - +<%= text_field 'custom_field', 'max_length', :size => 5 %>
(<%=l(:text_min_max_length_info)%>)

+ +

+<%= text_field 'custom_field', 'regexp', :size => 50 %>
(<%=l(:text_regexp_info)%>)

+ +

+<%= text_area 'custom_field', 'possible_values', :rows => 5, :cols => 60 %>
(<%=l(:text_possible_values_info)%>)

+
+ + +
+<% case type.to_s + when "IssueCustomField" %> + +
<%=l(:label_tracker_plural)%> +<% for tracker in @trackers %> + checked="checked"<%end%> + > <%= tracker.name %> +<% end %>
+  + +

+<%= check_box 'custom_field', 'is_required' %>

+ +

+<%= check_box 'custom_field', 'is_for_all' %>

+ +<% when "UserCustomField" %> +

+<%= check_box 'custom_field', 'is_required' %>

+ +<% when "ProjectCustomField" %> +

+<%= check_box 'custom_field', 'is_required' %>

+ +<% end %> +
diff --git a/app/views/custom_fields/edit.rhtml b/app/views/custom_fields/edit.rhtml new file mode 100644 index 000000000..201047a8d --- /dev/null +++ b/app/views/custom_fields/edit.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_custom_field)%> (<%=l(@custom_field.type_name)%>)

+ +<%= start_form_tag({:action => 'edit', :id => @custom_field}, :class => "tabular") %> + <%= render :partial => 'form', :locals => { :type => @custom_field.type } %> + <%= submit_tag l(:button_save) %> +<%= end_form_tag %> diff --git a/app/views/custom_fields/list.rhtml b/app/views/custom_fields/list.rhtml new file mode 100644 index 000000000..858590c49 --- /dev/null +++ b/app/views/custom_fields/list.rhtml @@ -0,0 +1,36 @@ +

<%=l(:label_custom_field_plural)%>

+ + + + + + + + + + + +<% for custom_field in @custom_fields %> + "> + + + + + + + + +<% end %> +
<%=l(:field_name)%><%=l(:field_type)%><%=l(:field_field_format)%><%=l(:field_is_required)%><%=l(:field_is_for_all)%><%=l(:label_used_by)%>
<%= link_to custom_field.name, :action => 'edit', :id => custom_field %><%= l(custom_field.type_name) %><%= l(CustomField::FIELD_FORMATS[custom_field.field_format]) %><%= image_tag 'true' if custom_field.is_required? %><%= image_tag 'true' if custom_field.is_for_all? %><%= custom_field.projects.count.to_s + ' ' + lwr(:label_project, custom_field.projects.count) if custom_field.is_a? IssueCustomField and !custom_field.is_for_all? %> + <%= button_to l(:button_delete), { :action => 'destroy', :id => custom_field }, :confirm => l(:text_are_you_sure), :class => "button-small" %> +
+ +<%= pagination_links_full @custom_field_pages %> + +
+<%=l(:label_custom_field_new)%>: +
    +
  • <%= link_to l(:label_issue_plural), :action => 'new', :type => 'IssueCustomField' %>
  • +
  • <%= link_to l(:label_project_plural), :action => 'new', :type => 'ProjectCustomField' %>
  • +
  • <%= link_to l(:label_user_plural), :action => 'new', :type => 'UserCustomField' %>
  • +
diff --git a/app/views/custom_fields/new.rhtml b/app/views/custom_fields/new.rhtml new file mode 100644 index 000000000..3b215dc9f --- /dev/null +++ b/app/views/custom_fields/new.rhtml @@ -0,0 +1,8 @@ +

<%=l(:label_custom_field_new)%> (<%=l(@custom_field.type_name)%>)

+ +<%= start_form_tag({:action => 'new'}, :class => "tabular") %> + <%= render :partial => 'form', :locals => { :type => @custom_field.type } %> + <%= hidden_field_tag 'type', @custom_field.type %> + <%= submit_tag l(:button_save) %> +<%= end_form_tag %> + diff --git a/app/views/documents/_form.rhtml b/app/views/documents/_form.rhtml new file mode 100644 index 000000000..873c96329 --- /dev/null +++ b/app/views/documents/_form.rhtml @@ -0,0 +1,29 @@ +<%= error_messages_for 'document' %> +
+ +

+

+ +

+<%= text_field 'document', 'title', :size => 60 %>

+ +

+<%= text_area 'document', 'description', :cols => 60, :rows => 15 %>

+ +
+ +<% unless $RDM_TEXTILE_DISABLED %> +<%= javascript_include_tag 'jstoolbar' %> + +<% end %> \ No newline at end of file diff --git a/app/views/documents/edit.rhtml b/app/views/documents/edit.rhtml new file mode 100644 index 000000000..3db4bcc6a --- /dev/null +++ b/app/views/documents/edit.rhtml @@ -0,0 +1,8 @@ +

<%=l(:label_document)%>

+ +<%= start_form_tag({:action => 'edit', :id => @document}, :class => "tabular") %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<%= end_form_tag %> + + diff --git a/app/views/documents/show.rhtml b/app/views/documents/show.rhtml new file mode 100644 index 000000000..2f021e1b8 --- /dev/null +++ b/app/views/documents/show.rhtml @@ -0,0 +1,48 @@ +

<%= @document.title %>

+ +

<%= @document.category.name %>
+<%= format_date @document.created_on %>

+<%= textilizable @document.description %> + + + + + +
<%= link_to_if_authorized l(:button_edit), :controller => 'documents', :action => 'edit', :id => @document %> +<% if authorize_for('documents', 'destroy') %> + <%= start_form_tag({ :controller => 'documents', :action => 'destroy', :id => @document } ) %> + <%= submit_tag l(:button_delete) %> + <%= end_form_tag %> +<% end %> +
+
+ +

<%= l(:label_attachment_plural) %>

+
    +<% for attachment in @attachments %> +
  • + <% if authorize_for('documents', 'destroy_attachment') %> +
    + <%= start_form_tag({ :controller => 'documents', :action => 'destroy_attachment', :id => @document, :attachment_id => attachment } ) %> + <%= submit_tag l(:button_delete), :class => 'button-small' %> + <%= end_form_tag %> +
    + <% end %> + + <%= link_to attachment.filename, :action => 'download', :id => @document, :attachment_id => attachment %> + (<%= human_size attachment.filesize %>)
    + <%= attachment.author.display_name %>, <%= format_date(attachment.created_on) %>
    + <%= lwr(:label_download, attachment.downloads) %> +
  • +<% end %> +
+
+ + +<% if authorize_for('documents', 'add_attachment') %> + <%= start_form_tag ({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true) %> +    + <%= file_field 'attachment', 'file' %> + <%= submit_tag l(:button_add) %> + <%= end_form_tag %> +<% end %> diff --git a/app/views/enumerations/_form.rhtml b/app/views/enumerations/_form.rhtml new file mode 100644 index 000000000..637605939 --- /dev/null +++ b/app/views/enumerations/_form.rhtml @@ -0,0 +1,9 @@ +<%= error_messages_for 'enumeration' %> +
+ +<%= hidden_field 'enumeration', 'opt' %> + +

+<%= text_field 'enumeration', 'name' %>

+ +
\ No newline at end of file diff --git a/app/views/enumerations/edit.rhtml b/app/views/enumerations/edit.rhtml new file mode 100644 index 000000000..3002b5936 --- /dev/null +++ b/app/views/enumerations/edit.rhtml @@ -0,0 +1,10 @@ +

<%=l(:label_enumerations)%>

+ +<%= start_form_tag({:action => 'update', :id => @enumeration}, :class => "tabular") %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<%= end_form_tag %> + +<%= start_form_tag :action => 'destroy', :id => @enumeration %> + <%= submit_tag l(:button_delete) %> +<%= end_form_tag %> \ No newline at end of file diff --git a/app/views/enumerations/list.rhtml b/app/views/enumerations/list.rhtml new file mode 100644 index 000000000..15b91c1ac --- /dev/null +++ b/app/views/enumerations/list.rhtml @@ -0,0 +1,21 @@ +

<%=l(:label_enumerations)%>

+ +<% Enumeration::OPTIONS.each do |option, name| %> + + <% if @params[:opt]==option %> + +

<%= image_tag 'dir_open' %> <%= l(name) %>

+
    + <% for value in Enumeration.find(:all, :conditions => ["opt = ?", option]) %> +
  • <%= link_to value.name, :action => 'edit', :id => value %>
  • + <% end %> +
+
    +
  • <%= link_to ('» ' + l(:label_new)), :action => 'new', :opt => option %>
  • +
+ + <% else %> +

<%= image_tag 'dir' %> <%= link_to l(name), :opt => option %>

+ <% end %> + +<% end %> \ No newline at end of file diff --git a/app/views/enumerations/new.rhtml b/app/views/enumerations/new.rhtml new file mode 100644 index 000000000..0a773519d --- /dev/null +++ b/app/views/enumerations/new.rhtml @@ -0,0 +1,6 @@ +

<%= l(@enumeration.option_name) %>: <%=l(:label_enumeration_new)%>

+ +<%= start_form_tag({:action => 'create'}, :class => "tabular") %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> +<%= end_form_tag %> diff --git a/app/views/issue_categories/_form.rhtml b/app/views/issue_categories/_form.rhtml new file mode 100644 index 000000000..765b8f53d --- /dev/null +++ b/app/views/issue_categories/_form.rhtml @@ -0,0 +1,7 @@ +<%= error_messages_for 'issue_category' %> + + +

+<%= text_field 'issue_category', 'name' %>

+ + diff --git a/app/views/issue_categories/edit.rhtml b/app/views/issue_categories/edit.rhtml new file mode 100644 index 000000000..053facbf7 --- /dev/null +++ b/app/views/issue_categories/edit.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_issue_category)%>

+ +<%= start_form_tag({:action => 'edit', :id => @category}, :class => "tabular") %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<%= end_form_tag %> diff --git a/app/views/issue_statuses/_form.rhtml b/app/views/issue_statuses/_form.rhtml new file mode 100644 index 000000000..f3b1cf2ca --- /dev/null +++ b/app/views/issue_statuses/_form.rhtml @@ -0,0 +1,18 @@ +<%= error_messages_for 'issue_status' %> + +
+ +

+<%= text_field 'issue_status', 'name' %>

+ +

+<%= check_box 'issue_status', 'is_closed' %>

+ +

+<%= check_box 'issue_status', 'is_default' %>

+ +

+#<%= text_field 'issue_status', 'html_color', :maxlength => 6 %>

+ + +
\ No newline at end of file diff --git a/app/views/issue_statuses/edit.rhtml b/app/views/issue_statuses/edit.rhtml new file mode 100644 index 000000000..80f856a2a --- /dev/null +++ b/app/views/issue_statuses/edit.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_issue_status)%>

+ +<%= start_form_tag({:action => 'update', :id => @issue_status}, :class => "tabular") %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<%= end_form_tag %> diff --git a/app/views/issue_statuses/list.rhtml b/app/views/issue_statuses/list.rhtml new file mode 100644 index 000000000..023863437 --- /dev/null +++ b/app/views/issue_statuses/list.rhtml @@ -0,0 +1,28 @@ +

<%=l(:label_issue_status_plural)%>

+ + + + + + + + + + +<% for status in @issue_statuses %> + "> + + + + + + +<% end %> +
<%=l(:field_status)%><%=l(:field_is_default)%><%=l(:field_is_closed)%><%=l(:field_html_color)%>
<%= link_to status.name, :action => 'edit', :id => status %><%= image_tag 'true' if status.is_default? %><%= image_tag 'true' if status.is_closed? %>
 
+ <%= button_to l(:button_delete), { :action => 'destroy', :id => status }, :confirm => l(:text_are_you_sure), :class => "button-small" %> +
+ +<%= pagination_links_full @issue_status_pages %> +
+ +<%= link_to '» ' + l(:label_issue_status_new), :action => 'new' %> diff --git a/app/views/issue_statuses/new.rhtml b/app/views/issue_statuses/new.rhtml new file mode 100644 index 000000000..2dacb1e21 --- /dev/null +++ b/app/views/issue_statuses/new.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_issue_status_new)%>

+ +<%= start_form_tag({:action => 'create'}, :class => "tabular") %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> +<%= end_form_tag %> diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml new file mode 100644 index 000000000..6dc2a84be --- /dev/null +++ b/app/views/issues/_history.rhtml @@ -0,0 +1,11 @@ +<% for journal in journals %> +

<%= format_time(journal.created_on) %> - <%= journal.user.name %>

+
    + <% for detail in journal.details %> +
  • <%= show_detail(detail) %>
  • + <% end %> +
+ <% if journal.notes? %> + <%= simple_format auto_link journal.notes %> + <% end %> +<% end %> diff --git a/app/views/issues/_list_simple.rhtml b/app/views/issues/_list_simple.rhtml new file mode 100644 index 000000000..94b63d613 --- /dev/null +++ b/app/views/issues/_list_simple.rhtml @@ -0,0 +1,28 @@ +<% if issues.length > 0 %> + + + +
+ + + + + + + <% for issue in issues %> + "> + + + + + <% end %> +
#<%=l(:field_tracker)%><%=l(:field_subject)%>
+ <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>
+

<%= issue.project.name %> - <%= issue.tracker.name %>
+ <%= issue.status.name %> - <%= format_time(issue.updated_on) %>

+

<%= link_to issue.subject, :controller => 'issues', :action => 'show', :id => issue %>

+
+
+<% else %> + <%=l(:label_no_data)%> +<% end %> \ No newline at end of file diff --git a/app/views/issues/_pdf.rfpdf b/app/views/issues/_pdf.rfpdf new file mode 100644 index 000000000..1f6a12283 --- /dev/null +++ b/app/views/issues/_pdf.rfpdf @@ -0,0 +1,100 @@ +<% pdf.SetFont('Arial','B',11) + pdf.Cell(190,10, "#{issue.project.name} - #{issue.tracker.name} # #{issue.long_id} - #{issue.subject}") + pdf.Ln + + y0 = pdf.GetY + + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_status) + ":","LT") + pdf.SetFont('Arial','',9) + pdf.Cell(60,5, issue.status.name,"RT") + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_priority) + ":","LT") + pdf.SetFont('Arial','',9) + pdf.Cell(60,5, issue.priority.name,"RT") + pdf.Ln + + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_author) + ":","L") + pdf.SetFont('Arial','',9) + pdf.Cell(60,5, issue.author.name,"R") + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_category) + ":","L") + pdf.SetFont('Arial','',9) + pdf.Cell(60,5, (issue.category ? issue.category.name : "-"),"R") + pdf.Ln + + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_created_on) + ":","L") + pdf.SetFont('Arial','',9) + pdf.Cell(60,5, format_date(issue.created_on),"R") + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_assigned_to) + ":","L") + pdf.SetFont('Arial','',9) + pdf.Cell(60,5, (issue.assigned_to ? issue.assigned_to.name : "-"),"R") + pdf.Ln + + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_updated_on) + ":","LB") + pdf.SetFont('Arial','',9) + pdf.Cell(60,5, format_date(issue.updated_on),"RB") + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_due_date) + ":","LB") + pdf.SetFont('Arial','',9) + pdf.Cell(60,5, format_date(issue.due_date),"RB") + pdf.Ln + + for custom_value in issue.custom_values + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, custom_value.custom_field.name + ":","L") + pdf.SetFont('Arial','',9) + pdf.MultiCell(155,5, (show_value custom_value),"R") + end + + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_subject) + ":","LTB") + pdf.SetFont('Arial','',9) + pdf.Cell(155,5, issue.subject,"RTB") + pdf.Ln + + pdf.SetFont('Arial','B',9) + pdf.Cell(35,5, l(:field_description) + ":") + pdf.SetFont('Arial','',9) + pdf.MultiCell(155,5, issue.description,"BR") + + pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY) + pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY) + + pdf.Ln + + pdf.SetFont('Arial','B',9) + pdf.Cell(190,5, l(:label_history), "B") + pdf.Ln + for journal in issue.journals.find(:all, :include => :user, :order => "journals.created_on desc") + pdf.SetFont('Arial','B',8) + pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) + pdf.Ln + pdf.SetFont('Arial','I',8) + for detail in journal.details + pdf.Cell(190,5, "- " + show_detail(detail, true)) + pdf.Ln + end + if journal.notes? + pdf.SetFont('Arial','',8) + pdf.MultiCell(190,5, journal.notes) + end + pdf.Ln + end + + pdf.SetFont('Arial','B',9) + pdf.Cell(190,5, l(:label_attachment_plural), "B") + pdf.Ln + for attachment in issue.attachments + pdf.SetFont('Arial','',8) + pdf.Cell(80,5, attachment.filename) + pdf.Cell(20,5, human_size(attachment.filesize),0,0,"R") + pdf.Cell(20,5, format_date(attachment.created_on),0,0,"R") + pdf.Cell(70,5, attachment.author.name,0,0,"R") + pdf.Ln + end +%> \ No newline at end of file diff --git a/app/views/issues/change_status.rhtml b/app/views/issues/change_status.rhtml new file mode 100644 index 000000000..2ef87183d --- /dev/null +++ b/app/views/issues/change_status.rhtml @@ -0,0 +1,37 @@ +

<%=l(:label_issue)%> #<%= @issue.id %>: <%= @issue.subject %>

+ +<%= error_messages_for 'issue' %> +<%= start_form_tag({:action => 'change_status', :id => @issue}, :class => "tabular") %> + +<%= hidden_field_tag 'confirm', 1 %> +<%= hidden_field_tag 'new_status_id', @new_status.id %> + +
+

<%= @new_status.name %>

+ +

+

+ + +

+<%= select("issue", "done_ratio", ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) ) %> +

+ + +

+

+ +

+<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10 %>

+ +
+ +<%= hidden_field 'issue', 'lock_version' %> +<%= submit_tag l(:button_save) %> +<%= end_form_tag %> diff --git a/app/views/issues/edit.rhtml b/app/views/issues/edit.rhtml new file mode 100644 index 000000000..60cdafc1e --- /dev/null +++ b/app/views/issues/edit.rhtml @@ -0,0 +1,49 @@ +

<%= @issue.tracker.name %> #<%= @issue.id %> - <%= @issue.subject %>

+ +<% labelled_tabular_form_for :issue, @issue, :url => {:action => 'edit'} do |f| %> +<%= error_messages_for 'issue' %> +
+ +
+

<%= @issue.status.name %>

+

<%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %>

+

<%= f.select :assigned_to_id, (@issue.project.members.collect {|m| [m.name, m.user_id]}), :include_blank => true %>

+

<%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}) %>

+
+ +
+

<%= f.text_field :start_date, :size => 10 %><%= calendar_for('issue_start_date') %>

+

<%= f.text_field :due_date, :size => 10 %><%= calendar_for('issue_due_date') %>

+

<%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

+
+ +
+

<%= f.text_field :subject, :size => 80, :required => true %>

+

<%= f.text_area :description, :cols => 60, :rows => [[10, @issue.description.length / 50].max, 100].min, :required => true %>

+ +<% for @custom_value in @custom_values %> +

<%= custom_field_tag_with_label @custom_value %>

+<% end %> + +

<%= f.select :fixed_version_id, (@project.versions.collect {|v| [v.name, v.id]}), { :include_blank => true } %> +

+
+ +
+<%= f.hidden_field :lock_version %> +<%= submit_tag l(:button_save) %> +<% end %> + +<% unless $RDM_TEXTILE_DISABLED %> +<%= javascript_include_tag 'jstoolbar' %> + +<% end %> \ No newline at end of file diff --git a/app/views/issues/export_pdf.rfpdf b/app/views/issues/export_pdf.rfpdf new file mode 100644 index 000000000..a8622dd51 --- /dev/null +++ b/app/views/issues/export_pdf.rfpdf @@ -0,0 +1,9 @@ +<% pdf=IfpdfHelper::IFPDF.new + pdf.AliasNbPages + pdf.footer_date = format_date(Date.today) + pdf.AddPage + + render :partial => 'issues/pdf', :locals => { :pdf => pdf, :issue => @issue } +%> + +<%= pdf.Output %> \ No newline at end of file diff --git a/app/views/issues/history.rhtml b/app/views/issues/history.rhtml new file mode 100644 index 000000000..2443cc739 --- /dev/null +++ b/app/views/issues/history.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_history)%>

+
+<%= render :partial => 'history', :locals => { :journals => @journals } %> +
+
+

<%= link_to l(:button_back), :action => 'show', :id => @issue %>

\ No newline at end of file diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml new file mode 100644 index 000000000..8128b74a9 --- /dev/null +++ b/app/views/issues/show.rhtml @@ -0,0 +1,133 @@ +

<%= @issue.tracker.name %> #<%= @issue.id %> - <%= @issue.subject %>

+
+ +<%= link_to 'PDF', :action => 'export_pdf', :id => @issue %> + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +<% n = 0 +for custom_value in @custom_values %> + +<% n = n + 1 + if (n > 1) + n = 0 %> + + <%end +end %> + +
<%=l(:field_status)%> :<%= @issue.status.name %><%=l(:field_priority)%> :<%= @issue.priority.name %>
<%=l(:field_assigned_to)%> :<%= @issue.assigned_to ? @issue.assigned_to.name : "-" %><%=l(:field_category)%> :<%= @issue.category ? @issue.category.name : "-" %>
<%=l(:field_author)%> :<%= link_to_user @issue.author %><%=l(:field_start_date)%> :<%= format_date(@issue.start_date) %>
<%=l(:field_created_on)%> :<%= format_date(@issue.created_on) %><%=l(:field_due_date)%> :<%= format_date(@issue.due_date) %>
<%=l(:field_updated_on)%> :<%= format_date(@issue.updated_on) %><%=l(:field_done_ratio)%> :<%= @issue.done_ratio %> %
<%= custom_value.custom_field.name %> :<%= show_value custom_value %>
+
+
+ +<%=l(:field_description)%> :

+<%= textilizable @issue.description %> +
+
+<% if authorize_for('issues', 'edit') %> + <%= start_form_tag ({:controller => 'issues', :action => 'edit', :id => @issue}, :method => "get" ) %> + <%= submit_tag l(:button_edit) %> + <%= end_form_tag %> +    +<% end %> + +<% if authorize_for('issues', 'change_status') and @status_options and !@status_options.empty? %> + <%= start_form_tag ({:controller => 'issues', :action => 'change_status', :id => @issue}) %> + <%=l(:label_change_status)%> : + + <%= submit_tag l(:button_change) %> + <%= end_form_tag %> +    +<% end %> + +<% if authorize_for('projects', 'move_issues') %> + <%= start_form_tag ({:controller => 'projects', :action => 'move_issues', :id => @project} ) %> + <%= hidden_field_tag "issue_ids[]", @issue.id %> + <%= submit_tag l(:button_move) %> + <%= end_form_tag %> +    +<% end %> +
+
+<% if authorize_for('issues', 'destroy') %> + <%= start_form_tag ({:controller => 'issues', :action => 'destroy', :id => @issue} ) %> + <%= submit_tag l(:button_delete) %> + <%= end_form_tag %> +    +<% end %> +
+
+
+ +
+

<%=l(:label_history)%> +<% if @journals_count > @journals.length %>(<%= l(:label_last_changes, @journals.length) %>)<% end %>

+<%= render :partial => 'history', :locals => { :journals => @journals } %> +<% if @journals_count > @journals.length %> +

[ <%= link_to l(:label_change_view_all), :action => 'history', :id => @issue %> ]

+<% end %> +
+ +
+

<%=l(:label_attachment_plural)%>

+ +<% for attachment in @issue.attachments %> + + + + +<% if authorize_for('issues', 'destroy_attachment') %> + +<% end %> + +<% end %> +
<%= image_tag('attachment') %> <%= link_to attachment.filename, :action => 'download', :id => @issue, :attachment_id => attachment %> (<%= human_size(attachment.filesize) %>)<%= format_date(attachment.created_on) %><%= attachment.author.display_name %> + <%= start_form_tag :action => 'destroy_attachment', :id => @issue, :attachment_id => attachment %> + <%= submit_tag l(:button_delete), :class => "button-small" %> + <%= end_form_tag %> +
+
+<% if authorize_for('issues', 'add_attachment') %> + <%= start_form_tag ({ :controller => 'issues', :action => 'add_attachment', :id => @issue }, :multipart => true, :class => "tabular") %> +

+ <%= file_field_tag 'attachments[]', :size => 30 %>

+ <%= submit_tag l(:button_add) %> + <%= end_form_tag %> +<% end %> +
+ +<% if authorize_for('issues', 'add_note') %> +
+

<%= l(:label_add_note) %>

+ <%= start_form_tag ({:controller => 'issues', :action => 'add_note', :id => @issue}, :class => "tabular" ) %> +

+ <%= text_area_tag 'notes', '', :cols => 60, :rows => 10 %>

+ <%= submit_tag l(:button_add) %> + <%= end_form_tag %> +
+<% end %> diff --git a/app/views/layouts/base.rhtml b/app/views/layouts/base.rhtml new file mode 100644 index 000000000..951fa88f7 --- /dev/null +++ b/app/views/layouts/base.rhtml @@ -0,0 +1,142 @@ + + + +<%= $RDM_HEADER_TITLE + (@html_title ? ": #{@html_title}" : "") %> + + + +<%= stylesheet_link_tag "application" %> +<%= stylesheet_link_tag "menu" %> +<%= stylesheet_link_tag "rails" %> +<%= javascript_include_tag :defaults %> +<%= javascript_include_tag 'menu' %> +<%= javascript_include_tag 'calendar/calendar' %> +<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %> +<%= javascript_include_tag 'calendar/calendar-setup' %> +<%= stylesheet_link_tag 'calendar' %> +<%= stylesheet_link_tag 'jstoolbar' %> + + + + + +
+ + + + + + +
+ + <% unless @project.nil? || @project.id.nil? %> +

<%= @project.name %>

+ + <% end %> + + <% if loggedin? and @logged_in_user.memberships.length > 0 %> +

<%=l(:label_my_projects) %>

+ + <% end %> +
+ +
+ <% if flash[:notice] %>

<%= flash[:notice] %>

<% end %> + <%= @content_for_layout %> +
+ + + +
+ + \ No newline at end of file diff --git a/app/views/mailer/_issue.rhtml b/app/views/mailer/_issue.rhtml new file mode 100644 index 000000000..c123ae30c --- /dev/null +++ b/app/views/mailer/_issue.rhtml @@ -0,0 +1,7 @@ +<%=l(:label_issue)%> #<%= issue.id %> - <%= issue.subject %> +<%=l(:field_author)%>: <%= issue.author.display_name %> +<%=l(:field_status)%>: <%= issue.status.name %> + +<%= issue.description %> + +http://<%= $RDM_HOST_NAME %>/issues/show/<%= issue.id %> \ No newline at end of file diff --git a/app/views/mailer/issue_add_de.rhtml b/app/views/mailer/issue_add_de.rhtml new file mode 100644 index 000000000..9efec9ad9 --- /dev/null +++ b/app/views/mailer/issue_add_de.rhtml @@ -0,0 +1,3 @@ +Issue #<%= @issue.id %> has been reported. +---------------------------------------- +<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/app/views/mailer/issue_add_en.rhtml b/app/views/mailer/issue_add_en.rhtml new file mode 100644 index 000000000..9efec9ad9 --- /dev/null +++ b/app/views/mailer/issue_add_en.rhtml @@ -0,0 +1,3 @@ +Issue #<%= @issue.id %> has been reported. +---------------------------------------- +<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/app/views/mailer/issue_add_es.rhtml b/app/views/mailer/issue_add_es.rhtml new file mode 100644 index 000000000..9efec9ad9 --- /dev/null +++ b/app/views/mailer/issue_add_es.rhtml @@ -0,0 +1,3 @@ +Issue #<%= @issue.id %> has been reported. +---------------------------------------- +<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/app/views/mailer/issue_add_fr.rhtml b/app/views/mailer/issue_add_fr.rhtml new file mode 100644 index 000000000..628ecae12 --- /dev/null +++ b/app/views/mailer/issue_add_fr.rhtml @@ -0,0 +1,3 @@ +Une nouvelle demande (#<%= @issue.id %>) a été soumise. +---------------------------------------- +<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/app/views/mailer/issue_edit_de.rhtml b/app/views/mailer/issue_edit_de.rhtml new file mode 100644 index 000000000..d22d6c534 --- /dev/null +++ b/app/views/mailer/issue_edit_de.rhtml @@ -0,0 +1,8 @@ +Issue #<%= @issue.id %> has been updated. +<%= @journal.user.name %> +<% for detail in @journal.details %> +<%= show_detail(detail, true) %> +<% end %> +<%= @journal.notes if @journal.notes? %> +---------------------------------------- +<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/app/views/mailer/issue_edit_en.rhtml b/app/views/mailer/issue_edit_en.rhtml new file mode 100644 index 000000000..d22d6c534 --- /dev/null +++ b/app/views/mailer/issue_edit_en.rhtml @@ -0,0 +1,8 @@ +Issue #<%= @issue.id %> has been updated. +<%= @journal.user.name %> +<% for detail in @journal.details %> +<%= show_detail(detail, true) %> +<% end %> +<%= @journal.notes if @journal.notes? %> +---------------------------------------- +<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/app/views/mailer/issue_edit_es.rhtml b/app/views/mailer/issue_edit_es.rhtml new file mode 100644 index 000000000..d22d6c534 --- /dev/null +++ b/app/views/mailer/issue_edit_es.rhtml @@ -0,0 +1,8 @@ +Issue #<%= @issue.id %> has been updated. +<%= @journal.user.name %> +<% for detail in @journal.details %> +<%= show_detail(detail, true) %> +<% end %> +<%= @journal.notes if @journal.notes? %> +---------------------------------------- +<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/app/views/mailer/issue_edit_fr.rhtml b/app/views/mailer/issue_edit_fr.rhtml new file mode 100644 index 000000000..9edacb703 --- /dev/null +++ b/app/views/mailer/issue_edit_fr.rhtml @@ -0,0 +1,8 @@ +La demande #<%= @issue.id %> a été mise à jour. +<%= @journal.user.name %> - <%= format_date(@journal.created_on) %> +<% for detail in @journal.details %> +<%= show_detail(detail, true) %> +<% end %> +<%= journal.notes if journal.notes? %> +---------------------------------------- +<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/app/views/mailer/lost_password_de.rhtml b/app/views/mailer/lost_password_de.rhtml new file mode 100644 index 000000000..2593edbda --- /dev/null +++ b/app/views/mailer/lost_password_de.rhtml @@ -0,0 +1,3 @@ +To change your password, use the following link: + +http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %> \ No newline at end of file diff --git a/app/views/mailer/lost_password_en.rhtml b/app/views/mailer/lost_password_en.rhtml new file mode 100644 index 000000000..2593edbda --- /dev/null +++ b/app/views/mailer/lost_password_en.rhtml @@ -0,0 +1,3 @@ +To change your password, use the following link: + +http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %> \ No newline at end of file diff --git a/app/views/mailer/lost_password_es.rhtml b/app/views/mailer/lost_password_es.rhtml new file mode 100644 index 000000000..2593edbda --- /dev/null +++ b/app/views/mailer/lost_password_es.rhtml @@ -0,0 +1,3 @@ +To change your password, use the following link: + +http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %> \ No newline at end of file diff --git a/app/views/mailer/lost_password_fr.rhtml b/app/views/mailer/lost_password_fr.rhtml new file mode 100644 index 000000000..30996f118 --- /dev/null +++ b/app/views/mailer/lost_password_fr.rhtml @@ -0,0 +1,3 @@ +Pour changer votre mot de passe, utilisez le lien suivant: + +http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %> \ No newline at end of file diff --git a/app/views/mailer/register_de.rhtml b/app/views/mailer/register_de.rhtml new file mode 100644 index 000000000..2c0341b24 --- /dev/null +++ b/app/views/mailer/register_de.rhtml @@ -0,0 +1,3 @@ +To activate your redMine account, use the following link: + +http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %> \ No newline at end of file diff --git a/app/views/mailer/register_en.rhtml b/app/views/mailer/register_en.rhtml new file mode 100644 index 000000000..2c0341b24 --- /dev/null +++ b/app/views/mailer/register_en.rhtml @@ -0,0 +1,3 @@ +To activate your redMine account, use the following link: + +http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %> \ No newline at end of file diff --git a/app/views/mailer/register_es.rhtml b/app/views/mailer/register_es.rhtml new file mode 100644 index 000000000..2c0341b24 --- /dev/null +++ b/app/views/mailer/register_es.rhtml @@ -0,0 +1,3 @@ +To activate your redMine account, use the following link: + +http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %> \ No newline at end of file diff --git a/app/views/mailer/register_fr.rhtml b/app/views/mailer/register_fr.rhtml new file mode 100644 index 000000000..3f5d0ccaf --- /dev/null +++ b/app/views/mailer/register_fr.rhtml @@ -0,0 +1,3 @@ +Pour activer votre compte sur redMine, utilisez le lien suivant: + +http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %> \ No newline at end of file diff --git a/app/views/my/_block.rhtml b/app/views/my/_block.rhtml new file mode 100644 index 000000000..3f72bdaf1 --- /dev/null +++ b/app/views/my/_block.rhtml @@ -0,0 +1,16 @@ +
+ +
+ <%= link_to_remote "", { + :url => { :action => "remove_block", :block => block_name }, + :complete => "removeBlock('block_#{block_name}')", + :loading => "Element.show('indicator')", + :loaded => "Element.hide('indicator')" }, + :class => "close-icon" + %> +
+ +
+ <%= render :partial => "my/blocks/#{block_name}", :locals => { :user => user } %> +
+
\ No newline at end of file diff --git a/app/views/my/account.rhtml b/app/views/my/account.rhtml new file mode 100644 index 000000000..23b236e29 --- /dev/null +++ b/app/views/my/account.rhtml @@ -0,0 +1,47 @@ +

<%=l(:label_my_account)%>

+ +

<%=l(:field_login)%>: <%= @user.login %>
+<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>, +<%=l(:field_updated_on)%>: <%= format_time(@user.updated_on) %>

+ +<%= error_messages_for 'user' %> + +
+

<%=l(:label_information_plural)%>

+ +<% labelled_tabular_form_for :user, @user, :url => { :action => "account" } do |f| %> + +

<%= f.text_field :firstname, :required => true %>

+

<%= f.text_field :lastname, :required => true %>

+

<%= f.text_field :mail, :required => true, :size => 40 %>

+

<%= f.select :language, lang_options_for_select %>

+

<%= f.check_box :mail_notification %>

+ +<% fields_for :pref, @user.pref, :builder => TabularFormBuilder, :lang => current_language do |pref_fields| %> +

<%= pref_fields.check_box :hide_mail %>

+<% end %> + +
<%= submit_tag l(:button_save) %>
+<% end %> +
+ + +<% unless @user.auth_source_id %> +
+

<%=l(:field_password)%>

+ + <%= start_form_tag({:action => 'change_password'}, :class => "tabular") %> + +

+ <%= password_field_tag 'password', nil, :size => 25 %>

+ +

+ <%= password_field_tag 'new_password', nil, :size => 25 %>

+ +

+ <%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

+ +
<%= submit_tag l(:button_save) %>
+ <%= end_form_tag %> +
+<% end %> diff --git a/app/views/my/blocks/_calendar.rhtml b/app/views/my/blocks/_calendar.rhtml new file mode 100644 index 000000000..2d7930f52 --- /dev/null +++ b/app/views/my/blocks/_calendar.rhtml @@ -0,0 +1,45 @@ +

<%= l(:label_calendar) %>

+ +<% +@date_from = Date.today - (Date.today.cwday-1) +@date_to = Date.today + (7-Date.today.cwday) +@issues = Issue.find :all, + :conditions => ["issues.project_id in (#{@user.projects.collect{|m| m.id}.join(',')}) AND ((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", @date_from, @date_to, @date_from, @date_to], + :include => [:project, :tracker] unless @user.projects.empty? +@issues ||= [] +%> + + + + +<% 1.upto(7) do |d| %> + +<% end %> + + +<% day = @date_from +while day <= @date_to + if day.cwday == 1 %> + + <% end %> + + <%= '' if day.cwday >= 7 and day!=@date_to %> + <% + day = day + 1 +end %> + +
<%= day_name(d) %>
<%= day.cweek %>"> +

<%= day==Date.today ? "#{day.day}" : day.day %>

+ <% day_issues = [] + @issues.each { |i| day_issues << i if i.start_date == day or i.due_date == day } + day_issues.each do |i| %> + <%= if day == i.start_date and day == i.due_date + image_tag('arrow_bw') + elsif day == i.start_date + image_tag('arrow_from') + elsif day == i.due_date + image_tag('arrow_to') + end %> + <%= link_to "#{i.tracker.name} ##{i.id}", :controller => 'issues', :action => 'show', :id => i %>: <%= i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %>
+ <% end %> +
\ No newline at end of file diff --git a/app/views/my/blocks/_documents.rhtml b/app/views/my/blocks/_documents.rhtml new file mode 100644 index 000000000..5fa8c7980 --- /dev/null +++ b/app/views/my/blocks/_documents.rhtml @@ -0,0 +1,15 @@ +

<%=l(:label_document_plural)%>

+ +
    +<% for document in Document.find :all, + :limit => 10, + :conditions => "documents.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", + :include => [:project] %> +
  • + <%= link_to document.title, :controller => 'documents', :action => 'show', :id => document %> +
    + <%= truncate document.description, 150 %>
    + <%= format_time(document.created_on) %>
      +
  • +<% end unless @user.projects.empty? %> +
\ No newline at end of file diff --git a/app/views/my/blocks/_issues_assigned_to_me.rhtml b/app/views/my/blocks/_issues_assigned_to_me.rhtml new file mode 100644 index 000000000..2a4e2a05d --- /dev/null +++ b/app/views/my/blocks/_issues_assigned_to_me.rhtml @@ -0,0 +1,10 @@ +

<%=l(:label_assigned_to_me_issues)%>

+<% assigned_issues = Issue.find(:all, + :conditions => ["assigned_to_id=?", user.id], + :limit => 10, + :include => [ :status, :project, :tracker ], + :order => 'issues.updated_on DESC') %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %> +<% if assigned_issues.length > 0 %> +

<%=lwr(:label_last_updates, assigned_issues.length)%>

+<% end %> diff --git a/app/views/my/blocks/_issues_reported_by_me.rhtml b/app/views/my/blocks/_issues_reported_by_me.rhtml new file mode 100644 index 000000000..9b40b3606 --- /dev/null +++ b/app/views/my/blocks/_issues_reported_by_me.rhtml @@ -0,0 +1,10 @@ +

<%=l(:label_reported_issues)%>

+<% reported_issues = Issue.find(:all, + :conditions => ["author_id=?", user.id], + :limit => 10, + :include => [ :status, :project, :tracker ], + :order => 'issues.updated_on DESC') %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %> +<% if reported_issues.length > 0 %> +

<%=lwr(:label_last_updates, reported_issues.length)%>

+<% end %> \ No newline at end of file diff --git a/app/views/my/blocks/_latest_news.rhtml b/app/views/my/blocks/_latest_news.rhtml new file mode 100644 index 000000000..85430ef54 --- /dev/null +++ b/app/views/my/blocks/_latest_news.rhtml @@ -0,0 +1,13 @@ +

<%=l(:label_news_latest)%>

+ +
    +<% for news in News.find :all, + :limit => 10, + :conditions => "news.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", + :include => [:project, :author] %> +
  • <%= link_to news.title, :controller => 'news', :action => 'show', :id => news %>
    + <% unless news.summary.empty? %><%= news.summary %>
    <% end %> + <%= news.author.name %>, <%= format_time(news.created_on) %>
      +
  • +<% end unless @user.projects.empty? %> +
\ No newline at end of file diff --git a/app/views/my/page.rhtml b/app/views/my/page.rhtml new file mode 100644 index 000000000..121d48ca9 --- /dev/null +++ b/app/views/my/page.rhtml @@ -0,0 +1,30 @@ +

<%=l(:label_my_page)%>

+ +
+ <%= link_to l(:label_personalize_page), :action => 'page_layout' %> +
+ +
+ <% @blocks['top'].each do |b| %> +
+ <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
+ <% end if @blocks['top'] %> +
+ +
+ <% @blocks['left'].each do |b| %> +
+ <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
+ <% end if @blocks['left'] %> +
+ +
+ <% @blocks['right'].each do |b| %> +
+ <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
+ <% end if @blocks['right'] %> +
+ diff --git a/app/views/my/page_layout.rhtml b/app/views/my/page_layout.rhtml new file mode 100644 index 000000000..59a38567d --- /dev/null +++ b/app/views/my/page_layout.rhtml @@ -0,0 +1,121 @@ + + +
+<%= start_form_tag({:action => "add_block"}, :id => "block-form") %> + +<%= select_tag 'block', "" + options_for_select(@block_options), :id => "block-select", :class => "select-small" %> + +<%= link_to_remote l(:button_add), + :url => { :action => "add_block" }, + :with => "Form.serialize('block-form')", + :update => "list-top", + :position => :top, + :complete => "afterAddBlock();", + :loading => "Element.show('indicator')", + :loaded => "Element.hide('indicator')" + %> + +<%= end_form_tag %> +| +<%= link_to l(:button_save), :action => 'page_layout_save' %> | +<%= link_to l(:button_cancel), :action => 'page' %> + +
+ +
+ +
+ +

<%=l(:label_my_page)%>

+ +
+ <% @blocks['top'].each do |b| %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['top'] %> +
+ +
+ <% @blocks['left'].each do |b| %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['left'] %> +
+ +
+ <% @blocks['right'].each do |b| %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['right'] %> +
+ +<%= sortable_element 'list-top', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :complete => visual_effect(:highlight, 'list-top'), + :url => { :action => "order_blocks", :group => "top" }, + :loading => "Element.show('indicator')", + :loaded => "Element.hide('indicator')" + %> + + +<%= sortable_element 'list-left', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :complete => visual_effect(:highlight, 'list-left'), + :url => { :action => "order_blocks", :group => "left" }, + :loading => "Element.show('indicator')", + :loaded => "Element.hide('indicator')" %> + +<%= sortable_element 'list-right', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :complete => visual_effect(:highlight, 'list-right'), + :url => { :action => "order_blocks", :group => "right" }, + :loading => "Element.show('indicator')", + :loaded => "Element.hide('indicator')" %> + +<%= javascript_tag "updateSelect()" %> \ No newline at end of file diff --git a/app/views/news/_form.rhtml b/app/views/news/_form.rhtml new file mode 100644 index 000000000..2dcdc9f80 --- /dev/null +++ b/app/views/news/_form.rhtml @@ -0,0 +1,20 @@ +<%= error_messages_for 'news' %> +
+

<%= f.text_field :title, :required => true, :size => 60 %>

+

<%= f.text_area :summary, :cols => 60, :rows => 2 %>

+

<%= f.text_area :description, :required => true, :cols => 60, :rows => 15 %>

+
+ +<% unless $RDM_TEXTILE_DISABLED %> +<%= javascript_include_tag 'jstoolbar' %> + +<% end %> \ No newline at end of file diff --git a/app/views/news/edit.rhtml b/app/views/news/edit.rhtml new file mode 100644 index 000000000..5e015c4c7 --- /dev/null +++ b/app/views/news/edit.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_news)%>

+ +<% labelled_tabular_form_for :news, @news, :url => { :action => "edit" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> \ No newline at end of file diff --git a/app/views/news/show.rhtml b/app/views/news/show.rhtml new file mode 100644 index 000000000..91df09f0f --- /dev/null +++ b/app/views/news/show.rhtml @@ -0,0 +1,16 @@ +

<%= @news.title %>

+ +

<%= @news.summary %>
+<%= @news.author.display_name %>, <%= format_time(@news.created_on) %>

+
+<%= textilizable auto_link @news.description %> + +
+<% if authorize_for('news', 'destroy') %> + <%= start_form_tag ({:controller => 'news', :action => 'destroy', :id => @news}) %> + <%= submit_tag l(:button_delete) %> + <%= end_form_tag %> +<% end %> +
+ +<%= link_to_if_authorized l(:button_edit), :controller => 'news', :action => 'edit', :id => @news %> diff --git a/app/views/projects/_form.rhtml b/app/views/projects/_form.rhtml new file mode 100644 index 000000000..ab0b35fab --- /dev/null +++ b/app/views/projects/_form.rhtml @@ -0,0 +1,26 @@ +<%= error_messages_for 'project' %> +
+ +

<%= f.text_field :name, :required => true %>

+ +<% if admin_loggedin? and !@root_projects.empty? %> +

<%= f.select :parent_id, (@root_projects.collect {|p| [p.name, p.id]}), { :include_blank => true } %>

+<% end %> + +

<%= f.text_area :description, :required => true, :cols => 60, :rows => 3 %>

+

<%= f.text_field :homepage, :size => 40 %>

+

<%= f.check_box :is_public %>

+ +<% for @custom_value in @custom_values %> +

<%= custom_field_tag_with_label @custom_value %>

+<% end %> + +<% unless @custom_fields.empty? %> +

+<% for custom_field in @custom_fields %> + <%= check_box_tag "custom_field_ids[]", custom_field.id, ((@project.custom_fields.include? custom_field) or custom_field.is_for_all?), (custom_field.is_for_all? ? {:disabled => "disabled"} : {}) %> + <%= custom_field.name %> +<% end %>

+<% end %> + +
diff --git a/app/views/projects/activity.rhtml b/app/views/projects/activity.rhtml new file mode 100644 index 000000000..d6e5a1a43 --- /dev/null +++ b/app/views/projects/activity.rhtml @@ -0,0 +1,41 @@ +

<%=l(:label_activity)%>

+ +
+
+ <%= start_form_tag %> +

<%= select_month(@month, :prefix => "month", :discard_type => true) %> +<%= select_year(@year, :prefix => "year", :discard_type => true) %>

+ <%= check_box_tag 'show_issues', 1, @show_issues %><%= hidden_field_tag 'show_issues', 0 %> <%=l(:label_issue_plural)%>
+ <%= check_box_tag 'show_news', 1, @show_news %><%= hidden_field_tag 'show_news', 0 %> <%=l(:label_news_plural)%>
+ <%= check_box_tag 'show_files', 1, @show_files %><%= hidden_field_tag 'show_files', 0 %> <%=l(:label_attachment_plural)%>
+ <%= check_box_tag 'show_documents', 1, @show_documents %><%= hidden_field_tag 'show_documents', 0 %> <%=l(:label_document_plural)%>
+

<%= submit_tag l(:button_apply), :class => 'button-small' %>

+ <%= end_form_tag %> +
+<% @events_by_day.keys.sort {|x,y| y <=> x }.each do |day| %> +

<%= day_name(day.cwday) %> <%= format_date(day) %>

+
    + <% @events_by_day[day].sort {|x,y| y.created_on <=> x.created_on }.each do |e| %> +
  • + <% if e.is_a? Issue %> + <%= e.created_on.strftime("%H:%M") %> <%= link_to "#{e.tracker.name} ##{e.id}", :controller => 'issues', :action => 'show', :id => e %> (<%= e.status.name %>): <%= e.subject %>
    + <%= e.author.name %> + <% elsif e.is_a? News %> + <%= e.created_on.strftime("%H:%M") %> <%=l(:label_news)%>: <%= link_to e.title, :controller => 'news', :action => 'show', :id => e %>
    + <% unless e.summary.empty? %><%= e.summary %>
    <% end %> + <%= e.author.name %> + <% elsif (e.is_a? Attachment) and (e.container.is_a? Version) %> + <%= e.created_on.strftime("%H:%M") %> <%=l(:label_attachment)%> (Version <%= e.container.name %>): <%= link_to e.filename, :controller => 'projects', :action => 'list_files', :id => @project %>
    + <%= e.author.name %> + <% elsif (e.is_a? Attachment) and (e.container.is_a? Document) %> + <%= e.created_on.strftime("%H:%M") %> <%=l(:label_document)%>: <%= link_to e.container.title, :controller => 'documents', :action => 'show', :id => e %>
    + <%= e.author.name %> + <% end %> +

  • + + <% end %> +
+<% end %> +<% if @events_by_day.empty? %>

<%= l(:label_no_data) %>

<% end %> +
+
\ No newline at end of file diff --git a/app/views/projects/add.rhtml b/app/views/projects/add.rhtml new file mode 100644 index 000000000..bafbf9145 --- /dev/null +++ b/app/views/projects/add.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_project_new)%>

+ +<% labelled_tabular_form_for :project, @project, :url => { :action => "add" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> \ No newline at end of file diff --git a/app/views/projects/add_document.rhtml b/app/views/projects/add_document.rhtml new file mode 100644 index 000000000..88572f409 --- /dev/null +++ b/app/views/projects/add_document.rhtml @@ -0,0 +1,14 @@ +

<%=l(:label_document_new)%>

+ +<%= start_form_tag( { :action => 'add_document', :id => @project }, :class => "tabular", :multipart => true) %> +<%= render :partial => 'documents/form' %> + +
+

+<%= file_field 'attachment', 'file' %>

+
+ +<%= submit_tag l(:button_create) %> +<%= end_form_tag %> + + diff --git a/app/views/projects/add_file.rhtml b/app/views/projects/add_file.rhtml new file mode 100644 index 000000000..fee67c53f --- /dev/null +++ b/app/views/projects/add_file.rhtml @@ -0,0 +1,14 @@ +

<%=l(:label_attachment_new)%>

+ +<%= error_messages_for 'attachment' %> +<%= start_form_tag ({ :action => 'add_file', :project => @project }, :multipart => true) %> + +


+

+ +

<%=l(:label_attachment)%>
<%= file_field 'attachment', 'file' %>

+
+<%= submit_tag l(:button_add) %> +<%= end_form_tag %> \ No newline at end of file diff --git a/app/views/projects/add_issue.rhtml b/app/views/projects/add_issue.rhtml new file mode 100644 index 000000000..b60f91a2e --- /dev/null +++ b/app/views/projects/add_issue.rhtml @@ -0,0 +1,50 @@ +

<%=l(:label_issue_new)%>: <%= @tracker.name %>

+ +<% labelled_tabular_form_for :issue, @issue, :url => {:action => 'add_issue'}, :html => {:multipart => true} do |f| %> +<%= error_messages_for 'issue' %> +
+ +<%= hidden_field_tag 'tracker_id', @tracker.id %> + +
+

<%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %>

+

<%= f.select :assigned_to_id, (@issue.project.members.collect {|m| [m.name, m.user_id]}), :include_blank => true %>

+

<%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>

+
+
+

<%= f.text_field :start_date, :size => 10 %><%= calendar_for('issue_start_date') %>

+

<%= f.text_field :due_date, :size => 10 %><%= calendar_for('issue_due_date') %>

+

<%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

+
+ +
+

<%= f.text_field :subject, :size => 80, :required => true %>

+

<%= f.text_area :description, :cols => 60, :rows => 10, :required => true %>

+ +<% for @custom_value in @custom_values %> +

<%= custom_field_tag_with_label @custom_value %>

+<% end %> + +

+<%= file_field_tag 'attachments[]', :size => 30 %>

+ +
+ +
+<%= submit_tag l(:button_create) %> +<% end %> + +<% unless $RDM_TEXTILE_DISABLED %> +<%= javascript_include_tag 'jstoolbar' %> + +<% end %> \ No newline at end of file diff --git a/app/views/projects/add_news.rhtml b/app/views/projects/add_news.rhtml new file mode 100644 index 000000000..a6ecd3da7 --- /dev/null +++ b/app/views/projects/add_news.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_news_new)%>

+ +<% labelled_tabular_form_for :news, @news, :url => { :action => "add_news" } do |f| %> +<%= render :partial => 'news/form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> \ No newline at end of file diff --git a/app/views/projects/add_version.rhtml b/app/views/projects/add_version.rhtml new file mode 100644 index 000000000..c038b7de9 --- /dev/null +++ b/app/views/projects/add_version.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_version_new)%>

+ +<% labelled_tabular_form_for :version, @version, :url => { :action => 'add_version' } do |f| %> +<%= render :partial => 'versions/form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> \ No newline at end of file diff --git a/app/views/projects/calendar.rhtml b/app/views/projects/calendar.rhtml new file mode 100644 index 000000000..fc62921d4 --- /dev/null +++ b/app/views/projects/calendar.rhtml @@ -0,0 +1,75 @@ +

<%= l(:label_calendar) %>

+ + + + + + +
+<%= start_form_tag :action => 'calendar', :id => @project %> +<%= select_month(@month, :prefix => "month", :discard_type => true) %> +<%= select_year(@year, :prefix => "year", :discard_type => true) %> +<%= submit_tag l(:button_submit), :class => "button-small" %> +<%= end_form_tag %> + +<%= image_tag 'gantt' %> +<%= link_to l(:label_gantt_chart), :action => 'gantt', :id => @project %>  +
+
+ + + + +<% 1.upto(7) do |d| %> + +<% end %> + + +<% day = @date_from +while day <= @date_to + if day.cwday == 1 %> + + <% end %> + + <%= '' if day.cwday >= 7 and day!=@date_to %> + <% + day = day + 1 +end %> + +
<%= day_name(d) %>
<%= day.cweek %>"> +

<%= day==Date.today ? "#{day.day}" : day.day %>

+ <% day_issues = [] + @issues.each { |i| day_issues << i if i.start_date == day or i.due_date == day } + day_issues.each do |i| %> + <%= if day == i.start_date and day == i.due_date + image_tag('arrow_bw') + elsif day == i.start_date + image_tag('arrow_from') + elsif day == i.due_date + image_tag('arrow_to') + end %> + <%= link_to "#{i.tracker.name} ##{i.id}", :controller => 'issues', :action => 'show', :id => i %>: <%= i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %>
+ <% end %> +
+ + + + + + +
+<%= link_to_remote ('« ' + l(:label_previous)), + {:update => "content", :url => { :year => (@month==1 ? @year-1 : @year), :month =>(@month==1 ? 12 : @month-1) }}, + {:href => url_for(:action => 'calendar', :year => (@month==1 ? @year-1 : @year), :month =>(@month==1 ? 12 : @month-1))} + %> + +<%= link_to_remote (l(:label_next) + ' »'), + {:update => "content", :url => { :year => (@month==12 ? @year+1 : @year), :month =>(@month==12 ? 1 : @month+1) }}, + {:href => url_for(:action => 'calendar', :year => (@month==12 ? @year+1 : @year), :month =>(@month==12 ? 1 : @month+1))} + %> +  +
+
+<%= image_tag 'arrow_from' %>  <%= l(:text_tip_task_begin_day) %>
+<%= image_tag 'arrow_to' %>  <%= l(:text_tip_task_end_day) %>
+<%= image_tag 'arrow_bw' %>  <%= l(:text_tip_task_begin_end_day) %>
\ No newline at end of file diff --git a/app/views/projects/changelog.rhtml b/app/views/projects/changelog.rhtml new file mode 100644 index 000000000..081456413 --- /dev/null +++ b/app/views/projects/changelog.rhtml @@ -0,0 +1,28 @@ +

<%=l(:label_change_log)%>

+ +
+ +
+<%= start_form_tag %> +<%=l(:label_tracker_plural)%>
+<% @trackers.each do |tracker| %> + <%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %> + <%= tracker.name %>
+<% end %> +

<%= submit_tag l(:button_apply), :class => 'button-small' %>

+<%= end_form_tag %> +
+ +<% ver_id = nil + @fixed_issues.each do |issue| %> + <% unless ver_id == issue.fixed_version_id %> + <% if ver_id %><% end %> +

<%= l(:label_version) %>: <%= issue.fixed_version.name %>

+

<%= format_date(issue.fixed_version.effective_date) %>
+ <%=h issue.fixed_version.description %>

+
    + <% ver_id = issue.fixed_version_id + end %> +
  • <%= link_to issue.long_id, :controller => 'issues', :action => 'show', :id => issue %> [<%= issue.tracker.name %>]: <%= issue.subject %>
  • +<% end %> +
\ No newline at end of file diff --git a/app/views/projects/destroy.rhtml b/app/views/projects/destroy.rhtml new file mode 100644 index 000000000..d11705be4 --- /dev/null +++ b/app/views/projects/destroy.rhtml @@ -0,0 +1,14 @@ +

<%=l(:label_confirmation)%>

+
+
+

<%= @project.name %>
+<%=l(:text_project_destroy_confirmation)%>

+ +

+ <%= start_form_tag({:controller => 'projects', :action => 'destroy', :id => @project}) %> + <%= hidden_field_tag "confirm", 1 %> + <%= submit_tag l(:button_delete) %> + <%= end_form_tag %> +

+
+
\ No newline at end of file diff --git a/app/views/projects/export_issues_pdf.rfpdf b/app/views/projects/export_issues_pdf.rfpdf new file mode 100644 index 000000000..2e0acf54b --- /dev/null +++ b/app/views/projects/export_issues_pdf.rfpdf @@ -0,0 +1,11 @@ +<% pdf=IfpdfHelper::IFPDF.new + pdf.AliasNbPages + pdf.footer_date = format_date(Date.today) + pdf.AddPage + @issues.each {|i| + render :partial => 'issues/pdf', :locals => { :pdf => pdf, :issue => i } + pdf.AddPage + } +%> + +<%= pdf.Output %> \ No newline at end of file diff --git a/app/views/projects/gantt.rfpdf b/app/views/projects/gantt.rfpdf new file mode 100644 index 000000000..545abb483 --- /dev/null +++ b/app/views/projects/gantt.rfpdf @@ -0,0 +1,168 @@ +<% +pdf=IfpdfHelper::IFPDF.new +pdf.AliasNbPages +pdf.footer_date = format_date(Date.today) +pdf.AddPage("L") +pdf.SetFont('Arial','B',12) +pdf.SetX(15) +pdf.Cell(70, 20, @project.name) +pdf.Ln +pdf.SetFont('Arial','B',9) + +subject_width = 70 +header_heigth = 5 + +headers_heigth = header_heigth +show_weeks = false +show_days = false + +if @months < 7 + show_weeks = true + headers_heigth = 2*header_heigth + if @months < 3 + show_days = true + headers_heigth = 3*header_heigth + end +end + +g_width = 210 +zoom = (g_width) / (@date_to - @date_from + 1) +g_height = 120 +t_height = g_height + headers_heigth + +y_start = pdf.GetY + + +# +# Months headers +# +month_f = @date_from +left = subject_width +height = header_heigth +@months.times do + width = ((month_f >> 1) - month_f) * zoom + pdf.SetY(y_start) + pdf.SetX(left) + pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C") + left = left + width + month_f = month_f >> 1 +end + +# +# Weeks headers +# +if show_weeks + left = subject_width + height = header_heigth + if @date_from.cwday == 1 + # @date_from is monday + week_f = @date_from + else + # find next monday after @date_from + week_f = @date_from + (7 - @date_from.cwday + 1) + width = (7 - @date_from.cwday + 1) * zoom-1 + pdf.SetY(y_start + header_heigth) + pdf.SetX(left) + pdf.Cell(width + 1, height, "", "LTR") + left = left + width+1 + end + while week_f < @date_to + width = (week_f + 6 <= @date_to) ? 7 * zoom : (@date_to - week_f + 1) * zoom + pdf.SetY(y_start + header_heigth) + pdf.SetX(left) + pdf.Cell(width, height, week_f.cweek.to_s, "LTR", 0, "C") + left = left + width + week_f = week_f+7 + end +end + +# +# Days headers +# +if show_days + left = subject_width + height = header_heigth + wday = @date_from.cwday + pdf.SetFont('Arial','B',7) + (@date_to - @date_from + 1).to_i.times do + width = zoom + pdf.SetY(y_start + 2 * header_heigth) + pdf.SetX(left) + pdf.Cell(width, height, day_name(wday)[0,1], "LTR", 0, "C") + left = left + width + wday = wday + 1 + wday = 1 if wday > 7 + end +end + +pdf.SetY(y_start) +pdf.SetX(15) +pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1) + + +# +# Tasks +# +top = headers_heigth + y_start +pdf.SetFont('Arial','B',7) +@issues.each do |i| + pdf.SetY(top) + pdf.SetX(15) + pdf.Cell(subject_width-15, 5, "#{i.tracker.name} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR") + + pdf.SetY(top) + pdf.SetX(subject_width) + pdf.Cell(g_width, 5, "", "LR") + + i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from ) + i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to ) + + i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor + i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date ) + i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date ) + + i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today + + i_left = ((i_start_date - @date_from)*zoom) + i_width = ((i_end_date - i_start_date + 1)*zoom) + d_width = ((i_done_date - i_start_date)*zoom) + l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date + l_width ||= 0 + + pdf.SetY(top+1.5) + pdf.SetX(subject_width + i_left) + pdf.SetFillColor(200,200,200) + pdf.Cell(i_width, 2, "", 0, 0, "", 1) + + if l_width > 0 + pdf.SetY(top+1.5) + pdf.SetX(subject_width + i_left) + pdf.SetFillColor(255,100,100) + pdf.Cell(l_width, 2, "", 0, 0, "", 1) + end + if d_width > 0 + pdf.SetY(top+1.5) + pdf.SetX(subject_width + i_left) + pdf.SetFillColor(100,100,255) + pdf.Cell(d_width, 2, "", 0, 0, "", 1) + end + + pdf.SetY(top+1.5) + pdf.SetX(subject_width + i_left + i_width) + pdf.Cell(30, 2, "#{i.status.name} #{i.done_ratio}%") + + top = top + 5 + pdf.SetDrawColor(200, 200, 200) + pdf.Line(15, top, subject_width+g_width, top) + if pdf.GetY() > 180 + pdf.AddPage("L") + top = 20 + pdf.Line(15, top, subject_width+g_width, top) + end + pdf.SetDrawColor(0, 0, 0) +end + +pdf.Line(15, top, subject_width+g_width, top) + +%> +<%= pdf.Output %> \ No newline at end of file diff --git a/app/views/projects/gantt.rhtml b/app/views/projects/gantt.rhtml new file mode 100644 index 000000000..78d3ac20a --- /dev/null +++ b/app/views/projects/gantt.rhtml @@ -0,0 +1,241 @@ +

<%= l(:label_gantt_chart) %>

+
+ +<%= l(:label_export_to) %>  <%= link_to 'PDF', :zoom => @zoom, :year => @year_from, :month => @month_from, :months => @months, :output => 'pdf' %> + +
+ + + + + + +
+<%= start_form_tag %> + +<%= l(:label_months_from) %> +<%= select_month(@month_from, :prefix => "month", :discard_type => true) %> +<%= select_year(@year_from, :prefix => "year", :discard_type => true) %> +<%= hidden_field_tag 'zoom', @zoom %> +<%= submit_tag l(:button_submit), :class => "button-small" %> +<%= end_form_tag %> + +<%= if @zoom < 4 + link_to image_tag('zoom_in'), {:zoom => (@zoom+1), :year => @year_from, :month => @month_from, :months => @months} + else + image_tag 'zoom_in_g' + end %> +<%= if @zoom > 1 + link_to image_tag('zoom_out'), :zoom => (@zoom-1), :year => @year_from, :month => @month_from, :months => @months + else + image_tag 'zoom_out_g' + end %> +
+
+ + + +<% zoom = 1 +@zoom.times { zoom = zoom * 2 } + +subject_width = 260 +header_heigth = 18 + +headers_heigth = header_heigth +show_weeks = false +show_days = false + +if @zoom >1 + show_weeks = true + headers_heigth = 2*header_heigth + if @zoom > 2 + show_days = true + headers_heigth = 3*header_heigth + end +end + +g_width = (@date_to - @date_from + 1)*zoom +g_height = [(20 * @issues.length + 6), 206].max +t_height = g_height + headers_heigth +%> + + + + + + +
+ +
+
+
+<% +# +# Tasks subjects +# +top = headers_heigth + 8 +@issues.each do |i| %> +
+ <%= link_to "#{i.tracker.name} ##{i.id}", :controller => 'issues', :action => 'show', :id => i %>: + <%= i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %> +
+<% top = top + 20 +end %> +
+
+ +
+
 
+<% +# +# Months headers +# +month_f = @date_from +left = 0 +height = (show_weeks ? header_heigth : header_heigth + g_height) +@months.times do + width = ((month_f >> 1) - month_f) * zoom - 1 + %> +
+ <%= link_to "#{month_f.year}-#{month_f.month}", :year => month_f.year, :month => month_f.month, :zoom => @zoom, :months => @months %> +
+ <% + left = left + width + 1 + month_f = month_f >> 1 +end %> + +<% +# +# Weeks headers +# +if show_weeks + left = 0 + height = (show_days ? header_heigth-1 : header_heigth-1 + g_height) + if @date_from.cwday == 1 + # @date_from is monday + week_f = @date_from + else + # find next monday after @date_from + week_f = @date_from + (7 - @date_from.cwday + 1) + width = (7 - @date_from.cwday + 1) * zoom-1 + %> +
 
+ <% + left = left + width+1 + end %> + <% + while week_f < @date_to + width = (week_f + 6 <= @date_to) ? 7 * zoom -1 : (@date_to - week_f + 1) * zoom-1 + %> +
+ <%= week_f.cweek %> +
+ <% + left = left + width+1 + week_f = week_f+7 + end +end %> + +<% +# +# Days headers +# +if show_days + left = 0 + height = g_height + header_heigth - 1 + wday = @date_from.cwday + (@date_to - @date_from + 1).to_i.times do + width = zoom - 1 + %> +
5 %>" class="m_bg"> + <%= day_name(wday)[0,1] %> +
+ <% + left = left + width+1 + wday = wday + 1 + wday = 1 if wday > 7 + end +end %> + +<% +# +# Today red line +# +if Date.today >= @date_from and Date.today <= @date_to %> +
 
+<% end %> + +<% +# +# Tasks +# +top = headers_heigth + 12 +@issues.each do |i| %> + <% + i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from ) + i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to ) + + i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor + i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date ) + i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date ) + + i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today + + i_left = ((i_start_date - @date_from)*zoom).floor + i_width = ((i_end_date - i_start_date + 1)*zoom).floor + d_width = ((i_done_date - i_start_date)*zoom).floor + l_width = ((i_late_date - i_start_date+1)*zoom).floor if i_late_date + l_width ||= 0 + %> +
 
+ <% if l_width > 0 %> +
 
+ <% end %> + <% if d_width > 0 %> +
 
+ <% end %> +
+ <%= i.status.name %> + <%= (i.done_ratio).to_i %>% +
+ <% top = top + 20 +end %> +
+
+ + + + + + +
<%= link_to ('« ' + l(:label_previous)), :year => (@date_from << @months).year, :month => (@date_from << @months).month, :zoom => @zoom, :months => @months %> +<%= link_to (l(:label_next) + ' »'), :year => (@date_from >> @months).year, :month => (@date_from >> @months).month, :zoom => @zoom, :months => @months %>
\ No newline at end of file diff --git a/app/views/projects/list.rhtml b/app/views/projects/list.rhtml new file mode 100644 index 000000000..0137086d9 --- /dev/null +++ b/app/views/projects/list.rhtml @@ -0,0 +1,20 @@ +

<%=l(:label_public_projects)%>

+ + + + <%= sort_header_tag('name', :caption => l(:label_project)) %> + + <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> + + +<% for project in @projects %> + "> + +<% end %> +
<%=l(:field_description)%>
<%= link_to project.name, :action => 'show', :id => project %> + <%= project.description %> + <%= format_date(project.created_on) %> +
+ +<%= pagination_links_full @project_pages %> +[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ] \ No newline at end of file diff --git a/app/views/projects/list_documents.rhtml b/app/views/projects/list_documents.rhtml new file mode 100644 index 000000000..e6cf2b828 --- /dev/null +++ b/app/views/projects/list_documents.rhtml @@ -0,0 +1,23 @@ +

<%=l(:label_document_plural)%>

+ +<% if @documents.empty? %>

<%= l(:label_no_data) %>

<% end %> + +<% documents = @documents.group_by {|d| d.category } %> +<% documents.each do |category, docs| %> +

<%= category.name %>

+
    +<% docs.each do |d| %> +
  • + <%= link_to d.title, :controller => 'documents', :action => 'show', :id => d %> +
    + <%= truncate d.description, 250 %>
    + <%= format_time(d.created_on) %>
      +
  • + +<% end %> +
+<% end %> + +

+<%= link_to_if_authorized '» ' + l(:label_document_new), :controller => 'projects', :action => 'add_document', :id => @project %> +

diff --git a/app/views/projects/list_files.rhtml b/app/views/projects/list_files.rhtml new file mode 100644 index 000000000..5fe65e6a6 --- /dev/null +++ b/app/views/projects/list_files.rhtml @@ -0,0 +1,46 @@ +

<%=l(:label_attachment_plural)%>

+ +<% delete_allowed = authorize_for('versions', 'destroy_file') %> + + + + + + + + + + <% if delete_allowed %><% end %> + + +<% for version in @versions %> + <% unless version.attachments.empty? %> + + <% for file in version.attachments %> + "> + + + + + + + <% if delete_allowed %> + + <% end %> + + <% end + reset_cycle %> + <% end %> +<% end %> +
<%=l(:field_version)%><%=l(:field_filename)%><%=l(:label_date)%><%=l(:field_filesize)%>D/LMD5
<%= image_tag 'package' %> <%= version.name %>
<%= link_to file.filename, :controller => 'versions', :action => 'download', :id => version, :attachment_id => file %><%= format_date(file.created_on) %><%= human_size(file.filesize) %><%= file.downloads %><%= file.digest %> + <%= start_form_tag :controller => 'versions', :action => 'destroy_file', :id => version, :attachment_id => file %> + <%= submit_tag l(:button_delete), :class => "button-small" %> + <%= end_form_tag %> +
+ +
+

+<%= link_to_if_authorized '» ' + l(:label_attachment_new), :controller => 'projects', :action => 'add_file', :id => @project %> +

+ + diff --git a/app/views/projects/list_issues.rhtml b/app/views/projects/list_issues.rhtml new file mode 100644 index 000000000..e7e3ceeda --- /dev/null +++ b/app/views/projects/list_issues.rhtml @@ -0,0 +1,76 @@ +

<%=l(:label_issue_plural)%>

+
+ +<%= l(:label_export_to) %>  +<%= link_to 'CSV', :action => 'export_issues_csv', :id => @project %>, +<%= link_to 'PDF', :action => 'export_issues_pdf', :id => @project %> + +
+ +<%= start_form_tag :action => 'list_issues' %> + + + + + + + + + + + + + +
<%=l(:field_status)%>:
<%= search_filter_tag 'status_id', :class => 'select-small' %>
<%=l(:field_tracker)%>:
<%= search_filter_tag 'tracker_id', :class => 'select-small' %>
<%=l(:field_priority)%>:
<%= search_filter_tag 'priority_id', :class => 'select-small' %>
<%=l(:field_category)%>:
<%= search_filter_tag 'category_id', :class => 'select-small' %>
<%=l(:field_fixed_version)%>:
<%= search_filter_tag 'fixed_version_id', :class => 'select-small' %>
<%=l(:field_author)%>:
<%= search_filter_tag 'author_id', :class => 'select-small' %>
<%=l(:field_assigned_to)%>:
<%= search_filter_tag 'assigned_to_id', :class => 'select-small' %>
<%=l(:label_subproject_plural)%>:
<%= search_filter_tag 'subproject_id', :class => 'select-small' %>
+ <%= hidden_field_tag 'set_filter', 1 %> + <%= submit_tag l(:button_apply), :class => 'button-small' %> + + <%= link_to l(:button_clear), :action => 'list_issues', :id => @project, :set_filter => 1 %> +
+<%= end_form_tag %> + +   + + + + + +
<%= check_all_links 'issues_form' %> + <%= l(:label_per_page) %>: + <%= start_form_tag %> + <%= select_tag 'per_page', options_for_select(@results_per_page_options, @results_per_page), :class => 'select-small'%> + <%= submit_tag l(:button_apply), :class => 'button-small'%> + <%= end_form_tag %> +
+<%= start_form_tag({:controller => 'projects', :action => 'move_issues', :id => @project}, :id => 'issues_form' ) %> + + + + + <%= sort_header_tag('issues.id', :caption => '#') %> + <%= sort_header_tag('issue_statuses.name', :caption => l(:field_status)) %> + <%= sort_header_tag('issues.tracker_id', :caption => l(:field_tracker)) %> + + <%= sort_header_tag('users.lastname', :caption => l(:field_author)) %> + <%= sort_header_tag('issues.created_on', :caption => l(:field_created_on)) %> + <%= sort_header_tag('issues.updated_on', :caption => l(:field_updated_on)) %> + + <% for issue in @issues %> + "> + + + + + + + + + + <% end %> +
<%=l(:field_subject)%>
<%= check_box_tag "issue_ids[]", issue.id %><%= link_to issue.long_id, :controller => 'issues', :action => 'show', :id => issue %><%= issue.status.name %><%= issue.tracker.name %><%= link_to issue.subject, :controller => 'issues', :action => 'show', :id => issue %><%= issue.author.display_name %><%= format_time(issue.created_on) %><%= format_time(issue.updated_on) %>
+

+<%= pagination_links_full @issue_pages %> +[ <%= @issue_pages.current.first_item %> - <%= @issue_pages.current.last_item %> / <%= @issue_count %> ] +

+<%= submit_tag l(:button_move) %> +<%= end_form_tag %> \ No newline at end of file diff --git a/app/views/projects/list_members.rhtml b/app/views/projects/list_members.rhtml new file mode 100644 index 000000000..655abb280 --- /dev/null +++ b/app/views/projects/list_members.rhtml @@ -0,0 +1,11 @@ +

<%=l(:label_member_plural)%>

+ +<% members = @members.group_by {|m| m.role } %> +<% members.each do |role, member| %> +

<%= role.name %>

+
    +<% member.each do |m| %> +
  • <%= link_to m.user.display_name, :controller => 'account', :action => 'show', :id => m.user %> (<%= format_date m.created_on %>)
  • +<% end %> +
+<% end %> diff --git a/app/views/projects/list_news.rhtml b/app/views/projects/list_news.rhtml new file mode 100644 index 000000000..6880de32f --- /dev/null +++ b/app/views/projects/list_news.rhtml @@ -0,0 +1,18 @@ +

<%=l(:label_news_plural)%>

+ +<% if @news.empty? %>

<%= l(:label_no_data) %>

<% end %> + +
    +<% for news in @news %> +
  • <%= link_to news.title, :controller => 'news', :action => 'show', :id => news %>
    + <% unless news.summary.empty? %><%= news.summary %>
    <% end %> + <%= news.author.name %>, <%= format_time(news.created_on) %>
      +
  • +<% end %> +
+ + +<%= pagination_links_full @news_pages %> +

+<%= link_to_if_authorized '» ' + l(:label_news_new), :controller => 'projects', :action => 'add_news', :id => @project %> +

diff --git a/app/views/projects/move_issues.rhtml b/app/views/projects/move_issues.rhtml new file mode 100644 index 000000000..380d47fd5 --- /dev/null +++ b/app/views/projects/move_issues.rhtml @@ -0,0 +1,24 @@ +

<%=l(:button_move)%>

+ + +<%= start_form_tag({:action => 'move_issues', :id => @project}, :class => "tabular") %> + +
+

+<% for issue in @issues %> + <%= link_to issue.long_id, :controller => 'issues', :action => 'show', :id => issue %> - <%= issue.subject %> + <%= hidden_field_tag "issue_ids[]", issue.id %>
+<% end %> +(<%= @issues.length%> <%= lwr(:label_issue, @issues.length)%>)

+ +  + + +

+<%= select_tag "new_project_id", options_from_collection_for_select(@projects, "id", "name", @project.id) %>

+ +

+<%= select_tag "new_tracker_id", options_from_collection_for_select(@trackers, "id", "name") %>

+
+<%= submit_tag l(:button_move) %> +<%= end_form_tag %> diff --git a/app/views/projects/settings.rhtml b/app/views/projects/settings.rhtml new file mode 100644 index 000000000..3f9cba0a0 --- /dev/null +++ b/app/views/projects/settings.rhtml @@ -0,0 +1,118 @@ +

<%=l(:label_settings)%>

+ +<% if authorize_for('projects', 'edit') %> + <% labelled_tabular_form_for :project, @project, :url => { :action => "edit", :id => @project } do |f| %> + <%= render :partial => 'form', :locals => { :f => f } %> + <%= submit_tag l(:button_save) %> + <% end %> +
  +<% end %> + +
+

<%=l(:label_member_plural)%>

+<%= error_messages_for 'member' %> + +<% for member in @project.members.find(:all, :include => :user) %> + <% unless member.new_record? %> + + + + + + <% end %> +<% end %> +
<%= member.user.display_name %> + <% if authorize_for('members', 'edit') %> + <%= start_form_tag :controller => 'members', :action => 'edit', :id => member %> + + <%= submit_tag l(:button_change), :class => "button-small" %> + <%= end_form_tag %> + <% end %> + + <% if authorize_for('members', 'destroy') %> + <%= start_form_tag :controller => 'members', :action => 'destroy', :id => member %> + <%= submit_tag l(:button_delete), :class => "button-small" %> + <%= end_form_tag %> + <% end %> +
+<% if authorize_for('projects', 'add_member') %> +
+
+ <%= start_form_tag :controller => 'projects', :action => 'add_member', :id => @project %> + + + <%= submit_tag l(:button_add) %> + <%= end_form_tag %> +<% end %> +
+ +
+

<%=l(:label_version_plural)%>

+ +<% for version in @project.versions %> + + + + + + +<% end %> +
<%=h version.name %><%= format_date(version.effective_date) %><%=h version.description %>    + <%= link_to_if_authorized l(:button_edit), :controller => 'versions', :action => 'edit', :id => version %> + <% if authorize_for('versions', 'destroy') %> +   + <%= start_form_tag :controller => 'versions', :action => 'destroy', :id => version %> + <%= submit_tag l(:button_delete), :class => "button-small" %> + <%= end_form_tag %> + <% end %> +
+<% if authorize_for('projects', 'add_version') %> +
+ <%= link_to l(:label_version_new), :controller => 'projects', :action => 'add_version', :id => @project %> +<% end %> +
+ + +
+

<%=l(:label_issue_category_plural)%>

+ +<% for @category in @project.issue_categories %> + <% unless @category.new_record? %> + + + + + + <% end %> +<% end %> +
+ <%= start_form_tag :controller => 'issue_categories', :action => 'edit', :id => @category %> + <%= text_field 'category', 'name', :size => 25 %> + + <% if authorize_for('issue_categories', 'edit') %> + <%= submit_tag l(:button_save), :class => "button-small" %> + <%= end_form_tag %> + <% end %> + + <% if authorize_for('issue_categories', 'destroy') %> + <%= start_form_tag :controller => 'issue_categories', :action => 'destroy', :id => @category %> + <%= submit_tag l(:button_delete), :class => "button-small" %> + <%= end_form_tag %> + <% end %> +
+<% if authorize_for('projects', 'add_issue_category') %> +
+ <%= start_form_tag :action => 'add_issue_category', :id => @project %> +
+ <%= error_messages_for 'issue_category' %> + <%= text_field 'issue_category', 'name', :size => 25 %> + <%= submit_tag l(:button_create) %> + <%= end_form_tag %> +<% end %> +
diff --git a/app/views/projects/show.rhtml b/app/views/projects/show.rhtml new file mode 100644 index 000000000..79e36a586 --- /dev/null +++ b/app/views/projects/show.rhtml @@ -0,0 +1,72 @@ +

<%=l(:label_overview)%>

+ +
+ <%= simple_format(auto_link(@project.description)) %> +
    + <% unless @project.homepage.empty? %>
  • <%=l(:field_homepage)%>: <%= auto_link @project.homepage %>
  • <% end %> +
  • <%=l(:field_created_on)%>: <%= format_date(@project.created_on) %>
  • + <% for custom_value in @custom_values %> + <% if !custom_value.value.empty? %> +
  • <%= custom_value.custom_field.name%>: <%= show_value(custom_value) %>
  • + <% end %> + <% end %> +
+ +
+

<%= image_tag "tracker" %> <%=l(:label_tracker_plural)%>

+
    + <% for tracker in @trackers %> +
  • <%= link_to tracker.name, :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "tracker_id" => tracker.id %>: + <%= issue_count = Issue.count(:conditions => ["project_id=? and tracker_id=? and issue_statuses.is_closed=?", @project.id, tracker.id, false], :include => :status) %> + <%= lwr(:label_open_issues, issue_count) %> +
  • + <% end %> +
+ <% if authorize_for 'projects', 'add_issue' %> + » <%=l(:label_issue_new)%>: +
    + <% @trackers.each do |tracker| %> +
  • <%= link_to tracker.name, :controller => 'projects', :action => 'add_issue', :id => @project, :tracker_id => tracker %>
  • + <% end %> +
+ <% end %> +
[ <%= link_to l(:label_issue_view_all), :controller => 'projects', :action => 'list_issues', :id => @project, :set_filter => 1 %> ]
+
+
+ +
+
+

<%= image_tag "users" %> <%=l(:label_member_plural)%>

+ <% for member in @members %> + <%= link_to_user member.user %> (<%= member.role.name %>)
+ <% end %> +
+ + <% if @subprojects %> +
+

<%= image_tag "projects" %> <%=l(:label_subproject_plural)%>

+ <% for subproject in @subprojects %> + <%= link_to subproject.name, :action => 'show', :id => subproject %>
+ <% end %> +
+ <% end %> + +
+

<%=l(:label_news_latest)%>

+ <% for news in @news %> +

<%= news.title %> (<%= link_to_user news.author %> <%= format_time(news.created_on) %>)
+ <%= news.summary %> + [<%= link_to l(:label_read), :controller => 'news', :action => 'show', :id => news %>]

+
+ <% end %> +
[ <%= link_to l(:label_news_view_all), :controller => 'projects', :action => 'list_news', :id => @project %> ]
+
+
+ + + + + + diff --git a/app/views/reports/_details.rhtml b/app/views/reports/_details.rhtml new file mode 100644 index 000000000..be4c82e77 --- /dev/null +++ b/app/views/reports/_details.rhtml @@ -0,0 +1,47 @@ +<% if @statuses.empty? or rows.empty? %> +

<%=l(:label_no_data)%>

+<% else %> +<% col_width = 70 / (@statuses.length+3) %> + + + +<% for status in @statuses %> + +<% end %> + + + + + +<% for row in rows %> +"> + + <% for status in @statuses %> + + <% end %> + + + +<% end %> + +
<%= status.name %><%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
<%= link_to row.name, :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "#{field_name}" => row.id %><%= link_to (aggregate data, { field_name => row.id, "status_id" => status.id }), + :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "status_id" => status.id, + "#{field_name}" => row.id %><%= link_to (aggregate data, { field_name => row.id, "closed" => 0 }), + :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "#{field_name}" => row.id, + "status_id" => "O" %><%= link_to (aggregate data, { field_name => row.id, "closed" => 1 }), + :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "#{field_name}" => row.id, + "status_id" => "C" %><%= link_to (aggregate data, { field_name => row.id }), + :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "#{field_name}" => row.id, + "status_id" => "A" %>
+<% end + reset_cycle %> \ No newline at end of file diff --git a/app/views/reports/_simple.rhtml b/app/views/reports/_simple.rhtml new file mode 100644 index 000000000..3be1281c5 --- /dev/null +++ b/app/views/reports/_simple.rhtml @@ -0,0 +1,36 @@ +<% if @statuses.empty? or rows.empty? %> +

<%=l(:label_no_data)%>

+<% else %> + + + + + + + + +<% for row in rows %> +"> + + + + +<% end %> + +
<%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
<%= link_to row.name, :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "#{field_name}" => row.id %><%= link_to (aggregate data, { field_name => row.id, "closed" => 0 }), + :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "#{field_name}" => row.id, + "status_id" => "O" %><%= link_to (aggregate data, { field_name => row.id, "closed" => 1 }), + :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "#{field_name}" => row.id, + "status_id" => "C" %><%= link_to (aggregate data, { field_name => row.id }), + :controller => 'projects', :action => 'list_issues', :id => @project, + :set_filter => 1, + "#{field_name}" => row.id, + "status_id" => "A" %>
+<% end + reset_cycle %> \ No newline at end of file diff --git a/app/views/reports/issue_report.rhtml b/app/views/reports/issue_report.rhtml new file mode 100644 index 000000000..4927186a9 --- /dev/null +++ b/app/views/reports/issue_report.rhtml @@ -0,0 +1,20 @@ +

<%=l(:label_report_plural)%>

+ +
+

<%=l(:field_tracker)%>  <%= link_to image_tag('details'), :detail => 'author' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => "tracker_id", :rows => @trackers } %> +
+

<%=l(:field_priority)%>  <%= link_to image_tag('details'), :detail => 'priority' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_priority, :field_name => "priority_id", :rows => @priorities } %> +
+

<%=l(:field_author)%>  <%= link_to image_tag('details'), :detail => 'author' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => "author_id", :rows => @authors } %> +
+
+ +
+

<%=l(:field_category)%>  <%= link_to image_tag('details'), :detail => 'category' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_category, :field_name => "category_id", :rows => @categories } %> +
+
+ diff --git a/app/views/reports/issue_report_details.rhtml b/app/views/reports/issue_report_details.rhtml new file mode 100644 index 000000000..e37d38649 --- /dev/null +++ b/app/views/reports/issue_report_details.rhtml @@ -0,0 +1,7 @@ +

<%=l(:label_report_plural)%>

+ +

<%=@report_title%>

+<%= render :partial => 'details', :locals => { :data => @data, :field_name => @field, :rows => @rows } %> +
+<%= link_to l(:button_back), :action => 'issue_report' %> + diff --git a/app/views/roles/_form.rhtml b/app/views/roles/_form.rhtml new file mode 100644 index 000000000..e0ab1c099 --- /dev/null +++ b/app/views/roles/_form.rhtml @@ -0,0 +1,20 @@ +<%= error_messages_for 'role' %> +
+ +

<%= f.text_field :name, :required => true %>

+ +<%=l(:label_permissions)%>: +<% permissions = @permissions.group_by {|p| p.group_id } %> +<% permissions.keys.sort.each do |group_id| %> +
<%= l(Permission::GROUPS[group_id]) %> +<% permissions[group_id].each do |p| %> +
<%= check_box_tag "permission_ids[]", p.id, (@role.permissions.include? p) %> + <%= l(p.description.to_sym) %> +
+<% end %> +
+<% end %> +
+<%= check_all_links 'role_form' %> + +
diff --git a/app/views/roles/edit.rhtml b/app/views/roles/edit.rhtml new file mode 100644 index 000000000..ffe117cef --- /dev/null +++ b/app/views/roles/edit.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_role)%>

+ +<% labelled_tabular_form_for :role, @role, :url => { :action => 'edit' }, :html => {:id => 'role_form'} do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/roles/list.rhtml b/app/views/roles/list.rhtml new file mode 100644 index 000000000..169b3d1c0 --- /dev/null +++ b/app/views/roles/list.rhtml @@ -0,0 +1,21 @@ +

<%=l(:label_role_plural)%>

+ + + + + + + +<% for role in @roles %> + "> + + +<% end %> +
<%=l(:label_role)%>
<%= link_to role.name, :action => 'edit', :id => role %> + <%= button_to l(:button_delete), { :action => 'destroy', :id => role }, :confirm => l(:text_are_you_sure), :class => "button-small" %> +
+ +<%= pagination_links_full @role_pages %> +
+ +<%= link_to '» ' + l(:label_role_new), :action => 'new' %> diff --git a/app/views/roles/new.rhtml b/app/views/roles/new.rhtml new file mode 100644 index 000000000..a73c36cb1 --- /dev/null +++ b/app/views/roles/new.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_role_new)%>

+ +<% labelled_tabular_form_for :role, @role, :url => { :action => 'new' }, :html => {:id => 'role_form'} do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> \ No newline at end of file diff --git a/app/views/roles/workflow.rhtml b/app/views/roles/workflow.rhtml new file mode 100644 index 000000000..ee5b3a278 --- /dev/null +++ b/app/views/roles/workflow.rhtml @@ -0,0 +1,71 @@ +

<%=l(:label_workflow)%>

+ +

<%=l(:text_workflow_edit)%>:

+ +<%= start_form_tag ({:action => 'workflow'}, :method => 'get') %> +
+


+

+
+ +
+


+ + +<%= submit_tag l(:button_edit) %> +

+
+<%= end_form_tag %> + + + +<% unless @tracker.nil? or @role.nil? %> +
+ <%= form_tag ({:action => 'workflow', :role_id => @role, :tracker_id => @tracker }, :id => 'workflow_form' ) %> + + + + + + + + <% for new_status in @statuses %> + + <% end %> + + + <% for old_status in @statuses %> + + + + + <% for new_status in @statuses %> + + <% end %> + + + <% end %> +
<%=l(:label_current_status)%><%=l(:label_new_statuses_allowed)%>
<%= new_status.name %>
 
<%= old_status.name %> + + checked="checked"<%end%> + <%if old_status==new_status%>disabled<%end%> + > +
+
+

+<%=l(:button_check_all)%> | +<%=l(:button_uncheck_all)%> +

+
+<%= submit_tag l(:button_save) %> +<%= end_form_tag %> + +<% end %> +
\ No newline at end of file diff --git a/app/views/trackers/_form.rhtml b/app/views/trackers/_form.rhtml new file mode 100644 index 000000000..625c0d636 --- /dev/null +++ b/app/views/trackers/_form.rhtml @@ -0,0 +1,7 @@ +<%= error_messages_for 'tracker' %> +
+ +

<%= f.text_field :name, :required => true %>

+

<%= f.check_box :is_in_chlog %>

+ +
diff --git a/app/views/trackers/edit.rhtml b/app/views/trackers/edit.rhtml new file mode 100644 index 000000000..d8411099c --- /dev/null +++ b/app/views/trackers/edit.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_tracker)%>

+ +<% labelled_tabular_form_for :tracker, @tracker, :url => { :action => 'edit' } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> \ No newline at end of file diff --git a/app/views/trackers/list.rhtml b/app/views/trackers/list.rhtml new file mode 100644 index 000000000..8d4a5c595 --- /dev/null +++ b/app/views/trackers/list.rhtml @@ -0,0 +1,22 @@ +

<%=l(:label_tracker_plural)%>

+ + + + + + + +<% for tracker in @trackers %> + "> + + + +<% end %> +
<%=l(:label_tracker)%>
<%= link_to tracker.name, :action => 'edit', :id => tracker %> + <%= button_to l(:button_delete), { :action => 'destroy', :id => tracker }, :confirm => l(:text_are_you_sure), :class => "button-small" %> +
+ +<%= pagination_links_full @tracker_pages %> +
+ +<%= link_to '» ' + l(:label_tracker_new), :action => 'new' %> diff --git a/app/views/trackers/new.rhtml b/app/views/trackers/new.rhtml new file mode 100644 index 000000000..b318a5dc4 --- /dev/null +++ b/app/views/trackers/new.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_tracker_new)%>

+ +<% labelled_tabular_form_for :tracker, @tracker, :url => { :action => 'new' } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> \ No newline at end of file diff --git a/app/views/users/_form.rhtml b/app/views/users/_form.rhtml new file mode 100644 index 000000000..089d4d23c --- /dev/null +++ b/app/views/users/_form.rhtml @@ -0,0 +1,30 @@ +<%= error_messages_for 'user' %> + + +
+

<%=l(:label_information_plural)%>

+

<%= f.text_field :login, :required => true, :size => 25 %>

+

<%= f.text_field :firstname, :required => true %>

+

<%= f.text_field :lastname, :required => true %>

+

<%= f.text_field :mail, :required => true %>

+

<%= f.select :language, lang_options_for_select %>

+ +<% for @custom_value in @custom_values %> +

<%= custom_field_tag_with_label @custom_value %>

+<% end %> + +

<%= f.check_box :admin %>

+

<%= f.check_box :mail_notification %>

+
+ +
+

<%=l(:label_authentication)%>

+<% unless @auth_sources.empty? %> +

<%= f.select :auth_source_id, [[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] } %>

+<% end %> +

+<%= password_field_tag 'password', nil, :size => 25 %>

+

+<%= password_field_tag 'password_confirmation', nil, :size => 25 %>

+
+ diff --git a/app/views/users/add.rhtml b/app/views/users/add.rhtml new file mode 100644 index 000000000..d4c6a15f4 --- /dev/null +++ b/app/views/users/add.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_user_new)%>

+ +<% labelled_tabular_form_for :user, @user, :url => { :action => "add" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> \ No newline at end of file diff --git a/app/views/users/edit.rhtml b/app/views/users/edit.rhtml new file mode 100644 index 000000000..2332b70ad --- /dev/null +++ b/app/views/users/edit.rhtml @@ -0,0 +1,6 @@ +

<%=l(:label_user)%>

+ +<% labelled_tabular_form_for :user, @user, :url => { :action => "edit" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/users/list.rhtml b/app/views/users/list.rhtml new file mode 100644 index 000000000..9f4438138 --- /dev/null +++ b/app/views/users/list.rhtml @@ -0,0 +1,46 @@ +

<%=l(:label_user_plural)%>

+ + + + <%= sort_header_tag('login', :caption => l(:field_login)) %> + <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %> + <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %> + + <%= sort_header_tag('admin', :caption => l(:field_admin)) %> + <%= sort_header_tag('status', :caption => l(:field_status)) %> + <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> + <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on)) %> + + +<% for user in @users %> + "> + + + + + + + + + + +<% end %> +
<%=l(:field_mail)%>
<%= link_to user.login, :action => 'edit', :id => user %><%= user.firstname %><%= user.lastname %><%= user.mail %><%= image_tag 'true' if user.admin? %><%= image_tag 'locked' if user.locked? %><%= image_tag 'user_new' if user.registered? %><%= format_time(user.created_on) %><%= format_time(user.last_login_on) unless user.last_login_on.nil? %> + <%= start_form_tag :action => 'edit', :id => user %> + <% if user.locked? %> + <%= hidden_field_tag 'user[status]', User::STATUS_ACTIVE %> + <%= submit_tag l(:button_unlock), :class => "button-small" %> + <% else %> + <%= hidden_field_tag 'user[status]', User::STATUS_LOCKED %> + <%= submit_tag l(:button_lock), :class => "button-small" %> + <% end %> + <%= end_form_tag %> +
+ +

<%= pagination_links_full @user_pages %> +[ <%= @user_pages.current.first_item %> - <%= @user_pages.current.last_item %> / <%= @user_count %> ] +

+ +

+<%= link_to '» ' + l(:label_user_new), :action => 'add' %> +

\ No newline at end of file diff --git a/app/views/versions/_form.rhtml b/app/views/versions/_form.rhtml new file mode 100644 index 000000000..3d0eb0a2d --- /dev/null +++ b/app/views/versions/_form.rhtml @@ -0,0 +1,9 @@ +<%= error_messages_for 'version' %> + +
+ +

<%= f.text_field :name, :size => 20, :required => true %>

+

<%= f.text_field :description, :size => 60 %>

+

<%= f.text_field :effective_date, :size => 10, :required => true %><%= calendar_for('version_effective_date') %>

+ +
\ No newline at end of file diff --git a/app/views/versions/edit.rhtml b/app/views/versions/edit.rhtml new file mode 100644 index 000000000..1556ebba1 --- /dev/null +++ b/app/views/versions/edit.rhtml @@ -0,0 +1,7 @@ +

<%=l(:label_version)%>

+ +<% labelled_tabular_form_for :version, @version, :url => { :action => 'edit' } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> + diff --git a/app/views/welcome/index.rhtml b/app/views/welcome/index.rhtml new file mode 100644 index 000000000..abee85691 --- /dev/null +++ b/app/views/welcome/index.rhtml @@ -0,0 +1,30 @@ +

<%= $RDM_WELCOME_TITLE || l(:label_home) %>

+ +
+ <% if $RDM_WELCOME_TEXT %>

<%= $RDM_WELCOME_TEXT %>


<% end %> +
+

<%=l(:label_news_latest)%>

+ <% for news in @news %> +

+ <%= news.title %> (<%= link_to_user news.author %> <%= format_time(news.created_on) %> - <%= news.project.name %>)
+ <% unless news.summary.empty? %><%= news.summary %>
<% end %> + [<%= link_to l(:label_read), :controller => 'news', :action => 'show', :id => news %>] +

+
+ <% end %> +
+
+ +
+
+

<%=l(:label_project_latest)%>

+
    + <% for project in @projects %> +
  • + <%= link_to project.name, :controller => 'projects', :action => 'show', :id => project %> (<%= format_time(project.created_on) %>)
    + <%= project.description %> +
  • + <% end %> +
+
+
diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 000000000..9fcd50fe3 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,19 @@ +# Don't change this file. Configuration is done in config/environment.rb and config/environments/*.rb + +unless defined?(RAILS_ROOT) + root_path = File.join(File.dirname(__FILE__), '..') + unless RUBY_PLATFORM =~ /mswin32/ + require 'pathname' + root_path = Pathname.new(root_path).cleanpath(true).to_s + end + RAILS_ROOT = root_path +end + +if File.directory?("#{RAILS_ROOT}/vendor/rails") + require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" +else + require 'rubygems' + require 'initializer' +end + +Rails::Initializer.run(:set_load_path) diff --git a/config/config_custom.example.rb b/config/config_custom.example.rb new file mode 100644 index 000000000..689d9daec --- /dev/null +++ b/config/config_custom.example.rb @@ -0,0 +1,65 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# To set your own configuration, rename this file to config_custom.rb +# and edit parameters below +# Don't forget to restart the application after any change. + + +# Application host name +# Used to provide absolute links in mail notifications +# $RDM_HOST_NAME = "somenet.foo" + +# File storage path +# Directory used to store uploaded files +# #{RAILS_ROOT} represents application's home directory +# $RDM_STORAGE_PATH = "#{RAILS_ROOT}/files" + +# Set $RDM_LOGIN_REQUIRED to true if you want to force users to login +# to access any page of the application +# $RDM_LOGIN_REQUIRED = false + +# Uncomment to disable user self-registration +# $RDM_SELF_REGISTRATION = false + +# Default langage ('en', 'es', 'de', 'fr' are available) +# $RDM_DEFAULT_LANG = 'en' + +# Email adress used to send mail notifications +# $RDM_MAIL_FROM = "redmine@somenet.foo" + +# Page title +# $RDM_HEADER_TITLE = "Title" + +# Page sub-title +# $RDM_HEADER_SUBTITLE = "Sub title" + +# Welcome page title +# $RDM_WELCOME_TITLE = "Welcome" + +# Welcome page text +# $RDM_WELCOME_TEXT = "" + +# Signature displayed in footer +# Email adresses will be automatically displayed as a mailto link +# $RDM_FOOTER_SIG = "admin@somenet.foo" + +# Textile formatting (only available if RedCloth is installed) +# Textile formatting is automativaly disabled if RedCloth is not available +# Set to true to manually disable. +# $RDM_TEXTILE_DISABLED = true diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 000000000..cfb6f13df --- /dev/null +++ b/config/database.yml @@ -0,0 +1,69 @@ +# MySQL (default setup). Versions 4.1 and 5.0 are recommended. +# +# Get the fast C bindings: +# gem install mysql +# (on OS X: gem install mysql -- --include=/usr/local/lib) +# And be sure to use new-style password hashing: +# http://dev.mysql.com/doc/refman/5.0/en/old-client.html + +production: + adapter: mysql + database: redmine + host: localhost + username: root + password: + +development: + adapter: mysql + database: redmine_development + host: localhost + username: root + password: + +development_pgsql: + adapter: postgresql + database: redmine + host: localhost + username: postgres + password: "postgres" + +development_oracle: + adapter: oci + host: 192.168.0.14 + username: rails + password: "rails" + +development_sqlserver: + adapter: sqlserver + host: localhost,1157 + database: redmine + +test: + adapter: mysql + database: redmine_test + host: localhost + username: root + password: + +test_pgsql: + adapter: postgresql + database: redmine + host: localhost + username: postgres + password: "postgres" + +test_oracle: + adapter: oci + host: 192.168.0.14 + username: rails_test + password: "rails" + +test_sqlserver: + adapter: sqlserver + host: localhost,1157 + database: redmine_test + +demo: + adapter: sqlite3 + dbfile: db/redmine_demo.db + diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 000000000..359293b6e --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,140 @@ +# Be sure to restart your web server when you modify this file. + +# Uncomment below to force Rails into production mode when +# you don't control web/app server and can't set it the proper way +# ENV['RAILS_ENV'] ||= 'production' + +# Bootstrap the Rails environment, frameworks, and default configuration +require File.join(File.dirname(__FILE__), 'boot') + +Rails::Initializer.run do |config| + # Settings in config/environments/* take precedence those specified here + + # Skip frameworks you're not going to use + # config.frameworks -= [ :action_web_service, :action_mailer ] + + # Add additional load paths for your own custom dirs + # config.load_paths += %W( #{RAILS_ROOT}/extras ) + + # Force all environments to use the same logger level + # (by default production uses :info, the others :debug) + # config.log_level = :debug + + # Use the database for sessions instead of the file system + # (create the session table with 'rake create_sessions_table') + # config.action_controller.session_store = :active_record_store + + # Enable page/fragment caching by setting a file-based store + # (remember to create the caching directory and make it readable to the application) + # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" + + # Activate observers that should always be running + # config.active_record.observers = :cacher, :garbage_collector + + # Make Active Record use UTC-base instead of local time + # config.active_record.default_timezone = :utc + + # Use Active Record's schema dumper instead of SQL when creating the test database + # (enables use of different database adapters for development and test environments) + # config.active_record.schema_format = :ruby + + # See Rails::Configuration for more options + + # SMTP server configuration + config.action_mailer.server_settings = { + :address => "127.0.0.1", + :port => 25, + :domain => "somenet.foo", + :authentication => :login, + :user_name => "redmine", + :password => "redmine", + } + + config.action_mailer.perform_deliveries = true + + # Tell ActionMailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + #config.action_mailer.delivery_method = :test + config.action_mailer.delivery_method = :smtp +end + +# Add new inflection rules using the following format +# (all these examples are active by default): +# Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end + +if File.exist? File.join(File.dirname(__FILE__), 'config_custom.rb') + begin + print "=> Loading config_custom.rb... " + require File.join(File.dirname(__FILE__), 'config_custom') + puts "done." + rescue Exception => detail + puts + puts detail + puts detail.backtrace.join("\n") + puts "=> Error in config_custom.rb. Check your configuration." + exit + end +end + +# IMPORTANT !!! DO NOT MODIFY PARAMETERS HERE +# Instead, rename config_custom.example.rb to config_custom.rb +# and set your own configuration in that file +# Parameters defined in config_custom.rb override those defined below + +# application host name +$RDM_HOST_NAME ||= "localhost:3000" +# file storage path +$RDM_STORAGE_PATH ||= "#{RAILS_ROOT}/files" +# if RDM_LOGIN_REQUIRED is set to true, login is required to access the application +$RDM_LOGIN_REQUIRED ||= false +# default langage +$RDM_DEFAULT_LANG ||= 'en' +# email sender adress +$RDM_MAIL_FROM ||= "redmine@somenet.foo" + +# page title +$RDM_HEADER_TITLE ||= "redMine" +# page sub-title +$RDM_HEADER_SUBTITLE ||= "Project management" +# footer signature +$RDM_FOOTER_SIG = "admin@somenet.foo" + +# textile formatting +# automaticaly disabled if 'textile' method is not defined (RedCloth unavailable) +$RDM_TEXTILE_DISABLED = true unless ActionView::Helpers::TextHelper.method_defined? "textilize" + +# application name +RDM_APP_NAME = "redMine" +# application version +RDM_APP_VERSION = "0.3.0" + +ActiveRecord::Errors.default_error_messages = { + :inclusion => "activerecord_error_inclusion", + :exclusion => "activerecord_error_exclusion", + :invalid => "activerecord_error_invalid", + :confirmation => "activerecord_error_confirmation", + :accepted => "activerecord_error_accepted", + :empty => "activerecord_error_empty", + :blank => "activerecord_error_blank", + :too_long => "activerecord_error_too_long", + :too_short => "activerecord_error_too_short", + :wrong_length => "activerecord_error_wrong_length", + :taken => "activerecord_error_taken", + :not_a_number => "activerecord_error_not_a_number" +} + +ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" } + +GLoc.set_config :default_language => $RDM_DEFAULT_LANG +GLoc.clear_strings +GLoc.set_kcode +GLoc.load_localized_strings +GLoc.set_config(:raise_string_not_found_errors => false) + + diff --git a/config/environments/demo.rb b/config/environments/demo.rb new file mode 100644 index 000000000..52aef32f1 --- /dev/null +++ b/config/environments/demo.rb @@ -0,0 +1,21 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The production environment is meant for finished, "live" apps. +# Code is not reloaded between requests +config.cache_classes = true + +# Use a different logger for distributed setups +# config.logger = SyslogLogger.new +config.log_level = :info + +# Full error reports are disabled and caching is turned on +config.action_controller.consider_all_requests_local = false +config.action_controller.perform_caching = true + +# Enable serving of images, stylesheets, and javascripts from an asset server +# config.action_controller.asset_host = "http://assets.example.com" + +# Disable mail delivery +config.action_mailer.perform_deliveries = false +config.action_mailer.raise_delivery_errors = false + diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 000000000..04b779200 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,19 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# In the development environment your application's code is reloaded on +# every request. This slows down response time but is perfect for development +# since you don't have to restart the webserver when you make code changes. +config.cache_classes = false + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Enable the breakpoint server that script/breakpointer connects to +config.breakpoint_server = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +# Don't care if the mailer can't send +config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/development_oracle.rb b/config/environments/development_oracle.rb new file mode 100644 index 000000000..04b779200 --- /dev/null +++ b/config/environments/development_oracle.rb @@ -0,0 +1,19 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# In the development environment your application's code is reloaded on +# every request. This slows down response time but is perfect for development +# since you don't have to restart the webserver when you make code changes. +config.cache_classes = false + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Enable the breakpoint server that script/breakpointer connects to +config.breakpoint_server = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +# Don't care if the mailer can't send +config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/development_pgsql.rb b/config/environments/development_pgsql.rb new file mode 100644 index 000000000..04b779200 --- /dev/null +++ b/config/environments/development_pgsql.rb @@ -0,0 +1,19 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# In the development environment your application's code is reloaded on +# every request. This slows down response time but is perfect for development +# since you don't have to restart the webserver when you make code changes. +config.cache_classes = false + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Enable the breakpoint server that script/breakpointer connects to +config.breakpoint_server = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +# Don't care if the mailer can't send +config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/development_sqlserver.rb b/config/environments/development_sqlserver.rb new file mode 100644 index 000000000..04b779200 --- /dev/null +++ b/config/environments/development_sqlserver.rb @@ -0,0 +1,19 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# In the development environment your application's code is reloaded on +# every request. This slows down response time but is perfect for development +# since you don't have to restart the webserver when you make code changes. +config.cache_classes = false + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Enable the breakpoint server that script/breakpointer connects to +config.breakpoint_server = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +# Don't care if the mailer can't send +config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 000000000..4cd4e086b --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,20 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The production environment is meant for finished, "live" apps. +# Code is not reloaded between requests +config.cache_classes = true + +# Use a different logger for distributed setups +# config.logger = SyslogLogger.new + + +# Full error reports are disabled and caching is turned on +config.action_controller.consider_all_requests_local = false +config.action_controller.perform_caching = true + +# Enable serving of images, stylesheets, and javascripts from an asset server +# config.action_controller.asset_host = "http://assets.example.com" + +# Disable delivery errors if you bad email addresses should just be ignored +config.action_mailer.raise_delivery_errors = false + diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 000000000..9ba9ae0f8 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,16 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! +config.cache_classes = true + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +config.action_mailer.delivery_method = :test diff --git a/config/environments/test_oracle.rb b/config/environments/test_oracle.rb new file mode 100644 index 000000000..35bb19bee --- /dev/null +++ b/config/environments/test_oracle.rb @@ -0,0 +1,16 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! +config.cache_classes = true + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +config.action_mailer.delivery_method = :test \ No newline at end of file diff --git a/config/environments/test_pgsql.rb b/config/environments/test_pgsql.rb new file mode 100644 index 000000000..35bb19bee --- /dev/null +++ b/config/environments/test_pgsql.rb @@ -0,0 +1,16 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! +config.cache_classes = true + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +config.action_mailer.delivery_method = :test \ No newline at end of file diff --git a/config/environments/test_sqlserver.rb b/config/environments/test_sqlserver.rb new file mode 100644 index 000000000..35bb19bee --- /dev/null +++ b/config/environments/test_sqlserver.rb @@ -0,0 +1,16 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! +config.cache_classes = true + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +config.action_mailer.delivery_method = :test \ No newline at end of file diff --git a/config/help.yml b/config/help.yml new file mode 100644 index 000000000..b02a06fb1 --- /dev/null +++ b/config/help.yml @@ -0,0 +1,63 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# available languages for help pages +langs: + - en + - fr + +# mapping between controller/action and help pages +# if action is not defined here, 'index' page will be displayed +pages: + # administration + admin: + index: ch01.html + mail_options: ch01s08.html + info: ch01s09.html + users: + index: ch01s01.html + roles: + index: ch01s02.html + workflow: ch01s06.html + trackers: + index: ch01s03.html + issue_statuses: + index: ch01s05.html + # projects + projects: + index: ch02.html + add: ch02s08.html + show: ch02s01.html + add_document: ch02s06.html + list_documents: ch02s06.html + add_issue: ch02s02.html + list_issues: ch02s02.html + add_news: ch02s05.html + list_news: ch02s05.html + add_file: ch02s07.html + list_files: ch02s07.html + changelog: ch02s04.html + issues: + index: ch02s02.html + documents: + index: ch02s06.html + news: + index: ch02s05.html + versions: + index: ch02s08.html + reports: + index: ch02s03.html \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 000000000..2559159f1 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,24 @@ +ActionController::Routing::Routes.draw do |map| + # Add your own custom routes here. + # The priority is based upon order of creation: first created -> highest priority. + + # Here's a sample route: + # map.connect 'products/:id', :controller => 'catalog', :action => 'view' + # Keep in mind you can assign values other than :controller and :action + + # You can have the root of your site routed by hooking up '' + # -- just remember to delete public/index.html. + map.connect '', :controller => "welcome" + + map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow' + map.connect 'help/:ctrl/:page', :controller => 'help' + map.connect ':controller/:action/:id/:sort_key/:sort_order' + + # Allow downloading Web Service WSDL as a file with an extension + # instead of a file named 'wsdl' + map.connect ':controller/service.wsdl', :action => 'wsdl' + + + # Install the default route as the lowest priority. + map.connect ':controller/:action/:id' +end diff --git a/db/migrate/001_setup.rb b/db/migrate/001_setup.rb new file mode 100644 index 000000000..ee22c148b --- /dev/null +++ b/db/migrate/001_setup.rb @@ -0,0 +1,317 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Setup < ActiveRecord::Migration + def self.up + create_table "attachments", :force => true do |t| + t.column "container_id", :integer, :default => 0, :null => false + t.column "container_type", :string, :limit => 30, :default => "", :null => false + t.column "filename", :string, :default => "", :null => false + t.column "disk_filename", :string, :default => "", :null => false + t.column "filesize", :integer, :default => 0, :null => false + t.column "content_type", :string, :limit => 60, :default => "" + t.column "digest", :string, :limit => 40, :default => "", :null => false + t.column "downloads", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end + + create_table "auth_sources", :force => true do |t| + t.column "type", :string, :limit => 30, :default => "", :null => false + t.column "name", :string, :limit => 60, :default => "", :null => false + t.column "host", :string, :limit => 60 + t.column "port", :integer + t.column "account", :string, :limit => 60 + t.column "account_password", :string, :limit => 60 + t.column "base_dn", :string, :limit => 255 + t.column "attr_login", :string, :limit => 30 + t.column "attr_firstname", :string, :limit => 30 + t.column "attr_lastname", :string, :limit => 30 + t.column "attr_mail", :string, :limit => 30 + t.column "onthefly_register", :boolean, :default => false, :null => false + end + + create_table "custom_fields", :force => true do |t| + t.column "type", :string, :limit => 30, :default => "", :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "field_format", :string, :limit => 30, :default => "", :null => false + t.column "possible_values", :text, :default => "" + t.column "regexp", :string, :default => "" + t.column "min_length", :integer, :default => 0, :null => false + t.column "max_length", :integer, :default => 0, :null => false + t.column "is_required", :boolean, :default => false, :null => false + t.column "is_for_all", :boolean, :default => false, :null => false + end + + create_table "custom_fields_projects", :id => false, :force => true do |t| + t.column "custom_field_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + end + + create_table "custom_fields_trackers", :id => false, :force => true do |t| + t.column "custom_field_id", :integer, :default => 0, :null => false + t.column "tracker_id", :integer, :default => 0, :null => false + end + + create_table "custom_values", :force => true do |t| + t.column "customized_type", :string, :limit => 30, :default => "", :null => false + t.column "customized_id", :integer, :default => 0, :null => false + t.column "custom_field_id", :integer, :default => 0, :null => false + t.column "value", :text, :default => "", :null => false + end + + create_table "documents", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "category_id", :integer, :default => 0, :null => false + t.column "title", :string, :limit => 60, :default => "", :null => false + t.column "description", :text, :default => "" + t.column "created_on", :timestamp + end + + add_index "documents", ["project_id"], :name => "documents_project_id" + + create_table "enumerations", :force => true do |t| + t.column "opt", :string, :limit => 4, :default => "", :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + end + + create_table "issue_categories", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + end + + add_index "issue_categories", ["project_id"], :name => "issue_categories_project_id" + + create_table "issue_histories", :force => true do |t| + t.column "issue_id", :integer, :default => 0, :null => false + t.column "status_id", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "notes", :text, :default => "" + t.column "created_on", :timestamp + end + + add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" + + create_table "issue_statuses", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "is_closed", :boolean, :default => false, :null => false + t.column "is_default", :boolean, :default => false, :null => false + t.column "html_color", :string, :limit => 6, :default => "FFFFFF", :null => false + end + + create_table "issues", :force => true do |t| + t.column "tracker_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + t.column "subject", :string, :default => "", :null => false + t.column "description", :text, :default => "", :null => false + t.column "due_date", :date + t.column "category_id", :integer + t.column "status_id", :integer, :default => 0, :null => false + t.column "assigned_to_id", :integer + t.column "priority_id", :integer, :default => 0, :null => false + t.column "fixed_version_id", :integer + t.column "author_id", :integer, :default => 0, :null => false + t.column "lock_version", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + add_index "issues", ["project_id"], :name => "issues_project_id" + + create_table "members", :force => true do |t| + t.column "user_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end + + create_table "news", :force => true do |t| + t.column "project_id", :integer + t.column "title", :string, :limit => 60, :default => "", :null => false + t.column "summary", :string, :limit => 255, :default => "" + t.column "description", :text, :default => "", :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end + + add_index "news", ["project_id"], :name => "news_project_id" + + create_table "permissions", :force => true do |t| + t.column "controller", :string, :limit => 30, :default => "", :null => false + t.column "action", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :limit => 60, :default => "", :null => false + t.column "is_public", :boolean, :default => false, :null => false + t.column "sort", :integer, :default => 0, :null => false + t.column "mail_option", :boolean, :default => false, :null => false + t.column "mail_enabled", :boolean, :default => false, :null => false + end + + create_table "permissions_roles", :id => false, :force => true do |t| + t.column "permission_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + end + + add_index "permissions_roles", ["role_id"], :name => "permissions_roles_role_id" + + create_table "projects", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :default => "", :null => false + t.column "homepage", :string, :limit => 60, :default => "" + t.column "is_public", :boolean, :default => true, :null => false + t.column "parent_id", :integer + t.column "projects_count", :integer, :default => 0 + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + create_table "roles", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + end + + create_table "tokens", :force => true do |t| + t.column "user_id", :integer, :default => 0, :null => false + t.column "action", :string, :limit => 30, :default => "", :null => false + t.column "value", :string, :limit => 40, :default => "", :null => false + t.column "created_on", :datetime, :null => false + end + + create_table "trackers", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "is_in_chlog", :boolean, :default => false, :null => false + end + + create_table "users", :force => true do |t| + t.column "login", :string, :limit => 30, :default => "", :null => false + t.column "hashed_password", :string, :limit => 40, :default => "", :null => false + t.column "firstname", :string, :limit => 30, :default => "", :null => false + t.column "lastname", :string, :limit => 30, :default => "", :null => false + t.column "mail", :string, :limit => 60, :default => "", :null => false + t.column "mail_notification", :boolean, :default => true, :null => false + t.column "admin", :boolean, :default => false, :null => false + t.column "status", :integer, :default => 1, :null => false + t.column "last_login_on", :datetime + t.column "language", :string, :limit => 2, :default => "" + t.column "auth_source_id", :integer + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + create_table "versions", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :default => "" + t.column "effective_date", :date, :null => false + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + add_index "versions", ["project_id"], :name => "versions_project_id" + + create_table "workflows", :force => true do |t| + t.column "tracker_id", :integer, :default => 0, :null => false + t.column "old_status_id", :integer, :default => 0, :null => false + t.column "new_status_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + end + + # project + Permission.create :controller => "projects", :action => "show", :description => "label_overview", :sort => 100, :is_public => true + Permission.create :controller => "projects", :action => "changelog", :description => "label_change_log", :sort => 105, :is_public => true + Permission.create :controller => "reports", :action => "issue_report", :description => "label_report_plural", :sort => 110, :is_public => true + Permission.create :controller => "projects", :action => "settings", :description => "label_settings", :sort => 150 + Permission.create :controller => "projects", :action => "edit", :description => "button_edit", :sort => 151 + # members + Permission.create :controller => "projects", :action => "list_members", :description => "button_list", :sort => 200, :is_public => true + Permission.create :controller => "projects", :action => "add_member", :description => "button_add", :sort => 220 + Permission.create :controller => "members", :action => "edit", :description => "button_edit", :sort => 221 + Permission.create :controller => "members", :action => "destroy", :description => "button_delete", :sort => 222 + # versions + Permission.create :controller => "projects", :action => "add_version", :description => "button_add", :sort => 320 + Permission.create :controller => "versions", :action => "edit", :description => "button_edit", :sort => 321 + Permission.create :controller => "versions", :action => "destroy", :description => "button_delete", :sort => 322 + # issue categories + Permission.create :controller => "projects", :action => "add_issue_category", :description => "button_add", :sort => 420 + Permission.create :controller => "issue_categories", :action => "edit", :description => "button_edit", :sort => 421 + Permission.create :controller => "issue_categories", :action => "destroy", :description => "button_delete", :sort => 422 + # issues + Permission.create :controller => "projects", :action => "list_issues", :description => "button_list", :sort => 1000, :is_public => true + Permission.create :controller => "projects", :action => "export_issues_csv", :description => "label_export_csv", :sort => 1001, :is_public => true + Permission.create :controller => "issues", :action => "show", :description => "button_view", :sort => 1005, :is_public => true + Permission.create :controller => "issues", :action => "download", :description => "button_download", :sort => 1010, :is_public => true + Permission.create :controller => "projects", :action => "add_issue", :description => "button_add", :sort => 1050, :mail_option => 1, :mail_enabled => 1 + Permission.create :controller => "issues", :action => "edit", :description => "button_edit", :sort => 1055 + Permission.create :controller => "issues", :action => "change_status", :description => "label_change_status", :sort => 1060, :mail_option => 1, :mail_enabled => 1 + Permission.create :controller => "issues", :action => "destroy", :description => "button_delete", :sort => 1065 + Permission.create :controller => "issues", :action => "add_attachment", :description => "label_attachment_new", :sort => 1070 + Permission.create :controller => "issues", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1075 + # news + Permission.create :controller => "projects", :action => "list_news", :description => "button_list", :sort => 1100, :is_public => true + Permission.create :controller => "news", :action => "show", :description => "button_view", :sort => 1101, :is_public => true + Permission.create :controller => "projects", :action => "add_news", :description => "button_add", :sort => 1120 + Permission.create :controller => "news", :action => "edit", :description => "button_edit", :sort => 1121 + Permission.create :controller => "news", :action => "destroy", :description => "button_delete", :sort => 1122 + # documents + Permission.create :controller => "projects", :action => "list_documents", :description => "button_list", :sort => 1200, :is_public => true + Permission.create :controller => "documents", :action => "show", :description => "button_view", :sort => 1201, :is_public => true + Permission.create :controller => "documents", :action => "download", :description => "button_download", :sort => 1202, :is_public => true + Permission.create :controller => "projects", :action => "add_document", :description => "button_add", :sort => 1220 + Permission.create :controller => "documents", :action => "edit", :description => "button_edit", :sort => 1221 + Permission.create :controller => "documents", :action => "destroy", :description => "button_delete", :sort => 1222 + Permission.create :controller => "documents", :action => "add_attachment", :description => "label_attachment_new", :sort => 1223 + Permission.create :controller => "documents", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1224 + # files + Permission.create :controller => "projects", :action => "list_files", :description => "button_list", :sort => 1300, :is_public => true + Permission.create :controller => "versions", :action => "download", :description => "button_download", :sort => 1301, :is_public => true + Permission.create :controller => "projects", :action => "add_file", :description => "button_add", :sort => 1320 + Permission.create :controller => "versions", :action => "destroy_file", :description => "button_delete", :sort => 1322 + + # create default administrator account + user = User.create :firstname => "redMine", :lastname => "Admin", :mail => "admin@somenet.foo", :mail_notification => true, :language => "en" + user.login = "admin" + user.password = "admin" + user.admin = true + user.save + + + end + + def self.down + drop_table :attachments + drop_table :auth_sources + drop_table :custom_fields + drop_table :custom_fields_projects + drop_table :custom_fields_trackers + drop_table :custom_values + drop_table :documents + drop_table :enumerations + drop_table :issue_categories + drop_table :issue_histories + drop_table :issue_statuses + drop_table :issues + drop_table :members + drop_table :news + drop_table :permissions + drop_table :permissions_roles + drop_table :projects + drop_table :roles + drop_table :trackers + drop_table :tokens + drop_table :users + drop_table :versions + drop_table :workflows + end +end diff --git a/db/migrate/002_issue_move.rb b/db/migrate/002_issue_move.rb new file mode 100644 index 000000000..d1acf7ee2 --- /dev/null +++ b/db/migrate/002_issue_move.rb @@ -0,0 +1,9 @@ +class IssueMove < ActiveRecord::Migration + def self.up + Permission.create :controller => "projects", :action => "move_issues", :description => "button_move", :sort => 1061, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'move_issues']).destroy + end +end diff --git a/db/migrate/003_issue_add_note.rb b/db/migrate/003_issue_add_note.rb new file mode 100644 index 000000000..9f20039b0 --- /dev/null +++ b/db/migrate/003_issue_add_note.rb @@ -0,0 +1,9 @@ +class IssueAddNote < ActiveRecord::Migration + def self.up + Permission.create :controller => "issues", :action => "add_note", :description => "label_add_note", :sort => 1057, :mail_option => 1, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'add_note']).destroy + end +end diff --git a/db/migrate/004_export_pdf.rb b/db/migrate/004_export_pdf.rb new file mode 100644 index 000000000..66045553f --- /dev/null +++ b/db/migrate/004_export_pdf.rb @@ -0,0 +1,11 @@ +class ExportPdf < ActiveRecord::Migration + def self.up + Permission.create :controller => "projects", :action => "export_issues_pdf", :description => "label_export_pdf", :sort => 1002, :is_public => true, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "issues", :action => "export_pdf", :description => "label_export_pdf", :sort => 1015, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'export_issues_pdf']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'export_pdf']).destroy + end +end diff --git a/db/migrate/005_issue_start_date.rb b/db/migrate/005_issue_start_date.rb new file mode 100644 index 000000000..3d1693fc6 --- /dev/null +++ b/db/migrate/005_issue_start_date.rb @@ -0,0 +1,11 @@ +class IssueStartDate < ActiveRecord::Migration + def self.up + add_column :issues, :start_date, :date + add_column :issues, :done_ratio, :integer, :default => 0, :null => false + end + + def self.down + remove_column :issues, :start_date + remove_column :issues, :done_ratio + end +end diff --git a/db/migrate/006_calendar_and_activity.rb b/db/migrate/006_calendar_and_activity.rb new file mode 100644 index 000000000..5d8474fc2 --- /dev/null +++ b/db/migrate/006_calendar_and_activity.rb @@ -0,0 +1,13 @@ +class CalendarAndActivity < ActiveRecord::Migration + def self.up + Permission.create :controller => "projects", :action => "activity", :description => "label_activity", :sort => 160, :is_public => true, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "projects", :action => "calendar", :description => "label_calendar", :sort => 165, :is_public => true, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "projects", :action => "gantt", :description => "label_gantt", :sort => 166, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'activity']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'calendar']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'gantt']).destroy + end +end diff --git a/db/migrate/007_create_journals.rb b/db/migrate/007_create_journals.rb new file mode 100644 index 000000000..6170b5bd3 --- /dev/null +++ b/db/migrate/007_create_journals.rb @@ -0,0 +1,54 @@ +class CreateJournals < ActiveRecord::Migration + + # model removed, but needed for data migration + class IssueHistory < ActiveRecord::Base; belongs_to :issue; end + + def self.up + create_table :journals, :force => true do |t| + t.column "journalized_id", :integer, :default => 0, :null => false + t.column "journalized_type", :string, :limit => 30, :default => "", :null => false + t.column "user_id", :integer, :default => 0, :null => false + t.column "notes", :text + t.column "created_on", :datetime, :null => false + end + create_table :journal_details, :force => true do |t| + t.column "journal_id", :integer, :default => 0, :null => false + t.column "property", :string, :limit => 30, :default => "", :null => false + t.column "prop_key", :string, :limit => 30, :default => "", :null => false + t.column "old_value", :string + t.column "value", :string + end + + # indexes + add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id" + add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id" + + Permission.create :controller => "issues", :action => "history", :description => "label_history", :sort => 1006, :is_public => true, :mail_option => 0, :mail_enabled => 0 + + # data migration + IssueHistory.find(:all, :include => :issue).each {|h| + j = Journal.new(:journalized => h.issue, :user_id => h.author_id, :notes => h.notes, :created_on => h.created_on) + j.details << JournalDetail.new(:property => 'attr', :prop_key => 'status_id', :value => h.status_id) + j.save + } + + drop_table :issue_histories + end + + def self.down + drop_table :journal_details + drop_table :journals + + create_table "issue_histories", :force => true do |t| + t.column "issue_id", :integer, :default => 0, :null => false + t.column "status_id", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "notes", :text, :default => "" + t.column "created_on", :timestamp + end + + add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" + + Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'history']).destroy + end +end diff --git a/db/migrate/008_create_user_preferences.rb b/db/migrate/008_create_user_preferences.rb new file mode 100644 index 000000000..80ae1cdf9 --- /dev/null +++ b/db/migrate/008_create_user_preferences.rb @@ -0,0 +1,12 @@ +class CreateUserPreferences < ActiveRecord::Migration + def self.up + create_table :user_preferences do |t| + t.column "user_id", :integer, :default => 0, :null => false + t.column "others", :text + end + end + + def self.down + drop_table :user_preferences + end +end diff --git a/db/migrate/009_add_hide_mail_pref.rb b/db/migrate/009_add_hide_mail_pref.rb new file mode 100644 index 000000000..a22eafd93 --- /dev/null +++ b/db/migrate/009_add_hide_mail_pref.rb @@ -0,0 +1,9 @@ +class AddHideMailPref < ActiveRecord::Migration + def self.up + add_column :user_preferences, :hide_mail, :boolean, :default => false + end + + def self.down + remove_column :user_preferences, :hide_mail + end +end diff --git a/doc/CHANGELOG b/doc/CHANGELOG new file mode 100644 index 000000000..145d848c0 --- /dev/null +++ b/doc/CHANGELOG @@ -0,0 +1,96 @@ +== redMine changelog + +redMine - project management software +Copyright (C) 2006 Jean-Philippe Lang +http://redmine.org/ + + +== xx/xx/2006 v0.x.x + +* "my page" is now customizable +* improved issues change history +* new functionality: move an issue to another project or tracker +* new functionality: add a note to an issue +* new report: project activity +* "start date" and "% done" fields added on issues +* project calendar added +* gantt chart added (exportable to pdf) +* single/multiple issues pdf export added +* issues reports improvements +* multiple file upload for issues attachments +* textile formating of issue and news descritions (RedCloth required) +* integration of DotClear jstoolbar for textile formatting +* calendar date picker for date fields (LGPL DHTML Calendar http://sourceforge.net/projects/jscalendar) +* new filter in issues list: Author +* ajaxified paginators +* option to set number of results per page on issues list +* localized csv separator (comma/semicolon) +* csv output encoded to ISO-8859-1 +* user custom field displayed on account/show +* default configuration improved (default roles, trackers, status, permissions and workflows) +* fixed: custom fields not in csv exports +* fixed: project settings now displayed according to user's permissions + +== 10/08/2006 v0.3.0 + +* user authentication against multiple LDAP (optional) +* token based "lost password" functionality +* user self-registration functionality (optional) +* custom fields now available for issues, users and projects +* new custom field format "text" (displayed as a textarea field) +* project & administration drop down menus in navigation bar for quicker access +* text formatting is preserved for long text fields (issues, projects and news descriptions) +* urls and emails are turned into clickable links in long text fields +* "due date" field added on issues +* tracker selection filter added on change log +* Localization plugin replaced with GLoc 1.1.0 (iconv required) +* error messages internationalization +* german translation added (thanks to Karim Trott) +* data locking for issues to prevent update conflicts (using ActiveRecord builtin optimistic locking) +* new filter in issues list: "Fixed version" +* active filters are displayed with colored background on issues list +* custom configuration is now defined in config/config_custom.rb +* user object no more stored in session (only user_id) +* news summary field is no longer required +* tables and forms redesign +* Fixed: boolean custom field not working +* Fixed: error messages for custom fields are not displayed +* Fixed: invalid custom fields should have a red border +* Fixed: custom fields values are not validated on issue update +* Fixed: unable to choose an empty value for 'List' custom fields +* Fixed: no issue categories sorting +* Fixed: incorrect versions sorting + + +== 07/12/2006 - v0.2.2 + +* Fixed: bug in "issues list" + + +== 07/09/2006 - v0.2.1 + +* new databases supported: Oracle, PostgreSQL, SQL Server +* projects/subprojects hierarchy (1 level of subprojects only) +* environment information display in admin/info +* more filter options in issues list (rev6) +* default language based on browser settings (Accept-Language HTTP header) +* issues list exportable to CSV (rev6) +* simple_format and auto_link on long text fields +* more data validations +* Fixed: error when all mail notifications are unchecked in admin/mail_options +* Fixed: all project news are displayed on project summary +* Fixed: Can't change user password in users/edit +* Fixed: Error on tables creation with PostgreSQL (rev5) +* Fixed: SQL error in "issue reports" view with PostgreSQL (rev5) + + +== 06/25/2006 - v0.1.0 + +* multiple users/multiple projects +* role based access control +* issue tracking system +* fully customizable workflow +* documents/files repository +* email notifications on issue creation and update +* multilanguage support (except for error messages):english, french, spanish +* online manual in french (unfinished) \ No newline at end of file diff --git a/doc/COPYING b/doc/COPYING new file mode 100644 index 000000000..82fa1daad --- /dev/null +++ b/doc/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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. + + This program 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 this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/doc/INSTALL b/doc/INSTALL new file mode 100644 index 000000000..9e29b6ddc --- /dev/null +++ b/doc/INSTALL @@ -0,0 +1,74 @@ +== redMine installation + +redMine - project management software +Copyright (C) 2006 Jean-Philippe Lang +http://redmine.org/ + + +== Requirements + +* Ruby on Rails 1.1 +* Iconv +* a database (see compatibility below) +* (recommended) Apache/Lighttpd with FCGI support + +Optional: +* RedCloth (for textile formatting) +* Net::LDAP for Ruby (for LDAP authentication) + +Supported databases: +* MySQL (tested with MySQL 5) +* PostgreSQL (tested with PostgreSQL 8.1) +* Oracle (tested with Oracle 10g) +* SQL Server (tested with SQL Server 2005) +* SQLite (tested with SQLite 3) + + +== Upgrade + +Due to major database changes, there is no migration support from beta 0.2.0. +Next releases (0.3.0+) will be provided with upgrade support. + + +== Installation + +1. Uncompress program archive: + tar zxvf + +2. Create an empty database: "redmine" for example + +3. Configure database parameters in config/database.yml + for "production" environment (default database is MySQL) + +4. Create the database structure. Under application main directory: + rake migrate RAILS_ENV="production" + It will create tables and default configuration data + +5. Insert default configuration data in database: + rake load_default_data RAILS_ENV="production" + This step is optional, as you can define your own configuration + (roles, trackers, statuses, workflows, enumerations) from sratch + +6. Test the installation by running WEBrick web server: + ruby script/server -e production + + Once WEBrick has started, point your browser to http://localhost:3000/ + You should now see the application welcome page + +7. Use default administrator account to log in: + login: admin + password: admin + +8. Setup Apache or Lighttpd with fastcgi for best performance. + + +== Configuration + +A sample configuration file is provided: "config/config_custom.example.rb" +Rename it to config_custom.rb and edit parameters. +Don't forget to restart the application after any change. + + +config.action_mailer.server_settings: SMTP server configuration +config.action_mailer.perform_deliveries: set to false to disable mail delivering + diff --git a/doc/README b/doc/README new file mode 100644 index 000000000..42a0bc18e --- /dev/null +++ b/doc/README @@ -0,0 +1,58 @@ +== redMine + +redMine - project management software +Copyright (C) 2006 Jean-Philippe Lang +http://redmine.org/ + +== License + +This program 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. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +== Main features + +redMine is a project management software written using Ruby on Rails. + +* multiple users/projects +* fully customizable role based access control +* issue tracking system +* fully customizable workflow +* documents/files repository +* email notifications +* custom fields for projects, users and issues +* multilanguage support +* multiple LDAP authentication support +* user self-registration support + + +== User documentation + +User documentation for redMine is written using DocBook XML format. +It's also avaible as HTML files in /public/manual (contextual help) + + +== Versioning + +redMine versioning scheme is major.minor.revision +Versions before 1.0.0 must be considered as beta versions and upgrading support +may not be provided for these versions. + + +== Credits + +* Jean-Francois Boutier (spanish translation) +* Andreas Viklund (open source XHTML layout, http://andreasviklund.com/) +* Karim Trott (german translation) + diff --git a/doc/docbook/en/redmine-userdoc-en.xml b/doc/docbook/en/redmine-userdoc-en.xml new file mode 100644 index 000000000..c290bb85d --- /dev/null +++ b/doc/docbook/en/redmine-userdoc-en.xml @@ -0,0 +1,429 @@ + + + + RedMine Documentation + + Administration +
+ Users + These screens allow you to manage the application users. +
+ Users’ List + + + Users’ List + + + + + + + The Lock/Unlock buttons allow you to lock/unlock the user accounts. + A user having a locked account cannot log in and access the application. +
+
+ User Creation or Modification + In modification mode, please leave the Password field blank in order to keep the user’s password unchanged. + A user designated as administrator has unrestricted access to the application and to all projects. + + + + Administrator + : designate the user as the administrator of the application. + + + + + E-mail notifications + : activate or de-activate automatic e-mail notifications for this user + + + + + Locked + : de-activates the user’s account + + + + +
+
+
+ Roles and Permissions + 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. + On the new or edit Role screen, check off the actions authorized for the Role. +
+
+ Trackers + Trackers allow the sorting of Issues and can define specific workflows. +
+
+ Customized fields + Customized fields allow you to add additional information in Projects, Issues or Users. A customized field can be of one the following types: + + + + Integer + : positive or negative number + + + + + String + : a string of characters - one single line of input. + + + + + Text + : a string of characters with multiple lines of input. Differs from String Format by providing multiple lines of input instead of a single line. + + + + + Date + : date + + + + + Boolean + : true or false (check if necessary) + + + + + List + : value to select from a predefined list (aka: scroll list or select box) + + + + Validation elements can be defined: + + + + Required + : A required field must have input in the forms + + + + + For all the projects + : field automatically associated to all of the projects + + + + + Min - max length + : minimum and maximum length for the input fields (0 means that there is no restriction) + + + + + Regular Expression + : regular expressions may provide validation of the input value + + Examples: + + ^\[A-Z]{4}\d+$ + : 4 capital letters followed by one or several digits + + + ^[^0-9]*$ + : characters only - no digits + + + + + Possible values + : possible values for the fields of "List" type. Values are separated by the character | + + + + +
+ Fields for Projects + + + + + Required + : required field + + + + +
+
+ Fields for Issues + + + + + For all projects + : field automatically associated to all project Issues + + 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). + + + +
+
+ Field for Users + + + + + Required + : required field + + + + +
+
+
+ Issue status + These screens allow you to define the different possible Issue statuses. + + + + Closed + : indicates Issue is considered as closed + + + + + Default + : status applied by default to new Issue requests (only one status can be Default status) + + + + + Color + : HTML color code (6 characters) representing the displayed status + + + + +
+
+ Workflow + The workflow allows to define changes the various project members are allowed to make on the Issues, according to their type. + 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. + + 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. + + + + Example of a workflow configuration + + + + + + + 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. +
+
+ Enumerations + 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: + + + Issue Priorities + + + Document Categories + + + +
+
+ E-mail notifications + This screen allows you to select the actions that will generate an e-mail notification for project members. + Note: E-mail sending must be activated in the application configuration if you want to make any notifications. +
+
+ Authentication + By default, redMine refers to its own database to authenticate users, by a specific password. + 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. + 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’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. + +
+ LDAP statement + + + + + Name + : reference display name + + + + + Host + : LDAP server host name + + + + + Port + : connection port to the LDAP server + + + + + Account + : DN of the connection account to LDAP (please leave it blank if the directory authorizes anonymous read access) + + + + + Password + : password of the connection account + + + + + Base DN + : Basic DN used for user search in the directory + + + + + LDAP screen + : User search screen in the directory (optional) + + + + + LDAP features + : + + + + + Identifier + : LDAP feature name used as user identifier (e.g.: uid) + + + + + First name + : LDAP feature name including the user’s first name (ex: givenName) + + + + + Last name + : LDAP feature name including the user’s last name (ex: familyName) + + + + + E-mail + : LDAP feature name including the user’s e-mail address (ex: mail) + + + + + + + The features" + First name + ", " + Last name + " and " + E-mail + " are not used except when the accounts are created on the fly. + +
+
+
+ Information + Displays application and environment information. +
+
+ + Projects +
+ Project preview + The preview presents the general project information, its main members, the latest announcements, as well as an synthesis of Issue requests open by tracker. + +
+
+ Issue management + +
+ Issue list + 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). + Once applied, a screen is valid during the entire session. You can re-define it or delete it by clicking Cancel. + + + Request list + + + + + + + +
+
+
+ Reports + 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. +
+
+ Change log + 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. +
+
+ News + Allows you to inform users on project activity. +
+
+ Documents + Documents are grouped by categories (see Value Lists). A document can contain several files (for example: revisions or successive versions). +
+
+ Files + This module allows you to display various folders (sources, binaires, ...) for each version of the application. +
+
+ Settings + +
+ Project features + + + + + Public + : if it’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’s not a public project, only the project members have access to it, according to their role. + + + + + Customized fields + : Select the customized fields that you want to use. Only the administrator can define new customized fields. + + + + +
+
+ Members + 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. +
+
+ Versions + 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). +
+
+ Request categories + Issue categories allow you to organize Issues. Categories can correspond to different project modules. +
+
+
+
\ No newline at end of file diff --git a/doc/docbook/fr/redmine-userdoc-fr.xml b/doc/docbook/fr/redmine-userdoc-fr.xml new file mode 100644 index 000000000..ba52da2c4 --- /dev/null +++ b/doc/docbook/fr/redmine-userdoc-fr.xml @@ -0,0 +1,553 @@ + + + + Documentation redMine + + + Administration + +
+ Utilisateurs + + Ces écrans vous permettent de gérer les utilisateurs de + l'application. + +
+ Liste des utilisateurs + + + + + Liste des utilisateurs + + + + + + + + + Les boutons Lock/Unlock vous permettent de + vérouiller/dévérouiller les comptes utilisateurs. + + Un utilisateur dont le compte est vérouillé ne peut plus + s'identifier pour accéder à l'application. +
+ +
+ Création ou modification d'un utilisateur + + En mode modification, laissez le champ Password vide pour + laisser le mot de passe de l'utilisateur inchangé. + + Un utilisateur déclaré comme administrateur dispose de toutes + les permissions sur l'application et sur tous les projets. + + + + Administrateur: déclare l'utilisateur + comme administrateur de l'application. + + + + Notifications par mail: permet + d'activer ou non l'envoi automatique de notifications par mail + pour cet utilisateur + + + + Vérouillé: désactive le compte de + l'utilisateur + + + + +
+
+ +
+ Rôles et permissions + + Les rôles permettent de définir les permissions des différents + membres d'un projet. Chaque membre d'un projet dispose d'un rôle unique + au sein d'un projet. Un utilisateur peut avoir différents rôles au sein + de différents projets. + + Sur l'écran d'édition du rôle, cochez les actions que vous + souhaitez autoriser pour le rôle. +
+ +
+ Trackers + + Les trackers permettent de typer les demandes et de définir des + workflows spécifiques pour chacun de ces types. +
+ +
+ Champs personnalisés + + Les champs personnalisés vous permettent d'ajouter des + informations supplémentaires sur les projets, les demandes ou les + utilisateurs. Un champ personnalisé peut être de l'un des types + suivants: + + + + Entier: entier positif ou négatif + + + + Chaîne: chaîne de caractère + + + + Date: date + + + + Booléen: booléen (case à cocher) + + + + Liste: valeur à sélectionnée parmi une + liste prédéfinie (liste déroulante) + + + + Des éléments de validation peuvent être définis: + + + + Obligatoire: champ dont la saisie est + obligatoire sur les demandes + + + + Pour tous les projects: champ + automatiquement associé à l'ensemble des projets + + + + Min - max length: longueurs minimales et + maximales pour les champs en saisie libre (0 signifie qu'il n'y a + pas de restriction) + + + + Expression régulière: expression + régulière permettant de valider la valeur saisie + + Exemples: + + ^\[A-Z]{4}\d+$ : 4 lettres majuscules suivies + d'un ou plusieurs chiffres + + ^[^0-9]*$ : chaîne ne comportant pas de + chiffres + + + + Valeurs possibles: valeurs possibles pour + les champs de type "Liste". Les valeurs sont séparées par le + caractère | + + + + + +
+ Champs pour les projets + + + + + + Obligatoire: champ dont la saisie est + obligatoire + + + + +
+ +
+ Champs pour les demandes + + + + + + Pour tous les projects: champ + automatiquement associé aux demandes de l'ensemble des + projets + + Si cette option n'est pas activée, chaque projet pourra + choisir d'utiliser ou non le champ pour ses demandes (voir + configuration du projet). + + + + +
+ +
+ Champs pour les utilisateurs + + + + + + Obligatoire: champ dont la saisie est + obligatoire + + + + +
+
+ +
+ Statut des demandes + + Ces écrans vous permettent de définir les différents statuts + possibles des demandes. + + + + Demande fermée: indique que le statut + correspond à une demande considérée comme fermée + + + + Statut par défaut: statut appliqué par + défaut aux nouvelles demandes (seul un statut peut être déclaré + comme statut par défaut) + + + + Couleur: code couleur HTML (6 caractères) + représentant le statut à l'affichage + + + + +
+ +
+ Workflow + + Le workflow permet de définir les changements que les différents + membres d'un projet sont autorisés à effectuer sur les demandes, en + fonction de leur type. + + Sélectionnez le rôle et le tracker pour lesquels vous souhaitez + modifier le workflow, puis cliquez sur Edit. L'écran vous permet alors + de modifier, pour le rôle et le tracker choisi, les changements + autorisés. Les lignes représentent les statuts initiaux des demandes. + Les colonnes représentent les statuts autorisés à être appliqués. + + Remarque: pour qu'un rôle puisse changer le statut des + demandes, la permission doit lui être explicitement donnée + indépendemment de la configuration du workflow. + + + + + Exemple de configuration d'un workflow + + + + + + + + + Dans l'exemple ci-dessus, les demandes de type Bug au statut + Nouveau pourront être passées au statut Assignée ou Résolue par le rôle + Développeur. Celles au statut Assignée pourront être passées au statut + Résolue. Le statut de toutes les autres demandes de type Bug ne pourra + pas être modifié par le Développeur. +
+ +
+ Listes de valeurs + + Les listes de valeurs utilisées par l'application (exemple: les + priorités des demandes) peuvent être personnalisées. Cet écran vous + permet de définir les valeurs possibles pour chacune des listes + suivantes: + + + + Priorités des demandes + + + + Catégories de documents + + + + +
+ +
+ Notifications par mail + + Cet écran vous permet de sélectionner les actions qui donneront + lieu à une notification par mail aux membres du projet. + + Remarque: l'envoi de mails doit être activé dans la configuration + de l'application si souhaitez effectuer des notifications. +
+ +
+ Authentification + + Par défaut, redMine s'appuie sur sa propre base de données pour + authentifier les utilisateurs, à l'aide d'un mot de passe + spécifique. + + Si vous disposez déjà d'un ou plusieurs référentiels externes + d'utilisateurs (annuaires LDAP), vous pouvez les déclarer afin qu'ils + soient utilisés pour l'authentification sur redMine. Cela permet aux + utilisateurs d'accéder à redMine avec leurs identifiants et mots de + passe habituels. + + Pour chaque référentiel déclaré, vous pouvez spécifier si les + comptes peuvent être créés à la volée dans redMine. Si c'est le cas, les + comptes utilisateurs sont automatiquement créés à la première connexion + de l'utilisateur (sans droits spécifiques sur les projets), à partir des + informations disponibles dans le référentiel. Sinon, l'administrateur + doit au préalable créer le compte de l'utilisateur dans redMine. + + + +
+ Déclaration d'un annuaire LDAP + + + + + + Nom: nom d'affichage du + référentiel + + + + Hôte: nom d'hôte du serveur LDAP + + + + Port: port de connexion au serveur + LDAP + + + + Compte: DN du compte de connexion au + LDAP (laisser vide si l'annuaire autorise l'accès anonyme en + lecture) + + + + Mot de passe: mot de passe du compte de + connexion + + + + Base DN: DN de base utilisé pour la + recherche des utilisateur dans l'annuaire + + + + Filtre LDAP: Filtre de recherche des + utilisateurs dans l'annuaire (optionnel) + + + + Attributs LDAP: + + + + Identifiant: nom de l'attribut LDAP + utilisé comme identifiant de l'utilisateur (ex: uid) + + + + Prénom: nom de l'attribut LDAP + contenant le prénom de l'utilisateur (ex: givenName) + + + + Nom: nom de l'attribut LDAP + contenant le nom de l'utilisateur (ex: sn) + + + + Email: nom de l'attribut LDAP + contenant l'adresse mail de l'utilisateur (ex: mail) + + + + + + Les attributs "Prénom", + "Nom" et "Email" ne sont + utilisés que lorsque les comptes sont créés à la volée. +
+
+ +
+ Informations + + Affiche des informations relatives à l'application et à son + environnement. +
+
+ + + Projets + +
+ Aperçu du projet + + L'aperçu vous présente les informations générales relatives au + projet, les principaux membres, les dernières annonces, ainsi qu'une + synthèse du nombre de demandes ouvertes par tracker. + + +
+ +
+ Gestion des demandes + + + +
+ Liste des demandes + + Par défaut, l'ensemble des demandes ouvertes du projet sont + affichées. Différents filtres vous permettent de sélectionner les + demandes à afficher. Si le projet comporte des sous-projets, vous avez + la possibilité d'afficher également les demandes relatives aux + sous-projets (non affichées par défaut). + + Une fois appliqué, un filtre reste valable durant toute votre + session. Vous pouvez le redéfinir, ou le supprimer en cliquant sur + Annuler. + + + + + Liste des demandes + + + + + + + + + +
+
+ +
+ Rapports + + Cet écran présente la synthèse du nombre de demandes par statut et + selon différents critères (tracker, priorité, catégorie). Des liens + directs permettent d'accéder à la liste détaillée des demandes pour + chaque critère. +
+ +
+ Historique + + Cette page présente l'ensemble des demandes résolues dans chacune + des versions du projet. Certains types de demande peuvent être exclus de + cet affichage. +
+ +
+ Annonces + + Les nouvelles vous permettent d'informer les utilisateurs sur + l'activité du projet. +
+ +
+ Documents + + Les documents sont groupés par catégories (voir Listes de + valeurs). Un document peut contenir plusieurs fichiers (exemple: + révisions ou versions successives). +
+ +
+ Fichiers + + Ce module vous permet de publier les différents fichiers (sources, + binaires, ...) pour chaque version de l'application. +
+ +
+ Configuration du projet + + + +
+ Propriétés du projet + + + + + + Public: 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ès, en fonction de leur rôle. + + + + Champs personnalisés: sélectionner les + champs personnalisés que vous souhaitez utiliser pour les demandes + du projet. Seul l'administrateur peut définir de nouveaux champs + personnalisés. + + + + +
+ +
+ Membres + + Cet écran vous permet de définir les membres du projet ainsi que + leurs rôles respectifs. Un utilisateur ne peut avoir qu'un rôle au + sein d'un projet donné. Le rôle d'un membre détermine les permissions + dont il bénéficie sur le projet. +
+ +
+ Versions + + 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érentes versions de l'application (voir + Fichiers). +
+ +
+ Catégories des demandes + + Les catégories de demande vous permettent de typer les demandes. + Les catégories peuvent par exemple correspondre aux différents modules + du projet. +
+
+
+
\ No newline at end of file diff --git a/files/delete.me b/files/delete.me new file mode 100644 index 000000000..18beddaa8 --- /dev/null +++ b/files/delete.me @@ -0,0 +1 @@ +default directory for uploaded files \ No newline at end of file diff --git a/lang/de.yml b/lang/de.yml new file mode 100644 index 000000000..7eaa3d05a --- /dev/null +++ b/lang/de.yml @@ -0,0 +1,320 @@ +_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' + +actionview_datehelper_select_day_prefix: +actionview_datehelper_select_month_names: January,February,March,April,May,June,July,August,September,October,November,December +actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec +actionview_datehelper_select_month_prefix: +actionview_datehelper_select_year_prefix: +actionview_datehelper_time_in_words_day: 1 day +actionview_datehelper_time_in_words_day_plural: %d days +actionview_datehelper_time_in_words_hour_about: about an hour +actionview_datehelper_time_in_words_hour_about_plural: about %d hours +actionview_datehelper_time_in_words_hour_about_single: about an hour +actionview_datehelper_time_in_words_minute: 1 minute +actionview_datehelper_time_in_words_minute_half: half a minute +actionview_datehelper_time_in_words_minute_less_than: less than a minute +actionview_datehelper_time_in_words_minute_plural: %d minutes +actionview_datehelper_time_in_words_minute_single: 1 minute +actionview_datehelper_time_in_words_second_less_than: less than a second +actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds +actionview_instancetag_blank_option: Bitte auserwählt + +activerecord_error_inclusion: ist nicht in der Liste eingeschlossen +activerecord_error_exclusion: ist reserviert +activerecord_error_invalid: ist unzulässig +activerecord_error_confirmation: bringt nicht Bestätigung zusammen +activerecord_error_accepted: muß angenommen werden +activerecord_error_empty: kann nicht leer sein +activerecord_error_blank: kann nicht leer sein +activerecord_error_too_long: ist zu lang +activerecord_error_too_short: ist zu kurz +activerecord_error_wrong_length: ist die falsche Länge +activerecord_error_taken: ist bereits genommen worden +activerecord_error_not_a_number: ist nicht eine Zahl +activerecord_error_not_a_date: ist nicht ein gültiges Datum +activerecord_error_greater_than_start_date: muß als grösser sein beginnen Datum + +general_fmt_age: %d yr +general_fmt_age_plural: %d yrs +general_fmt_date: %%b %%d, %%Y (%%a) +general_fmt_datetime: %%b %%d, %%Y (%%a), %%I:%%M %%p +general_fmt_datetime_short: %%b %%d, %%I:%%M %%p +general_fmt_time: %%I:%%M %%p +general_text_No: 'Nein' +general_text_Yes: 'Ja' +general_text_no: 'nein' +general_text_yes: 'ja' +general_lang_de: 'Deutsch' +general_csv_separator: ';' +general_day_names: Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag,Sonntag + +notice_account_updated: Konto wurde erfolgreich aktualisiert. +notice_account_invalid_creditentials: Unzulässiger Benutzer oder Passwort +notice_account_password_updated: Passwort wurde erfolgreich aktualisiert. +notice_account_wrong_password: Falsches Passwort +notice_account_register_done: Konto wurde erfolgreich verursacht. +notice_account_unknown_email: Unbekannter Benutzer. +notice_can_t_change_password: Dieses Konto verwendet eine externe Authentisierung Quelle. Unmöglich, das Kennwort zu ändern. +notice_account_lost_email_sent: Ein email mit Anweisungen, ein neues Kennwort zu wählen ist dir geschickt worden. +notice_account_activated: Dein Konto ist aktiviert worden. Du kannst jetzt einloggen. +notice_successful_create: Erfolgreiche Kreation. +notice_successful_update: Erfolgreiches Update. +notice_successful_delete: Erfolgreiche Auslassung. +notice_successful_connection: Erfolgreicher Anschluß. +notice_file_not_found: Erbetene Akte besteht nicht oder ist gelöscht worden. +notice_locking_conflict: Data have been updated by another user. + +mail_subject_lost_password: Dein redMine Kennwort +mail_subject_register: redMine Kontoaktivierung + +gui_validation_error: 1 Störung +gui_validation_error_plural: %d Störungen + +field_name: Name +field_description: Beschreibung +field_summary: Zusammenfassung +field_is_required: Erforderlich +field_firstname: Vorname +field_lastname: Nachname +field_mail: Email +field_filename: Datei +field_filesize: Grootte +field_downloads: Downloads +field_author: Autor +field_created_on: Angelegt +field_updated_on: aktualisiert +field_field_format: Format +field_is_for_all: Für alle Projekte +field_possible_values: Mögliche Werte +field_regexp: Regulärer Ausdruck +field_min_length: Minimale Länge +field_max_length: Maximale Länge +field_value: Wert +field_category: Kategorie +field_title: Títel +field_project: Projekt +field_issue: Antrag +field_status: Status +field_notes: Anmerkungen +field_is_closed: Problem erledigt +field_is_default: Rückstellung status +field_html_color: Farbe +field_tracker: Tracker +field_subject: Thema +field_due_date: Abgabedatum +field_assigned_to: Zugewiesen an +field_priority: Priorität +field_fixed_version: Erledigt in Version +field_user: Benutzer +field_role: Rolle +field_homepage: Startseite +field_is_public: Öffentlich +field_parent: Subprojekt von +field_is_in_chlog: Ansicht der Issues in der Historie +field_login: Mitgliedsname +field_mail_notification: Mailbenachrichtigung +field_admin: Administrator +field_locked: Gesperrt +field_last_login_on: Letzte Anmeldung +field_language: Sprache +field_effective_date: Datum +field_password: Passwort +field_new_password: Neues Passwort +field_password_confirmation: Bestätigung +field_version: Version +field_type: Typ +field_host: Host +field_port: Port +field_account: Konto +field_base_dn: Base DN +field_attr_login: Mitgliedsnameattribut +field_attr_firstname: Vornamensattribut +field_attr_lastname: Namenattribut +field_attr_mail: Emailattribut +field_onthefly: On-the-fly Benutzerkreation +field_start_date: Beginn +field_done_ratio: %% Getan +field_hide_mail: Mein email address verstecken + +label_user: Benutzer +label_user_plural: Benutzer +label_user_new: Neuer Benutzer +label_project: Projekt +label_project_new: Neues Projekt +label_project_plural: Projekte +label_project_latest: Neueste Projekte +label_issue: Antrag +label_issue_new: Neue Antrag +label_issue_plural: Anträge +label_issue_view_all: Alle Anträge ansehen +label_document: Dokument +label_document_new: Neues Dokument +label_document_plural: Dokumente +label_role: Rolle +label_role_plural: Rollen +label_role_new: Neue Rolle +label_role_and_permissions: Rollen und Rechte +label_member: Mitglied +label_member_new: Neues Mitglied +label_member_plural: Mitglieder +label_tracker: Tracker +label_tracker_plural: Tracker +label_tracker_new: Neuer Tracker +label_workflow: Workflow +label_issue_status: Antrag Status +label_issue_status_plural: Antrag Stati +label_issue_status_new: Neuer Status +label_issue_category: Antrag Kategorie +label_issue_category_plural: Antrag Kategorien +label_issue_category_new: Neue Kategorie +label_custom_field: Benutzerdefiniertes Feld +label_custom_field_plural: Benutzerdefinierte Felder +label_custom_field_new: Neues Feld +label_enumerations: Enumerationen +label_enumeration_new: Neuer Wert +label_information: Information +label_information_plural: Informationen +label_please_login: Anmelden +label_register: Anmelden +label_password_lost: Passwort vergessen +label_home: Hauptseite +label_my_page: Meine Seite +label_my_account: Mein Konto +label_my_projects: Meine Projekte +label_administration: Administration +label_login: Einloggen +label_logout: Abmelden +label_help: Hilfe +label_reported_issues: Gemeldete Issues +label_assigned_to_me_issues: Mir zugewiesen +label_last_login: Letzte Anmeldung +label_last_updates: Letztes aktualisiertes +label_last_updates_plural: %d Letztes aktualisiertes +label_registered_on: Angemeldet am +label_activity: Aktivität +label_new: Neue +label_logged_as: Angemeldet als +label_environment: Environment +label_authentication: Authentisierung +label_auth_source: Authentisierung Modus +label_auth_source_new: Neuer Authentisierung Modus +label_auth_source_plural: Authentisierung Modi +label_subproject: Vorprojekt von +label_subproject_plural: Vorprojekte +label_min_max_length: Min - Max Länge +label_list: Liste +label_date: Date +label_integer: Zahl +label_boolean: Boolesch +label_string: Text +label_text: Langer Text +label_attribute: Attribut +label_attribute_plural: Attribute +label_download: %d Herunterlade +label_download_plural: %d Herunterlade +label_no_data: Nichts anzuzeigen +label_change_status: Statuswechsel +label_history: Historie +label_attachment: Datei +label_attachment_new: Neue Datei +label_attachment_delete: Löschungakten +label_attachment_plural: Dateien +label_report: Bericht +label_report_plural: Berichte +label_news: Neuigkeit +label_news_new: Neuigkeite addieren +label_news_plural: Neuigkeiten +label_news_latest: Letzte Neuigkeiten +label_news_view_all: Alle Neuigkeiten anzeigen +label_change_log: Change log +label_settings: Konfiguration +label_overview: Übersicht +label_version: Version +label_version_new: Neue Version +label_version_plural: Versionen +label_confirmation: Bestätigung +label_export_to: Export zu +label_read: Lesen... +label_public_projects: Öffentliche Projekte +label_open_issues: Geöffnet +label_open_issues_plural: Geöffnet +label_closed_issues: Geschlossen +label_closed_issues_plural: Geschlossen +label_total: Gesamtzahl +label_permissions: Berechtigungen +label_current_status: Gegenwärtiger Status +label_new_statuses_allowed: Neue Status gewährten +label_all: Alle +label_none: Kein +label_next: Weiter +label_previous: Zurück +label_used_by: Benutzt von +label_details: Details... +label_add_note: Eine Anmerkung addieren +label_per_page: Pro Seite +label_calendar: Kalender +label_months_from: Monate von +label_gantt_chart: Gantt Diagramm +label_internal: Intern +label_last_changes: %d änderungen des Letzten +label_change_view_all: Alle änderungen ansehen +label_personalize_page: Diese Seite personifizieren + +button_login: Einloggen +button_submit: Einreichen +button_save: Speichern +button_check_all: Alles auswählen +button_uncheck_all: Alles abwählen +button_delete: Löschen +button_create: Anlegen +button_test: Testen +button_edit: Bearbeiten +button_add: Hinzufügen +button_change: Wechseln +button_apply: Anwenden +button_clear: Zurücksetzen +button_lock: Verriegeln +button_unlock: Entriegeln +button_download: Fernzuladen +button_list: Aufzulisten +button_view: Siehe +button_move: Bewegen +button_back: Rückkehr +button_cancel: Annullieren + +text_select_mail_notifications: Aktionen für die Mailbenachrichtigung aktiviert werden soll. +text_regexp_info: eg. ^[A-Z0-9]+$ +text_min_max_length_info: 0 heisst keine Beschränkung +text_possible_values_info: Werte trennten sich mit | +text_project_destroy_confirmation: Sind sie sicher, daß sie das Projekt löschen wollen ? +text_workflow_edit: Auswahl Workflow zum Bearbeiten +text_are_you_sure: Sind sie sicher ? +text_journal_changed: geändert von %s zu %s +text_journal_set_to: gestellt zu %s +text_journal_deleted: gelöscht +text_tip_task_begin_day: Aufgabe, die an diesem Tag beginnt +text_tip_task_end_day: Aufgabe, die an diesem Tag beendet +text_tip_task_begin_end_day: Aufgabe, die an diesem Tag beginnt und beendet + +default_role_manager: Manager +default_role_developper: Developer +default_role_reporter: Reporter +default_tracker_bug: Fehler +default_tracker_feature: Feature +default_tracker_support: Support +default_issue_status_new: Neu +default_issue_status_assigned: Zugewiesen +default_issue_status_resolved: Gelöst +default_issue_status_feedback: Feedback +default_issue_status_closed: Erledigt +default_issue_status_rejected: Abgewiesen +default_doc_category_user: Benutzerdokumentation +default_doc_category_tech: Technische Dokumentation +default_priority_low: Niedrig +default_priority_normal: Normal +default_priority_high: Hoch +default_priority_urgent: Dringend +default_priority_immediate: Sofort + +enumeration_issue_priorities: Issue-Prioritäten +enumeration_doc_categories: Dokumentenkategorien diff --git a/lang/en.yml b/lang/en.yml new file mode 100644 index 000000000..a3aad0467 --- /dev/null +++ b/lang/en.yml @@ -0,0 +1,320 @@ +_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' + +actionview_datehelper_select_day_prefix: +actionview_datehelper_select_month_names: January,February,March,April,May,June,July,August,September,October,November,December +actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec +actionview_datehelper_select_month_prefix: +actionview_datehelper_select_year_prefix: +actionview_datehelper_time_in_words_day: 1 day +actionview_datehelper_time_in_words_day_plural: %d days +actionview_datehelper_time_in_words_hour_about: about an hour +actionview_datehelper_time_in_words_hour_about_plural: about %d hours +actionview_datehelper_time_in_words_hour_about_single: about an hour +actionview_datehelper_time_in_words_minute: 1 minute +actionview_datehelper_time_in_words_minute_half: half a minute +actionview_datehelper_time_in_words_minute_less_than: less than a minute +actionview_datehelper_time_in_words_minute_plural: %d minutes +actionview_datehelper_time_in_words_minute_single: 1 minute +actionview_datehelper_time_in_words_second_less_than: less than a second +actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds +actionview_instancetag_blank_option: Please select + +activerecord_error_inclusion: is not included in the list +activerecord_error_exclusion: is reserved +activerecord_error_invalid: is invalid +activerecord_error_confirmation: doesn't match confirmation +activerecord_error_accepted: must be accepted +activerecord_error_empty: can't be empty +activerecord_error_blank: can't be blank +activerecord_error_too_long: is too long +activerecord_error_too_short: is too short +activerecord_error_wrong_length: is the wrong length +activerecord_error_taken: has already been taken +activerecord_error_not_a_number: is not a number +activerecord_error_not_a_date: is not a valid date +activerecord_error_greater_than_start_date: must be greater than start date + +general_fmt_age: %d yr +general_fmt_age_plural: %d yrs +general_fmt_date: %%m/%%d/%%Y +general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p +general_fmt_datetime_short: %%b %%d, %%I:%%M %%p +general_fmt_time: %%I:%%M %%p +general_text_No: 'No' +general_text_Yes: 'Yes' +general_text_no: 'no' +general_text_yes: 'yes' +general_lang_en: 'English' +general_csv_separator: ',' +general_day_names: Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday + +notice_account_updated: Account was successfully updated. +notice_account_invalid_creditentials: Invalid user or password +notice_account_password_updated: Password was successfully updated. +notice_account_wrong_password: Wrong password +notice_account_register_done: Account was successfully created. +notice_account_unknown_email: Unknown user. +notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. +notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. +notice_account_activated: Your account has been activated. You can now log in. +notice_successful_create: Successful creation. +notice_successful_update: Successful update. +notice_successful_delete: Successful deletion. +notice_successful_connection: Successful connection. +notice_file_not_found: Requested file doesn't exist or has been deleted. +notice_locking_conflict: Data have been updated by another user. + +mail_subject_lost_password: Your redMine password +mail_subject_register: redMine account activation + +gui_validation_error: 1 error +gui_validation_error_plural: %d errors + +field_name: Name +field_description: Description +field_summary: Summary +field_is_required: Required +field_firstname: Firstname +field_lastname: Lastname +field_mail: Email +field_filename: File +field_filesize: Size +field_downloads: Downloads +field_author: Author +field_created_on: Created +field_updated_on: Updated +field_field_format: Format +field_is_for_all: For all projects +field_possible_values: Possible values +field_regexp: Regular expression +field_min_length: Minimum length +field_max_length: Maximum length +field_value: Value +field_category: Category +field_title: Title +field_project: Project +field_issue: Issue +field_status: Status +field_notes: Notes +field_is_closed: Issue closed +field_is_default: Default status +field_html_color: Color +field_tracker: Tracker +field_subject: Subject +field_due_date: Due date +field_assigned_to: Assigned to +field_priority: Priority +field_fixed_version: Fixed version +field_user: User +field_role: Role +field_homepage: Homepage +field_is_public: Public +field_parent: Subproject of +field_is_in_chlog: Issues displayed in changelog +field_login: Login +field_mail_notification: Mail notifications +field_admin: Administrator +field_locked: Locked +field_last_login_on: Last connection +field_language: Language +field_effective_date: Date +field_password: Password +field_new_password: New password +field_password_confirmation: Confirmation +field_version: Version +field_type: Type +field_host: Host +field_port: Port +field_account: Account +field_base_dn: Base DN +field_attr_login: Login attribute +field_attr_firstname: Firstname attribute +field_attr_lastname: Lastname attribute +field_attr_mail: Email attribute +field_onthefly: On-the-fly user creation +field_start_date: Start +field_done_ratio: %% Done +field_hide_mail: Hide my email address + +label_user: User +label_user_plural: Users +label_user_new: New user +label_project: Project +label_project_new: New project +label_project_plural: Projects +label_project_latest: Latest projects +label_issue: Issue +label_issue_new: New issue +label_issue_plural: Issues +label_issue_view_all: View all issues +label_document: Document +label_document_new: New document +label_document_plural: Documents +label_role: Role +label_role_plural: Roles +label_role_new: New role +label_role_and_permissions: Roles and permissions +label_member: Member +label_member_new: New member +label_member_plural: Members +label_tracker: Tracker +label_tracker_plural: Trackers +label_tracker_new: New tracker +label_workflow: Workflow +label_issue_status: Issue status +label_issue_status_plural: Issue statuses +label_issue_status_new: New status +label_issue_category: Issue category +label_issue_category_plural: Issue categories +label_issue_category_new: New category +label_custom_field: Custom field +label_custom_field_plural: Custom fields +label_custom_field_new: New custom field +label_enumerations: Enumerations +label_enumeration_new: New value +label_information: Information +label_information_plural: Information +label_please_login: Please login +label_register: Register +label_password_lost: Lost password +label_home: Home +label_my_page: My page +label_my_account: My account +label_my_projects: My projects +label_administration: Administration +label_login: Login +label_logout: Logout +label_help: Help +label_reported_issues: Reported issues +label_assigned_to_me_issues: Issues assigned to me +label_last_login: Last connection +label_last_updates: Last updated +label_last_updates_plural: %d last updated +label_registered_on: Registered on +label_activity: Activity +label_new: New +label_logged_as: Logged as +label_environment: Environment +label_authentication: Authentication +label_auth_source: Authentication mode +label_auth_source_new: New authentication mode +label_auth_source_plural: Authentication modes +label_subproject: Subproject +label_subproject_plural: Subprojects +label_min_max_length: Min - Max length +label_list: List +label_date: Date +label_integer: Integer +label_boolean: Boolean +label_string: Text +label_text: Long text +label_attribute: Attribute +label_attribute_plural: Attributes +label_download: %d Download +label_download_plural: %d Downloads +label_no_data: No data to display +label_change_status: Change status +label_history: History +label_attachment: File +label_attachment_new: New file +label_attachment_delete: Delete file +label_attachment_plural: Files +label_report: Report +label_report_plural: Reports +label_news: News +label_news_new: Add news +label_news_plural: News +label_news_latest: Latest news +label_news_view_all: View all news +label_change_log: Change log +label_settings: Settings +label_overview: Overview +label_version: Version +label_version_new: New version +label_version_plural: Versions +label_confirmation: Confirmation +label_export_to: Export to +label_read: Read... +label_public_projects: Public projects +label_open_issues: Open +label_open_issues_plural: Open +label_closed_issues: Closed +label_closed_issues_plural: Closed +label_total: Total +label_permissions: Permissions +label_current_status: Current status +label_new_statuses_allowed: New statuses allowed +label_all: All +label_none: None +label_next: Next +label_previous: Previous +label_used_by: Used by +label_details: Details... +label_add_note: Add a note +label_per_page: Per page +label_calendar: Calendar +label_months_from: months from +label_gantt_chart: Gantt chart +label_internal: Internal +label_last_changes: last %d changes +label_change_view_all: View all changes +label_personalize_page: Personalize this page + +button_login: Login +button_submit: Submit +button_save: Save +button_check_all: Check all +button_uncheck_all: Uncheck all +button_delete: Delete +button_create: Create +button_test: Test +button_edit: Edit +button_add: Add +button_change: Change +button_apply: Apply +button_clear: Clear +button_lock: Lock +button_unlock: Unlock +button_download: Download +button_list: List +button_view: View +button_move: Move +button_back: Back +button_cancel: Cancel + +text_select_mail_notifications: Select actions for which mail notifications should be sent. +text_regexp_info: eg. ^[A-Z0-9]+$ +text_min_max_length_info: 0 means no restriction +text_possible_values_info: values separated with | +text_project_destroy_confirmation: Are you sure you want to delete this project and all related data ? +text_workflow_edit: Select a role and a tracker to edit the workflow +text_are_you_sure: Are you sure ? +text_journal_changed: changed from %s to %s +text_journal_set_to: set to %s +text_journal_deleted: deleted +text_tip_task_begin_day: task beginning this day +text_tip_task_end_day: task ending this day +text_tip_task_begin_end_day: task beginning and ending this day + +default_role_manager: Manager +default_role_developper: Developer +default_role_reporter: Reporter +default_tracker_bug: Bug +default_tracker_feature: Feature +default_tracker_support: Support +default_issue_status_new: New +default_issue_status_assigned: Assigned +default_issue_status_resolved: Resolved +default_issue_status_feedback: Feedback +default_issue_status_closed: Closed +default_issue_status_rejected: Rejected +default_doc_category_user: User documentation +default_doc_category_tech: Technical documentation +default_priority_low: Low +default_priority_normal: Normal +default_priority_high: High +default_priority_urgent: Urgent +default_priority_immediate: Immediate + +enumeration_issue_priorities: Issue priorities +enumeration_doc_categories: Document categories diff --git a/lang/es.yml b/lang/es.yml new file mode 100644 index 000000000..f87a31133 --- /dev/null +++ b/lang/es.yml @@ -0,0 +1,320 @@ +_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' + +actionview_datehelper_select_day_prefix: +actionview_datehelper_select_month_names: Enero,Febrero,Marzo,Abril,Mayo,Junio,Julio,Agosto,Septiembre,Octubre,Noviembre,Diciembre +actionview_datehelper_select_month_names_abbr: Ene,Feb,Mar,Abr,Mayo,Jun,Jul,Ago,Sep,Oct,Nov,Dic +actionview_datehelper_select_month_prefix: +actionview_datehelper_select_year_prefix: +actionview_datehelper_time_in_words_day: 1 day +actionview_datehelper_time_in_words_day_plural: %d days +actionview_datehelper_time_in_words_hour_about: about an hour +actionview_datehelper_time_in_words_hour_about_plural: about %d hours +actionview_datehelper_time_in_words_hour_about_single: about an hour +actionview_datehelper_time_in_words_minute: 1 minute +actionview_datehelper_time_in_words_minute_half: half a minute +actionview_datehelper_time_in_words_minute_less_than: less than a minute +actionview_datehelper_time_in_words_minute_plural: %d minutes +actionview_datehelper_time_in_words_minute_single: 1 minute +actionview_datehelper_time_in_words_second_less_than: less than a second +actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds +actionview_instancetag_blank_option: Please select + +activerecord_error_inclusion: is not included in the list +activerecord_error_exclusion: is reserved +activerecord_error_invalid: is invalid +activerecord_error_confirmation: doesn't match confirmation +activerecord_error_accepted: must be accepted +activerecord_error_empty: can't be empty +activerecord_error_blank: can't be blank +activerecord_error_too_long: is too long +activerecord_error_too_short: is too short +activerecord_error_wrong_length: is the wrong length +activerecord_error_taken: has already been taken +activerecord_error_not_a_number: is not a number +activerecord_error_not_a_date: no es una fecha válida +activerecord_error_greater_than_start_date: debe ser la fecha mayor que del comienzo + +general_fmt_age: %d año +general_fmt_age_plural: %d años +general_fmt_date: %%d/%%m/%%Y +general_fmt_datetime: %%d/%%m/%%Y %%H:%%M +general_fmt_datetime_short: %%d/%%m %%H:%%M +general_fmt_time: %%H:%%M +general_text_No: 'No' +general_text_Yes: 'Sí' +general_text_no: 'no' +general_text_yes: 'sí' +general_lang_es: 'Español' +general_csv_separator: ';' +general_day_names: Lunes,Martes,Miércoles,Jueves,Viernes,Sábado,Domingo + +notice_account_updated: Account was successfully updated. +notice_account_invalid_creditentials: Invalid user or password +notice_account_password_updated: Password was successfully updated. +notice_account_wrong_password: Wrong password +notice_account_register_done: Account was successfully created. +notice_account_unknown_email: Unknown user. +notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. +notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. +notice_account_activated: Your account has been activated. You can now log in. +notice_successful_create: Successful creation. +notice_successful_update: Successful update. +notice_successful_delete: Successful deletion. +notice_successful_connection: Successful connection. +notice_file_not_found: Requested file doesn't exist or has been deleted. +notice_locking_conflict: Data have been updated by another user. + +mail_subject_lost_password: Tu contraseña del redMine +mail_subject_register: Activación de la cuenta del redMine + +gui_validation_error: 1 error +gui_validation_error_plural: %d errores + +field_name: Nombre +field_description: Descripción +field_summary: Resumen +field_is_required: Obligatorio +field_firstname: Nombre +field_lastname: Apellido +field_mail: Email +field_filename: Fichero +field_filesize: Tamaño +field_downloads: Telecargas +field_author: Autor +field_created_on: Creado +field_updated_on: Actualizado +field_field_format: Formato +field_is_for_all: Para todos los proyectos +field_possible_values: Valores posibles +field_regexp: Expresión regular +field_min_length: Longitud mínima +field_max_length: Longitud máxima +field_value: Valor +field_category: Categoría +field_title: Título +field_project: Proyecto +field_issue: Petición +field_status: Estatuto +field_notes: Notas +field_is_closed: Petición resuelta +field_is_default: Estatuto por defecto +field_html_color: Color +field_tracker: Tracker +field_subject: Tema +field_due_date: Fecha debida +field_assigned_to: Asignado a +field_priority: Prioridad +field_fixed_version: Versión corregida +field_user: Usuario +field_role: Papel +field_homepage: Sitio web +field_is_public: Público +field_parent: Proyecto secundario de +field_is_in_chlog: Consultar las peticiones en el histórico +field_login: Identificador +field_mail_notification: Notificación por mail +field_admin: Administrador +field_locked: Cerrado +field_last_login_on: Última conexión +field_language: Lengua +field_effective_date: Fecha +field_password: Contraseña +field_new_password: Nueva contraseña +field_password_confirmation: Confirmación +field_version: Versión +field_type: Tipo +field_host: Anfitrión +field_port: Puerto +field_account: Cuenta +field_base_dn: Base DN +field_attr_login: Cualidad del identificador +field_attr_firstname: Cualidad del nombre +field_attr_lastname: Cualidad del apellido +field_attr_mail: Cualidad del Email +field_onthefly: Creación del usuario On-the-fly +field_start_date: Comienzo +field_done_ratio: %% Realizado +field_hide_mail: Ocultar mi email address + +label_user: Usuario +label_user_plural: Usuarios +label_user_new: Nuevo usuario +label_project: Proyecto +label_project_new: Nuevo proyecto +label_project_plural: Proyectos +label_project_latest: Los proyectos más últimos +label_issue: Petición +label_issue_new: Nueva petición +label_issue_plural: Peticiones +label_issue_view_all: Ver todas las peticiones +label_document: Documento +label_document_new: Nuevo documento +label_document_plural: Documentos +label_role: Papel +label_role_plural: Papeles +label_role_new: Nuevo papel +label_role_and_permissions: Papeles y permisos +label_member: Miembro +label_member_new: Nuevo miembro +label_member_plural: Miembros +label_tracker: Tracker +label_tracker_plural: Trackers +label_tracker_new: Nuevo tracker +label_workflow: Workflow +label_issue_status: Estatuto de petición +label_issue_status_plural: Estatutos de las peticiones +label_issue_status_new: Nuevo estatuto +label_issue_category: Categoría de las peticiones +label_issue_category_plural: Categorías de las peticiones +label_issue_category_new: Nueva categoría +label_custom_field: Campo personalizado +label_custom_field_plural: Campos personalizados +label_custom_field_new: Nuevo campo personalizado +label_enumerations: Listas de valores +label_enumeration_new: Nuevo valor +label_information: Informacion +label_information_plural: Informaciones +label_please_login: Conexión +label_register: Registrar +label_password_lost: ¿Olvidaste la contraseña? +label_home: Acogida +label_my_page: Mi página +label_my_account: Mi cuenta +label_my_projects: Mis proyectos +label_administration: Administración +label_login: Conexión +label_logout: Desconexión +label_help: Ayuda +label_reported_issues: Peticiones registradas +label_assigned_to_me_issues: Peticiones que me están asignadas +label_last_login: Última conexión +label_last_updates: Actualizado +label_last_updates_plural: %d Actualizados +label_registered_on: Inscrito el +label_activity: Actividad +label_new: Nuevo +label_logged_as: Conectado como +label_environment: Environment +label_authentication: Autentificación +label_auth_source: Modo de la autentificación +label_auth_source_new: Nuevo modo de la autentificación +label_auth_source_plural: Modos de la autentificación +label_subproject: Proyecto secundario +label_subproject_plural: Proyectos secundarios +label_min_max_length: Longitud mín - máx +label_list: Lista +label_date: Fecha +label_integer: Número +label_boolean: Boleano +label_string: Texto +label_text: Texto largo +label_attribute: Cualidad +label_attribute_plural: Cualidades +label_download: %d Telecarga +label_download_plural: %d Telecargas +label_no_data: Ningunos datos a exhibir +label_change_status: Cambiar el estatuto +label_history: Histórico +label_attachment: Fichero +label_attachment_new: Nuevo fichero +label_attachment_delete: Suprimir el fichero +label_attachment_plural: Ficheros +label_report: Informe +label_report_plural: Informes +label_news: Noticia +label_news_new: Nueva noticia +label_news_plural: Noticias +label_news_latest: Últimas noticias +label_news_view_all: Ver todas las noticias +label_change_log: Cambios +label_settings: Configuración +label_overview: Vistazo +label_version: Versión +label_version_new: Nueva versión +label_version_plural: Versiónes +label_confirmation: Confirmación +label_export_to: Exportar a +label_read: Leer... +label_public_projects: Proyectos publicos +label_open_issues: Abierta +label_open_issues_plural: Abiertas +label_closed_issues: Cerrada +label_closed_issues_plural: Cerradas +label_total: Total +label_permissions: Permisos +label_current_status: Estado actual +label_new_statuses_allowed: Nuevos estatutos autorizados +label_all: Todos +label_none: Ninguno +label_next: Próximo +label_previous: Precedente +label_used_by: Utilizado por +label_details: Detalles... +label_add_note: Agregar una nota +label_per_page: Por la página +label_calendar: Calendario +label_months_from: meses de +label_gantt_chart: Diagrama de Gantt +label_internal: Interno +label_last_changes: %d cambios del último +label_change_view_all: Ver todos los cambios +label_personalize_page: Personalizar esta página + +button_login: Conexión +button_submit: Someter +button_save: Validar +button_check_all: Seleccionar todo +button_uncheck_all: No seleccionar nada +button_delete: Suprimir +button_create: Crear +button_test: Testar +button_edit: Modificar +button_add: Añadir +button_change: Cambiar +button_apply: Aplicar +button_clear: Anular +button_lock: Bloquear +button_unlock: Desbloquear +button_download: Telecargar +button_list: Listar +button_view: Ver +button_move: Mover +button_back: Atrás +button_cancel: Cancelar + +text_select_mail_notifications: Seleccionar las actividades que necesitan la activación de la notificación por mail. +text_regexp_info: eg. ^[A-Z0-9]+$ +text_min_max_length_info: 0 para ninguna restricción +text_possible_values_info: Los valores se separaron con | +text_project_destroy_confirmation: ¿ Estás seguro de querer eliminar el proyecto ? +text_workflow_edit: Seleccionar un workflow para actualizar +text_are_you_sure: ¿ Estás seguro ? +text_journal_changed: cambiado de %s a %s +text_journal_set_to: fijado a %s +text_journal_deleted: suprimido +text_tip_task_begin_day: tarea que comienza este día +text_tip_task_end_day: tarea que termina este día +text_tip_task_begin_end_day: tarea que comienza y termina este día + +default_role_manager: Manager +default_role_developper: Desarrollador +default_role_reporter: Informador +default_tracker_bug: Anomalía +default_tracker_feature: Evolución +default_tracker_support: Asistencia +default_issue_status_new: Nuevo +default_issue_status_assigned: Asignada +default_issue_status_resolved: Resuelta +default_issue_status_feedback: Comentario +default_issue_status_closed: Cerrada +default_issue_status_rejected: Rechazada +default_doc_category_user: Documentación del usuario +default_doc_category_tech: Documentación tecnica +default_priority_low: Bajo +default_priority_normal: Normal +default_priority_high: Alto +default_priority_urgent: Urgente +default_priority_immediate: Ahora + +enumeration_issue_priorities: Prioridad de las peticiones +enumeration_doc_categories: Categorías del documento diff --git a/lang/fr.yml b/lang/fr.yml new file mode 100644 index 000000000..8e7829b19 --- /dev/null +++ b/lang/fr.yml @@ -0,0 +1,321 @@ +_gloc_rule_default: '|n| n<=1 ? "" : "_plural" ' + +actionview_datehelper_select_day_prefix: +actionview_datehelper_select_month_names: Janvier,Février,Mars,Avril,Mai,Juin,Juillet,Août,Septembre,Octobre,Novembre,Décembre +actionview_datehelper_select_month_names_abbr: Jan,Fév,Mars,Avril,Mai,Juin,Juil,Août,Sept,Oct,Nov,Déc +actionview_datehelper_select_month_prefix: +actionview_datehelper_select_year_prefix: +actionview_datehelper_time_in_words_day: 1 jour +actionview_datehelper_time_in_words_day_plural: %d jours +actionview_datehelper_time_in_words_hour_about: about an hour +actionview_datehelper_time_in_words_hour_about_plural: about %d hours +actionview_datehelper_time_in_words_hour_about_single: about an hour +actionview_datehelper_time_in_words_minute: 1 minute +actionview_datehelper_time_in_words_minute_half: 30 secondes +actionview_datehelper_time_in_words_minute_less_than: moins d'une minute +actionview_datehelper_time_in_words_minute_plural: %d minutes +actionview_datehelper_time_in_words_minute_single: 1 minute +actionview_datehelper_time_in_words_second_less_than: moins d'une seconde +actionview_datehelper_time_in_words_second_less_than_plural: moins de %d secondes +actionview_instancetag_blank_option: Choisir + +activerecord_error_inclusion: n'est pas inclus dans la liste +activerecord_error_exclusion: est reservé +activerecord_error_invalid: est invalide +activerecord_error_confirmation: ne correspond pas à la confirmation +activerecord_error_accepted: doit être accepté +activerecord_error_empty: doit être renseigné +activerecord_error_blank: doit être renseigné +activerecord_error_too_long: est trop long +activerecord_error_too_short: est trop court +activerecord_error_wrong_length: n'est pas de la bonne longueur +activerecord_error_taken: est déjà utilisé +activerecord_error_not_a_number: n'est pas un nombre +activerecord_error_not_a_date: n'est pas une date valide +activerecord_error_greater_than_start_date: doit être postérieur à la date de début + +general_fmt_age: %d an +general_fmt_age_plural: %d ans +general_fmt_date: %%d/%%m/%%Y +general_fmt_datetime: %%d/%%m/%%Y %%H:%%M +general_fmt_datetime_short: %%d/%%m %%H:%%M +general_fmt_time: %%H:%%M +general_text_No: 'Non' +general_text_Yes: 'Oui' +general_text_no: 'non' +general_text_yes: 'oui' +general_lang_fr: 'Français' +general_csv_separator: ';' +general_day_names: Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche + +notice_account_updated: Le compte a été mis à jour avec succès. +notice_account_invalid_creditentials: Identifiant ou mot de passe invalide. +notice_account_password_updated: Mot de passe mis à jour avec succès. +notice_account_wrong_password: Mot de passe incorrect +notice_account_register_done: Un message contenant les instructions pour activer votre compte vous a été envoyé. +notice_account_unknown_email: Aucun compte ne correspond à cette adresse. +notice_can_t_change_password: Ce compte utilise une authentification externe. Impossible de changer le mot de passe. +notice_account_lost_email_sent: Un message contenant les instructions pour choisir un nouveau mot de passe vous a été envoyé. +notice_account_activated: Votre compte a été activé. Vous pouvez à présent vous connecter. +notice_successful_create: Création effectuée avec succès. +notice_successful_update: Mise à jour effectuée avec succès. +notice_successful_delete: Suppression effectuée avec succès. +notice_successful_connection: Connection réussie. +notice_file_not_found: Le fichier demandé n'existe pas ou a été supprimé. +notice_locking_conflict: Les données ont été mises à jour par un autre utilisateur. Mise à jour impossible. + +mail_subject_lost_password: Votre mot de passe redMine +mail_subject_register: Activation de votre compte redMine + +gui_validation_error: 1 erreur +gui_validation_error_plural: %d erreurs + +field_name: Nom +field_description: Description +field_summary: Résumé +field_is_required: Obligatoire +field_firstname: Prénom +field_lastname: Nom +field_mail: Email +field_filename: Fichier +field_filesize: Taille +field_downloads: Téléchargements +field_author: Auteur +field_created_on: Créé +field_updated_on: Mis à jour +field_field_format: Format +field_is_for_all: Pour tous les projets +field_possible_values: Valeurs possibles +field_regexp: Expression régulière +field_min_length: Longueur minimum +field_max_length: Longueur maximum +field_value: Valeur +field_category: Catégorie +field_title: Titre +field_project: Projet +field_issue: Demande +field_status: Statut +field_notes: Notes +field_is_closed: Demande fermée +field_is_default: Statut par défaut +field_html_color: Couleur +field_tracker: Tracker +field_subject: Sujet +field_due_date: Date d'échéance +field_assigned_to: Assigné à +field_priority: Priorité +field_fixed_version: Version corrigée +field_user: Utilisateur +field_role: Rôle +field_homepage: Site web +field_is_public: Public +field_parent: Sous-projet de +field_is_in_chlog: Demandes affichées dans l'historique +field_login: Identifiant +field_mail_notification: Notifications par mail +field_admin: Administrateur +field_locked: Verrouillé +field_last_login_on: Dernière connexion +field_language: Langue +field_effective_date: Date +field_password: Mot de passe +field_new_password: Nouveau mot de passe +field_password_confirmation: Confirmation +field_version: Version +field_type: Type +field_host: Hôte +field_port: Port +field_account: Compte +field_base_dn: Base DN +field_attr_login: Attribut Identifiant +field_attr_firstname: Attribut Prénom +field_attr_lastname: Attribut Nom +field_attr_mail: Attribut Email +field_onthefly: Création des utilisateurs à la volée +field_start_date: Début +field_done_ratio: %% Réalisé +field_auth_source: Mode d'authentification +field_hide_mail: Cacher mon adresse mail + +label_user: Utilisateur +label_user_plural: Utilisateurs +label_user_new: Nouvel utilisateur +label_project: Projet +label_project_new: Nouveau projet +label_project_plural: Projets +label_project_latest: Derniers projets +label_issue: Demande +label_issue_new: Nouvelle demande +label_issue_plural: Demandes +label_issue_view_all: Voir toutes les demandes +label_document: Document +label_document_new: Nouveau document +label_document_plural: Documents +label_role: Rôle +label_role_plural: Rôles +label_role_new: Nouveau rôle +label_role_and_permissions: Rôles et permissions +label_member: Membre +label_member_new: Nouveau membre +label_member_plural: Membres +label_tracker: Tracker +label_tracker_plural: Trackers +label_tracker_new: Nouveau tracker +label_workflow: Workflow +label_issue_status: Statut de demandes +label_issue_status_plural: Statuts de demandes +label_issue_status_new: Nouveau statut +label_issue_category: Catégorie de demandes +label_issue_category_plural: Catégories de demandes +label_issue_category_new: Nouvelle catégorie +label_custom_field: Champ personnalisé +label_custom_field_plural: Champs personnalisés +label_custom_field_new: Nouveau champ personnalisé +label_enumerations: Listes de valeurs +label_enumeration_new: Nouvelle valeur +label_information: Information +label_information_plural: Informations +label_please_login: Identification +label_register: S'enregistrer +label_password_lost: Mot de passe perdu +label_home: Accueil +label_my_page: Ma page +label_my_account: Mon compte +label_my_projects: Mes projets +label_administration: Administration +label_login: Connexion +label_logout: Déconnexion +label_help: Aide +label_reported_issues: Demandes soumises +label_assigned_to_me_issues: Demandes qui me sont assignées +label_last_login: Dernière connexion +label_last_updates: Dernière mise à jour +label_last_updates_plural: %d dernières mises à jour +label_registered_on: Inscrit le +label_activity: Activité +label_new: Nouveau +label_logged_as: Connecté en tant que +label_environment: Environnement +label_authentication: Authentification +label_auth_source: Mode d'authentification +label_auth_source_new: Nouveau mode d'authentification +label_auth_source_plural: Modes d'authentification +label_subproject: Sous-projet +label_subproject_plural: Sous-projets +label_min_max_length: Longueurs mini - maxi +label_list: Liste +label_date: Date +label_integer: Entier +label_boolean: Booléen +label_string: Texte +label_text: Texte long +label_attribute: Attribut +label_attribute_plural: Attributs +label_download: %d Téléchargement +label_download_plural: %d Téléchargements +label_no_data: Aucune donnée à afficher +label_change_status: Changer le statut +label_history: Historique +label_attachment: Fichier +label_attachment_new: Nouveau fichier +label_attachment_delete: Supprimer le fichier +label_attachment_plural: Fichiers +label_report: Rapport +label_report_plural: Rapports +label_news: Annonce +label_news_new: Nouvelle annonce +label_news_plural: Annonces +label_news_latest: Dernières annonces +label_news_view_all: Voir toutes les annonces +label_change_log: Historique +label_settings: Configuration +label_overview: Aperçu +label_version: Version +label_version_new: Nouvelle version +label_version_plural: Versions +label_confirmation: Confirmation +label_export_to: Exporter en +label_read: Lire... +label_public_projects: Projets publics +label_open_issues: Ouverte +label_open_issues_plural: Ouvertes +label_closed_issues: Fermée +label_closed_issues_plural: Fermées +label_total: Total +label_permissions: Permissions +label_current_status: Statut actuel +label_new_statuses_allowed: Nouveaux statuts autorisés +label_all: Tous +label_none: Aucun +label_next: Suivant +label_previous: Précédent +label_used_by: Utilisé par +label_details: Détails... +label_add_note: Ajouter une note +label_per_page: Par page +label_calendar: Calendrier +label_months_from: mois depuis +label_gantt_chart: Diagramme de Gantt +label_internal: Interne +label_last_changes: %d derniers changements +label_change_view_all: Voir tous les changements +label_personalize_page: Personnaliser cette page + +button_login: Connexion +button_submit: Soumettre +button_save: Sauvegarder +button_check_all: Tout cocher +button_uncheck_all: Tout décocher +button_delete: Supprimer +button_create: Créer +button_test: Tester +button_edit: Modifier +button_add: Ajouter +button_change: Changer +button_apply: Appliquer +button_clear: Effacer +button_lock: Verrouiller +button_unlock: Déverrouiller +button_download: Télécharger +button_list: Lister +button_view: Voir +button_move: Déplacer +button_back: Retour +button_cancel: Annuler + +text_select_mail_notifications: Sélectionner les actions pour lesquelles la notification par mail doit être activée. +text_regexp_info: ex. ^[A-Z0-9]+$ +text_min_max_length_info: 0 pour aucune restriction +text_possible_values_info: valeurs séparées par | +text_project_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce projet et tout ce qui lui est rattaché ? +text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow +text_are_you_sure: Etes-vous sûr ? +text_journal_changed: changé de %s à %s +text_journal_set_to: mis à %s +text_journal_deleted: supprimé +text_tip_task_begin_day: tâche commençant ce jour +text_tip_task_end_day: tâche finissant ce jour +text_tip_task_begin_end_day: tâche commençant et finissant ce jour + +default_role_manager: Manager +default_role_developper: Développeur +default_role_reporter: Rapporteur +default_tracker_bug: Anomalie +default_tracker_feature: Evolution +default_tracker_support: Assistance +default_issue_status_new: Nouveau +default_issue_status_assigned: Assigné +default_issue_status_resolved: Résolu +default_issue_status_feedback: Commentaire +default_issue_status_closed: Fermé +default_issue_status_rejected: Rejeté +default_doc_category_user: Documentation utilisateur +default_doc_category_tech: Documentation technique +default_priority_low: Bas +default_priority_normal: Normal +default_priority_high: Haut +default_priority_urgent: Urgent +default_priority_immediate: Immédiat + +enumeration_issue_priorities: Priorités des demandes +enumeration_doc_categories: Catégories des documents diff --git a/lib/tasks/extract_fixtures.rake b/lib/tasks/extract_fixtures.rake new file mode 100644 index 000000000..49834e5ab --- /dev/null +++ b/lib/tasks/extract_fixtures.rake @@ -0,0 +1,24 @@ +desc 'Create YAML test fixtures from data in an existing database. +Defaults to development database. Set RAILS_ENV to override.' + +task :extract_fixtures => :environment do + sql = "SELECT * FROM %s" + skip_tables = ["schema_info"] + ActiveRecord::Base.establish_connection + (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name| + i = "000" + File.open("#{RAILS_ROOT}/#{table_name}.yml", 'w' ) do |file| + data = ActiveRecord::Base.connection.select_all(sql % table_name) + file.write data.inject({}) { |hash, record| + + # cast extracted values + ActiveRecord::Base.connection.columns(table_name).each { |col| + record[col.name] = col.type_cast(record[col.name]) if record[col.name] + } + + hash["#{table_name}_#{i.succ!}"] = record + hash + }.to_yaml + end + end +end \ No newline at end of file diff --git a/lib/tasks/load_default_data.rake b/lib/tasks/load_default_data.rake new file mode 100644 index 000000000..d672802db --- /dev/null +++ b/lib/tasks/load_default_data.rake @@ -0,0 +1,88 @@ +desc 'Load default configuration data (using default language)' + +task :load_default_data => :environment do + include GLoc + set_language_if_valid($RDM_DEFAULT_LANG) + +begin + # check that no data already exists + if Role.find(:first) + raise "Some roles are already defined." + end + if Tracker.find(:first) + raise "Some trackers are already defined." + end + if IssueStatus.find(:first) + raise "Some statuses are already defined." + end + if Enumeration.find(:first) + raise "Some enumerations are already defined." + end + + puts "Loading default configuration for language: #{current_language}" + + # roles + manager = Role.create :name => l(:default_role_manager) + manager.permissions = Permission.find(:all, :conditions => ["is_public=?", false]) + + developper = Role.create :name => l(:default_role_developper) + perms = [150, 320, 321, 322, 420, 421, 422, 1050, 1060, 1070, 1075, 1220, 1221, 1222, 1223, 1224, 1320, 1322, 1061, 1057] + developper.permissions = Permission.find(:all, :conditions => ["sort IN (#{perms.join(',')})"]) + + reporter = Role.create :name => l(:default_role_reporter) + perms = [1050, 1060, 1070, 1057] + reporter.permissions = Permission.find(:all, :conditions => ["sort IN (#{perms.join(',')})"]) + + # trackers + Tracker.create(:name => l(:default_tracker_bug), :is_in_chlog => true) + Tracker.create(:name => l(:default_tracker_feature), :is_in_chlog => true) + Tracker.create(:name => l(:default_tracker_support), :is_in_chlog => false) + + # issue statuses + new = IssueStatus.create(:name => l(:default_issue_status_new), :is_closed => false, :is_default => true, :html_color => 'F98787') + assigned = IssueStatus.create(:name => l(:default_issue_status_assigned), :is_closed => false, :is_default => false, :html_color => 'C0C0FF') + resolved = IssueStatus.create(:name => l(:default_issue_status_resolved), :is_closed => false, :is_default => false, :html_color => '88E0B3') + feedback = IssueStatus.create(:name => l(:default_issue_status_feedback), :is_closed => false, :is_default => false, :html_color => 'F3A4F4') + closed = IssueStatus.create(:name => l(:default_issue_status_closed), :is_closed => true, :is_default => false, :html_color => 'DBDBDB') + rejected = IssueStatus.create(:name => l(:default_issue_status_rejected), :is_closed => true, :is_default => false, :html_color => 'F5C28B') + + # workflow + Tracker.find(:all).each { |t| + IssueStatus.find(:all).each { |os| + IssueStatus.find(:all).each { |ns| + Workflow.create(:tracker_id => t.id, :role_id => manager.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + } + + Tracker.find(:all).each { |t| + [new, assigned, resolved, feedback].each { |os| + [assigned, resolved, feedback, closed].each { |ns| + Workflow.create(:tracker_id => t.id, :role_id => developper.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + } + + Tracker.find(:all).each { |t| + [new, assigned, resolved, feedback].each { |os| + [closed].each { |ns| + Workflow.create(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + Workflow.create(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => resolved.id, :new_status_id => feedback.id) + } + + # enumerations + Enumeration.create(:opt => "DCAT", :name => l(:default_doc_category_user)) + Enumeration.create(:opt => "DCAT", :name => l(:default_doc_category_tech)) + Enumeration.create(:opt => "IPRI", :name => l(:default_priority_low)) + Enumeration.create(:opt => "IPRI", :name => l(:default_priority_normal)) + Enumeration.create(:opt => "IPRI", :name => l(:default_priority_high)) + Enumeration.create(:opt => "IPRI", :name => l(:default_priority_urgent)) + Enumeration.create(:opt => "IPRI", :name => l(:default_priority_immediate)) + +rescue => error + puts "Error: " + error + puts "Default configuration can't be loaded." +end +end \ No newline at end of file diff --git a/log/delete.me b/log/delete.me new file mode 100644 index 000000000..18beddaa8 --- /dev/null +++ b/log/delete.me @@ -0,0 +1 @@ +default directory for uploaded files \ No newline at end of file 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 "

Application error

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 @@ + + +redMine 404 error + + +

Page not found

+

The page you were trying to access doesn't exist or has been removed.

+

Back

+ + \ 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 @@ + + +redMine 500 error + + +

Internal error

+

An error occurred on the page you were trying to access.
+ If you continue to experience problems please contact your redMine administrator for assistance.

+

Back

+ + \ 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 diff --git a/public/images/add.png b/public/images/add.png new file mode 100644 index 000000000..90032e9d8 Binary files /dev/null and b/public/images/add.png differ diff --git a/public/images/admin.png b/public/images/admin.png new file mode 100644 index 000000000..0c190984f Binary files /dev/null and b/public/images/admin.png differ diff --git a/public/images/alert.png b/public/images/alert.png new file mode 100644 index 000000000..ba107e83b Binary files /dev/null and b/public/images/alert.png differ diff --git a/public/images/arrow_bw.png b/public/images/arrow_bw.png new file mode 100644 index 000000000..52dfc96f0 Binary files /dev/null and b/public/images/arrow_bw.png differ diff --git a/public/images/arrow_from.png b/public/images/arrow_from.png new file mode 100644 index 000000000..4d5eeb9ea Binary files /dev/null and b/public/images/arrow_from.png differ diff --git a/public/images/arrow_to.png b/public/images/arrow_to.png new file mode 100644 index 000000000..4f969716f Binary files /dev/null and b/public/images/arrow_to.png differ diff --git a/public/images/attachment.png b/public/images/attachment.png new file mode 100644 index 000000000..eea26921b Binary files /dev/null and b/public/images/attachment.png differ diff --git a/public/images/bulletgreen.png b/public/images/bulletgreen.png new file mode 100644 index 000000000..abe41592b Binary files /dev/null and b/public/images/bulletgreen.png differ diff --git a/public/images/bulletred.png b/public/images/bulletred.png new file mode 100644 index 000000000..26a121057 Binary files /dev/null and b/public/images/bulletred.png differ diff --git a/public/images/calendar.png b/public/images/calendar.png new file mode 100644 index 000000000..aa269da38 Binary files /dev/null and b/public/images/calendar.png differ diff --git a/public/images/close.png b/public/images/close.png new file mode 100644 index 000000000..3501ed4d5 Binary files /dev/null and b/public/images/close.png differ diff --git a/public/images/close_hl.png b/public/images/close_hl.png new file mode 100644 index 000000000..a433f7515 Binary files /dev/null and b/public/images/close_hl.png differ diff --git a/public/images/delete.png b/public/images/delete.png new file mode 100644 index 000000000..2ed33bdf3 Binary files /dev/null and b/public/images/delete.png differ diff --git a/public/images/details.png b/public/images/details.png new file mode 100644 index 000000000..7c813b04a Binary files /dev/null and b/public/images/details.png differ diff --git a/public/images/dir.png b/public/images/dir.png new file mode 100644 index 000000000..d078094ac Binary files /dev/null and b/public/images/dir.png differ diff --git a/public/images/dir_new.png b/public/images/dir_new.png new file mode 100644 index 000000000..2d29814f2 Binary files /dev/null and b/public/images/dir_new.png differ diff --git a/public/images/dir_open.png b/public/images/dir_open.png new file mode 100644 index 000000000..a248cba3c Binary files /dev/null and b/public/images/dir_open.png differ diff --git a/public/images/document.png b/public/images/document.png new file mode 100644 index 000000000..34fde6eb3 Binary files /dev/null and b/public/images/document.png differ diff --git a/public/images/edit_small.png b/public/images/edit_small.png new file mode 100644 index 000000000..dea7c92ea Binary files /dev/null and b/public/images/edit_small.png differ diff --git a/public/images/file_new.png b/public/images/file_new.png new file mode 100644 index 000000000..9a12ca732 Binary files /dev/null and b/public/images/file_new.png differ diff --git a/public/images/gantt.png b/public/images/gantt.png new file mode 100644 index 000000000..2673d23d2 Binary files /dev/null and b/public/images/gantt.png differ diff --git a/public/images/help.png b/public/images/help.png new file mode 100644 index 000000000..da8feb993 Binary files /dev/null and b/public/images/help.png differ diff --git a/public/images/home.png b/public/images/home.png new file mode 100644 index 000000000..7a12add6a Binary files /dev/null and b/public/images/home.png differ diff --git a/public/images/issues.png b/public/images/issues.png new file mode 100644 index 000000000..e6948bff7 Binary files /dev/null and b/public/images/issues.png differ diff --git a/public/images/jstoolbar/bt_br.png b/public/images/jstoolbar/bt_br.png new file mode 100644 index 000000000..f8211a997 Binary files /dev/null and b/public/images/jstoolbar/bt_br.png differ diff --git a/public/images/jstoolbar/bt_code.png b/public/images/jstoolbar/bt_code.png new file mode 100644 index 000000000..52924abf7 Binary files /dev/null and b/public/images/jstoolbar/bt_code.png differ diff --git a/public/images/jstoolbar/bt_del.png b/public/images/jstoolbar/bt_del.png new file mode 100644 index 000000000..c6f3a8b40 Binary files /dev/null and b/public/images/jstoolbar/bt_del.png differ diff --git a/public/images/jstoolbar/bt_em.png b/public/images/jstoolbar/bt_em.png new file mode 100644 index 000000000..f08de4f30 Binary files /dev/null and b/public/images/jstoolbar/bt_em.png differ diff --git a/public/images/jstoolbar/bt_ins.png b/public/images/jstoolbar/bt_ins.png new file mode 100644 index 000000000..f6697db51 Binary files /dev/null and b/public/images/jstoolbar/bt_ins.png differ diff --git a/public/images/jstoolbar/bt_link.png b/public/images/jstoolbar/bt_link.png new file mode 100644 index 000000000..9b3acbae5 Binary files /dev/null and b/public/images/jstoolbar/bt_link.png differ diff --git a/public/images/jstoolbar/bt_ol.png b/public/images/jstoolbar/bt_ol.png new file mode 100644 index 000000000..2dfaec7c7 Binary files /dev/null and b/public/images/jstoolbar/bt_ol.png differ diff --git a/public/images/jstoolbar/bt_quote.png b/public/images/jstoolbar/bt_quote.png new file mode 100644 index 000000000..25b2b8abe Binary files /dev/null and b/public/images/jstoolbar/bt_quote.png differ diff --git a/public/images/jstoolbar/bt_strong.png b/public/images/jstoolbar/bt_strong.png new file mode 100644 index 000000000..7e200d3f6 Binary files /dev/null and b/public/images/jstoolbar/bt_strong.png differ diff --git a/public/images/jstoolbar/bt_ul.png b/public/images/jstoolbar/bt_ul.png new file mode 100644 index 000000000..6e20851ec Binary files /dev/null and b/public/images/jstoolbar/bt_ul.png differ diff --git a/public/images/loading.gif b/public/images/loading.gif new file mode 100644 index 000000000..085ccaeca Binary files /dev/null and b/public/images/loading.gif differ diff --git a/public/images/locked.png b/public/images/locked.png new file mode 100644 index 000000000..5199dfe22 Binary files /dev/null and b/public/images/locked.png differ diff --git a/public/images/login.png b/public/images/login.png new file mode 100644 index 000000000..7e0c62d9c Binary files /dev/null and b/public/images/login.png differ diff --git a/public/images/mailer.png b/public/images/mailer.png new file mode 100644 index 000000000..8008bb84b Binary files /dev/null and b/public/images/mailer.png differ diff --git a/public/images/notes.png b/public/images/notes.png new file mode 100644 index 000000000..d26b1d577 Binary files /dev/null and b/public/images/notes.png differ diff --git a/public/images/options.png b/public/images/options.png new file mode 100644 index 000000000..a907c20f1 Binary files /dev/null and b/public/images/options.png differ diff --git a/public/images/package.png b/public/images/package.png new file mode 100644 index 000000000..634d13d9f Binary files /dev/null and b/public/images/package.png differ diff --git a/public/images/projects.png b/public/images/projects.png new file mode 100644 index 000000000..b42347a92 Binary files /dev/null and b/public/images/projects.png differ diff --git a/public/images/rails.png b/public/images/rails.png new file mode 100644 index 000000000..b8441f182 Binary files /dev/null and b/public/images/rails.png differ diff --git a/public/images/rails_powered.png b/public/images/rails_powered.png new file mode 100644 index 000000000..5255e62de Binary files /dev/null and b/public/images/rails_powered.png differ diff --git a/public/images/rails_small.png b/public/images/rails_small.png new file mode 100644 index 000000000..aff4b7a84 Binary files /dev/null and b/public/images/rails_small.png differ diff --git a/public/images/role.png b/public/images/role.png new file mode 100644 index 000000000..ad36d1ca8 Binary files /dev/null and b/public/images/role.png differ diff --git a/public/images/rss.png b/public/images/rss.png new file mode 100644 index 000000000..89ce35f80 Binary files /dev/null and b/public/images/rss.png differ diff --git a/public/images/sort_asc.png b/public/images/sort_asc.png new file mode 100644 index 000000000..05dfa15f4 Binary files /dev/null and b/public/images/sort_asc.png differ diff --git a/public/images/sort_desc.png b/public/images/sort_desc.png new file mode 100644 index 000000000..f82d53917 Binary files /dev/null and b/public/images/sort_desc.png differ diff --git a/public/images/tracker.png b/public/images/tracker.png new file mode 100644 index 000000000..f29cfb2af Binary files /dev/null and b/public/images/tracker.png differ diff --git a/public/images/true.png b/public/images/true.png new file mode 100644 index 000000000..9afc0b52a Binary files /dev/null and b/public/images/true.png differ diff --git a/public/images/user.png b/public/images/user.png new file mode 100644 index 000000000..89d591c0b Binary files /dev/null and b/public/images/user.png differ diff --git a/public/images/user_new.png b/public/images/user_new.png new file mode 100644 index 000000000..c7c718822 Binary files /dev/null and b/public/images/user_new.png differ diff --git a/public/images/user_page.png b/public/images/user_page.png new file mode 100644 index 000000000..940a7b8e1 Binary files /dev/null and b/public/images/user_page.png differ diff --git a/public/images/users.png b/public/images/users.png new file mode 100644 index 000000000..3b9fc5aa9 Binary files /dev/null and b/public/images/users.png differ diff --git a/public/images/workflow.png b/public/images/workflow.png new file mode 100644 index 000000000..868332fed Binary files /dev/null and b/public/images/workflow.png differ diff --git a/public/images/zoom_in.png b/public/images/zoom_in.png new file mode 100644 index 000000000..d9abe7f52 Binary files /dev/null and b/public/images/zoom_in.png differ diff --git a/public/images/zoom_in_g.png b/public/images/zoom_in_g.png new file mode 100644 index 000000000..72b271c5e Binary files /dev/null and b/public/images/zoom_in_g.png differ diff --git a/public/images/zoom_out.png b/public/images/zoom_out.png new file mode 100644 index 000000000..906e4a4e5 Binary files /dev/null and b/public/images/zoom_out.png differ diff --git a/public/images/zoom_out_g.png b/public/images/zoom_out_g.png new file mode 100644 index 000000000..7f2416be2 Binary files /dev/null and b/public/images/zoom_out_g.png 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 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 = "
" + text + "
"; + 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("×", 1, 200).ttip = Calendar._TT["CLOSE"]; + } + + row = Calendar.createElement("tr", thead); + row.className = "headrow"; + + this._nav_py = hh("«", 1, -2); + this._nav_py.ttip = Calendar._TT["PREV_YEAR"]; + + this._nav_pm = hh("‹", 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("›", 1, 1); + this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"]; + + this._nav_ny = hh("»", 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"] || " "; + + 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 = " "; + + 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 = " "; + 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), +// 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, +// 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, +// Updater: Servilio Afre Puentes +// 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, +// 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, 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, + ''); + 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 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("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + 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("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + 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 "
      " + ret.join('') + "
    "; + } + }, 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(/
    /i); + }, + convertHTMLLineBreaks: function(string) { + return string.replace(/
    /gi, "\n").replace(//gi, "\n").replace(/<\/p>/gi, "\n").replace(/

    /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.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-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 + * + * 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: '(?:)((\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 '#'; + } +} + +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 '#'; + } +} + +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 = '' + this.content + '
    '; + 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 @@ + + + Chapter 1. AdministrationredMine home

    \ 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 @@ + + + 1. UsersredMine home

    1. Users

    These screens allow you to manage the application users.

    1.1. Users’ List

    The Lock/Unlock buttons allow you to lock/unlock the user accounts.

    A user having a locked account cannot log in and access the application.

    1.2. User Creation or Modification

    In modification mode, please leave the Password field blank in order to keep the user’s password unchanged.

    A user designated as administrator has unrestricted access to the application and to all projects.

    • Administrator : designate the user as the administrator of the application.

    • E-mail notifications : activate or de-activate automatic e-mail notifications for this user

    • Locked : de-activates the user’s account

    \ 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 @@ + + + 2. Roles and PermissionsredMine home

    2. Roles and Permissions

    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.

    On the new or edit Role screen, check off the actions authorized for the Role.

    \ 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 @@ + + + 3. TrackersredMine home

    3. Trackers

    Trackers allow the sorting of Issues and can define specific workflows.

    \ 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 @@ + + + 4. Customized fieldsredMine home

    4. Customized fields

    Customized fields allow you to add additional information in Projects, Issues or Users. A customized field can be of one the following types:

    • Integer : positive or negative number

    • String : a string of characters - one single line of input.

    • Text : a string of characters with multiple lines of input. Differs from String Format by providing multiple lines of input instead of a single line.

    • Date : date

    • Boolean : true or false (check if necessary)

    • List : value to select from a predefined list (aka: scroll list or select box)

    Validation elements can be defined:

    • Required : A required field must have input in the forms

    • For all the projects : field automatically associated to all of the projects

    • Min - max length : minimum and maximum length for the input fields (0 means that there is no restriction)

    • Regular Expression : regular expressions may provide validation of the input value

      Examples:

      ^\[A-Z]{4}\d+$ : 4 capital letters followed by one or several digits

      ^[^0-9]*$ : characters only - no digits

    • Possible values : possible values for the fields of "List" type. Values are separated by the character |

    4.1. Fields for Projects

    • Required : required field

    4.2. Fields for Issues

    • For all projects : field automatically associated to all project Issues

      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).

    4.3. Field for Users

    • Required : required field

    \ 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 @@ + + + 5. Issue statusredMine home

    5. Issue status

    These screens allow you to define the different possible Issue statuses.

    • Closed : indicates Issue is considered as closed

    • Default : status applied by default to new Issue requests (only one status can be Default status)

    • Color : HTML color code (6 characters) representing the displayed status

    \ 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 @@ + + + 6. WorkflowredMine home

    6. Workflow

    The workflow allows to define changes the various project members are allowed to make on the Issues, according to their type.

    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.

    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.

    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.

    \ 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 @@ + + + 7. EnumerationsredMine home

    7. Enumerations

    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:

    • Issue Priorities

    • Document Categories

    \ 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 @@ + + + 8. E-mail notificationsredMine home

    8. E-mail notifications

    This screen allows you to select the actions that will generate an e-mail notification for project members.

    Note: E-mail sending must be activated in the application configuration if you want to make any notifications.

    \ 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 @@ + + + 9. AuthenticationredMine home

    9. Authentication

    By default, redMine refers to its own database to authenticate users, by a specific password.

    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.

    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’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.

    9.1. LDAP statement

    • Name : reference display name

    • Host : LDAP server host name

    • Port : connection port to the LDAP server

    • Account : DN of the connection account to LDAP (please leave it blank if the directory authorizes anonymous read access)

    • Password : password of the connection account

    • Base DN : Basic DN used for user search in the directory

    • LDAP screen : User search screen in the directory (optional)

    • LDAP features :

      • Identifier : LDAP feature name used as user identifier (e.g.: uid)

      • First name : LDAP feature name including the user’s first name (ex: givenName)

      • Last name : LDAP feature name including the user’s last name (ex: familyName)

      • E-mail : LDAP feature name including the user’s e-mail address (ex: mail)

    The features" First name ", " Last name " and " E-mail " are not used except when the accounts are created on the fly.

    \ 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 @@ + + + 10. InformationredMine home

    10. Information

    Displays application and environment information.

    \ 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 @@ + + + Chapter 2. ProjectsredMine home \ 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 @@ + + + 1. Project previewredMine home

    1. Project preview

    The preview presents the general project information, its main members, the latest announcements, as well as an synthesis of Issue requests open by tracker.

    \ 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 @@ + + + 2. Issue managementredMine home

    2. Issue management

    2.1. Issue list

    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).

    Once applied, a screen is valid during the entire session. You can re-define it or delete it by clicking Cancel.

    \ 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 @@ + + + 3. ReportsredMine home

    3. Reports

    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.

    \ 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 @@ + + + 4. Change logredMine home

    4. Change log

    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.

    \ 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 @@ + + + 5. NewsredMine home

    5. News

    Allows you to inform users on project activity.

    \ 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 @@ + + + 6. DocumentsredMine home

    6. Documents

    Documents are grouped by categories (see Value Lists). A document can contain several files (for example: revisions or successive versions).

    \ 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 @@ + + + 7. FilesredMine home

    7. Files

    This module allows you to display various folders (sources, binaires, ...) for each version of the application.

    \ 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 @@ + + + 8. SettingsredMine home

    8. Settings

    8.1. Project features

    • Public : if it’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’s not a public project, only the project members have access to it, according to their role.

    • Customized fields : Select the customized fields that you want to use. Only the administrator can define new customized fields.

    8.2. Members

    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.

    8.3. Versions

    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).

    8.4. Request categories

    Issue categories allow you to organize Issues. Categories can correspond to different project modules.

    \ 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 @@ + + + RedMine DocumentationredMine home \ 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 Binary files /dev/null and b/public/manual/en/resources/issues_list.png 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 Binary files /dev/null and b/public/manual/en/resources/users_list.png differ diff --git a/public/manual/en/resources/workflow.png b/public/manual/en/resources/workflow.png new file mode 100644 index 000000000..04e79d61e Binary files /dev/null and b/public/manual/en/resources/workflow.png 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 @@ + + + Chapter 1. Administration \ 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 @@ + + + 1. Utilisateurs

    1. Utilisateurs

    Ces écrans vous permettent de gérer les utilisateurs de l'application.

    1.1. Liste des utilisateurs

    Les boutons Lock/Unlock vous permettent de vérouiller/dévérouiller les comptes utilisateurs.

    Un utilisateur dont le compte est vérouillé ne peut plus s'identifier pour accéder à l'application.

    1.2. Création ou modification d'un utilisateur

    En mode modification, laissez le champ Password vide pour laisser le mot de passe de l'utilisateur inchangé.

    Un utilisateur déclaré comme administrateur dispose de toutes les permissions sur l'application et sur tous les projets.

    • Administrateur: déclare l'utilisateur comme administrateur de l'application.

    • Notifications par mail: permet d'activer ou non l'envoi automatique de notifications par mail pour cet utilisateur

    • Vérouillé: désactive le compte de l'utilisateur

    \ 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 @@ + + + 2. Rôles et permissions

    2. Rôles et permissions

    Les rôles permettent de définir les permissions des différents membres d'un projet. Chaque membre d'un projet dispose d'un rôle unique au sein d'un projet. Un utilisateur peut avoir différents rôles au sein de différents projets.

    Sur l'écran d'édition du rôle, cochez les actions que vous souhaitez autoriser pour le rôle.

    \ 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 @@ + + + 3. Trackers

    3. Trackers

    Les trackers permettent de typer les demandes et de définir des workflows spécifiques pour chacun de ces types.

    \ 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 @@ + + + 4. Champs personnalisés

    4. Champs personnalisés

    Les champs personnalisés vous permettent d'ajouter des informations supplémentaires sur les projets, les demandes ou les utilisateurs. Un champ personnalisé peut être de l'un des types suivants:

    • Entier: entier positif ou négatif

    • Chaîne: chaîne de caractère

    • Date: date

    • Booléen: booléen (case à cocher)

    • Liste: valeur à sélectionnée parmi une liste prédéfinie (liste déroulante)

    Des éléments de validation peuvent être définis:

    • Obligatoire: champ dont la saisie est obligatoire sur les demandes

    • Pour tous les projects: champ automatiquement associé à l'ensemble des projets

    • Min - max length: longueurs minimales et maximales pour les champs en saisie libre (0 signifie qu'il n'y a pas de restriction)

    • Expression régulière: expression régulière permettant de valider la valeur saisie

      Exemples:

      ^\[A-Z]{4}\d+$ : 4 lettres majuscules suivies d'un ou plusieurs chiffres

      ^[^0-9]*$ : chaîne ne comportant pas de chiffres

    • Valeurs possibles: valeurs possibles pour les champs de type "Liste". Les valeurs sont séparées par le caractère |

    4.1. Champs pour les projets

    • Obligatoire: champ dont la saisie est obligatoire

    4.2. Champs pour les demandes

    • Pour tous les projects: champ automatiquement associé aux demandes de l'ensemble des projets

      Si cette option n'est pas activée, chaque projet pourra choisir d'utiliser ou non le champ pour ses demandes (voir configuration du projet).

    4.3. Champs pour les utilisateurs

    • Obligatoire: champ dont la saisie est obligatoire

    \ 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 @@ + + + 5. Statut des demandes

    5. Statut des demandes

    Ces écrans vous permettent de définir les différents statuts possibles des demandes.

    • Demande fermée: indique que le statut correspond à une demande considérée comme fermée

    • Statut par défaut: statut appliqué par défaut aux nouvelles demandes (seul un statut peut être déclaré comme statut par défaut)

    • Couleur: code couleur HTML (6 caractères) représentant le statut à l'affichage

    \ 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 @@ + + + 6. Workflow

    6. Workflow

    Le workflow permet de définir les changements que les différents membres d'un projet sont autorisés à effectuer sur les demandes, en fonction de leur type.

    Sélectionnez le rôle et le tracker pour lesquels vous souhaitez modifier le workflow, puis cliquez sur Edit. L'écran vous permet alors de modifier, pour le rôle et le tracker choisi, les changements autorisés. Les lignes représentent les statuts initiaux des demandes. Les colonnes représentent les statuts autorisés à être appliqués.

    Remarque: pour qu'un rôle puisse changer le statut des demandes, la permission doit lui être explicitement donnée indépendemment de la configuration du workflow.

    Dans l'exemple ci-dessus, les demandes de type Bug au statut Nouveau pourront être passées au statut Assignée ou Résolue par le rôle Développeur. Celles au statut Assignée pourront être passées au statut Résolue. Le statut de toutes les autres demandes de type Bug ne pourra pas être modifié par le Développeur.

    \ 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 @@ + + + 7. Listes de valeurs

    7. Listes de valeurs

    Les listes de valeurs utilisées par l'application (exemple: les priorités des demandes) peuvent être personnalisées. Cet écran vous permet de définir les valeurs possibles pour chacune des listes suivantes:

    • Priorités des demandes

    • Catégories de documents

    \ 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 @@ + + + 8. Notifications par mail

    8. Notifications par mail

    Cet écran vous permet de sélectionner les actions qui donneront lieu à une notification par mail aux membres du projet.

    Remarque: l'envoi de mails doit être activé dans la configuration de l'application si souhaitez effectuer des notifications.

    \ 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 @@ + + + 9. Authentification

    9. Authentification

    Par défaut, redMine s'appuie sur sa propre base de données pour authentifier les utilisateurs, à l'aide d'un mot de passe spécifique.

    Si vous disposez déjà d'un ou plusieurs référentiels externes d'utilisateurs (annuaires LDAP), vous pouvez les déclarer afin qu'ils soient utilisés pour l'authentification sur redMine. Cela permet aux utilisateurs d'accéder à redMine avec leurs identifiants et mots de passe habituels.

    Pour chaque référentiel déclaré, vous pouvez spécifier si les comptes peuvent être créés à la volée dans redMine. Si c'est le cas, les comptes utilisateurs sont automatiquement créés à la première connexion de l'utilisateur (sans droits spécifiques sur les projets), à partir des informations disponibles dans le référentiel. Sinon, l'administrateur doit au préalable créer le compte de l'utilisateur dans redMine.

    9.1. Déclaration d'un annuaire LDAP

    • Nom: nom d'affichage du référentiel

    • Hôte: nom d'hôte du serveur LDAP

    • Port: port de connexion au serveur LDAP

    • Compte: DN du compte de connexion au LDAP (laisser vide si l'annuaire autorise l'accès anonyme en lecture)

    • Mot de passe: mot de passe du compte de connexion

    • Base DN: DN de base utilisé pour la recherche des utilisateur dans l'annuaire

    • Filtre LDAP: Filtre de recherche des utilisateurs dans l'annuaire (optionnel)

    • Attributs LDAP:

      • Identifiant: nom de l'attribut LDAP utilisé comme identifiant de l'utilisateur (ex: uid)

      • Prénom: nom de l'attribut LDAP contenant le prénom de l'utilisateur (ex: givenName)

      • Nom: nom de l'attribut LDAP contenant le nom de l'utilisateur (ex: sn)

      • Email: nom de l'attribut LDAP contenant l'adresse mail de l'utilisateur (ex: mail)

    Les attributs "Prénom", "Nom" et "Email" ne sont utilisés que lorsque les comptes sont créés à la volée.

    \ 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 @@ + + + 10. Informations

    10. Informations

    Affiche des informations relatives à l'application et à son environnement.

    \ 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 @@ + + + Chapter 2. Projets \ 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 @@ + + + 1. Aperçu du projet

    1. Aperçu du projet

    L'aperçu vous présente les informations générales relatives au projet, les principaux membres, les dernières annonces, ainsi qu'une synthèse du nombre de demandes ouvertes par tracker.

    \ 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 @@ + + + 2. Gestion des demandes

    2. Gestion des demandes

    2.1. Liste des demandes

    Par défaut, l'ensemble des demandes ouvertes du projet sont affichées. Différents filtres vous permettent de sélectionner les demandes à afficher. Si le projet comporte des sous-projets, vous avez la possibilité d'afficher également les demandes relatives aux sous-projets (non affichées par défaut).

    Une fois appliqué, un filtre reste valable durant toute votre session. Vous pouvez le redéfinir, ou le supprimer en cliquant sur Annuler.

    \ 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 @@ + + + 3. Rapports

    3. Rapports

    Cet écran présente la synthèse du nombre de demandes par statut et selon différents critères (tracker, priorité, catégorie). Des liens directs permettent d'accéder à la liste détaillée des demandes pour chaque critère.

    \ 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 @@ + + + 4. Historique

    4. Historique

    Cette page présente l'ensemble des demandes résolues dans chacune des versions du projet. Certains types de demande peuvent être exclus de cet affichage.

    \ 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 @@ + + + 5. Annonces

    5. Annonces

    Les nouvelles vous permettent d'informer les utilisateurs sur l'activité du projet.

    \ 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 @@ + + + 6. Documents

    6. Documents

    Les documents sont groupés par catégories (voir Listes de valeurs). Un document peut contenir plusieurs fichiers (exemple: révisions ou versions successives).

    \ 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 @@ + + + 7. Fichiers

    7. Fichiers

    Ce module vous permet de publier les différents fichiers (sources, binaires, ...) pour chaque version de l'application.

    \ 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 @@ + + + 8. Configuration du projet

    8. Configuration du projet

    8.1. Propriétés du projet

    • Public: 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ès, en fonction de leur rôle.

    • Champs personnalisés: sélectionner les champs personnalisés que vous souhaitez utiliser pour les demandes du projet. Seul l'administrateur peut définir de nouveaux champs personnalisés.

    8.2. Membres

    Cet écran vous permet de définir les membres du projet ainsi que leurs rôles respectifs. Un utilisateur ne peut avoir qu'un rôle au sein d'un projet donné. Le rôle d'un membre détermine les permissions dont il bénéficie sur le projet.

    8.3. Versions

    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érentes versions de l'application (voir Fichiers).

    8.4. Catégories des demandes

    Les catégories de demande vous permettent de typer les demandes. Les catégories peuvent par exemple correspondre aux différents modules du projet.

    \ 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 @@ + + + Documentation redMine \ 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 Binary files /dev/null and b/public/manual/fr/resources/issues_list.png 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 Binary files /dev/null and b/public/manual/fr/resources/users_list.png differ diff --git a/public/manual/fr/resources/workflow.png b/public/manual/fr/resources/workflow.png new file mode 100644 index 000000000..04e79d61e Binary files /dev/null and b/public/manual/fr/resources/workflow.png 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 containing navigation buttons */ + background: #467aa7; + color: #fff; +} + +.calendar thead .daynames { /* Row containing the day names */ + background: #bdf; +} + +.calendar thead .name { /* Cells 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 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 */ + background: #80b0da; + padding: 1px 3px 1px 1px; + border: 1px solid #bbb; +} + +.calendar tbody td.active { /* Active (pressed) cells */ + 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 in footer (only one right now) */ + text-align: center; + background: #556; + color: #fff; +} + +.calendar tfoot .ttip { /* Tooltip (status bar) cell */ + 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%; +} diff --git a/redmine/Rakefile b/redmine/Rakefile deleted file mode 100644 index cffd19f0c..000000000 --- a/redmine/Rakefile +++ /dev/null @@ -1,10 +0,0 @@ -# Add your own tasks in files placed in lib/tasks ending in .rake, -# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake. - -require(File.join(File.dirname(__FILE__), 'config', 'boot')) - -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -require 'tasks/rails' \ No newline at end of file diff --git a/redmine/app/controllers/account_controller.rb b/redmine/app/controllers/account_controller.rb deleted file mode 100644 index ffd2419b3..000000000 --- a/redmine/app/controllers/account_controller.rb +++ /dev/null @@ -1,131 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class AccountController < ApplicationController - layout 'base' - helper :custom_fields - include CustomFieldsHelper - - # prevents login action to be filtered by check_if_login_required application scope filter - skip_before_filter :check_if_login_required, :only => [:login, :lost_password, :register] - before_filter :require_login, :except => [:show, :login, :lost_password, :register] - - # Show user's account - def show - @user = User.find(params[:id]) - @custom_values = @user.custom_values.find(:all, :include => :custom_field) - end - - # Login request and validation - def login - if request.get? - # Logout user - self.logged_in_user = nil - else - # Authenticate user - user = User.try_to_login(params[:login], params[:password]) - if user - self.logged_in_user = user - redirect_back_or_default :controller => 'my', :action => 'page' - else - flash.now[:notice] = l(:notice_account_invalid_creditentials) - end - end - end - - # Log out current user and redirect to welcome page - def logout - self.logged_in_user = nil - redirect_to :controller => '' - end - - # Enable user to choose a new password - def lost_password - if params[:token] - @token = Token.find_by_action_and_value("recovery", params[:token]) - redirect_to :controller => '' and return unless @token and !@token.expired? - @user = @token.user - if request.post? - @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] - if @user.save - @token.destroy - flash[:notice] = l(:notice_account_password_updated) - redirect_to :action => 'login' - return - end - end - render :template => "account/password_recovery" - return - else - if request.post? - user = User.find_by_mail(params[:mail]) - # user not found in db - flash.now[:notice] = l(:notice_account_unknown_email) and return unless user - # user uses an external authentification - flash.now[:notice] = l(:notice_can_t_change_password) and return if user.auth_source_id - # create a new token for password recovery - token = Token.new(:user => user, :action => "recovery") - if token.save - # send token to user via email - Mailer.set_language_if_valid(user.language) - Mailer.deliver_lost_password(token) - flash[:notice] = l(:notice_account_lost_email_sent) - redirect_to :action => 'login' - return - end - end - end - end - - # User self-registration - def register - redirect_to :controller => '' and return if $RDM_SELF_REGISTRATION == false - if params[:token] - token = Token.find_by_action_and_value("register", params[:token]) - redirect_to :controller => '' and return unless token and !token.expired? - user = token.user - redirect_to :controller => '' and return unless user.status == User::STATUS_REGISTERED - user.status = User::STATUS_ACTIVE - if user.save - token.destroy - flash[:notice] = l(:notice_account_activated) - redirect_to :action => 'login' - return - end - else - if request.get? - @user = User.new(:language => $RDM_DEFAULT_LANG) - @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) } - else - @user = User.new(params[:user]) - @user.admin = false - @user.login = params[:user][:login] - @user.status = User::STATUS_REGISTERED - @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] - @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) } - @user.custom_values = @custom_values - token = Token.new(:user => @user, :action => "register") - if @user.save and token.save - Mailer.set_language_if_valid(@user.language) - Mailer.deliver_register(token) - flash[:notice] = l(:notice_account_register_done) - redirect_to :controller => '' - end - end - end - end -end diff --git a/redmine/app/controllers/admin_controller.rb b/redmine/app/controllers/admin_controller.rb deleted file mode 100644 index 2c9f67586..000000000 --- a/redmine/app/controllers/admin_controller.rb +++ /dev/null @@ -1,56 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class AdminController < ApplicationController - layout 'base' - before_filter :require_admin - - helper :sort - include SortHelper - - def index - end - - def projects - sort_init 'name', 'asc' - sort_update - @project_count = Project.count - @project_pages = Paginator.new self, @project_count, - 15, - @params['page'] - @projects = Project.find :all, :order => sort_clause, - :limit => @project_pages.items_per_page, - :offset => @project_pages.current.offset - - render :action => "projects", :layout => false if request.xhr? - end - - def mail_options - @actions = Permission.find(:all, :conditions => ["mail_option=?", true]) || [] - if request.post? - @actions.each { |a| - a.mail_enabled = (params[:action_ids] || []).include? a.id.to_s - a.save - } - flash.now[:notice] = l(:notice_successful_update) - end - end - - def info - @adapter_name = ActiveRecord::Base.connection.adapter_name - end -end diff --git a/redmine/app/controllers/application.rb b/redmine/app/controllers/application.rb deleted file mode 100644 index 3bebf4de5..000000000 --- a/redmine/app/controllers/application.rb +++ /dev/null @@ -1,126 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class ApplicationController < ActionController::Base - before_filter :check_if_login_required, :set_localization - - def logged_in_user=(user) - @logged_in_user = user - session[:user_id] = (user ? user.id : nil) - end - - def logged_in_user - if session[:user_id] - @logged_in_user ||= User.find(session[:user_id], :include => :memberships) - else - nil - end - end - - # check if login is globally required to access the application - def check_if_login_required - require_login if $RDM_LOGIN_REQUIRED - end - - def set_localization - lang = begin - if self.logged_in_user and self.logged_in_user.language and !self.logged_in_user.language.empty? and GLoc.valid_languages.include? self.logged_in_user.language.to_sym - self.logged_in_user.language - elsif request.env['HTTP_ACCEPT_LANGUAGE'] - accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first - if accept_lang and !accept_lang.empty? and GLoc.valid_languages.include? accept_lang.to_sym - accept_lang - end - end - rescue - nil - end || $RDM_DEFAULT_LANG - set_language_if_valid(lang) - end - - def require_login - unless self.logged_in_user - store_location - redirect_to :controller => "account", :action => "login" - return false - end - true - end - - def require_admin - return unless require_login - unless self.logged_in_user.admin? - render :nothing => true, :status => 403 - return false - end - true - end - - # authorizes the user for the requested action. - def authorize - # check if action is allowed on public projects - if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ @params[:controller], @params[:action] ] - return true - end - # if action is not public, force login - return unless require_login - # admin is always authorized - return true if self.logged_in_user.admin? - # if not admin, check membership permission - @user_membership ||= Member.find(:first, :conditions => ["user_id=? and project_id=?", self.logged_in_user.id, @project.id]) - if @user_membership and Permission.allowed_to_role( "%s/%s" % [ @params[:controller], @params[:action] ], @user_membership.role_id ) - return true - end - render :nothing => true, :status => 403 - false - end - - # store current uri in session. - # return to this location by calling redirect_back_or_default - def store_location - session[:return_to] = @request.request_uri - end - - # move to the last store_location call or to the passed default one - def redirect_back_or_default(default) - if session[:return_to].nil? - redirect_to default - else - redirect_to_url session[:return_to] - session[:return_to] = nil - end - end - - # qvalues http header parser - # code taken from webrick - def parse_qvalues(value) - tmp = [] - if value - parts = value.split(/,\s*/) - parts.each {|part| - if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) - val = m[1] - q = (m[2] or 1).to_f - tmp.push([val, q]) - end - } - tmp = tmp.sort_by{|val, q| -q} - tmp.collect!{|val, q| val} - end - return tmp - end -end \ No newline at end of file diff --git a/redmine/app/controllers/auth_sources_controller.rb b/redmine/app/controllers/auth_sources_controller.rb deleted file mode 100644 index 86b58d365..000000000 --- a/redmine/app/controllers/auth_sources_controller.rb +++ /dev/null @@ -1,83 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class AuthSourcesController < ApplicationController - layout 'base' - before_filter :require_admin - - def index - list - render :action => 'list' unless request.xhr? - end - - # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) - verify :method => :post, :only => [ :destroy, :create, :update ], - :redirect_to => { :action => :list } - - def list - @auth_source_pages, @auth_sources = paginate :auth_sources, :per_page => 10 - render :action => "list", :layout => false if request.xhr? - end - - def new - @auth_source = AuthSourceLdap.new - end - - def create - @auth_source = AuthSourceLdap.new(params[:auth_source]) - if @auth_source.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list' - else - render :action => 'new' - end - end - - def edit - @auth_source = AuthSource.find(params[:id]) - end - - def update - @auth_source = AuthSource.find(params[:id]) - if @auth_source.update_attributes(params[:auth_source]) - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list' - else - render :action => 'edit' - end - end - - def test_connection - @auth_method = AuthSource.find(params[:id]) - begin - @auth_method.test_connection - rescue => text - flash[:notice] = text - end - flash[:notice] ||= l(:notice_successful_connection) - redirect_to :action => 'list' - end - - def destroy - @auth_source = AuthSource.find(params[:id]) - unless @auth_source.users.find(:first) - @auth_source.destroy - flash[:notice] = l(:notice_successful_delete) - end - redirect_to :action => 'list' - end -end diff --git a/redmine/app/controllers/custom_fields_controller.rb b/redmine/app/controllers/custom_fields_controller.rb deleted file mode 100644 index bfa152fd1..000000000 --- a/redmine/app/controllers/custom_fields_controller.rb +++ /dev/null @@ -1,71 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class CustomFieldsController < ApplicationController - layout 'base' - before_filter :require_admin - - def index - list - render :action => 'list' unless request.xhr? - end - - def list - @custom_field_pages, @custom_fields = paginate :custom_fields, :per_page => 15 - render :action => "list", :layout => false if request.xhr? - end - - def new - case params[:type] - when "IssueCustomField" - @custom_field = IssueCustomField.new(params[:custom_field]) - @custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids] - when "UserCustomField" - @custom_field = UserCustomField.new(params[:custom_field]) - when "ProjectCustomField" - @custom_field = ProjectCustomField.new(params[:custom_field]) - else - redirect_to :action => 'list' - return - end - if request.post? and @custom_field.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list' - end - @trackers = Tracker.find(:all) - end - - def edit - @custom_field = CustomField.find(params[:id]) - if request.post? and @custom_field.update_attributes(params[:custom_field]) - if @custom_field.is_a? IssueCustomField - @custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : [] - end - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list' - end - @trackers = Tracker.find(:all) - end - - def destroy - CustomField.find(params[:id]).destroy - redirect_to :action => 'list' - rescue - flash[:notice] = "Unable to delete custom field" - redirect_to :action => 'list' - end -end diff --git a/redmine/app/controllers/documents_controller.rb b/redmine/app/controllers/documents_controller.rb deleted file mode 100644 index 3107b3ed1..000000000 --- a/redmine/app/controllers/documents_controller.rb +++ /dev/null @@ -1,68 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class DocumentsController < ApplicationController - layout 'base' - before_filter :find_project, :authorize - - def show - @attachments = @document.attachments.find(:all, :order => "created_on DESC") - end - - def edit - @categories = Enumeration::get_values('DCAT') - if request.post? and @document.update_attributes(params[:document]) - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'show', :id => @document - end - end - - def destroy - @document.destroy - redirect_to :controller => 'projects', :action => 'list_documents', :id => @project - end - - def download - @attachment = @document.attachments.find(params[:attachment_id]) - @attachment.increment_download - send_file @attachment.diskfile, :filename => @attachment.filename - rescue - flash.now[:notice] = l(:notice_file_not_found) - render :text => "", :layout => true, :status => 404 - end - - def add_attachment - # Save the attachment - if params[:attachment][:file].size > 0 - @attachment = @document.attachments.build(params[:attachment]) - @attachment.author_id = self.logged_in_user.id if self.logged_in_user - @attachment.save - end - redirect_to :action => 'show', :id => @document - end - - def destroy_attachment - @document.attachments.find(params[:attachment_id]).destroy - redirect_to :action => 'show', :id => @document - end - -private - def find_project - @document = Document.find(params[:id]) - @project = @document.project - end -end diff --git a/redmine/app/controllers/enumerations_controller.rb b/redmine/app/controllers/enumerations_controller.rb deleted file mode 100644 index 8e5be0a20..000000000 --- a/redmine/app/controllers/enumerations_controller.rb +++ /dev/null @@ -1,70 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class EnumerationsController < ApplicationController - layout 'base' - before_filter :require_admin - - def index - list - render :action => 'list' - end - - # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) - verify :method => :post, :only => [ :destroy, :create, :update ], - :redirect_to => { :action => :list } - - def list - end - - def new - @enumeration = Enumeration.new(:opt => params[:opt]) - end - - def create - @enumeration = Enumeration.new(params[:enumeration]) - if @enumeration.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list', :opt => @enumeration.opt - else - render :action => 'new' - end - end - - def edit - @enumeration = Enumeration.find(params[:id]) - end - - def update - @enumeration = Enumeration.find(params[:id]) - if @enumeration.update_attributes(params[:enumeration]) - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list', :opt => @enumeration.opt - else - render :action => 'edit' - end - end - - def destroy - Enumeration.find(params[:id]).destroy - flash[:notice] = l(:notice_successful_delete) - redirect_to :action => 'list' - rescue - flash[:notice] = "Unable to delete enumeration" - redirect_to :action => 'list' - end -end diff --git a/redmine/app/controllers/help_controller.rb b/redmine/app/controllers/help_controller.rb deleted file mode 100644 index 32d822993..000000000 --- a/redmine/app/controllers/help_controller.rb +++ /dev/null @@ -1,47 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class HelpController < ApplicationController - - skip_before_filter :check_if_login_required - before_filter :load_help_config - - # displays help page for the requested controller/action - def index - # select help page to display - if @params[:ctrl] and @help_config['pages'][@params[:ctrl]] - if @params[:page] and @help_config['pages'][@params[:ctrl]][@params[:page]] - template = @help_config['pages'][@params[:ctrl]][@params[:page]] - else - template = @help_config['pages'][@params[:ctrl]]['index'] - end - end - # choose language according to available help translations - lang = (@help_config['langs'].include? current_language.to_s) ? current_language.to_s : @help_config['langs'].first - - if template - redirect_to "/manual/#{lang}/#{template}" - else - redirect_to "/manual/#{lang}/" - end - end - -private - def load_help_config - @help_config = YAML::load(File.open("#{RAILS_ROOT}/config/help.yml")) - end -end diff --git a/redmine/app/controllers/issue_categories_controller.rb b/redmine/app/controllers/issue_categories_controller.rb deleted file mode 100644 index 965a15e78..000000000 --- a/redmine/app/controllers/issue_categories_controller.rb +++ /dev/null @@ -1,42 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueCategoriesController < ApplicationController - layout 'base' - before_filter :find_project, :authorize - - def edit - if request.post? and @category.update_attributes(params[:category]) - flash[:notice] = l(:notice_successful_update) - redirect_to :controller => 'projects', :action => 'settings', :id => @project - end - end - - def destroy - @category.destroy - redirect_to :controller => 'projects', :action => 'settings', :id => @project - rescue - flash[:notice] = "Categorie can't be deleted" - redirect_to :controller => 'projects', :action => 'settings', :id => @project - end - -private - def find_project - @category = IssueCategory.find(params[:id]) - @project = @category.project - end -end diff --git a/redmine/app/controllers/issue_statuses_controller.rb b/redmine/app/controllers/issue_statuses_controller.rb deleted file mode 100644 index 18ca9c76d..000000000 --- a/redmine/app/controllers/issue_statuses_controller.rb +++ /dev/null @@ -1,69 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueStatusesController < ApplicationController - layout 'base' - before_filter :require_admin - - def index - list - render :action => 'list' unless request.xhr? - end - - def list - @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 10 - render :action => "list", :layout => false if request.xhr? - end - - def new - @issue_status = IssueStatus.new - end - - def create - @issue_status = IssueStatus.new(params[:issue_status]) - if @issue_status.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list' - else - render :action => 'new' - end - end - - def edit - @issue_status = IssueStatus.find(params[:id]) - end - - def update - @issue_status = IssueStatus.find(params[:id]) - if @issue_status.update_attributes(params[:issue_status]) - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list' - else - render :action => 'edit' - end - end - - def destroy - IssueStatus.find(params[:id]).destroy - redirect_to :action => 'list' - rescue - flash[:notice] = "Unable to delete issue status" - redirect_to :action => 'list' - end - - -end diff --git a/redmine/app/controllers/issues_controller.rb b/redmine/app/controllers/issues_controller.rb deleted file mode 100644 index 94e036ab3..000000000 --- a/redmine/app/controllers/issues_controller.rb +++ /dev/null @@ -1,145 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssuesController < ApplicationController - layout 'base', :except => :export_pdf - before_filter :find_project, :authorize - - helper :custom_fields - include CustomFieldsHelper - helper :ifpdf - include IfpdfHelper - - def show - @status_options = @issue.status.workflows.find(:all, :include => :new_status, :conditions => ["role_id=? and tracker_id=?", self.logged_in_user.role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if self.logged_in_user - @custom_values = @issue.custom_values.find(:all, :include => :custom_field) - @journals_count = @issue.journals.count - @journals = @issue.journals.find(:all, :include => [:user, :details], :limit => 15, :order => "journals.created_on desc") - end - - def history - @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "journals.created_on desc") - @journals_count = @journals.length - end - - def export_pdf - @custom_values = @issue.custom_values.find(:all, :include => :custom_field) - @options_for_rfpdf ||= {} - @options_for_rfpdf[:file_name] = "#{@project.name}_#{@issue.long_id}.pdf" - end - - def edit - @priorities = Enumeration::get_values('IPRI') - if request.get? - @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) } - else - begin - @issue.init_journal(self.logged_in_user) - # Retrieve custom fields and values - @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) } - @issue.custom_values = @custom_values - @issue.attributes = params[:issue] - if @issue.save - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'show', :id => @issue - end - rescue ActiveRecord::StaleObjectError - # Optimistic locking exception - flash[:notice] = l(:notice_locking_conflict) - end - end - end - - def add_note - unless params[:notes].empty? - journal = @issue.init_journal(self.logged_in_user, params[:notes]) - #@history = @issue.histories.build(params[:history]) - #@history.author_id = self.logged_in_user.id if self.logged_in_user - #@history.status = @issue.status - if @issue.save - flash[:notice] = l(:notice_successful_update) - Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled? - redirect_to :action => 'show', :id => @issue - return - end - end - show - render :action => 'show' - end - - def change_status - #@history = @issue.histories.build(params[:history]) - @status_options = @issue.status.workflows.find(:all, :conditions => ["role_id=? and tracker_id=?", self.logged_in_user.role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if self.logged_in_user - @new_status = IssueStatus.find(params[:new_status_id]) - if params[:confirm] - begin - #@history.author_id = self.logged_in_user.id if self.logged_in_user - #@issue.status = @history.status - #@issue.fixed_version_id = (params[:issue][:fixed_version_id]) - #@issue.assigned_to_id = (params[:issue][:assigned_to_id]) - #@issue.done_ratio = (params[:issue][:done_ratio]) - #@issue.lock_version = (params[:issue][:lock_version]) - journal = @issue.init_journal(self.logged_in_user, params[:notes]) - @issue.status = @new_status - if @issue.update_attributes(params[:issue]) - flash[:notice] = l(:notice_successful_update) - Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled? - redirect_to :action => 'show', :id => @issue - end - rescue ActiveRecord::StaleObjectError - # Optimistic locking exception - flash[:notice] = l(:notice_locking_conflict) - end - end - @assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user } - end - - def destroy - @issue.destroy - redirect_to :controller => 'projects', :action => 'list_issues', :id => @project - end - - def add_attachment - # Save the attachments - params[:attachments].each { |a| - @attachment = @issue.attachments.build(:file => a, :author => self.logged_in_user) unless a.size == 0 - @attachment.save - } if params[:attachments] and params[:attachments].is_a? Array - redirect_to :action => 'show', :id => @issue - end - - def destroy_attachment - @issue.attachments.find(params[:attachment_id]).destroy - redirect_to :action => 'show', :id => @issue - end - - # Send the file in stream mode - def download - @attachment = @issue.attachments.find(params[:attachment_id]) - send_file @attachment.diskfile, :filename => @attachment.filename - rescue - flash.now[:notice] = l(:notice_file_not_found) - render :text => "", :layout => true, :status => 404 - end - -private - def find_project - @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) - @project = @issue.project - @html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}" - end -end diff --git a/redmine/app/controllers/members_controller.rb b/redmine/app/controllers/members_controller.rb deleted file mode 100644 index be3f717d1..000000000 --- a/redmine/app/controllers/members_controller.rb +++ /dev/null @@ -1,41 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class MembersController < ApplicationController - layout 'base' - before_filter :find_project, :authorize - - def edit - if request.post? and @member.update_attributes(params[:member]) - flash[:notice] = l(:notice_successful_update) - redirect_to :controller => 'projects', :action => 'settings', :id => @project - end - end - - def destroy - @member.destroy - flash[:notice] = l(:notice_successful_delete) - redirect_to :controller => 'projects', :action => 'settings', :id => @project - end - -private - def find_project - @member = Member.find(params[:id]) - @project = @member.project - end - -end diff --git a/redmine/app/controllers/my_controller.rb b/redmine/app/controllers/my_controller.rb deleted file mode 100644 index ff12b74d7..000000000 --- a/redmine/app/controllers/my_controller.rb +++ /dev/null @@ -1,131 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class MyController < ApplicationController - layout 'base' - before_filter :require_login - - BLOCKS = { 'issues_assigned_to_me' => :label_assigned_to_me_issues, - 'issues_reported_by_me' => :label_reported_issues, - 'latest_news' => :label_news_latest, - 'calendar' => :label_calendar, - 'documents' => :label_document_plural - }.freeze - - verify :xhr => true, - :session => :page_layout, - :only => [:add_block, :remove_block, :order_blocks] - - def index - page - render :action => 'page' - end - - # Show user's page - def page - @user = self.logged_in_user - @blocks = @user.pref[:my_page_layout] || { 'left' => ['issues_assigned_to_me'], 'right' => ['issues_reported_by_me'] } - end - - # Edit user's account - def account - @user = self.logged_in_user - @pref = @user.pref - @user.attributes = params[:user] - @user.pref.attributes = params[:pref] - if request.post? and @user.save - set_localization - flash.now[:notice] = l(:notice_account_updated) - self.logged_in_user.reload - end - end - - # Change user's password - def change_password - @user = self.logged_in_user - flash[:notice] = l(:notice_can_t_change_password) and redirect_to :action => 'account' and return if @user.auth_source_id - if @user.check_password?(@params[:password]) - @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] - if @user.save - flash[:notice] = l(:notice_account_password_updated) - else - render :action => 'account' - return - end - else - flash[:notice] = l(:notice_account_wrong_password) - end - redirect_to :action => 'account' - end - - # User's page layout configuration - def page_layout - @user = self.logged_in_user - @blocks = @user.pref[:my_page_layout] || { 'left' => ['issues_assigned_to_me'], 'right' => ['issues_reported_by_me'] } - session[:page_layout] = @blocks - %w(top left right).each {|f| session[:page_layout][f] ||= [] } - @block_options = [] - BLOCKS.each {|k, v| @block_options << [l(v), k]} - end - - # Add a block to user's page - # The block is added on top of the page - # params[:block] : id of the block to add - def add_block - @user = self.logged_in_user - block = params[:block] - # remove if already present in a group - %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block } - # add it on top - session[:page_layout]['top'].unshift block - render :partial => "block", :locals => {:user => @user, :block_name => block} - end - - # Remove a block to user's page - # params[:block] : id of the block to remove - def remove_block - block = params[:block] - # remove block in all groups - %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block } - render :nothing => true - end - - # Change blocks order on user's page - # params[:group] : group to order (top, left or right) - # params[:list-(top|left|right)] : array of block ids of the group - def order_blocks - group = params[:group] - group_items = params["list-#{group}"] - if group_items and group_items.is_a? Array - # remove group blocks if they are presents in other groups - %w(top left right).each {|f| - session[:page_layout][f] = (session[:page_layout][f] || []) - group_items - } - session[:page_layout][group] = group_items - end - render :nothing => true - end - - # Save user's page layout - def page_layout_save - @user = self.logged_in_user - @user.pref[:my_page_layout] = session[:page_layout] if session[:page_layout] - @user.pref.save - session[:page_layout] = nil - redirect_to :action => 'page' - end -end diff --git a/redmine/app/controllers/news_controller.rb b/redmine/app/controllers/news_controller.rb deleted file mode 100644 index b50b59dc0..000000000 --- a/redmine/app/controllers/news_controller.rb +++ /dev/null @@ -1,42 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class NewsController < ApplicationController - layout 'base' - before_filter :find_project, :authorize - - def show - end - - def edit - if request.post? and @news.update_attributes(params[:news]) - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'show', :id => @news - end - end - - def destroy - @news.destroy - redirect_to :controller => 'projects', :action => 'list_news', :id => @project - end - -private - def find_project - @news = News.find(params[:id]) - @project = @news.project - end -end diff --git a/redmine/app/controllers/projects_controller.rb b/redmine/app/controllers/projects_controller.rb deleted file mode 100644 index c968800c3..000000000 --- a/redmine/app/controllers/projects_controller.rb +++ /dev/null @@ -1,469 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class ProjectsController < ApplicationController - layout 'base', :except => :export_issues_pdf - before_filter :find_project, :authorize, :except => [ :index, :list, :add ] - before_filter :require_admin, :only => [ :add, :destroy ] - - helper :sort - include SortHelper - helper :search_filter - include SearchFilterHelper - helper :custom_fields - include CustomFieldsHelper - helper :ifpdf - include IfpdfHelper - helper IssuesHelper - - def index - list - render :action => 'list' unless request.xhr? - end - - # Lists public projects - def list - sort_init 'name', 'asc' - sort_update - @project_count = Project.count(["is_public=?", true]) - @project_pages = Paginator.new self, @project_count, - 15, - @params['page'] - @projects = Project.find :all, :order => sort_clause, - :conditions => ["is_public=?", true], - :limit => @project_pages.items_per_page, - :offset => @project_pages.current.offset - - render :action => "list", :layout => false if request.xhr? - end - - # Add a new project - def add - @custom_fields = IssueCustomField.find(:all) - @root_projects = Project.find(:all, :conditions => "parent_id is null") - @project = Project.new(params[:project]) - if request.get? - @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project) } - else - @project.custom_fields = CustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids] - @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) } - @project.custom_values = @custom_values - if @project.save - flash[:notice] = l(:notice_successful_create) - redirect_to :controller => 'admin', :action => 'projects' - end - end - end - - # Show @project - def show - @custom_values = @project.custom_values.find(:all, :include => :custom_field) - @members = @project.members.find(:all, :include => [:user, :role]) - @subprojects = @project.children if @project.children_count > 0 - @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC") - @trackers = Tracker.find(:all) - end - - def settings - @root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id]) - @custom_fields = IssueCustomField::find_all - @issue_category ||= IssueCategory.new - @member ||= @project.members.new - @roles = Role.find_all - @users = User.find_all - @project.members.find(:all, :include => :user).collect{|m| m.user } - @custom_values ||= ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) } - end - - # Edit @project - def edit - if request.post? - @project.custom_fields = IssueCustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids] - if params[:custom_fields] - @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) } - @project.custom_values = @custom_values - end - if @project.update_attributes(params[:project]) - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'settings', :id => @project - else - settings - render :action => 'settings' - end - end - end - - # Delete @project - def destroy - if request.post? and params[:confirm] - @project.destroy - redirect_to :controller => 'admin', :action => 'projects' - end - end - - # Add a new issue category to @project - def add_issue_category - if request.post? - @issue_category = @project.issue_categories.build(params[:issue_category]) - if @issue_category.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'settings', :id => @project - else - settings - render :action => 'settings' - end - end - end - - # Add a new version to @project - def add_version - @version = @project.versions.build(params[:version]) - if request.post? and @version.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'settings', :id => @project - end - end - - # Add a new member to @project - def add_member - @member = @project.members.build(params[:member]) - if request.post? - if @member.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'settings', :id => @project - else - settings - render :action => 'settings' - end - end - end - - # Show members list of @project - def list_members - @members = @project.members - end - - # Add a new document to @project - def add_document - @categories = Enumeration::get_values('DCAT') - @document = @project.documents.build(params[:document]) - if request.post? - # Save the attachment - if params[:attachment][:file].size > 0 - @attachment = @document.attachments.build(params[:attachment]) - @attachment.author_id = self.logged_in_user.id if self.logged_in_user - end - if @document.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list_documents', :id => @project - end - end - end - - # Show documents list of @project - def list_documents - @documents = @project.documents - end - - # Add a new issue to @project - def add_issue - @tracker = Tracker.find(params[:tracker_id]) - @priorities = Enumeration::get_values('IPRI') - @issue = Issue.new(:project => @project, :tracker => @tracker) - if request.get? - @issue.start_date = Date.today - @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) } - else - @issue.attributes = params[:issue] - @issue.author_id = self.logged_in_user.id if self.logged_in_user - # Multiple file upload - params[:attachments].each { |a| - @attachment = @issue.attachments.build(:file => a, :author => self.logged_in_user) unless a.size == 0 - } if params[:attachments] and params[:attachments].is_a? Array - @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) } - @issue.custom_values = @custom_values - if @issue.save - flash[:notice] = l(:notice_successful_create) - Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled? - redirect_to :action => 'list_issues', :id => @project - end - end - end - - # Show filtered/sorted issues list of @project - def list_issues - sort_init 'issues.id', 'desc' - sort_update - - search_filter_init_list_issues - search_filter_update if params[:set_filter] - - @results_per_page_options = [ 15, 25, 50, 100 ] - if params[:per_page] and @results_per_page_options.include? params[:per_page].to_i - @results_per_page = params[:per_page].to_i - session[:results_per_page] = @results_per_page - else - @results_per_page = session[:results_per_page] || 25 - end - - @issue_count = Issue.count(:include => [:status, :project], :conditions => search_filter_clause) - @issue_pages = Paginator.new self, @issue_count, @results_per_page, @params['page'] - @issues = Issue.find :all, :order => sort_clause, - :include => [ :author, :status, :tracker, :project ], - :conditions => search_filter_clause, - :limit => @issue_pages.items_per_page, - :offset => @issue_pages.current.offset - - render :layout => false if request.xhr? - end - - # Export filtered/sorted issues list to CSV - def export_issues_csv - sort_init 'issues.id', 'desc' - sort_update - - search_filter_init_list_issues - - @issues = Issue.find :all, :order => sort_clause, - :include => [ :author, :status, :tracker, :project, :custom_values ], - :conditions => search_filter_clause - - ic = Iconv.new('ISO-8859-1', 'UTF-8') - export = StringIO.new - CSV::Writer.generate(export, l(:general_csv_separator)) do |csv| - # csv header fields - headers = [ "#", l(:field_status), l(:field_tracker), l(:field_subject), l(:field_author), l(:field_created_on), l(:field_updated_on) ] - for custom_field in @project.all_custom_fields - headers << custom_field.name - end - csv << headers.collect {|c| ic.iconv(c) } - # csv lines - @issues.each do |issue| - fields = [issue.id, issue.status.name, issue.tracker.name, issue.subject, issue.author.display_name, l_datetime(issue.created_on), l_datetime(issue.updated_on)] - for custom_field in @project.all_custom_fields - fields << (show_value issue.custom_value_for(custom_field)) - end - csv << fields.collect {|c| ic.iconv(c.to_s) } - end - end - export.rewind - send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv') - end - - # Export filtered/sorted issues to PDF - def export_issues_pdf - sort_init 'issues.id', 'desc' - sort_update - - search_filter_init_list_issues - - @issues = Issue.find :all, :order => sort_clause, - :include => [ :author, :status, :tracker, :project, :custom_values ], - :conditions => search_filter_clause - - @options_for_rfpdf ||= {} - @options_for_rfpdf[:file_name] = "export.pdf" - end - - def move_issues - @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids] - redirect_to :action => 'list_issues', :id => @project and return unless @issues - @projects = [] - # find projects to which the user is allowed to move the issue - @logged_in_user.memberships.each {|m| @projects << m.project if Permission.allowed_to_role("projects/move_issues", m.role_id)} - # issue can be moved to any tracker - @trackers = Tracker.find(:all) - if request.post? and params[:new_project_id] and params[:new_tracker_id] - new_project = Project.find(params[:new_project_id]) - new_tracker = Tracker.find(params[:new_tracker_id]) - @issues.each { |i| - # category is project dependent - i.category = nil unless i.project_id == new_project.id - # move the issue - i.project = new_project - i.tracker = new_tracker - i.save - } - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list_issues', :id => @project - end - end - - # Add a news to @project - def add_news - @news = News.new(:project => @project) - if request.post? - @news.attributes = params[:news] - @news.author_id = self.logged_in_user.id if self.logged_in_user - if @news.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list_news', :id => @project - end - end - end - - # Show news list of @project - def list_news - @news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "news.created_on DESC" - render :action => "list_news", :layout => false if request.xhr? - end - - def add_file - if request.post? - # Save the attachment - if params[:attachment][:file].size > 0 - @attachment = @project.versions.find(params[:version_id]).attachments.build(params[:attachment]) - @attachment.author_id = self.logged_in_user.id if self.logged_in_user - if @attachment.save - flash[:notice] = l(:notice_successful_create) - redirect_to :controller => 'projects', :action => 'list_files', :id => @project - end - end - end - @versions = @project.versions - end - - def list_files - @versions = @project.versions - end - - # Show changelog for @project - def changelog - @trackers = Tracker.find(:all, :conditions => ["is_in_chlog=?", true]) - if request.get? - @selected_tracker_ids = @trackers.collect {|t| t.id.to_s } - else - @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array - end - @selected_tracker_ids ||= [] - @fixed_issues = @project.issues.find(:all, - :include => [ :fixed_version, :status, :tracker ], - :conditions => [ "issue_statuses.is_closed=? and issues.tracker_id in (#{@selected_tracker_ids.join(',')}) and issues.fixed_version_id is not null", true], - :order => "versions.effective_date DESC, issues.id DESC" - ) unless @selected_tracker_ids.empty? - @fixed_issues ||= [] - end - - def activity - if params[:year] and params[:year].to_i > 1900 - @year = params[:year].to_i - if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 - @month = params[:month].to_i - end - end - @year ||= Date.today.year - @month ||= Date.today.month - - @date_from = Date.civil(@year, @month, 1) - @date_to = (@date_from >> 1)-1 - - @events_by_day = {} - - unless params[:show_issues] == "0" - @project.issues.find(:all, :include => [:author, :status], :conditions => ["issues.created_on>=? and issues.created_on<=?", @date_from, @date_to] ).each { |i| - @events_by_day[i.created_on.to_date] ||= [] - @events_by_day[i.created_on.to_date] << i - } - @show_issues = 1 - end - - unless params[:show_news] == "0" - @project.news.find(:all, :conditions => ["news.created_on>=? and news.created_on<=?", @date_from, @date_to] ).each { |i| - @events_by_day[i.created_on.to_date] ||= [] - @events_by_day[i.created_on.to_date] << i - } - @show_news = 1 - end - - unless params[:show_files] == "0" - Attachment.find(:all, :joins => "LEFT JOIN versions ON versions.id = attachments.container_id", :conditions => ["attachments.container_type='Version' and versions.project_id=? and attachments.created_on>=? and attachments.created_on<=?", @project.id, @date_from, @date_to] ).each { |i| - @events_by_day[i.created_on.to_date] ||= [] - @events_by_day[i.created_on.to_date] << i - } - @show_files = 1 - end - - unless params[:show_documents] == "0" - Attachment.find(:all, :joins => "LEFT JOIN documents ON documents.id = attachments.container_id", :conditions => ["attachments.container_type='Document' and documents.project_id=? and attachments.created_on>=? and attachments.created_on<=?", @project.id, @date_from, @date_to] ).each { |i| - @events_by_day[i.created_on.to_date] ||= [] - @events_by_day[i.created_on.to_date] << i - } - @show_documents = 1 - end - - end - - def calendar - if params[:year] and params[:year].to_i > 1900 - @year = params[:year].to_i - if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 - @month = params[:month].to_i - end - end - @year ||= Date.today.year - @month ||= Date.today.month - - @date_from = Date.civil(@year, @month, 1) - @date_to = (@date_from >> 1)-1 - # start on monday - @date_from = @date_from - (@date_from.cwday-1) - # finish on sunday - @date_to = @date_to + (7-@date_to.cwday) - - @issues = @project.issues.find(:all, :include => :tracker, :conditions => ["((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", @date_from, @date_to, @date_from, @date_to]) - render :layout => false if request.xhr? - end - - def gantt - if params[:year] and params[:year].to_i >0 - @year_from = params[:year].to_i - if params[:month] and params[:month].to_i >=1 and params[:month].to_i <= 12 - @month_from = params[:month].to_i - else - @month_from = 1 - end - else - @month_from ||= (Date.today << 1).month - @year_from ||= (Date.today << 1).year - end - - @zoom = (params[:zoom].to_i > 0 and params[:zoom].to_i < 5) ? params[:zoom].to_i : 2 - @months = (params[:months].to_i > 0 and params[:months].to_i < 25) ? params[:months].to_i : 6 - - @date_from = Date.civil(@year_from, @month_from, 1) - @date_to = (@date_from >> @months) - 1 - @issues = @project.issues.find(:all, :order => "start_date, due_date", :conditions => ["(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date?)) and start_date is not null and due_date is not null)", @date_from, @date_to, @date_from, @date_to, @date_from, @date_to]) - - if params[:output]=='pdf' - @options_for_rfpdf ||= {} - @options_for_rfpdf[:file_name] = "gantt.pdf" - render :template => "projects/gantt.rfpdf", :layout => false - else - render :template => "projects/gantt.rhtml" - end - end - -private - # Find project of id params[:id] - # if not found, redirect to project list - # Used as a before_filter - def find_project - @project = Project.find(params[:id]) - @html_title = @project.name - rescue - redirect_to :action => 'list' - end -end diff --git a/redmine/app/controllers/reports_controller.rb b/redmine/app/controllers/reports_controller.rb deleted file mode 100644 index 985c937fc..000000000 --- a/redmine/app/controllers/reports_controller.rb +++ /dev/null @@ -1,164 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class ReportsController < ApplicationController - layout 'base' - before_filter :find_project, :authorize - - def issue_report - @statuses = IssueStatus.find_all - - case params[:detail] - when "tracker" - @field = "tracker_id" - @rows = Tracker.find_all - @data = issues_by_tracker - @report_title = l(:field_tracker) - render :template => "reports/issue_report_details" - when "priority" - @field = "priority_id" - @rows = Enumeration::get_values('IPRI') - @data = issues_by_priority - @report_title = l(:field_priority) - render :template => "reports/issue_report_details" - when "category" - @field = "category_id" - @rows = @project.issue_categories - @data = issues_by_category - @report_title = l(:field_category) - render :template => "reports/issue_report_details" - when "author" - @field = "author_id" - @rows = @project.members.collect { |m| m.user } - @data = issues_by_author - @report_title = l(:field_author) - render :template => "reports/issue_report_details" - else - @trackers = Tracker.find(:all) - @priorities = Enumeration::get_values('IPRI') - @categories = @project.issue_categories - @authors = @project.members.collect { |m| m.user } - issues_by_tracker - issues_by_priority - issues_by_category - issues_by_author - render :template => "reports/issue_report" - end - end - - def delays - @trackers = Tracker.find(:all) - if request.get? - @selected_tracker_ids = @trackers.collect {|t| t.id.to_s } - else - @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array - end - @selected_tracker_ids ||= [] - @raw = - ActiveRecord::Base.connection.select_all("SELECT datediff( a.created_on, b.created_on ) as delay, count(a.id) as total - FROM issue_histories a, issue_histories b, issues i - WHERE a.status_id =5 - AND a.issue_id = b.issue_id - AND a.issue_id = i.id - AND i.tracker_id in (#{@selected_tracker_ids.join(',')}) - AND b.id = ( - SELECT min( c.id ) - FROM issue_histories c - WHERE b.issue_id = c.issue_id ) - GROUP BY delay") unless @selected_tracker_ids.empty? - @raw ||=[] - - @x_from = 0 - @x_to = 0 - @y_from = 0 - @y_to = 0 - @sum_total = 0 - @sum_delay = 0 - @raw.each do |r| - @x_to = [r['delay'].to_i, @x_to].max - @y_to = [r['total'].to_i, @y_to].max - @sum_total = @sum_total + r['total'].to_i - @sum_delay = @sum_delay + r['total'].to_i * r['delay'].to_i - end - end - -private - # Find project of id params[:id] - def find_project - @project = Project.find(params[:id]) - end - - def issues_by_tracker - @issues_by_tracker ||= - ActiveRecord::Base.connection.select_all("select s.id as status_id, - s.is_closed as closed, - t.id as tracker_id, - count(i.id) as total - from - issues i, issue_statuses s, trackers t - where - i.status_id=s.id - and i.tracker_id=t.id - and i.project_id=#{@project.id} - group by s.id, s.is_closed, t.id") - end - - def issues_by_priority - @issues_by_priority ||= - ActiveRecord::Base.connection.select_all("select s.id as status_id, - s.is_closed as closed, - p.id as priority_id, - count(i.id) as total - from - issues i, issue_statuses s, enumerations p - where - i.status_id=s.id - and i.priority_id=p.id - and i.project_id=#{@project.id} - group by s.id, s.is_closed, p.id") - end - - def issues_by_category - @issues_by_category ||= - ActiveRecord::Base.connection.select_all("select s.id as status_id, - s.is_closed as closed, - c.id as category_id, - count(i.id) as total - from - issues i, issue_statuses s, issue_categories c - where - i.status_id=s.id - and i.category_id=c.id - and i.project_id=#{@project.id} - group by s.id, s.is_closed, c.id") - end - - def issues_by_author - @issues_by_author ||= - ActiveRecord::Base.connection.select_all("select s.id as status_id, - s.is_closed as closed, - a.id as author_id, - count(i.id) as total - from - issues i, issue_statuses s, users a - where - i.status_id=s.id - and i.author_id=a.id - and i.project_id=#{@project.id} - group by s.id, s.is_closed, a.id") - end -end diff --git a/redmine/app/controllers/roles_controller.rb b/redmine/app/controllers/roles_controller.rb deleted file mode 100644 index e16127b61..000000000 --- a/redmine/app/controllers/roles_controller.rb +++ /dev/null @@ -1,84 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class RolesController < ApplicationController - layout 'base' - before_filter :require_admin - - def index - list - render :action => 'list' unless request.xhr? - end - - def list - @role_pages, @roles = paginate :roles, :per_page => 10 - render :action => "list", :layout => false if request.xhr? - end - - def new - @role = Role.new(params[:role]) - if request.post? - @role.permissions = Permission.find(@params[:permission_ids]) if @params[:permission_ids] - if @role.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list' - end - end - @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC') - end - - def edit - @role = Role.find(params[:id]) - if request.post? and @role.update_attributes(params[:role]) - @role.permissions = Permission.find(@params[:permission_ids] || []) - Permission.allowed_to_role_expired - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list' - end - @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC') - end - - def destroy - @role = Role.find(params[:id]) - unless @role.members.empty? - flash[:notice] = 'Some members have this role. Can\'t delete it.' - else - @role.destroy - end - redirect_to :action => 'list' - end - - def workflow - @role = Role.find_by_id(params[:role_id]) - @tracker = Tracker.find_by_id(params[:tracker_id]) - - if request.post? - Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) - (params[:issue_status] || []).each { |old, news| - news.each { |new| - @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new) - } - } - if @role.save - flash[:notice] = l(:notice_successful_update) - end - end - @roles = Role.find_all - @trackers = Tracker.find_all - @statuses = IssueStatus.find(:all, :include => :workflows) - end -end diff --git a/redmine/app/controllers/trackers_controller.rb b/redmine/app/controllers/trackers_controller.rb deleted file mode 100644 index bbfb4f48b..000000000 --- a/redmine/app/controllers/trackers_controller.rb +++ /dev/null @@ -1,61 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class TrackersController < ApplicationController - layout 'base' - before_filter :require_admin - - def index - list - render :action => 'list' unless request.xhr? - end - - # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) - verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :list } - - def list - @tracker_pages, @trackers = paginate :trackers, :per_page => 10 - render :action => "list", :layout => false if request.xhr? - end - - def new - @tracker = Tracker.new(params[:tracker]) - if request.post? and @tracker.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list' - end - end - - def edit - @tracker = Tracker.find(params[:id]) - if request.post? and @tracker.update_attributes(params[:tracker]) - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list' - end - end - - def destroy - @tracker = Tracker.find(params[:id]) - unless @tracker.issues.empty? - flash[:notice] = "This tracker contains issues and can\'t be deleted." - else - @tracker.destroy - end - redirect_to :action => 'list' - end - -end diff --git a/redmine/app/controllers/users_controller.rb b/redmine/app/controllers/users_controller.rb deleted file mode 100644 index 47d0e51c9..000000000 --- a/redmine/app/controllers/users_controller.rb +++ /dev/null @@ -1,92 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class UsersController < ApplicationController - layout 'base' - before_filter :require_admin - - helper :sort - include SortHelper - helper :custom_fields - include CustomFieldsHelper - - def index - list - render :action => 'list' unless request.xhr? - end - - def list - sort_init 'login', 'asc' - sort_update - @user_count = User.count - @user_pages = Paginator.new self, @user_count, - 15, - @params['page'] - @users = User.find :all,:order => sort_clause, - :limit => @user_pages.items_per_page, - :offset => @user_pages.current.offset - - render :action => "list", :layout => false if request.xhr? - end - - def add - if request.get? - @user = User.new(:language => $RDM_DEFAULT_LANG) - @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) } - else - @user = User.new(params[:user]) - @user.admin = params[:user][:admin] || false - @user.login = params[:user][:login] - @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id - @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) } - @user.custom_values = @custom_values - if @user.save - flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list' - end - end - @auth_sources = AuthSource.find(:all) - end - - def edit - @user = User.find(params[:id]) - if request.get? - @custom_values = UserCustomField.find(:all).collect { |x| @user.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) } - else - @user.admin = params[:user][:admin] if params[:user][:admin] - @user.login = params[:user][:login] if params[:user][:login] - @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty? or @user.auth_source_id - if params[:custom_fields] - @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) } - @user.custom_values = @custom_values - end - if @user.update_attributes(params[:user]) - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list' - end - end - @auth_sources = AuthSource.find(:all) - end - - def destroy - User.find(params[:id]).destroy - redirect_to :action => 'list' - rescue - flash[:notice] = "Unable to delete user" - redirect_to :action => 'list' - end -end diff --git a/redmine/app/controllers/versions_controller.rb b/redmine/app/controllers/versions_controller.rb deleted file mode 100644 index d1980d74f..000000000 --- a/redmine/app/controllers/versions_controller.rb +++ /dev/null @@ -1,57 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class VersionsController < ApplicationController - layout 'base' - before_filter :find_project, :authorize - - def edit - if request.post? and @version.update_attributes(params[:version]) - flash[:notice] = l(:notice_successful_update) - redirect_to :controller => 'projects', :action => 'settings', :id => @project - end - end - - def destroy - @version.destroy - redirect_to :controller => 'projects', :action => 'settings', :id => @project - rescue - flash[:notice] = "Unable to delete version" - redirect_to :controller => 'projects', :action => 'settings', :id => @project - end - - def download - @attachment = @version.attachments.find(params[:attachment_id]) - @attachment.increment_download - send_file @attachment.diskfile, :filename => @attachment.filename - rescue - flash.now[:notice] = l(:notice_file_not_found) - render :text => "", :layout => true, :status => 404 - end - - def destroy_file - @version.attachments.find(params[:attachment_id]).destroy - flash[:notice] = l(:notice_successful_delete) - redirect_to :controller => 'projects', :action => 'list_files', :id => @project - end - -private - def find_project - @version = Version.find(params[:id]) - @project = @version.project - end -end diff --git a/redmine/app/controllers/welcome_controller.rb b/redmine/app/controllers/welcome_controller.rb deleted file mode 100644 index c47198d51..000000000 --- a/redmine/app/controllers/welcome_controller.rb +++ /dev/null @@ -1,25 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class WelcomeController < ApplicationController - layout 'base' - - def index - @news = News.latest - @projects = Project.latest - end -end diff --git a/redmine/app/helpers/account_helper.rb b/redmine/app/helpers/account_helper.rb deleted file mode 100644 index e18ab6ff4..000000000 --- a/redmine/app/helpers/account_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module AccountHelper -end diff --git a/redmine/app/helpers/admin_helper.rb b/redmine/app/helpers/admin_helper.rb deleted file mode 100644 index db2777392..000000000 --- a/redmine/app/helpers/admin_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module AdminHelper -end diff --git a/redmine/app/helpers/application_helper.rb b/redmine/app/helpers/application_helper.rb deleted file mode 100644 index 0f0deeb30..000000000 --- a/redmine/app/helpers/application_helper.rb +++ /dev/null @@ -1,179 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module ApplicationHelper - - # Return current logged in user or nil - def loggedin? - @logged_in_user - end - - # Return true if user is logged in and is admin, otherwise false - def admin_loggedin? - @logged_in_user and @logged_in_user.admin? - end - - # Return true if user is authorized for controller/action, otherwise false - def authorize_for(controller, action) - # check if action is allowed on public projects - if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ controller, action ] - return true - end - # check if user is authorized - if @logged_in_user and (@logged_in_user.admin? or Permission.allowed_to_role( "%s/%s" % [ controller, action ], @logged_in_user.role_for_project(@project.id) ) ) - return true - end - return false - end - - # Display a link if user is authorized - def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) - link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller], options[:action]) - end - - # Display a link to user's account page - def link_to_user(user) - link_to user.display_name, :controller => 'account', :action => 'show', :id => user - end - - def format_date(date) - l_date(date) if date - end - - def format_time(time) - l_datetime(time) if time - end - - def day_name(day) - l(:general_day_names).split(',')[day-1] - end - - def pagination_links_full(paginator, options={}, html_options={}) - html = '' - html << link_to_remote(('« ' + l(:label_previous)), - {:update => "content", :url => { :page => paginator.current.previous }}, - {:href => url_for(:action => 'list', :params => @params.merge({:page => paginator.current.previous}))}) + ' ' if paginator.current.previous - - html << (pagination_links_each(paginator, options) do |n| - link_to_remote(n.to_s, - {:url => {:action => 'list', :params => @params.merge({:page => n})}, :update => 'content'}, - {:href => url_for(:action => 'list', :params => @params.merge({:page => n}))}) - end || '') - - html << ' ' + link_to_remote((l(:label_next) + ' »'), - {:update => "content", :url => { :page => paginator.current.next }}, - {:href => url_for(:action => 'list', :params => @params.merge({:page => paginator.current.next}))}) if paginator.current.next - html - end - - def textilizable(text) - $RDM_TEXTILE_DISABLED ? text : RedCloth.new(text).to_html - end - - def error_messages_for(object_name, options = {}) - options = options.symbolize_keys - object = instance_variable_get("@#{object_name}") - if object && !object.errors.empty? - # build full_messages here with controller current language - full_messages = [] - object.errors.each do |attr, msg| - next if msg.nil? - if attr == "base" - full_messages << l(msg) - else - full_messages << "« " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " » " + l(msg) unless attr == "custom_values" - end - end - # retrieve custom values error messages - if object.errors[:custom_values] - object.custom_values.each do |v| - v.errors.each do |attr, msg| - next if msg.nil? - full_messages << "« " + v.custom_field.name + " » " + l(msg) - end - end - end - content_tag("div", - content_tag( - options[:header_tag] || "h2", lwr(:gui_validation_error, full_messages.length) + " :" - ) + - content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }), - "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation" - ) - else - "" - end - end - - def lang_options_for_select - (GLoc.valid_languages.sort {|x,y| x.to_s <=> y.to_s }).collect {|lang| [ l_lang_name(lang.to_s, lang), lang.to_s]} - end - - def label_tag_for(name, option_tags = nil, options = {}) - label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") - content_tag("label", label_text) - end - - def labelled_tabular_form_for(name, object, options, &proc) - options[:html] ||= {} - options[:html].store :class, "tabular" - form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc) - end - - def check_all_links(form_name) - link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + - " | " + - link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") - end - - def calendar_for(field_id) - image_tag("calendar", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) + - javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });") - end -end - -class TabularFormBuilder < ActionView::Helpers::FormBuilder - include GLoc - - def initialize(object_name, object, template, options, proc) - set_language_if_valid options.delete(:lang) - @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc - end - - (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector| - src = <<-END_SRC - def #{selector}(field, options = {}) - label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") - label = @template.content_tag("label", label_text, - :class => (@object.errors[field] ? "error" : nil), - :for => (@object_name.to_s + "_" + field.to_s)) - label + super - end - END_SRC - class_eval src, __FILE__, __LINE__ - end - - def select(field, choices, options = {}) - label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") - label = @template.content_tag("label", label_text, - :class => (@object.errors[field] ? "error" : nil), - :for => (@object_name.to_s + "_" + field.to_s)) - label + super - end - -end - diff --git a/redmine/app/helpers/auth_sources_helper.rb b/redmine/app/helpers/auth_sources_helper.rb deleted file mode 100644 index d47e9856a..000000000 --- a/redmine/app/helpers/auth_sources_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module AuthSourcesHelper -end diff --git a/redmine/app/helpers/custom_fields_helper.rb b/redmine/app/helpers/custom_fields_helper.rb deleted file mode 100644 index 9df5c50a3..000000000 --- a/redmine/app/helpers/custom_fields_helper.rb +++ /dev/null @@ -1,77 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module CustomFieldsHelper - - # Return custom field html tag corresponding to its format - def custom_field_tag(custom_value) - custom_field = custom_value.custom_field - field_name = "custom_fields[#{custom_field.id}]" - field_id = "custom_fields_#{custom_field.id}" - - case custom_field.field_format - when "string", "int" - text_field 'custom_value', 'value', :name => field_name, :id => field_id - when "date" - text_field('custom_value', 'value', :name => field_name, :id => field_id, :size => 10) + - calendar_for(field_id) - when "text" - text_area 'custom_value', 'value', :name => field_name, :id => field_id, :cols => 60, :rows => 3 - when "bool" - check_box 'custom_value', 'value', :name => field_name, :id => field_id - when "list" - select 'custom_value', 'value', custom_field.possible_values.split('|'), { :include_blank => true }, :name => field_name, :id => field_id - end - end - - # Return custom field label tag - def custom_field_label_tag(custom_value) - content_tag "label", custom_value.custom_field.name + - (custom_value.custom_field.is_required? ? " *" : ""), - :for => "custom_fields_#{custom_value.custom_field.id}", - :class => (custom_value.errors.empty? ? nil : "error" ) - end - - # Return custom field tag with its label tag - def custom_field_tag_with_label(custom_value) - custom_field_label_tag(custom_value) + custom_field_tag(custom_value) - end - - # Return a string used to display a custom value - def show_value(custom_value) - return "" unless custom_value - format_value(custom_value.value, custom_value.custom_field.field_format) - end - - # Return a string used to display a custom value - def format_value(value, field_format) - return "" unless value - case field_format - when "date" - value.empty? ? "" : l_date(value.to_date) - when "bool" - l_YesNo(value == "1") - else - value - end - end - - # Return an array of custom field formats which can be used in select_tag - def custom_field_formats_for_select - CustomField::FIELD_FORMATS.keys.collect { |k| [ l(CustomField::FIELD_FORMATS[k]), k ] } - end -end diff --git a/redmine/app/helpers/documents_helper.rb b/redmine/app/helpers/documents_helper.rb deleted file mode 100644 index c9897647d..000000000 --- a/redmine/app/helpers/documents_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module DocumentsHelper -end diff --git a/redmine/app/helpers/enumerations_helper.rb b/redmine/app/helpers/enumerations_helper.rb deleted file mode 100644 index 11a216a82..000000000 --- a/redmine/app/helpers/enumerations_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module EnumerationsHelper -end diff --git a/redmine/app/helpers/help_helper.rb b/redmine/app/helpers/help_helper.rb deleted file mode 100644 index bb629316c..000000000 --- a/redmine/app/helpers/help_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module HelpHelper -end diff --git a/redmine/app/helpers/ifpdf_helper.rb b/redmine/app/helpers/ifpdf_helper.rb deleted file mode 100644 index a0dab0f94..000000000 --- a/redmine/app/helpers/ifpdf_helper.rb +++ /dev/null @@ -1,48 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'iconv' - -module IfpdfHelper - - class IFPDF < FPDF - - attr_accessor :footer_date - - def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='') - @ic ||= Iconv.new('ISO-8859-1', 'UTF-8') - txt = begin - @ic.iconv(txt) - rescue - txt - end - super w,h,txt,border,ln,align,fill,link - end - - def Footer - SetFont('Helvetica', 'I', 8) - SetY(-15) - SetX(15) - Cell(0, 5, @footer_date, 0, 0, 'L') - SetY(-15) - SetX(-30) - Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C') - end - - end - -end diff --git a/redmine/app/helpers/issue_categories_helper.rb b/redmine/app/helpers/issue_categories_helper.rb deleted file mode 100644 index 997d830d7..000000000 --- a/redmine/app/helpers/issue_categories_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module IssueCategoriesHelper -end diff --git a/redmine/app/helpers/issue_statuses_helper.rb b/redmine/app/helpers/issue_statuses_helper.rb deleted file mode 100644 index 17704b7ba..000000000 --- a/redmine/app/helpers/issue_statuses_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module IssueStatusesHelper -end diff --git a/redmine/app/helpers/issues_helper.rb b/redmine/app/helpers/issues_helper.rb deleted file mode 100644 index 93bd6c050..000000000 --- a/redmine/app/helpers/issues_helper.rb +++ /dev/null @@ -1,74 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module IssuesHelper - - def show_detail(detail, no_html=false) - case detail.property - when 'attr' - label = l(("field_" + detail.prop_key.to_s.gsub(/\_id$/, "")).to_sym) - case detail.prop_key - when 'due_date', 'start_date' - value = format_date(detail.value.to_date) if detail.value - old_value = format_date(detail.old_value.to_date) if detail.old_value - when 'status_id' - s = IssueStatus.find_by_id(detail.value) and value = s.name if detail.value - s = IssueStatus.find_by_id(detail.old_value) and old_value = s.name if detail.old_value - when 'assigned_to_id' - u = User.find_by_id(detail.value) and value = u.name if detail.value - u = User.find_by_id(detail.old_value) and old_value = u.name if detail.old_value - when 'priority_id' - e = Enumeration.find_by_id(detail.value) and value = e.name if detail.value - e = Enumeration.find_by_id(detail.old_value) and old_value = e.name if detail.old_value - when 'category_id' - c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value - c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value - when 'fixed_version_id' - v = Version.find_by_id(detail.value) and value = v.name if detail.value - v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value - end - when 'cf' - custom_field = CustomField.find_by_id(detail.prop_key) - if custom_field - label = custom_field.name - value = format_value(detail.value, custom_field.field_format) if detail.value - old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value - end - end - - label ||= detail.prop_key - value ||= detail.value - old_value ||= detail.old_value - - unless no_html - label = content_tag('strong', label) - old_value = content_tag("i", old_value) if old_value - old_value = content_tag("strike", old_value) if old_value and !value - value = content_tag("i", value) if value - end - - if value - if old_value - label + " " + l(:text_journal_changed, old_value, value) - else - label + " " + l(:text_journal_set_to, value) - end - else - label + " " + l(:text_journal_deleted) + " (#{old_value})" - end - end -end diff --git a/redmine/app/helpers/members_helper.rb b/redmine/app/helpers/members_helper.rb deleted file mode 100644 index 8bf90913d..000000000 --- a/redmine/app/helpers/members_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module MembersHelper -end diff --git a/redmine/app/helpers/my_helper.rb b/redmine/app/helpers/my_helper.rb deleted file mode 100644 index 9098f67bc..000000000 --- a/redmine/app/helpers/my_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module MyHelper -end diff --git a/redmine/app/helpers/news_helper.rb b/redmine/app/helpers/news_helper.rb deleted file mode 100644 index f4a633f4b..000000000 --- a/redmine/app/helpers/news_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module NewsHelper -end diff --git a/redmine/app/helpers/projects_helper.rb b/redmine/app/helpers/projects_helper.rb deleted file mode 100644 index 0c85ce24c..000000000 --- a/redmine/app/helpers/projects_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module ProjectsHelper -end diff --git a/redmine/app/helpers/reports_helper.rb b/redmine/app/helpers/reports_helper.rb deleted file mode 100644 index ed7fd7884..000000000 --- a/redmine/app/helpers/reports_helper.rb +++ /dev/null @@ -1,32 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module ReportsHelper - - def aggregate(data, criteria) - a = 0 - data.each { |row| - match = 1 - criteria.each { |k, v| - match = 0 unless row[k].to_s == v.to_s - } unless criteria.nil? - a = a + row["total"].to_i if match == 1 - } unless data.nil? - a - end - -end diff --git a/redmine/app/helpers/roles_helper.rb b/redmine/app/helpers/roles_helper.rb deleted file mode 100644 index 8ae339053..000000000 --- a/redmine/app/helpers/roles_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module RolesHelper -end diff --git a/redmine/app/helpers/search_filter_helper.rb b/redmine/app/helpers/search_filter_helper.rb deleted file mode 100644 index f17ffeebf..000000000 --- a/redmine/app/helpers/search_filter_helper.rb +++ /dev/null @@ -1,106 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module SearchFilterHelper - - def search_filter_criteria(name, options = {}) - @search_filter ||= {} - @search_filter[name] ||= {} - @search_filter[name][:options] = [] - @search_filter[name][:conditions] = {} - yield.each { |c| - @search_filter[name][:options] << [c[0], c[1].to_s] - @search_filter[name][:conditions].store(c[1].to_s, c[2]) - } - end - - def search_filter_update - session[:search_filter] ||= {} - @search_filter.each_key {|field| session[:search_filter][field] = params[field] } - end - - def search_filter_clause - session[:search_filter] ||= {} - clause = ["1=1"] - @search_filter.each { |k, v| - filter_value = session[:search_filter][k] || v[:options][0][1] - if v[:conditions][filter_value] - clause[0] = clause[0] + " AND " + v[:conditions][filter_value].first - clause += v[:conditions][filter_value][1..-1] - end - } - clause - end - - def search_filter_tag(criteria, options = {}) - session[:search_filter] ||= {} - options[:name] = criteria - options[:class] += " active-filter" if session[:search_filter][criteria] and session[:search_filter][criteria] != @search_filter[criteria][:options][0][1] - content_tag("select", - options_for_select(@search_filter[criteria][:options], session[:search_filter][criteria]), - options - ) - end - - def search_filter_init_list_issues - search_filter_criteria('status_id') { - [ [('['+l(:label_open_issues_plural)+']'), "O", ["issue_statuses.is_closed=?", false]], - [('['+l(:label_closed_issues_plural)+']'), "C", ["issue_statuses.is_closed=?", true]], - [('['+l(:label_all)+']'), "A", nil] - ] + IssueStatus.find(:all).collect {|s| [s.name, s.id, ["issues.status_id=?", s.id]] } - } - - search_filter_criteria('tracker_id') { - [ [('['+l(:label_all)+']'), "A", nil] - ] + Tracker.find(:all).collect {|s| [s.name, s.id, ["issues.tracker_id=?", s.id]] } - } - - search_filter_criteria('priority_id') { - [ [('['+l(:label_all)+']'), "A", nil] - ] + Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect {|s| [s.name, s.id, ["issues.priority_id=?", s.id]] } - } - - search_filter_criteria('category_id') { - [ [('['+l(:label_all)+']'), "A", nil], - [('['+l(:label_none)+']'), "N", ["issues.category_id is null"]] - ] + @project.issue_categories.find(:all).collect {|s| [s.name, s.id, ["issues.category_id=?", s.id]] } - } - - search_filter_criteria('fixed_version_id') { - [ [('['+l(:label_all)+']'), "A", nil], - [('['+l(:label_none)+']'), "N", ["issues.fixed_version_id is null"]] - ] + @project.versions.collect {|s| [s.name, s.id, ["issues.fixed_version_id=?", s.id]] } - } - - search_filter_criteria('author_id') { - [ [('['+l(:label_all)+']'), "A", nil], - ] + @project.users.collect {|s| [s.display_name, s.id, ["issues.author_id=?", s.id]] } - } - - search_filter_criteria('assigned_to_id') { - [ [('['+l(:label_all)+']'), "A", nil], - [('['+l(:label_none)+']'), "N", ["issues.assigned_to_id is null"]] - ] + @project.users.collect {|s| [s.display_name, s.id, ["issues.assigned_to_id=?", s.id]] } - } - - search_filter_criteria('subproject_id') { - [ [('['+l(:label_none)+']'), "N", ["issues.project_id=?", @project.id]], - [('['+l(:label_all)+']'), "A", ["(issues.project_id=? or projects.parent_id=?)", @project.id, @project.id]] - ] - } - end -end \ No newline at end of file diff --git a/redmine/app/helpers/sort_helper.rb b/redmine/app/helpers/sort_helper.rb deleted file mode 100644 index 04a84c8e4..000000000 --- a/redmine/app/helpers/sort_helper.rb +++ /dev/null @@ -1,160 +0,0 @@ -# Helpers to sort tables using clickable column headers. -# -# Author: Stuart Rackham , March 2005. -# License: This source code is released under the MIT license. -# -# - Consecutive clicks toggle the column's sort order. -# - Sort state is maintained by a session hash entry. -# - Icon image identifies sort column and state. -# - Typically used in conjunction with the Pagination module. -# -# Example code snippets: -# -# Controller: -# -# helper :sort -# include SortHelper -# -# def list -# sort_init 'last_name' -# sort_update -# @items = Contact.find_all nil, sort_clause -# end -# -# Controller (using Pagination module): -# -# helper :sort -# include SortHelper -# -# def list -# sort_init 'last_name' -# sort_update -# @contact_pages, @items = paginate :contacts, -# :order_by => sort_clause, -# :per_page => 10 -# end -# -# View (table header in list.rhtml): -# -# -# -# <%= sort_header_tag('id', :title => 'Sort by contact ID') %> -# <%= sort_header_tag('last_name', :caption => 'Name') %> -# <%= sort_header_tag('phone') %> -# <%= sort_header_tag('address', :width => 200) %> -# -# -# -# - The ascending and descending sort icon images are sort_asc.png and -# sort_desc.png and reside in the application's images directory. -# - Introduces instance variables: @sort_name, @sort_default. -# - Introduces params :sort_key and :sort_order. -# -module SortHelper - - # Initializes the default sort column (default_key) and sort order - # (default_order). - # - # - default_key is a column attribute name. - # - default_order is 'asc' or 'desc'. - # - name is the name of the session hash entry that stores the sort state, - # defaults to '_sort'. - # - def sort_init(default_key, default_order='asc', name=nil) - @sort_name = name || @params[:controller] + @params[:action] + '_sort' - @sort_default = {:key => default_key, :order => default_order} - end - - # Updates the sort state. Call this in the controller prior to calling - # sort_clause. - # - def sort_update() - if @params[:sort_key] - sort = {:key => @params[:sort_key], :order => @params[:sort_order]} - elsif @session[@sort_name] - sort = @session[@sort_name] # Previous sort. - else - sort = @sort_default - end - @session[@sort_name] = sort - end - - # Returns an SQL sort clause corresponding to the current sort state. - # Use this to sort the controller's table items collection. - # - def sort_clause() - @session[@sort_name][:key] + ' ' + @session[@sort_name][:order] - end - - # Returns a link which sorts by the named column. - # - # - column is the name of an attribute in the sorted record collection. - # - The optional caption explicitly specifies the displayed link text. - # - A sort icon image is positioned to the right of the sort link. - # - def sort_link(column, caption=nil) - key, order = @session[@sort_name][:key], @session[@sort_name][:order] - if key == column - if order.downcase == 'asc' - icon = 'sort_asc' - order = 'desc' - else - icon = 'sort_desc' - order = 'asc' - end - else - icon = nil - order = 'desc' # changed for desc order by default - end - caption = titleize(Inflector::humanize(column)) unless caption - params = {:params => {:sort_key => column, :sort_order => order}} - link_to_remote(caption, - {:update => "content", :url => { :sort_key => column, :sort_order => order}}, - {:href => url_for(:params => { :sort_key => column, :sort_order => order})}) + - (icon ? nbsp(2) + image_tag(icon) : '') - end - - # Returns a table header tag with a sort link for the named column - # attribute. - # - # Options: - # :caption The displayed link name (defaults to titleized column name). - # :title The tag's 'title' attribute (defaults to 'Sort by :caption'). - # - # Other options hash entries generate additional table header tag attributes. - # - # Example: - # - # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %> - # - # Renders: - # - # - # Id - #   Sort_asc - # - # - def sort_header_tag(column, options = {}) - if options[:caption] - caption = options[:caption] - options.delete(:caption) - else - caption = titleize(Inflector::humanize(column)) - end - options[:title]= "Sort by #{caption}" unless options[:title] - content_tag('th', sort_link(column, caption), options) - end - - private - - # Return n non-breaking spaces. - def nbsp(n) - ' ' * n - end - - # Return capitalized title. - def titleize(title) - title.split.map {|w| w.capitalize }.join(' ') - end - -end diff --git a/redmine/app/helpers/trackers_helper.rb b/redmine/app/helpers/trackers_helper.rb deleted file mode 100644 index 839327efe..000000000 --- a/redmine/app/helpers/trackers_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module TrackersHelper -end diff --git a/redmine/app/helpers/users_helper.rb b/redmine/app/helpers/users_helper.rb deleted file mode 100644 index 035db3d00..000000000 --- a/redmine/app/helpers/users_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module UsersHelper -end diff --git a/redmine/app/helpers/versions_helper.rb b/redmine/app/helpers/versions_helper.rb deleted file mode 100644 index e2724fe84..000000000 --- a/redmine/app/helpers/versions_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module VersionsHelper -end diff --git a/redmine/app/helpers/welcome_helper.rb b/redmine/app/helpers/welcome_helper.rb deleted file mode 100644 index cace5f542..000000000 --- a/redmine/app/helpers/welcome_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module WelcomeHelper -end diff --git a/redmine/app/models/attachment.rb b/redmine/app/models/attachment.rb deleted file mode 100644 index 2e1e9b156..000000000 --- a/redmine/app/models/attachment.rb +++ /dev/null @@ -1,81 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require "digest/md5" - -class Attachment < ActiveRecord::Base - belongs_to :container, :polymorphic => true - belongs_to :author, :class_name => "User", :foreign_key => "author_id" - - validates_presence_of :filename - - def file=(incomming_file) - unless incomming_file.nil? - @temp_file = incomming_file - if @temp_file.size > 0 - self.filename = sanitize_filename(@temp_file.original_filename) - self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename - self.content_type = @temp_file.content_type - self.filesize = @temp_file.size - end - end - end - - # Copy temp file to its final location - def before_save - if @temp_file && (@temp_file.size > 0) - logger.debug("saving '#{self.diskfile}'") - File.open(diskfile, "wb") do |f| - f.write(@temp_file.read) - end - self.digest = Digest::MD5.hexdigest(File.read(diskfile)) - end - end - - # Deletes file on the disk - def after_destroy - if self.filename? - File.delete(diskfile) if File.exist?(diskfile) - end - end - - # Returns file's location on disk - def diskfile - "#{$RDM_STORAGE_PATH}/#{self.disk_filename}" - end - - def increment_download - increment!(:downloads) - end - - # returns last created projects - def self.most_downloaded - find(:all, :limit => 5, :order => "downloads DESC") - end - -private - def sanitize_filename(value) - # get only the filename, not the whole path - just_filename = value.gsub(/^.*(\\|\/)/, '') - # NOTE: File.basename doesn't work right with Windows paths on Unix - # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/')) - - # Finally, replace all non alphanumeric, underscore or periods with underscore - @filename = just_filename.gsub(/[^\w\.\-]/,'_') - end - -end diff --git a/redmine/app/models/auth_source.rb b/redmine/app/models/auth_source.rb deleted file mode 100644 index 47eec106d..000000000 --- a/redmine/app/models/auth_source.rb +++ /dev/null @@ -1,47 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class AuthSource < ActiveRecord::Base - has_many :users - - validates_presence_of :name - validates_uniqueness_of :name - - def authenticate(login, password) - end - - def test_connection - end - - def auth_method_name - "Abstract" - end - - # Try to authenticate a user not yet registered against available sources - def self.authenticate(login, password) - AuthSource.find(:all, :conditions => ["onthefly_register=?", true]).each do |source| - begin - logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug? - attrs = source.authenticate(login, password) - rescue - attrs = nil - end - return attrs if attrs - end - return nil - end -end diff --git a/redmine/app/models/auth_source_ldap.rb b/redmine/app/models/auth_source_ldap.rb deleted file mode 100644 index 895cf1c63..000000000 --- a/redmine/app/models/auth_source_ldap.rb +++ /dev/null @@ -1,79 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'net/ldap' -require 'iconv' - -class AuthSourceLdap < AuthSource - validates_presence_of :host, :port, :attr_login - - def after_initialize - self.port = 389 if self.port == 0 - end - - def authenticate(login, password) - attrs = [] - # get user's DN - ldap_con = initialize_ldap_con(self.account, self.account_password) - login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) - object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) - dn = String.new - ldap_con.search( :base => self.base_dn, - :filter => object_filter & login_filter, - :attributes=> ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]) do |entry| - dn = entry.dn - attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname), - :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname), - :mail => AuthSourceLdap.get_attr(entry, self.attr_mail), - :auth_source_id => self.id ] - end - return nil if dn.empty? - logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug? - # authenticate user - ldap_con = initialize_ldap_con(dn, password) - return nil unless ldap_con.bind - # return user's attributes - logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? - attrs - rescue Net::LDAP::LdapError => text - raise "LdapError: " + text - end - - # test the connection to the LDAP - def test_connection - ldap_con = initialize_ldap_con(self.account, self.account_password) - ldap_con.open { } - rescue Net::LDAP::LdapError => text - raise "LdapError: " + text - end - - def auth_method_name - "LDAP" - end - -private - def initialize_ldap_con(ldap_user, ldap_password) - Net::LDAP.new( {:host => self.host, - :port => self.port, - :auth => { :method => :simple, :username => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_user), :password => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_password) }} - ) - end - - def self.get_attr(entry, attr_name) - entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] - end -end diff --git a/redmine/app/models/custom_field.rb b/redmine/app/models/custom_field.rb deleted file mode 100644 index 924a874a3..000000000 --- a/redmine/app/models/custom_field.rb +++ /dev/null @@ -1,42 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class CustomField < ActiveRecord::Base - has_many :custom_values, :dependent => true - - FIELD_FORMATS = { "list" => :label_list, - "date" => :label_date, - "bool" => :label_boolean, - "int" => :label_integer, - "string" => :label_string, - "text" => :label_text - }.freeze - - validates_presence_of :name, :field_format - validates_uniqueness_of :name - validates_inclusion_of :field_format, :in => FIELD_FORMATS.keys - validates_presence_of :possible_values, :if => Proc.new { |field| field.field_format == "list" } - - # to move in project_custom_field - def self.for_all - find(:all, :conditions => ["is_for_all=?", true]) - end - - def type_name - nil - end -end diff --git a/redmine/app/models/custom_value.rb b/redmine/app/models/custom_value.rb deleted file mode 100644 index 015ccd244..000000000 --- a/redmine/app/models/custom_value.rb +++ /dev/null @@ -1,38 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class CustomValue < ActiveRecord::Base - belongs_to :custom_field - belongs_to :customized, :polymorphic => true - -protected - def validate - errors.add(:value, :activerecord_error_blank) and return if custom_field.is_required? and value.empty? - errors.add(:value, :activerecord_error_invalid) unless custom_field.regexp.empty? or value =~ Regexp.new(custom_field.regexp) - errors.add(:value, :activerecord_error_too_short) if custom_field.min_length > 0 and value.length < custom_field.min_length and value.length > 0 - errors.add(:value, :activerecord_error_too_long) if custom_field.max_length > 0 and value.length > custom_field.max_length - case custom_field.field_format - when "int" - errors.add(:value, :activerecord_error_not_a_number) unless value =~ /^[0-9]*$/ - when "date" - errors.add(:value, :activerecord_error_not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ or value.empty? - when "list" - errors.add(:value, :activerecord_error_inclusion) unless custom_field.possible_values.split('|').include? value or value.empty? - end - end -end - diff --git a/redmine/app/models/document.rb b/redmine/app/models/document.rb deleted file mode 100644 index 08e0ef607..000000000 --- a/redmine/app/models/document.rb +++ /dev/null @@ -1,24 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Document < ActiveRecord::Base - belongs_to :project - belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id" - has_many :attachments, :as => :container, :dependent => true - - validates_presence_of :project, :title, :category -end diff --git a/redmine/app/models/enumeration.rb b/redmine/app/models/enumeration.rb deleted file mode 100644 index b5c8ed6e7..000000000 --- a/redmine/app/models/enumeration.rb +++ /dev/null @@ -1,46 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Enumeration < ActiveRecord::Base - before_destroy :check_integrity - - validates_presence_of :opt, :name - validates_uniqueness_of :name, :scope => [:opt] - - OPTIONS = { - "IPRI" => :enumeration_issue_priorities, - "DCAT" => :enumeration_doc_categories - }.freeze - - def self.get_values(option) - find(:all, :conditions => ['opt=?', option]) - end - - def option_name - OPTIONS[self.opt] - end - -private - def check_integrity - case self.opt - when "IPRI" - raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id]) - when "DCAT" - raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id]) - end - end -end diff --git a/redmine/app/models/issue.rb b/redmine/app/models/issue.rb deleted file mode 100644 index f00eb7a9c..000000000 --- a/redmine/app/models/issue.rb +++ /dev/null @@ -1,103 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Issue < ActiveRecord::Base - - belongs_to :project - belongs_to :tracker - belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' - belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' - belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' - belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' - belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id' - belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' - - #has_many :histories, :class_name => 'IssueHistory', :dependent => true, :order => "issue_histories.created_on DESC", :include => :status - has_many :journals, :as => :journalized, :dependent => true - has_many :attachments, :as => :container, :dependent => true - - has_many :custom_values, :dependent => true, :as => :customized - has_many :custom_fields, :through => :custom_values - - validates_presence_of :subject, :description, :priority, :tracker, :author, :status - validates_inclusion_of :done_ratio, :in => 0..100 - validates_associated :custom_values, :on => :update - - # set default status for new issues - def before_validation - self.status = IssueStatus.default if new_record? - end - - def validate - if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty? - errors.add :due_date, :activerecord_error_not_a_date - end - - if self.due_date and self.start_date and self.due_date < self.start_date - errors.add :due_date, :activerecord_error_greater_than_start_date - end - end - - #def before_create - # build_history - #end - - def before_save - if @current_journal - # attributes changes - (Issue.column_names - %w(id description)).each {|c| - @current_journal.details << JournalDetail.new(:property => 'attr', - :prop_key => c, - :old_value => @issue_before_change.send(c), - :value => send(c)) unless send(c)==@issue_before_change.send(c) - } - # custom fields changes - custom_values.each {|c| - @current_journal.details << JournalDetail.new(:property => 'cf', - :prop_key => c.custom_field_id, - :old_value => @custom_values_before_change[c.custom_field_id], - :value => c.value) unless @custom_values_before_change[c.custom_field_id]==c.value - } - @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty? - end - end - - def long_id - "%05d" % self.id - end - - def custom_value_for(custom_field) - self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id } - return nil - end - - def init_journal(user, notes = "") - @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) - @issue_before_change = self.clone - @custom_values_before_change = {} - self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } - @current_journal - end - -private - # Creates an history for the issue - #def build_history - # @history = self.histories.build - # @history.status = self.status - # @history.author = self.author - #end -end diff --git a/redmine/app/models/issue_category.rb b/redmine/app/models/issue_category.rb deleted file mode 100644 index 74adb8f52..000000000 --- a/redmine/app/models/issue_category.rb +++ /dev/null @@ -1,29 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueCategory < ActiveRecord::Base - before_destroy :check_integrity - belongs_to :project - - validates_presence_of :name - validates_uniqueness_of :name, :scope => [:project_id] - -private - def check_integrity - raise "Can't delete category" if Issue.find(:first, :conditions => ["category_id=?", self.id]) - end -end diff --git a/redmine/app/models/issue_custom_field.rb b/redmine/app/models/issue_custom_field.rb deleted file mode 100644 index 209ae206b..000000000 --- a/redmine/app/models/issue_custom_field.rb +++ /dev/null @@ -1,27 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueCustomField < CustomField - has_and_belongs_to_many :projects, :join_table => "custom_fields_projects", :foreign_key => "custom_field_id" - has_and_belongs_to_many :trackers, :join_table => "custom_fields_trackers", :foreign_key => "custom_field_id" - has_many :issues, :through => :issue_custom_values - - def type_name - :label_issue_plural - end -end - diff --git a/redmine/app/models/issue_history.rb b/redmine/app/models/issue_history.rb deleted file mode 100644 index 4b6682600..000000000 --- a/redmine/app/models/issue_history.rb +++ /dev/null @@ -1,24 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueHistory < ActiveRecord::Base - belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' - belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' - belongs_to :issue - - validates_presence_of :status -end diff --git a/redmine/app/models/issue_status.rb b/redmine/app/models/issue_status.rb deleted file mode 100644 index c8a40d330..000000000 --- a/redmine/app/models/issue_status.rb +++ /dev/null @@ -1,49 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueStatus < ActiveRecord::Base - before_destroy :check_integrity - has_many :workflows, :foreign_key => "old_status_id" - - validates_presence_of :name - validates_uniqueness_of :name - validates_length_of :html_color, :is => 6 - validates_format_of :html_color, :with => /^[a-f0-9]*$/i - - def before_save - IssueStatus.update_all "is_default=false" if self.is_default? - end - - # Returns the default status for new issues - def self.default - find(:first, :conditions =>["is_default=?", true]) - end - - # Returns an array of all statuses the given role can switch to - def new_statuses_allowed_to(role, tracker) - statuses = [] - for workflow in self.workflows - statuses << workflow.new_status if workflow.role_id == role.id and workflow.tracker_id == tracker.id - end unless role.nil? or tracker.nil? - statuses - end - -private - def check_integrity - raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id]) or IssueHistory.find(:first, :conditions => ["status_id=?", self.id]) - end -end diff --git a/redmine/app/models/journal.rb b/redmine/app/models/journal.rb deleted file mode 100644 index 9d173552f..000000000 --- a/redmine/app/models/journal.rb +++ /dev/null @@ -1,22 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Journal < ActiveRecord::Base - belongs_to :journalized, :polymorphic => true - belongs_to :user - has_many :details, :class_name => "JournalDetail", :dependent => true -end diff --git a/redmine/app/models/journal_detail.rb b/redmine/app/models/journal_detail.rb deleted file mode 100644 index 784e98bf7..000000000 --- a/redmine/app/models/journal_detail.rb +++ /dev/null @@ -1,20 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class JournalDetail < ActiveRecord::Base - belongs_to :journal -end diff --git a/redmine/app/models/mailer.rb b/redmine/app/models/mailer.rb deleted file mode 100644 index 07047c594..000000000 --- a/redmine/app/models/mailer.rb +++ /dev/null @@ -1,53 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Mailer < ActionMailer::Base - - helper IssuesHelper - - def issue_add(issue) - # Sends to all project members - @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification } - @from = $RDM_MAIL_FROM - @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" - @body['issue'] = issue - end - - def issue_edit(journal) - # Sends to all project members - issue = journal.journalized - @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification } - @from = $RDM_MAIL_FROM - @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" - @body['issue'] = issue - @body['journal']= journal - end - - def lost_password(token) - @recipients = token.user.mail - @from = $RDM_MAIL_FROM - @subject = l(:mail_subject_lost_password) - @body['token'] = token - end - - def register(token) - @recipients = token.user.mail - @from = $RDM_MAIL_FROM - @subject = l(:mail_subject_register) - @body['token'] = token - end -end diff --git a/redmine/app/models/member.rb b/redmine/app/models/member.rb deleted file mode 100644 index 1214b6443..000000000 --- a/redmine/app/models/member.rb +++ /dev/null @@ -1,29 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Member < ActiveRecord::Base - belongs_to :user - belongs_to :role - belongs_to :project - - validates_presence_of :role, :user, :project - validates_uniqueness_of :user_id, :scope => :project_id - - def name - self.user.display_name - end -end diff --git a/redmine/app/models/news.rb b/redmine/app/models/news.rb deleted file mode 100644 index faafa7eef..000000000 --- a/redmine/app/models/news.rb +++ /dev/null @@ -1,28 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class News < ActiveRecord::Base - belongs_to :project - belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' - - validates_presence_of :title, :description - - # returns last created news - def self.latest - find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC") - end -end diff --git a/redmine/app/models/permission.rb b/redmine/app/models/permission.rb deleted file mode 100644 index 620974608..000000000 --- a/redmine/app/models/permission.rb +++ /dev/null @@ -1,63 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Permission < ActiveRecord::Base - has_and_belongs_to_many :roles - - validates_presence_of :controller, :action, :description - - GROUPS = { - 100 => :label_project, - 200 => :label_member_plural, - 300 => :label_version_plural, - 400 => :label_issue_category_plural, - 1000 => :label_issue_plural, - 1100 => :label_news_plural, - 1200 => :label_document_plural, - 1300 => :label_attachment_plural, - }.freeze - - @@cached_perms_for_public = nil - @@cached_perms_for_roles = nil - - def name - self.controller + "/" + self.action - end - - def group_id - (self.sort / 100)*100 - end - - def self.allowed_to_public(action) - @@cached_perms_for_public ||= find(:all, :conditions => ["is_public=?", true]).collect {|p| "#{p.controller}/#{p.action}"} - @@cached_perms_for_public.include? action - end - - def self.allowed_to_role(action, role) - @@cached_perms_for_roles ||= - begin - perms = {} - find(:all, :include => :roles).each {|p| perms.store "#{p.controller}/#{p.action}", p.roles.collect {|r| r.id } } - perms - end - @@cached_perms_for_roles[action] and @@cached_perms_for_roles[action].include? role - end - - def self.allowed_to_role_expired - @@cached_perms_for_roles = nil - end -end diff --git a/redmine/app/models/project.rb b/redmine/app/models/project.rb deleted file mode 100644 index ae7436910..000000000 --- a/redmine/app/models/project.rb +++ /dev/null @@ -1,57 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Project < ActiveRecord::Base - has_many :versions, :dependent => true, :order => "versions.effective_date DESC, versions.name DESC" - has_many :members, :dependent => true - has_many :users, :through => :members - has_many :custom_values, :dependent => true, :as => :customized - has_many :issues, :dependent => true, :order => "issues.created_on DESC", :include => :status - has_many :documents, :dependent => true - has_many :news, :dependent => true, :include => :author - has_many :issue_categories, :dependent => true, :order => "issue_categories.name" - has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_projects', :association_foreign_key => 'custom_field_id' - acts_as_tree :order => "name", :counter_cache => true - - validates_presence_of :name, :description - validates_uniqueness_of :name - validates_associated :custom_values, :on => :update - - # returns 5 last created projects - def self.latest - find(:all, :limit => 5, :order => "created_on DESC") - end - - # Returns an array of all custom fields enabled for project issues - # (explictly associated custom fields and custom fields enabled for all projects) - def custom_fields_for_issues(tracker) - tracker.custom_fields.find(:all, :include => :projects, - :conditions => ["is_for_all=? or project_id=?", true, self.id]) - #(CustomField.for_all + custom_fields).uniq - end - - def all_custom_fields - @all_custom_fields ||= IssueCustomField.find(:all, :include => :projects, - :conditions => ["is_for_all=? or project_id=?", true, self.id]) - end - -protected - def validate - errors.add(parent_id, " must be a root project") if parent and parent.parent - errors.add_to_base("A project with subprojects can't be a subproject") if parent and projects_count > 0 - end -end diff --git a/redmine/app/models/project_custom_field.rb b/redmine/app/models/project_custom_field.rb deleted file mode 100644 index baa533812..000000000 --- a/redmine/app/models/project_custom_field.rb +++ /dev/null @@ -1,22 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class ProjectCustomField < CustomField - def type_name - :label_project_plural - end -end diff --git a/redmine/app/models/role.rb b/redmine/app/models/role.rb deleted file mode 100644 index 6908095e9..000000000 --- a/redmine/app/models/role.rb +++ /dev/null @@ -1,31 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Role < ActiveRecord::Base - before_destroy :check_integrity - has_and_belongs_to_many :permissions - has_many :workflows, :dependent => true - has_many :members - - validates_presence_of :name - validates_uniqueness_of :name - -private - def check_integrity - raise "Can't delete role" if Member.find(:first, :conditions =>["role_id=?", self.id]) - end -end diff --git a/redmine/app/models/token.rb b/redmine/app/models/token.rb deleted file mode 100644 index 98745d29e..000000000 --- a/redmine/app/models/token.rb +++ /dev/null @@ -1,44 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Token < ActiveRecord::Base - belongs_to :user - - @@validity_time = 1.day - - def before_create - self.value = Token.generate_token_value - end - - # Return true if token has expired - def expired? - return Time.now > self.created_on + @@validity_time - end - - # Delete all expired tokens - def self.destroy_expired - Token.delete_all ["created_on < ?", Time.now - @@validity_time] - end - -private - def self.generate_token_value - chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a - token_value = '' - 40.times { |i| token_value << chars[rand(chars.size-1)] } - token_value - end -end diff --git a/redmine/app/models/tracker.rb b/redmine/app/models/tracker.rb deleted file mode 100644 index a4376a351..000000000 --- a/redmine/app/models/tracker.rb +++ /dev/null @@ -1,31 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Tracker < ActiveRecord::Base - before_destroy :check_integrity - has_many :issues - has_many :workflows, :dependent => true - has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_trackers', :association_foreign_key => 'custom_field_id' - - validates_presence_of :name - validates_uniqueness_of :name - -private - def check_integrity - raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id]) - end -end diff --git a/redmine/app/models/user.rb b/redmine/app/models/user.rb deleted file mode 100644 index a82c98a88..000000000 --- a/redmine/app/models/user.rb +++ /dev/null @@ -1,129 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require "digest/sha1" - -class User < ActiveRecord::Base - has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => true - has_many :projects, :through => :memberships - has_many :custom_values, :dependent => true, :as => :customized - has_one :preference, :dependent => true, :class_name => 'UserPreference' - belongs_to :auth_source - - attr_accessor :password, :password_confirmation - attr_accessor :last_before_login_on - # Prevents unauthorized assignments - attr_protected :login, :admin, :password, :password_confirmation, :hashed_password - - validates_presence_of :login, :firstname, :lastname, :mail - validates_uniqueness_of :login, :mail - # Login must contain lettres, numbers, underscores only - validates_format_of :login, :with => /^[a-z0-9_]+$/i - validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i - # Password length between 4 and 12 - validates_length_of :password, :in => 4..12, :allow_nil => true - validates_confirmation_of :password, :allow_nil => true - validates_associated :custom_values, :on => :update - - # Account statuses - STATUS_ACTIVE = 1 - STATUS_REGISTERED = 2 - STATUS_LOCKED = 3 - - def before_save - # update hashed_password if password was set - self.hashed_password = User.hash_password(self.password) if self.password - end - - # Returns the user that matches provided login and password, or nil - def self.try_to_login(login, password) - user = find(:first, :conditions => ["login=?", login]) - if user - # user is already in local database - return nil if !user.active? - if user.auth_source - # user has an external authentication method - return nil unless user.auth_source.authenticate(login, password) - else - # authentication with local password - return nil unless User.hash_password(password) == user.hashed_password - end - else - # user is not yet registered, try to authenticate with available sources - attrs = AuthSource.authenticate(login, password) - if attrs - onthefly = new(*attrs) - onthefly.login = login - onthefly.language = $RDM_DEFAULT_LANG - if onthefly.save - user = find(:first, :conditions => ["login=?", login]) - logger.info("User '#{user.login}' created on the fly.") if logger - end - end - end - user.update_attribute(:last_login_on, Time.now) if user - user - - rescue => text - raise text - end - - # Return user's full name for display - def display_name - firstname + " " + lastname - end - - def name - display_name - end - - def active? - self.status == STATUS_ACTIVE - end - - def registered? - self.status == STATUS_REGISTERED - end - - def locked? - self.status == STATUS_LOCKED - end - - def check_password?(clear_password) - User.hash_password(clear_password) == self.hashed_password - end - - def role_for_project(project_id) - @role_for_projects ||= - begin - roles = {} - self.memberships.each { |m| roles.store m.project_id, m.role_id } - roles - end - @role_for_projects[project_id] - end - - def pref - self.preference ||= UserPreference.new(:user => self) - end - -private - # Return password digest - def self.hash_password(clear_password) - Digest::SHA1.hexdigest(clear_password || "") - end -end diff --git a/redmine/app/models/user_custom_field.rb b/redmine/app/models/user_custom_field.rb deleted file mode 100644 index 866234a7f..000000000 --- a/redmine/app/models/user_custom_field.rb +++ /dev/null @@ -1,23 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class UserCustomField < CustomField - def type_name - :label_user_plural - end -end - diff --git a/redmine/app/models/user_preference.rb b/redmine/app/models/user_preference.rb deleted file mode 100644 index 5240c9757..000000000 --- a/redmine/app/models/user_preference.rb +++ /dev/null @@ -1,44 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class UserPreference < ActiveRecord::Base - belongs_to :user - serialize :others, Hash - - attr_protected :others - - def initialize(attributes = nil) - super - self.others ||= {} - end - - def [](attr_name) - if attribute_present? attr_name - super - else - others[attr_name] - end - end - - def []=(attr_name, value) - if attribute_present? attr_name - super - else - others.store attr_name, value - end - end -end diff --git a/redmine/app/models/version.rb b/redmine/app/models/version.rb deleted file mode 100644 index 0ae1edda8..000000000 --- a/redmine/app/models/version.rb +++ /dev/null @@ -1,32 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Version < ActiveRecord::Base - before_destroy :check_integrity - belongs_to :project - has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id' - has_many :attachments, :as => :container, :dependent => true - - validates_presence_of :name - validates_uniqueness_of :name, :scope => [:project_id] - validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date - -private - def check_integrity - raise "Can't delete version" if self.fixed_issues.find(:first) - end -end diff --git a/redmine/app/models/workflow.rb b/redmine/app/models/workflow.rb deleted file mode 100644 index 22c873fc7..000000000 --- a/redmine/app/models/workflow.rb +++ /dev/null @@ -1,24 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Workflow < ActiveRecord::Base - belongs_to :role - belongs_to :old_status, :class_name => 'IssueStatus', :foreign_key => 'old_status_id' - belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id' - - validates_presence_of :role, :old_status, :new_status -end diff --git a/redmine/app/views/account/login.rhtml b/redmine/app/views/account/login.rhtml deleted file mode 100644 index 74c075516..000000000 --- a/redmine/app/views/account/login.rhtml +++ /dev/null @@ -1,18 +0,0 @@ -
    - -
    \ No newline at end of file diff --git a/redmine/app/views/account/lost_password.rhtml b/redmine/app/views/account/lost_password.rhtml deleted file mode 100644 index 3f32e7153..000000000 --- a/redmine/app/views/account/lost_password.rhtml +++ /dev/null @@ -1,14 +0,0 @@ -
    - -
    \ No newline at end of file diff --git a/redmine/app/views/account/password_recovery.rhtml b/redmine/app/views/account/password_recovery.rhtml deleted file mode 100644 index 39a8071a9..000000000 --- a/redmine/app/views/account/password_recovery.rhtml +++ /dev/null @@ -1,21 +0,0 @@ -
    - -
    \ No newline at end of file diff --git a/redmine/app/views/account/register.rhtml b/redmine/app/views/account/register.rhtml deleted file mode 100644 index b34aff79c..000000000 --- a/redmine/app/views/account/register.rhtml +++ /dev/null @@ -1,39 +0,0 @@ -

    <%=l(:label_register)%>

    - -<%= start_form_tag({:action => 'register'}, :class => "tabular") %> -<%= error_messages_for 'user' %> - -
    - -

    -<%= text_field 'user', 'login', :size => 25 %>

    - -

    -<%= password_field_tag 'password', nil, :size => 25 %>

    - -

    -<%= password_field_tag 'password_confirmation', nil, :size => 25 %>

    - -

    -<%= text_field 'user', 'firstname' %>

    - -

    -<%= text_field 'user', 'lastname' %>

    - -

    -<%= text_field 'user', 'mail' %>

    - -

    -<%= select("user", "language", lang_options_for_select) %>

    - -<% for @custom_value in @custom_values %> -

    <%= custom_field_tag_with_label @custom_value %>

    -<% end %> - -

    -<%= check_box 'user', 'mail_notification' %>

    - -
    - -<%= submit_tag l(:button_submit) %> -<%= end_form_tag %> diff --git a/redmine/app/views/account/show.rhtml b/redmine/app/views/account/show.rhtml deleted file mode 100644 index 985238951..000000000 --- a/redmine/app/views/account/show.rhtml +++ /dev/null @@ -1,26 +0,0 @@ -

    <%= @user.display_name %>

    - -

    -<%= mail_to @user.mail unless @user.pref.hide_mail %> -

      -
    • <%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %>
    • -<% for custom_value in @custom_values %> -<% if !custom_value.value.empty? %> -
    • <%= custom_value.custom_field.name%>: <%= show_value(custom_value) %>
    • -<% end %> -<% end %> -
    -

    - -

    <%=l(:label_project_plural)%>

    -

    -<% for membership in @user.memberships %> - <%= membership.project.name %> (<%= membership.role.name %>, <%= format_date(membership.created_on) %>) -
    -<% end %> -

    - -

    <%=l(:label_activity)%>

    -

    -<%=l(:label_reported_issues)%>: <%= Issue.count(["author_id=?", @user.id]) %> -

    \ No newline at end of file diff --git a/redmine/app/views/admin/index.rhtml b/redmine/app/views/admin/index.rhtml deleted file mode 100644 index d937e287c..000000000 --- a/redmine/app/views/admin/index.rhtml +++ /dev/null @@ -1,50 +0,0 @@ -

    <%=l(:label_administration)%>

    - -

    -<%= image_tag "projects" %> -<%= link_to l(:label_project_plural), :controller => 'admin', :action => 'projects' %> | -<%= link_to l(:label_new), :controller => 'projects', :action => 'add' %> -

    - -

    -<%= image_tag "users" %> -<%= link_to l(:label_user_plural), :controller => 'users' %> | -<%= link_to l(:label_new), :controller => 'users', :action => 'add' %> -

    - -

    -<%= image_tag "role" %> -<%= link_to l(:label_role_and_permissions), :controller => 'roles' %> -

    - -

    -<%= image_tag "tracker" %> -<%= link_to l(:label_tracker_plural), :controller => 'trackers' %> | -<%= link_to l(:label_custom_field_plural), :controller => 'custom_fields' %> -

    - -

    -<%= image_tag "workflow" %> -<%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses' %> | -<%= link_to l(:label_workflow), :controller => 'roles', :action => 'workflow' %> -

    - -

    -<%= image_tag "options" %> -<%= link_to l(:label_enumerations), :controller => 'enumerations' %> -

    - -

    -<%= image_tag "mailer" %> -<%= link_to l(:field_mail_notification), :controller => 'admin', :action => 'mail_options' %> -

    - -

    -<%= image_tag "login" %> -<%= link_to l(:label_authentication), :controller => 'auth_sources' %> -

    - -

    -<%= image_tag "help" %> -<%= link_to l(:label_information_plural), :controller => 'admin', :action => 'info' %> -

    \ No newline at end of file diff --git a/redmine/app/views/admin/info.rhtml b/redmine/app/views/admin/info.rhtml deleted file mode 100644 index 4777a151e..000000000 --- a/redmine/app/views/admin/info.rhtml +++ /dev/null @@ -1,10 +0,0 @@ -

    <%=l(:label_information_plural)%>

    - -

    <%=l(:field_version)%>: <%= RDM_APP_NAME %> <%= RDM_APP_VERSION %>

    - -<%=l(:label_environment)%>: -
      -<% Rails::Info.properties.each do |name, value| %> -
    • <%= name %>: <%= value %>
    • -<% end %> -
    \ No newline at end of file diff --git a/redmine/app/views/admin/mail_options.rhtml b/redmine/app/views/admin/mail_options.rhtml deleted file mode 100644 index 54e2daf3e..000000000 --- a/redmine/app/views/admin/mail_options.rhtml +++ /dev/null @@ -1,24 +0,0 @@ -

    <%=l(:field_mail_notification)%>

    - -<%= start_form_tag ({}, :id => 'mail_options_form')%> - -
    -

    <%=l(:text_select_mail_notifications)%>

    - -<% actions = @actions.group_by {|p| p.group_id } %> -<% actions.keys.sort.each do |group_id| %> -
    <%= l(Permission::GROUPS[group_id]) %> -<% actions[group_id].each do |p| %> -
    <%= check_box_tag "action_ids[]", p.id, p.mail_enabled? %> - <%= l(p.description.to_sym) %> -
    -<% end %> -
    -<% end %> - -
    -

    <%= check_all_links 'mail_options_form' %>

    -
    - -<%= submit_tag l(:button_save) %> -<%= end_form_tag %> diff --git a/redmine/app/views/admin/projects.rhtml b/redmine/app/views/admin/projects.rhtml deleted file mode 100644 index 39e4d9bf7..000000000 --- a/redmine/app/views/admin/projects.rhtml +++ /dev/null @@ -1,30 +0,0 @@ -

    <%=l(:label_project_plural)%>

    - - - - <%= sort_header_tag('name', :caption => l(:label_project)) %> - - - - <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> - - - -<% for project in @projects %> - "> - - -<% end %> -
    <%=l(:field_description)%><%=l(:field_is_public)%><%=l(:label_subproject_plural)%>
    <%= link_to project.name, :controller => 'projects', :action => 'settings', :id => project %> - <%= project.description %> - <%= image_tag 'true' if project.is_public? %> - <%= project.projects_count %> - <%= format_date(project.created_on) %> - - <%= button_to l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => "button-small" %> -
    - -

    <%= pagination_links_full @project_pages %> -[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ]

    - -

    <%= link_to ('» ' + l(:label_project_new)), :controller => 'projects', :action => 'add' %>

    \ No newline at end of file diff --git a/redmine/app/views/auth_sources/_form.rhtml b/redmine/app/views/auth_sources/_form.rhtml deleted file mode 100644 index b6365dce5..000000000 --- a/redmine/app/views/auth_sources/_form.rhtml +++ /dev/null @@ -1,45 +0,0 @@ -<%= error_messages_for 'auth_source' %> - -
    - -

    -<%= text_field 'auth_source', 'name' %>

    - -

    -<%= text_field 'auth_source', 'host' %>

    - -

    -<%= text_field 'auth_source', 'port', :size => 6 %>

    - -

    -<%= text_field 'auth_source', 'account' %>

    - -

    -<%= password_field 'auth_source', 'account_password' %>

    - -

    -<%= text_field 'auth_source', 'base_dn', :size => 60 %>

    -
    - -
    -

    -<%= check_box 'auth_source', 'onthefly_register' %>

    - -

    -

    <%=l(:label_attribute_plural)%> -

    -<%= text_field 'auth_source', 'attr_login', :size => 20 %>

    - -

    -<%= text_field 'auth_source', 'attr_firstname', :size => 20 %>

    - -

    -<%= text_field 'auth_source', 'attr_lastname', :size => 20 %>

    - -

    -<%= text_field 'auth_source', 'attr_mail', :size => 20 %>

    -
    -

    -
    - - diff --git a/redmine/app/views/auth_sources/edit.rhtml b/redmine/app/views/auth_sources/edit.rhtml deleted file mode 100644 index 149463e7f..000000000 --- a/redmine/app/views/auth_sources/edit.rhtml +++ /dev/null @@ -1,7 +0,0 @@ -

    <%=l(:label_auth_source)%> (<%= @auth_source.auth_method_name %>)

    - -<%= start_form_tag({:action => 'update', :id => @auth_source}, :class => "tabular") %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<%= end_form_tag %> - diff --git a/redmine/app/views/auth_sources/list.rhtml b/redmine/app/views/auth_sources/list.rhtml deleted file mode 100644 index 47cbeeaff..000000000 --- a/redmine/app/views/auth_sources/list.rhtml +++ /dev/null @@ -1,30 +0,0 @@ -

    <%=l(:label_auth_source_plural)%>

    - - - - - - - - - - -<% for source in @auth_sources %> - "> - - - - - - -<% end %> -
    <%=l(:field_name)%><%=l(:field_type)%><%=l(:field_host)%>
    <%= link_to source.name, :action => 'edit', :id => source%><%= source.auth_method_name %><%= source.host %> - <%= link_to l(:button_test), :action => 'test_connection', :id => source %> - - <%= button_to l(:button_delete), { :action => 'destroy', :id => source }, :confirm => l(:text_are_you_sure), :class => "button-small" %> -
    - -<%= pagination_links_full @auth_source_pages %> -
    -<%= link_to '» ' + l(:label_auth_source_new), :action => 'new' %> - diff --git a/redmine/app/views/auth_sources/new.rhtml b/redmine/app/views/auth_sources/new.rhtml deleted file mode 100644 index 29d66327b..000000000 --- a/redmine/app/views/auth_sources/new.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_auth_source_new)%> (<%= @auth_source.auth_method_name %>)

    - -<%= start_form_tag({:action => 'create'}, :class => "tabular") %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_create) %> -<%= end_form_tag %> diff --git a/redmine/app/views/custom_fields/_form.rhtml b/redmine/app/views/custom_fields/_form.rhtml deleted file mode 100644 index f7f968e33..000000000 --- a/redmine/app/views/custom_fields/_form.rhtml +++ /dev/null @@ -1,52 +0,0 @@ -<%= error_messages_for 'custom_field' %> - - -
    -

    -<%= text_field 'custom_field', 'name' %>

    - -

    -<%= select("custom_field", "field_format", custom_field_formats_for_select) %>

    - -

    -<%= text_field 'custom_field', 'min_length', :size => 5 %> - -<%= text_field 'custom_field', 'max_length', :size => 5 %>
    (<%=l(:text_min_max_length_info)%>)

    - -

    -<%= text_field 'custom_field', 'regexp', :size => 50 %>
    (<%=l(:text_regexp_info)%>)

    - -

    -<%= text_area 'custom_field', 'possible_values', :rows => 5, :cols => 60 %>
    (<%=l(:text_possible_values_info)%>)

    -
    - - -
    -<% case type.to_s - when "IssueCustomField" %> - -
    <%=l(:label_tracker_plural)%> -<% for tracker in @trackers %> - checked="checked"<%end%> - > <%= tracker.name %> -<% end %>
    -  - -

    -<%= check_box 'custom_field', 'is_required' %>

    - -

    -<%= check_box 'custom_field', 'is_for_all' %>

    - -<% when "UserCustomField" %> -

    -<%= check_box 'custom_field', 'is_required' %>

    - -<% when "ProjectCustomField" %> -

    -<%= check_box 'custom_field', 'is_required' %>

    - -<% end %> -
    diff --git a/redmine/app/views/custom_fields/edit.rhtml b/redmine/app/views/custom_fields/edit.rhtml deleted file mode 100644 index 201047a8d..000000000 --- a/redmine/app/views/custom_fields/edit.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_custom_field)%> (<%=l(@custom_field.type_name)%>)

    - -<%= start_form_tag({:action => 'edit', :id => @custom_field}, :class => "tabular") %> - <%= render :partial => 'form', :locals => { :type => @custom_field.type } %> - <%= submit_tag l(:button_save) %> -<%= end_form_tag %> diff --git a/redmine/app/views/custom_fields/list.rhtml b/redmine/app/views/custom_fields/list.rhtml deleted file mode 100644 index 858590c49..000000000 --- a/redmine/app/views/custom_fields/list.rhtml +++ /dev/null @@ -1,36 +0,0 @@ -

    <%=l(:label_custom_field_plural)%>

    - - - - - - - - - - - -<% for custom_field in @custom_fields %> - "> - - - - - - - - -<% end %> -
    <%=l(:field_name)%><%=l(:field_type)%><%=l(:field_field_format)%><%=l(:field_is_required)%><%=l(:field_is_for_all)%><%=l(:label_used_by)%>
    <%= link_to custom_field.name, :action => 'edit', :id => custom_field %><%= l(custom_field.type_name) %><%= l(CustomField::FIELD_FORMATS[custom_field.field_format]) %><%= image_tag 'true' if custom_field.is_required? %><%= image_tag 'true' if custom_field.is_for_all? %><%= custom_field.projects.count.to_s + ' ' + lwr(:label_project, custom_field.projects.count) if custom_field.is_a? IssueCustomField and !custom_field.is_for_all? %> - <%= button_to l(:button_delete), { :action => 'destroy', :id => custom_field }, :confirm => l(:text_are_you_sure), :class => "button-small" %> -
    - -<%= pagination_links_full @custom_field_pages %> - -
    -<%=l(:label_custom_field_new)%>: -
      -
    • <%= link_to l(:label_issue_plural), :action => 'new', :type => 'IssueCustomField' %>
    • -
    • <%= link_to l(:label_project_plural), :action => 'new', :type => 'ProjectCustomField' %>
    • -
    • <%= link_to l(:label_user_plural), :action => 'new', :type => 'UserCustomField' %>
    • -
    diff --git a/redmine/app/views/custom_fields/new.rhtml b/redmine/app/views/custom_fields/new.rhtml deleted file mode 100644 index 3b215dc9f..000000000 --- a/redmine/app/views/custom_fields/new.rhtml +++ /dev/null @@ -1,8 +0,0 @@ -

    <%=l(:label_custom_field_new)%> (<%=l(@custom_field.type_name)%>)

    - -<%= start_form_tag({:action => 'new'}, :class => "tabular") %> - <%= render :partial => 'form', :locals => { :type => @custom_field.type } %> - <%= hidden_field_tag 'type', @custom_field.type %> - <%= submit_tag l(:button_save) %> -<%= end_form_tag %> - diff --git a/redmine/app/views/documents/_form.rhtml b/redmine/app/views/documents/_form.rhtml deleted file mode 100644 index 873c96329..000000000 --- a/redmine/app/views/documents/_form.rhtml +++ /dev/null @@ -1,29 +0,0 @@ -<%= error_messages_for 'document' %> -
    - -

    -

    - -

    -<%= text_field 'document', 'title', :size => 60 %>

    - -

    -<%= text_area 'document', 'description', :cols => 60, :rows => 15 %>

    - -
    - -<% unless $RDM_TEXTILE_DISABLED %> -<%= javascript_include_tag 'jstoolbar' %> - -<% end %> \ No newline at end of file diff --git a/redmine/app/views/documents/edit.rhtml b/redmine/app/views/documents/edit.rhtml deleted file mode 100644 index 3db4bcc6a..000000000 --- a/redmine/app/views/documents/edit.rhtml +++ /dev/null @@ -1,8 +0,0 @@ -

    <%=l(:label_document)%>

    - -<%= start_form_tag({:action => 'edit', :id => @document}, :class => "tabular") %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<%= end_form_tag %> - - diff --git a/redmine/app/views/documents/show.rhtml b/redmine/app/views/documents/show.rhtml deleted file mode 100644 index 2f021e1b8..000000000 --- a/redmine/app/views/documents/show.rhtml +++ /dev/null @@ -1,48 +0,0 @@ -

    <%= @document.title %>

    - -

    <%= @document.category.name %>
    -<%= format_date @document.created_on %>

    -<%= textilizable @document.description %> - - - - - -
    <%= link_to_if_authorized l(:button_edit), :controller => 'documents', :action => 'edit', :id => @document %> -<% if authorize_for('documents', 'destroy') %> - <%= start_form_tag({ :controller => 'documents', :action => 'destroy', :id => @document } ) %> - <%= submit_tag l(:button_delete) %> - <%= end_form_tag %> -<% end %> -
    -
    - -

    <%= l(:label_attachment_plural) %>

    -
      -<% for attachment in @attachments %> -
    • - <% if authorize_for('documents', 'destroy_attachment') %> -
      - <%= start_form_tag({ :controller => 'documents', :action => 'destroy_attachment', :id => @document, :attachment_id => attachment } ) %> - <%= submit_tag l(:button_delete), :class => 'button-small' %> - <%= end_form_tag %> -
      - <% end %> - - <%= link_to attachment.filename, :action => 'download', :id => @document, :attachment_id => attachment %> - (<%= human_size attachment.filesize %>)
      - <%= attachment.author.display_name %>, <%= format_date(attachment.created_on) %>
      - <%= lwr(:label_download, attachment.downloads) %> -
    • -<% end %> -
    -
    - - -<% if authorize_for('documents', 'add_attachment') %> - <%= start_form_tag ({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true) %> -    - <%= file_field 'attachment', 'file' %> - <%= submit_tag l(:button_add) %> - <%= end_form_tag %> -<% end %> diff --git a/redmine/app/views/enumerations/_form.rhtml b/redmine/app/views/enumerations/_form.rhtml deleted file mode 100644 index 637605939..000000000 --- a/redmine/app/views/enumerations/_form.rhtml +++ /dev/null @@ -1,9 +0,0 @@ -<%= error_messages_for 'enumeration' %> -
    - -<%= hidden_field 'enumeration', 'opt' %> - -

    -<%= text_field 'enumeration', 'name' %>

    - -
    \ No newline at end of file diff --git a/redmine/app/views/enumerations/edit.rhtml b/redmine/app/views/enumerations/edit.rhtml deleted file mode 100644 index 3002b5936..000000000 --- a/redmine/app/views/enumerations/edit.rhtml +++ /dev/null @@ -1,10 +0,0 @@ -

    <%=l(:label_enumerations)%>

    - -<%= start_form_tag({:action => 'update', :id => @enumeration}, :class => "tabular") %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<%= end_form_tag %> - -<%= start_form_tag :action => 'destroy', :id => @enumeration %> - <%= submit_tag l(:button_delete) %> -<%= end_form_tag %> \ No newline at end of file diff --git a/redmine/app/views/enumerations/list.rhtml b/redmine/app/views/enumerations/list.rhtml deleted file mode 100644 index 15b91c1ac..000000000 --- a/redmine/app/views/enumerations/list.rhtml +++ /dev/null @@ -1,21 +0,0 @@ -

    <%=l(:label_enumerations)%>

    - -<% Enumeration::OPTIONS.each do |option, name| %> - - <% if @params[:opt]==option %> - -

    <%= image_tag 'dir_open' %> <%= l(name) %>

    -
      - <% for value in Enumeration.find(:all, :conditions => ["opt = ?", option]) %> -
    • <%= link_to value.name, :action => 'edit', :id => value %>
    • - <% end %> -
    -
      -
    • <%= link_to ('» ' + l(:label_new)), :action => 'new', :opt => option %>
    • -
    - - <% else %> -

    <%= image_tag 'dir' %> <%= link_to l(name), :opt => option %>

    - <% end %> - -<% end %> \ No newline at end of file diff --git a/redmine/app/views/enumerations/new.rhtml b/redmine/app/views/enumerations/new.rhtml deleted file mode 100644 index 0a773519d..000000000 --- a/redmine/app/views/enumerations/new.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%= l(@enumeration.option_name) %>: <%=l(:label_enumeration_new)%>

    - -<%= start_form_tag({:action => 'create'}, :class => "tabular") %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_create) %> -<%= end_form_tag %> diff --git a/redmine/app/views/issue_categories/_form.rhtml b/redmine/app/views/issue_categories/_form.rhtml deleted file mode 100644 index 765b8f53d..000000000 --- a/redmine/app/views/issue_categories/_form.rhtml +++ /dev/null @@ -1,7 +0,0 @@ -<%= error_messages_for 'issue_category' %> - - -

    -<%= text_field 'issue_category', 'name' %>

    - - diff --git a/redmine/app/views/issue_categories/edit.rhtml b/redmine/app/views/issue_categories/edit.rhtml deleted file mode 100644 index 053facbf7..000000000 --- a/redmine/app/views/issue_categories/edit.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_issue_category)%>

    - -<%= start_form_tag({:action => 'edit', :id => @category}, :class => "tabular") %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<%= end_form_tag %> diff --git a/redmine/app/views/issue_statuses/_form.rhtml b/redmine/app/views/issue_statuses/_form.rhtml deleted file mode 100644 index f3b1cf2ca..000000000 --- a/redmine/app/views/issue_statuses/_form.rhtml +++ /dev/null @@ -1,18 +0,0 @@ -<%= error_messages_for 'issue_status' %> - -
    - -

    -<%= text_field 'issue_status', 'name' %>

    - -

    -<%= check_box 'issue_status', 'is_closed' %>

    - -

    -<%= check_box 'issue_status', 'is_default' %>

    - -

    -#<%= text_field 'issue_status', 'html_color', :maxlength => 6 %>

    - - -
    \ No newline at end of file diff --git a/redmine/app/views/issue_statuses/edit.rhtml b/redmine/app/views/issue_statuses/edit.rhtml deleted file mode 100644 index 80f856a2a..000000000 --- a/redmine/app/views/issue_statuses/edit.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_issue_status)%>

    - -<%= start_form_tag({:action => 'update', :id => @issue_status}, :class => "tabular") %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<%= end_form_tag %> diff --git a/redmine/app/views/issue_statuses/list.rhtml b/redmine/app/views/issue_statuses/list.rhtml deleted file mode 100644 index 023863437..000000000 --- a/redmine/app/views/issue_statuses/list.rhtml +++ /dev/null @@ -1,28 +0,0 @@ -

    <%=l(:label_issue_status_plural)%>

    - - - - - - - - - - -<% for status in @issue_statuses %> - "> - - - - - - -<% end %> -
    <%=l(:field_status)%><%=l(:field_is_default)%><%=l(:field_is_closed)%><%=l(:field_html_color)%>
    <%= link_to status.name, :action => 'edit', :id => status %><%= image_tag 'true' if status.is_default? %><%= image_tag 'true' if status.is_closed? %>
     
    - <%= button_to l(:button_delete), { :action => 'destroy', :id => status }, :confirm => l(:text_are_you_sure), :class => "button-small" %> -
    - -<%= pagination_links_full @issue_status_pages %> -
    - -<%= link_to '» ' + l(:label_issue_status_new), :action => 'new' %> diff --git a/redmine/app/views/issue_statuses/new.rhtml b/redmine/app/views/issue_statuses/new.rhtml deleted file mode 100644 index 2dacb1e21..000000000 --- a/redmine/app/views/issue_statuses/new.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_issue_status_new)%>

    - -<%= start_form_tag({:action => 'create'}, :class => "tabular") %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_create) %> -<%= end_form_tag %> diff --git a/redmine/app/views/issues/_history.rhtml b/redmine/app/views/issues/_history.rhtml deleted file mode 100644 index 6dc2a84be..000000000 --- a/redmine/app/views/issues/_history.rhtml +++ /dev/null @@ -1,11 +0,0 @@ -<% for journal in journals %> -

    <%= format_time(journal.created_on) %> - <%= journal.user.name %>

    -
      - <% for detail in journal.details %> -
    • <%= show_detail(detail) %>
    • - <% end %> -
    - <% if journal.notes? %> - <%= simple_format auto_link journal.notes %> - <% end %> -<% end %> diff --git a/redmine/app/views/issues/_list_simple.rhtml b/redmine/app/views/issues/_list_simple.rhtml deleted file mode 100644 index 94b63d613..000000000 --- a/redmine/app/views/issues/_list_simple.rhtml +++ /dev/null @@ -1,28 +0,0 @@ -<% if issues.length > 0 %> - - - -
    - - - - - - - <% for issue in issues %> - "> - - - - - <% end %> -
    #<%=l(:field_tracker)%><%=l(:field_subject)%>
    - <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>
    -

    <%= issue.project.name %> - <%= issue.tracker.name %>
    - <%= issue.status.name %> - <%= format_time(issue.updated_on) %>

    -

    <%= link_to issue.subject, :controller => 'issues', :action => 'show', :id => issue %>

    -
    -
    -<% else %> - <%=l(:label_no_data)%> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/issues/_pdf.rfpdf b/redmine/app/views/issues/_pdf.rfpdf deleted file mode 100644 index 1f6a12283..000000000 --- a/redmine/app/views/issues/_pdf.rfpdf +++ /dev/null @@ -1,100 +0,0 @@ -<% pdf.SetFont('Arial','B',11) - pdf.Cell(190,10, "#{issue.project.name} - #{issue.tracker.name} # #{issue.long_id} - #{issue.subject}") - pdf.Ln - - y0 = pdf.GetY - - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_status) + ":","LT") - pdf.SetFont('Arial','',9) - pdf.Cell(60,5, issue.status.name,"RT") - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_priority) + ":","LT") - pdf.SetFont('Arial','',9) - pdf.Cell(60,5, issue.priority.name,"RT") - pdf.Ln - - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_author) + ":","L") - pdf.SetFont('Arial','',9) - pdf.Cell(60,5, issue.author.name,"R") - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_category) + ":","L") - pdf.SetFont('Arial','',9) - pdf.Cell(60,5, (issue.category ? issue.category.name : "-"),"R") - pdf.Ln - - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_created_on) + ":","L") - pdf.SetFont('Arial','',9) - pdf.Cell(60,5, format_date(issue.created_on),"R") - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_assigned_to) + ":","L") - pdf.SetFont('Arial','',9) - pdf.Cell(60,5, (issue.assigned_to ? issue.assigned_to.name : "-"),"R") - pdf.Ln - - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_updated_on) + ":","LB") - pdf.SetFont('Arial','',9) - pdf.Cell(60,5, format_date(issue.updated_on),"RB") - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_due_date) + ":","LB") - pdf.SetFont('Arial','',9) - pdf.Cell(60,5, format_date(issue.due_date),"RB") - pdf.Ln - - for custom_value in issue.custom_values - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, custom_value.custom_field.name + ":","L") - pdf.SetFont('Arial','',9) - pdf.MultiCell(155,5, (show_value custom_value),"R") - end - - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_subject) + ":","LTB") - pdf.SetFont('Arial','',9) - pdf.Cell(155,5, issue.subject,"RTB") - pdf.Ln - - pdf.SetFont('Arial','B',9) - pdf.Cell(35,5, l(:field_description) + ":") - pdf.SetFont('Arial','',9) - pdf.MultiCell(155,5, issue.description,"BR") - - pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY) - pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY) - - pdf.Ln - - pdf.SetFont('Arial','B',9) - pdf.Cell(190,5, l(:label_history), "B") - pdf.Ln - for journal in issue.journals.find(:all, :include => :user, :order => "journals.created_on desc") - pdf.SetFont('Arial','B',8) - pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) - pdf.Ln - pdf.SetFont('Arial','I',8) - for detail in journal.details - pdf.Cell(190,5, "- " + show_detail(detail, true)) - pdf.Ln - end - if journal.notes? - pdf.SetFont('Arial','',8) - pdf.MultiCell(190,5, journal.notes) - end - pdf.Ln - end - - pdf.SetFont('Arial','B',9) - pdf.Cell(190,5, l(:label_attachment_plural), "B") - pdf.Ln - for attachment in issue.attachments - pdf.SetFont('Arial','',8) - pdf.Cell(80,5, attachment.filename) - pdf.Cell(20,5, human_size(attachment.filesize),0,0,"R") - pdf.Cell(20,5, format_date(attachment.created_on),0,0,"R") - pdf.Cell(70,5, attachment.author.name,0,0,"R") - pdf.Ln - end -%> \ No newline at end of file diff --git a/redmine/app/views/issues/change_status.rhtml b/redmine/app/views/issues/change_status.rhtml deleted file mode 100644 index 2ef87183d..000000000 --- a/redmine/app/views/issues/change_status.rhtml +++ /dev/null @@ -1,37 +0,0 @@ -

    <%=l(:label_issue)%> #<%= @issue.id %>: <%= @issue.subject %>

    - -<%= error_messages_for 'issue' %> -<%= start_form_tag({:action => 'change_status', :id => @issue}, :class => "tabular") %> - -<%= hidden_field_tag 'confirm', 1 %> -<%= hidden_field_tag 'new_status_id', @new_status.id %> - -
    -

    <%= @new_status.name %>

    - -

    -

    - - -

    -<%= select("issue", "done_ratio", ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) ) %> -

    - - -

    -

    - -

    -<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10 %>

    - -
    - -<%= hidden_field 'issue', 'lock_version' %> -<%= submit_tag l(:button_save) %> -<%= end_form_tag %> diff --git a/redmine/app/views/issues/edit.rhtml b/redmine/app/views/issues/edit.rhtml deleted file mode 100644 index 60cdafc1e..000000000 --- a/redmine/app/views/issues/edit.rhtml +++ /dev/null @@ -1,49 +0,0 @@ -

    <%= @issue.tracker.name %> #<%= @issue.id %> - <%= @issue.subject %>

    - -<% labelled_tabular_form_for :issue, @issue, :url => {:action => 'edit'} do |f| %> -<%= error_messages_for 'issue' %> -
    - -
    -

    <%= @issue.status.name %>

    -

    <%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %>

    -

    <%= f.select :assigned_to_id, (@issue.project.members.collect {|m| [m.name, m.user_id]}), :include_blank => true %>

    -

    <%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}) %>

    -
    - -
    -

    <%= f.text_field :start_date, :size => 10 %><%= calendar_for('issue_start_date') %>

    -

    <%= f.text_field :due_date, :size => 10 %><%= calendar_for('issue_due_date') %>

    -

    <%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

    -
    - -
    -

    <%= f.text_field :subject, :size => 80, :required => true %>

    -

    <%= f.text_area :description, :cols => 60, :rows => [[10, @issue.description.length / 50].max, 100].min, :required => true %>

    - -<% for @custom_value in @custom_values %> -

    <%= custom_field_tag_with_label @custom_value %>

    -<% end %> - -

    <%= f.select :fixed_version_id, (@project.versions.collect {|v| [v.name, v.id]}), { :include_blank => true } %> -

    -
    - -
    -<%= f.hidden_field :lock_version %> -<%= submit_tag l(:button_save) %> -<% end %> - -<% unless $RDM_TEXTILE_DISABLED %> -<%= javascript_include_tag 'jstoolbar' %> - -<% end %> \ No newline at end of file diff --git a/redmine/app/views/issues/export_pdf.rfpdf b/redmine/app/views/issues/export_pdf.rfpdf deleted file mode 100644 index a8622dd51..000000000 --- a/redmine/app/views/issues/export_pdf.rfpdf +++ /dev/null @@ -1,9 +0,0 @@ -<% pdf=IfpdfHelper::IFPDF.new - pdf.AliasNbPages - pdf.footer_date = format_date(Date.today) - pdf.AddPage - - render :partial => 'issues/pdf', :locals => { :pdf => pdf, :issue => @issue } -%> - -<%= pdf.Output %> \ No newline at end of file diff --git a/redmine/app/views/issues/history.rhtml b/redmine/app/views/issues/history.rhtml deleted file mode 100644 index 2443cc739..000000000 --- a/redmine/app/views/issues/history.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_history)%>

    -
    -<%= render :partial => 'history', :locals => { :journals => @journals } %> -
    -
    -

    <%= link_to l(:button_back), :action => 'show', :id => @issue %>

    \ No newline at end of file diff --git a/redmine/app/views/issues/show.rhtml b/redmine/app/views/issues/show.rhtml deleted file mode 100644 index 8128b74a9..000000000 --- a/redmine/app/views/issues/show.rhtml +++ /dev/null @@ -1,133 +0,0 @@ -

    <%= @issue.tracker.name %> #<%= @issue.id %> - <%= @issue.subject %>

    -
    - -<%= link_to 'PDF', :action => 'export_pdf', :id => @issue %> - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - -<% n = 0 -for custom_value in @custom_values %> - -<% n = n + 1 - if (n > 1) - n = 0 %> - - <%end -end %> - -
    <%=l(:field_status)%> :<%= @issue.status.name %><%=l(:field_priority)%> :<%= @issue.priority.name %>
    <%=l(:field_assigned_to)%> :<%= @issue.assigned_to ? @issue.assigned_to.name : "-" %><%=l(:field_category)%> :<%= @issue.category ? @issue.category.name : "-" %>
    <%=l(:field_author)%> :<%= link_to_user @issue.author %><%=l(:field_start_date)%> :<%= format_date(@issue.start_date) %>
    <%=l(:field_created_on)%> :<%= format_date(@issue.created_on) %><%=l(:field_due_date)%> :<%= format_date(@issue.due_date) %>
    <%=l(:field_updated_on)%> :<%= format_date(@issue.updated_on) %><%=l(:field_done_ratio)%> :<%= @issue.done_ratio %> %
    <%= custom_value.custom_field.name %> :<%= show_value custom_value %>
    -
    -
    - -<%=l(:field_description)%> :

    -<%= textilizable @issue.description %> -
    -
    -<% if authorize_for('issues', 'edit') %> - <%= start_form_tag ({:controller => 'issues', :action => 'edit', :id => @issue}, :method => "get" ) %> - <%= submit_tag l(:button_edit) %> - <%= end_form_tag %> -    -<% end %> - -<% if authorize_for('issues', 'change_status') and @status_options and !@status_options.empty? %> - <%= start_form_tag ({:controller => 'issues', :action => 'change_status', :id => @issue}) %> - <%=l(:label_change_status)%> : - - <%= submit_tag l(:button_change) %> - <%= end_form_tag %> -    -<% end %> - -<% if authorize_for('projects', 'move_issues') %> - <%= start_form_tag ({:controller => 'projects', :action => 'move_issues', :id => @project} ) %> - <%= hidden_field_tag "issue_ids[]", @issue.id %> - <%= submit_tag l(:button_move) %> - <%= end_form_tag %> -    -<% end %> -
    -
    -<% if authorize_for('issues', 'destroy') %> - <%= start_form_tag ({:controller => 'issues', :action => 'destroy', :id => @issue} ) %> - <%= submit_tag l(:button_delete) %> - <%= end_form_tag %> -    -<% end %> -
    -
    -
    - -
    -

    <%=l(:label_history)%> -<% if @journals_count > @journals.length %>(<%= l(:label_last_changes, @journals.length) %>)<% end %>

    -<%= render :partial => 'history', :locals => { :journals => @journals } %> -<% if @journals_count > @journals.length %> -

    [ <%= link_to l(:label_change_view_all), :action => 'history', :id => @issue %> ]

    -<% end %> -
    - -
    -

    <%=l(:label_attachment_plural)%>

    - -<% for attachment in @issue.attachments %> - - - - -<% if authorize_for('issues', 'destroy_attachment') %> - -<% end %> - -<% end %> -
    <%= image_tag('attachment') %> <%= link_to attachment.filename, :action => 'download', :id => @issue, :attachment_id => attachment %> (<%= human_size(attachment.filesize) %>)<%= format_date(attachment.created_on) %><%= attachment.author.display_name %> - <%= start_form_tag :action => 'destroy_attachment', :id => @issue, :attachment_id => attachment %> - <%= submit_tag l(:button_delete), :class => "button-small" %> - <%= end_form_tag %> -
    -
    -<% if authorize_for('issues', 'add_attachment') %> - <%= start_form_tag ({ :controller => 'issues', :action => 'add_attachment', :id => @issue }, :multipart => true, :class => "tabular") %> -

    - <%= file_field_tag 'attachments[]', :size => 30 %>

    - <%= submit_tag l(:button_add) %> - <%= end_form_tag %> -<% end %> -
    - -<% if authorize_for('issues', 'add_note') %> -
    -

    <%= l(:label_add_note) %>

    - <%= start_form_tag ({:controller => 'issues', :action => 'add_note', :id => @issue}, :class => "tabular" ) %> -

    - <%= text_area_tag 'notes', '', :cols => 60, :rows => 10 %>

    - <%= submit_tag l(:button_add) %> - <%= end_form_tag %> -
    -<% end %> diff --git a/redmine/app/views/layouts/base.rhtml b/redmine/app/views/layouts/base.rhtml deleted file mode 100644 index 951fa88f7..000000000 --- a/redmine/app/views/layouts/base.rhtml +++ /dev/null @@ -1,142 +0,0 @@ - - - -<%= $RDM_HEADER_TITLE + (@html_title ? ": #{@html_title}" : "") %> - - - -<%= stylesheet_link_tag "application" %> -<%= stylesheet_link_tag "menu" %> -<%= stylesheet_link_tag "rails" %> -<%= javascript_include_tag :defaults %> -<%= javascript_include_tag 'menu' %> -<%= javascript_include_tag 'calendar/calendar' %> -<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %> -<%= javascript_include_tag 'calendar/calendar-setup' %> -<%= stylesheet_link_tag 'calendar' %> -<%= stylesheet_link_tag 'jstoolbar' %> - - - - - -
    - - - - - - -
    - - <% unless @project.nil? || @project.id.nil? %> -

    <%= @project.name %>

    - - <% end %> - - <% if loggedin? and @logged_in_user.memberships.length > 0 %> -

    <%=l(:label_my_projects) %>

    - - <% end %> -
    - -
    - <% if flash[:notice] %>

    <%= flash[:notice] %>

    <% end %> - <%= @content_for_layout %> -
    - - - -
    - - \ No newline at end of file diff --git a/redmine/app/views/mailer/_issue.rhtml b/redmine/app/views/mailer/_issue.rhtml deleted file mode 100644 index c123ae30c..000000000 --- a/redmine/app/views/mailer/_issue.rhtml +++ /dev/null @@ -1,7 +0,0 @@ -<%=l(:label_issue)%> #<%= issue.id %> - <%= issue.subject %> -<%=l(:field_author)%>: <%= issue.author.display_name %> -<%=l(:field_status)%>: <%= issue.status.name %> - -<%= issue.description %> - -http://<%= $RDM_HOST_NAME %>/issues/show/<%= issue.id %> \ No newline at end of file diff --git a/redmine/app/views/mailer/issue_add_de.rhtml b/redmine/app/views/mailer/issue_add_de.rhtml deleted file mode 100644 index 9efec9ad9..000000000 --- a/redmine/app/views/mailer/issue_add_de.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Issue #<%= @issue.id %> has been reported. ----------------------------------------- -<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/redmine/app/views/mailer/issue_add_en.rhtml b/redmine/app/views/mailer/issue_add_en.rhtml deleted file mode 100644 index 9efec9ad9..000000000 --- a/redmine/app/views/mailer/issue_add_en.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Issue #<%= @issue.id %> has been reported. ----------------------------------------- -<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/redmine/app/views/mailer/issue_add_es.rhtml b/redmine/app/views/mailer/issue_add_es.rhtml deleted file mode 100644 index 9efec9ad9..000000000 --- a/redmine/app/views/mailer/issue_add_es.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Issue #<%= @issue.id %> has been reported. ----------------------------------------- -<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/redmine/app/views/mailer/issue_add_fr.rhtml b/redmine/app/views/mailer/issue_add_fr.rhtml deleted file mode 100644 index 628ecae12..000000000 --- a/redmine/app/views/mailer/issue_add_fr.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Une nouvelle demande (#<%= @issue.id %>) a été soumise. ----------------------------------------- -<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/redmine/app/views/mailer/issue_edit_de.rhtml b/redmine/app/views/mailer/issue_edit_de.rhtml deleted file mode 100644 index d22d6c534..000000000 --- a/redmine/app/views/mailer/issue_edit_de.rhtml +++ /dev/null @@ -1,8 +0,0 @@ -Issue #<%= @issue.id %> has been updated. -<%= @journal.user.name %> -<% for detail in @journal.details %> -<%= show_detail(detail, true) %> -<% end %> -<%= @journal.notes if @journal.notes? %> ----------------------------------------- -<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/redmine/app/views/mailer/issue_edit_en.rhtml b/redmine/app/views/mailer/issue_edit_en.rhtml deleted file mode 100644 index d22d6c534..000000000 --- a/redmine/app/views/mailer/issue_edit_en.rhtml +++ /dev/null @@ -1,8 +0,0 @@ -Issue #<%= @issue.id %> has been updated. -<%= @journal.user.name %> -<% for detail in @journal.details %> -<%= show_detail(detail, true) %> -<% end %> -<%= @journal.notes if @journal.notes? %> ----------------------------------------- -<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/redmine/app/views/mailer/issue_edit_es.rhtml b/redmine/app/views/mailer/issue_edit_es.rhtml deleted file mode 100644 index d22d6c534..000000000 --- a/redmine/app/views/mailer/issue_edit_es.rhtml +++ /dev/null @@ -1,8 +0,0 @@ -Issue #<%= @issue.id %> has been updated. -<%= @journal.user.name %> -<% for detail in @journal.details %> -<%= show_detail(detail, true) %> -<% end %> -<%= @journal.notes if @journal.notes? %> ----------------------------------------- -<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/redmine/app/views/mailer/issue_edit_fr.rhtml b/redmine/app/views/mailer/issue_edit_fr.rhtml deleted file mode 100644 index 9edacb703..000000000 --- a/redmine/app/views/mailer/issue_edit_fr.rhtml +++ /dev/null @@ -1,8 +0,0 @@ -La demande #<%= @issue.id %> a été mise à jour. -<%= @journal.user.name %> - <%= format_date(@journal.created_on) %> -<% for detail in @journal.details %> -<%= show_detail(detail, true) %> -<% end %> -<%= journal.notes if journal.notes? %> ----------------------------------------- -<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %> \ No newline at end of file diff --git a/redmine/app/views/mailer/lost_password_de.rhtml b/redmine/app/views/mailer/lost_password_de.rhtml deleted file mode 100644 index 2593edbda..000000000 --- a/redmine/app/views/mailer/lost_password_de.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -To change your password, use the following link: - -http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %> \ No newline at end of file diff --git a/redmine/app/views/mailer/lost_password_en.rhtml b/redmine/app/views/mailer/lost_password_en.rhtml deleted file mode 100644 index 2593edbda..000000000 --- a/redmine/app/views/mailer/lost_password_en.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -To change your password, use the following link: - -http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %> \ No newline at end of file diff --git a/redmine/app/views/mailer/lost_password_es.rhtml b/redmine/app/views/mailer/lost_password_es.rhtml deleted file mode 100644 index 2593edbda..000000000 --- a/redmine/app/views/mailer/lost_password_es.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -To change your password, use the following link: - -http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %> \ No newline at end of file diff --git a/redmine/app/views/mailer/lost_password_fr.rhtml b/redmine/app/views/mailer/lost_password_fr.rhtml deleted file mode 100644 index 30996f118..000000000 --- a/redmine/app/views/mailer/lost_password_fr.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Pour changer votre mot de passe, utilisez le lien suivant: - -http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %> \ No newline at end of file diff --git a/redmine/app/views/mailer/register_de.rhtml b/redmine/app/views/mailer/register_de.rhtml deleted file mode 100644 index 2c0341b24..000000000 --- a/redmine/app/views/mailer/register_de.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -To activate your redMine account, use the following link: - -http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %> \ No newline at end of file diff --git a/redmine/app/views/mailer/register_en.rhtml b/redmine/app/views/mailer/register_en.rhtml deleted file mode 100644 index 2c0341b24..000000000 --- a/redmine/app/views/mailer/register_en.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -To activate your redMine account, use the following link: - -http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %> \ No newline at end of file diff --git a/redmine/app/views/mailer/register_es.rhtml b/redmine/app/views/mailer/register_es.rhtml deleted file mode 100644 index 2c0341b24..000000000 --- a/redmine/app/views/mailer/register_es.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -To activate your redMine account, use the following link: - -http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %> \ No newline at end of file diff --git a/redmine/app/views/mailer/register_fr.rhtml b/redmine/app/views/mailer/register_fr.rhtml deleted file mode 100644 index 3f5d0ccaf..000000000 --- a/redmine/app/views/mailer/register_fr.rhtml +++ /dev/null @@ -1,3 +0,0 @@ -Pour activer votre compte sur redMine, utilisez le lien suivant: - -http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %> \ No newline at end of file diff --git a/redmine/app/views/my/_block.rhtml b/redmine/app/views/my/_block.rhtml deleted file mode 100644 index 3f72bdaf1..000000000 --- a/redmine/app/views/my/_block.rhtml +++ /dev/null @@ -1,16 +0,0 @@ -
    - -
    - <%= link_to_remote "", { - :url => { :action => "remove_block", :block => block_name }, - :complete => "removeBlock('block_#{block_name}')", - :loading => "Element.show('indicator')", - :loaded => "Element.hide('indicator')" }, - :class => "close-icon" - %> -
    - -
    - <%= render :partial => "my/blocks/#{block_name}", :locals => { :user => user } %> -
    -
    \ No newline at end of file diff --git a/redmine/app/views/my/account.rhtml b/redmine/app/views/my/account.rhtml deleted file mode 100644 index 23b236e29..000000000 --- a/redmine/app/views/my/account.rhtml +++ /dev/null @@ -1,47 +0,0 @@ -

    <%=l(:label_my_account)%>

    - -

    <%=l(:field_login)%>: <%= @user.login %>
    -<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>, -<%=l(:field_updated_on)%>: <%= format_time(@user.updated_on) %>

    - -<%= error_messages_for 'user' %> - -
    -

    <%=l(:label_information_plural)%>

    - -<% labelled_tabular_form_for :user, @user, :url => { :action => "account" } do |f| %> - -

    <%= f.text_field :firstname, :required => true %>

    -

    <%= f.text_field :lastname, :required => true %>

    -

    <%= f.text_field :mail, :required => true, :size => 40 %>

    -

    <%= f.select :language, lang_options_for_select %>

    -

    <%= f.check_box :mail_notification %>

    - -<% fields_for :pref, @user.pref, :builder => TabularFormBuilder, :lang => current_language do |pref_fields| %> -

    <%= pref_fields.check_box :hide_mail %>

    -<% end %> - -
    <%= submit_tag l(:button_save) %>
    -<% end %> -
    - - -<% unless @user.auth_source_id %> -
    -

    <%=l(:field_password)%>

    - - <%= start_form_tag({:action => 'change_password'}, :class => "tabular") %> - -

    - <%= password_field_tag 'password', nil, :size => 25 %>

    - -

    - <%= password_field_tag 'new_password', nil, :size => 25 %>

    - -

    - <%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

    - -
    <%= submit_tag l(:button_save) %>
    - <%= end_form_tag %> -
    -<% end %> diff --git a/redmine/app/views/my/blocks/_calendar.rhtml b/redmine/app/views/my/blocks/_calendar.rhtml deleted file mode 100644 index 2d7930f52..000000000 --- a/redmine/app/views/my/blocks/_calendar.rhtml +++ /dev/null @@ -1,45 +0,0 @@ -

    <%= l(:label_calendar) %>

    - -<% -@date_from = Date.today - (Date.today.cwday-1) -@date_to = Date.today + (7-Date.today.cwday) -@issues = Issue.find :all, - :conditions => ["issues.project_id in (#{@user.projects.collect{|m| m.id}.join(',')}) AND ((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", @date_from, @date_to, @date_from, @date_to], - :include => [:project, :tracker] unless @user.projects.empty? -@issues ||= [] -%> - - - - -<% 1.upto(7) do |d| %> - -<% end %> - - -<% day = @date_from -while day <= @date_to - if day.cwday == 1 %> - - <% end %> - - <%= '' if day.cwday >= 7 and day!=@date_to %> - <% - day = day + 1 -end %> - -
    <%= day_name(d) %>
    <%= day.cweek %>"> -

    <%= day==Date.today ? "#{day.day}" : day.day %>

    - <% day_issues = [] - @issues.each { |i| day_issues << i if i.start_date == day or i.due_date == day } - day_issues.each do |i| %> - <%= if day == i.start_date and day == i.due_date - image_tag('arrow_bw') - elsif day == i.start_date - image_tag('arrow_from') - elsif day == i.due_date - image_tag('arrow_to') - end %> - <%= link_to "#{i.tracker.name} ##{i.id}", :controller => 'issues', :action => 'show', :id => i %>: <%= i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %>
    - <% end %> -
    \ No newline at end of file diff --git a/redmine/app/views/my/blocks/_documents.rhtml b/redmine/app/views/my/blocks/_documents.rhtml deleted file mode 100644 index 5fa8c7980..000000000 --- a/redmine/app/views/my/blocks/_documents.rhtml +++ /dev/null @@ -1,15 +0,0 @@ -

    <%=l(:label_document_plural)%>

    - -
      -<% for document in Document.find :all, - :limit => 10, - :conditions => "documents.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", - :include => [:project] %> -
    • - <%= link_to document.title, :controller => 'documents', :action => 'show', :id => document %> -
      - <%= truncate document.description, 150 %>
      - <%= format_time(document.created_on) %>
        -
    • -<% end unless @user.projects.empty? %> -
    \ No newline at end of file diff --git a/redmine/app/views/my/blocks/_issues_assigned_to_me.rhtml b/redmine/app/views/my/blocks/_issues_assigned_to_me.rhtml deleted file mode 100644 index 2a4e2a05d..000000000 --- a/redmine/app/views/my/blocks/_issues_assigned_to_me.rhtml +++ /dev/null @@ -1,10 +0,0 @@ -

    <%=l(:label_assigned_to_me_issues)%>

    -<% assigned_issues = Issue.find(:all, - :conditions => ["assigned_to_id=?", user.id], - :limit => 10, - :include => [ :status, :project, :tracker ], - :order => 'issues.updated_on DESC') %> -<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %> -<% if assigned_issues.length > 0 %> -

    <%=lwr(:label_last_updates, assigned_issues.length)%>

    -<% end %> diff --git a/redmine/app/views/my/blocks/_issues_reported_by_me.rhtml b/redmine/app/views/my/blocks/_issues_reported_by_me.rhtml deleted file mode 100644 index 9b40b3606..000000000 --- a/redmine/app/views/my/blocks/_issues_reported_by_me.rhtml +++ /dev/null @@ -1,10 +0,0 @@ -

    <%=l(:label_reported_issues)%>

    -<% reported_issues = Issue.find(:all, - :conditions => ["author_id=?", user.id], - :limit => 10, - :include => [ :status, :project, :tracker ], - :order => 'issues.updated_on DESC') %> -<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %> -<% if reported_issues.length > 0 %> -

    <%=lwr(:label_last_updates, reported_issues.length)%>

    -<% end %> \ No newline at end of file diff --git a/redmine/app/views/my/blocks/_latest_news.rhtml b/redmine/app/views/my/blocks/_latest_news.rhtml deleted file mode 100644 index 85430ef54..000000000 --- a/redmine/app/views/my/blocks/_latest_news.rhtml +++ /dev/null @@ -1,13 +0,0 @@ -

    <%=l(:label_news_latest)%>

    - -
      -<% for news in News.find :all, - :limit => 10, - :conditions => "news.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", - :include => [:project, :author] %> -
    • <%= link_to news.title, :controller => 'news', :action => 'show', :id => news %>
      - <% unless news.summary.empty? %><%= news.summary %>
      <% end %> - <%= news.author.name %>, <%= format_time(news.created_on) %>
        -
    • -<% end unless @user.projects.empty? %> -
    \ No newline at end of file diff --git a/redmine/app/views/my/page.rhtml b/redmine/app/views/my/page.rhtml deleted file mode 100644 index 121d48ca9..000000000 --- a/redmine/app/views/my/page.rhtml +++ /dev/null @@ -1,30 +0,0 @@ -

    <%=l(:label_my_page)%>

    - -
    - <%= link_to l(:label_personalize_page), :action => 'page_layout' %> -
    - -
    - <% @blocks['top'].each do |b| %> -
    - <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> -
    - <% end if @blocks['top'] %> -
    - -
    - <% @blocks['left'].each do |b| %> -
    - <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> -
    - <% end if @blocks['left'] %> -
    - -
    - <% @blocks['right'].each do |b| %> -
    - <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> -
    - <% end if @blocks['right'] %> -
    - diff --git a/redmine/app/views/my/page_layout.rhtml b/redmine/app/views/my/page_layout.rhtml deleted file mode 100644 index 59a38567d..000000000 --- a/redmine/app/views/my/page_layout.rhtml +++ /dev/null @@ -1,121 +0,0 @@ - - -
    -<%= start_form_tag({:action => "add_block"}, :id => "block-form") %> - -<%= select_tag 'block', "" + options_for_select(@block_options), :id => "block-select", :class => "select-small" %> - -<%= link_to_remote l(:button_add), - :url => { :action => "add_block" }, - :with => "Form.serialize('block-form')", - :update => "list-top", - :position => :top, - :complete => "afterAddBlock();", - :loading => "Element.show('indicator')", - :loaded => "Element.hide('indicator')" - %> - -<%= end_form_tag %> -| -<%= link_to l(:button_save), :action => 'page_layout_save' %> | -<%= link_to l(:button_cancel), :action => 'page' %> - -
    - -
    - -
    - -

    <%=l(:label_my_page)%>

    - -
    - <% @blocks['top'].each do |b| %> - <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> - <% end if @blocks['top'] %> -
    - -
    - <% @blocks['left'].each do |b| %> - <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> - <% end if @blocks['left'] %> -
    - -
    - <% @blocks['right'].each do |b| %> - <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> - <% end if @blocks['right'] %> -
    - -<%= sortable_element 'list-top', - :tag => 'div', - :only => 'mypage-box', - :handle => "handle", - :dropOnEmpty => true, - :containment => ['list-top', 'list-left', 'list-right'], - :constraint => false, - :complete => visual_effect(:highlight, 'list-top'), - :url => { :action => "order_blocks", :group => "top" }, - :loading => "Element.show('indicator')", - :loaded => "Element.hide('indicator')" - %> - - -<%= sortable_element 'list-left', - :tag => 'div', - :only => 'mypage-box', - :handle => "handle", - :dropOnEmpty => true, - :containment => ['list-top', 'list-left', 'list-right'], - :constraint => false, - :complete => visual_effect(:highlight, 'list-left'), - :url => { :action => "order_blocks", :group => "left" }, - :loading => "Element.show('indicator')", - :loaded => "Element.hide('indicator')" %> - -<%= sortable_element 'list-right', - :tag => 'div', - :only => 'mypage-box', - :handle => "handle", - :dropOnEmpty => true, - :containment => ['list-top', 'list-left', 'list-right'], - :constraint => false, - :complete => visual_effect(:highlight, 'list-right'), - :url => { :action => "order_blocks", :group => "right" }, - :loading => "Element.show('indicator')", - :loaded => "Element.hide('indicator')" %> - -<%= javascript_tag "updateSelect()" %> \ No newline at end of file diff --git a/redmine/app/views/news/_form.rhtml b/redmine/app/views/news/_form.rhtml deleted file mode 100644 index 2dcdc9f80..000000000 --- a/redmine/app/views/news/_form.rhtml +++ /dev/null @@ -1,20 +0,0 @@ -<%= error_messages_for 'news' %> -
    -

    <%= f.text_field :title, :required => true, :size => 60 %>

    -

    <%= f.text_area :summary, :cols => 60, :rows => 2 %>

    -

    <%= f.text_area :description, :required => true, :cols => 60, :rows => 15 %>

    -
    - -<% unless $RDM_TEXTILE_DISABLED %> -<%= javascript_include_tag 'jstoolbar' %> - -<% end %> \ No newline at end of file diff --git a/redmine/app/views/news/edit.rhtml b/redmine/app/views/news/edit.rhtml deleted file mode 100644 index 5e015c4c7..000000000 --- a/redmine/app/views/news/edit.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_news)%>

    - -<% labelled_tabular_form_for :news, @news, :url => { :action => "edit" } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/news/show.rhtml b/redmine/app/views/news/show.rhtml deleted file mode 100644 index 91df09f0f..000000000 --- a/redmine/app/views/news/show.rhtml +++ /dev/null @@ -1,16 +0,0 @@ -

    <%= @news.title %>

    - -

    <%= @news.summary %>
    -<%= @news.author.display_name %>, <%= format_time(@news.created_on) %>

    -
    -<%= textilizable auto_link @news.description %> - -
    -<% if authorize_for('news', 'destroy') %> - <%= start_form_tag ({:controller => 'news', :action => 'destroy', :id => @news}) %> - <%= submit_tag l(:button_delete) %> - <%= end_form_tag %> -<% end %> -
    - -<%= link_to_if_authorized l(:button_edit), :controller => 'news', :action => 'edit', :id => @news %> diff --git a/redmine/app/views/projects/_form.rhtml b/redmine/app/views/projects/_form.rhtml deleted file mode 100644 index ab0b35fab..000000000 --- a/redmine/app/views/projects/_form.rhtml +++ /dev/null @@ -1,26 +0,0 @@ -<%= error_messages_for 'project' %> -
    - -

    <%= f.text_field :name, :required => true %>

    - -<% if admin_loggedin? and !@root_projects.empty? %> -

    <%= f.select :parent_id, (@root_projects.collect {|p| [p.name, p.id]}), { :include_blank => true } %>

    -<% end %> - -

    <%= f.text_area :description, :required => true, :cols => 60, :rows => 3 %>

    -

    <%= f.text_field :homepage, :size => 40 %>

    -

    <%= f.check_box :is_public %>

    - -<% for @custom_value in @custom_values %> -

    <%= custom_field_tag_with_label @custom_value %>

    -<% end %> - -<% unless @custom_fields.empty? %> -

    -<% for custom_field in @custom_fields %> - <%= check_box_tag "custom_field_ids[]", custom_field.id, ((@project.custom_fields.include? custom_field) or custom_field.is_for_all?), (custom_field.is_for_all? ? {:disabled => "disabled"} : {}) %> - <%= custom_field.name %> -<% end %>

    -<% end %> - -
    diff --git a/redmine/app/views/projects/activity.rhtml b/redmine/app/views/projects/activity.rhtml deleted file mode 100644 index d6e5a1a43..000000000 --- a/redmine/app/views/projects/activity.rhtml +++ /dev/null @@ -1,41 +0,0 @@ -

    <%=l(:label_activity)%>

    - -
    -
    - <%= start_form_tag %> -

    <%= select_month(@month, :prefix => "month", :discard_type => true) %> -<%= select_year(@year, :prefix => "year", :discard_type => true) %>

    - <%= check_box_tag 'show_issues', 1, @show_issues %><%= hidden_field_tag 'show_issues', 0 %> <%=l(:label_issue_plural)%>
    - <%= check_box_tag 'show_news', 1, @show_news %><%= hidden_field_tag 'show_news', 0 %> <%=l(:label_news_plural)%>
    - <%= check_box_tag 'show_files', 1, @show_files %><%= hidden_field_tag 'show_files', 0 %> <%=l(:label_attachment_plural)%>
    - <%= check_box_tag 'show_documents', 1, @show_documents %><%= hidden_field_tag 'show_documents', 0 %> <%=l(:label_document_plural)%>
    -

    <%= submit_tag l(:button_apply), :class => 'button-small' %>

    - <%= end_form_tag %> -
    -<% @events_by_day.keys.sort {|x,y| y <=> x }.each do |day| %> -

    <%= day_name(day.cwday) %> <%= format_date(day) %>

    -
      - <% @events_by_day[day].sort {|x,y| y.created_on <=> x.created_on }.each do |e| %> -
    • - <% if e.is_a? Issue %> - <%= e.created_on.strftime("%H:%M") %> <%= link_to "#{e.tracker.name} ##{e.id}", :controller => 'issues', :action => 'show', :id => e %> (<%= e.status.name %>): <%= e.subject %>
      - <%= e.author.name %> - <% elsif e.is_a? News %> - <%= e.created_on.strftime("%H:%M") %> <%=l(:label_news)%>: <%= link_to e.title, :controller => 'news', :action => 'show', :id => e %>
      - <% unless e.summary.empty? %><%= e.summary %>
      <% end %> - <%= e.author.name %> - <% elsif (e.is_a? Attachment) and (e.container.is_a? Version) %> - <%= e.created_on.strftime("%H:%M") %> <%=l(:label_attachment)%> (Version <%= e.container.name %>): <%= link_to e.filename, :controller => 'projects', :action => 'list_files', :id => @project %>
      - <%= e.author.name %> - <% elsif (e.is_a? Attachment) and (e.container.is_a? Document) %> - <%= e.created_on.strftime("%H:%M") %> <%=l(:label_document)%>: <%= link_to e.container.title, :controller => 'documents', :action => 'show', :id => e %>
      - <%= e.author.name %> - <% end %> -

    • - - <% end %> -
    -<% end %> -<% if @events_by_day.empty? %>

    <%= l(:label_no_data) %>

    <% end %> -
    -
    \ No newline at end of file diff --git a/redmine/app/views/projects/add.rhtml b/redmine/app/views/projects/add.rhtml deleted file mode 100644 index bafbf9145..000000000 --- a/redmine/app/views/projects/add.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_project_new)%>

    - -<% labelled_tabular_form_for :project, @project, :url => { :action => "add" } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/projects/add_document.rhtml b/redmine/app/views/projects/add_document.rhtml deleted file mode 100644 index 88572f409..000000000 --- a/redmine/app/views/projects/add_document.rhtml +++ /dev/null @@ -1,14 +0,0 @@ -

    <%=l(:label_document_new)%>

    - -<%= start_form_tag( { :action => 'add_document', :id => @project }, :class => "tabular", :multipart => true) %> -<%= render :partial => 'documents/form' %> - -
    -

    -<%= file_field 'attachment', 'file' %>

    -
    - -<%= submit_tag l(:button_create) %> -<%= end_form_tag %> - - diff --git a/redmine/app/views/projects/add_file.rhtml b/redmine/app/views/projects/add_file.rhtml deleted file mode 100644 index fee67c53f..000000000 --- a/redmine/app/views/projects/add_file.rhtml +++ /dev/null @@ -1,14 +0,0 @@ -

    <%=l(:label_attachment_new)%>

    - -<%= error_messages_for 'attachment' %> -<%= start_form_tag ({ :action => 'add_file', :project => @project }, :multipart => true) %> - -


    -

    - -

    <%=l(:label_attachment)%>
    <%= file_field 'attachment', 'file' %>

    -
    -<%= submit_tag l(:button_add) %> -<%= end_form_tag %> \ No newline at end of file diff --git a/redmine/app/views/projects/add_issue.rhtml b/redmine/app/views/projects/add_issue.rhtml deleted file mode 100644 index b60f91a2e..000000000 --- a/redmine/app/views/projects/add_issue.rhtml +++ /dev/null @@ -1,50 +0,0 @@ -

    <%=l(:label_issue_new)%>: <%= @tracker.name %>

    - -<% labelled_tabular_form_for :issue, @issue, :url => {:action => 'add_issue'}, :html => {:multipart => true} do |f| %> -<%= error_messages_for 'issue' %> -
    - -<%= hidden_field_tag 'tracker_id', @tracker.id %> - -
    -

    <%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %>

    -

    <%= f.select :assigned_to_id, (@issue.project.members.collect {|m| [m.name, m.user_id]}), :include_blank => true %>

    -

    <%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>

    -
    -
    -

    <%= f.text_field :start_date, :size => 10 %><%= calendar_for('issue_start_date') %>

    -

    <%= f.text_field :due_date, :size => 10 %><%= calendar_for('issue_due_date') %>

    -

    <%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

    -
    - -
    -

    <%= f.text_field :subject, :size => 80, :required => true %>

    -

    <%= f.text_area :description, :cols => 60, :rows => 10, :required => true %>

    - -<% for @custom_value in @custom_values %> -

    <%= custom_field_tag_with_label @custom_value %>

    -<% end %> - -

    -<%= file_field_tag 'attachments[]', :size => 30 %>

    - -
    - -
    -<%= submit_tag l(:button_create) %> -<% end %> - -<% unless $RDM_TEXTILE_DISABLED %> -<%= javascript_include_tag 'jstoolbar' %> - -<% end %> \ No newline at end of file diff --git a/redmine/app/views/projects/add_news.rhtml b/redmine/app/views/projects/add_news.rhtml deleted file mode 100644 index a6ecd3da7..000000000 --- a/redmine/app/views/projects/add_news.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_news_new)%>

    - -<% labelled_tabular_form_for :news, @news, :url => { :action => "add_news" } do |f| %> -<%= render :partial => 'news/form', :locals => { :f => f } %> -<%= submit_tag l(:button_create) %> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/projects/add_version.rhtml b/redmine/app/views/projects/add_version.rhtml deleted file mode 100644 index c038b7de9..000000000 --- a/redmine/app/views/projects/add_version.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_version_new)%>

    - -<% labelled_tabular_form_for :version, @version, :url => { :action => 'add_version' } do |f| %> -<%= render :partial => 'versions/form', :locals => { :f => f } %> -<%= submit_tag l(:button_create) %> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/projects/calendar.rhtml b/redmine/app/views/projects/calendar.rhtml deleted file mode 100644 index fc62921d4..000000000 --- a/redmine/app/views/projects/calendar.rhtml +++ /dev/null @@ -1,75 +0,0 @@ -

    <%= l(:label_calendar) %>

    - - - - - - -
    -<%= start_form_tag :action => 'calendar', :id => @project %> -<%= select_month(@month, :prefix => "month", :discard_type => true) %> -<%= select_year(@year, :prefix => "year", :discard_type => true) %> -<%= submit_tag l(:button_submit), :class => "button-small" %> -<%= end_form_tag %> - -<%= image_tag 'gantt' %> -<%= link_to l(:label_gantt_chart), :action => 'gantt', :id => @project %>  -
    -
    - - - - -<% 1.upto(7) do |d| %> - -<% end %> - - -<% day = @date_from -while day <= @date_to - if day.cwday == 1 %> - - <% end %> - - <%= '' if day.cwday >= 7 and day!=@date_to %> - <% - day = day + 1 -end %> - -
    <%= day_name(d) %>
    <%= day.cweek %>"> -

    <%= day==Date.today ? "#{day.day}" : day.day %>

    - <% day_issues = [] - @issues.each { |i| day_issues << i if i.start_date == day or i.due_date == day } - day_issues.each do |i| %> - <%= if day == i.start_date and day == i.due_date - image_tag('arrow_bw') - elsif day == i.start_date - image_tag('arrow_from') - elsif day == i.due_date - image_tag('arrow_to') - end %> - <%= link_to "#{i.tracker.name} ##{i.id}", :controller => 'issues', :action => 'show', :id => i %>: <%= i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %>
    - <% end %> -
    - - - - - - -
    -<%= link_to_remote ('« ' + l(:label_previous)), - {:update => "content", :url => { :year => (@month==1 ? @year-1 : @year), :month =>(@month==1 ? 12 : @month-1) }}, - {:href => url_for(:action => 'calendar', :year => (@month==1 ? @year-1 : @year), :month =>(@month==1 ? 12 : @month-1))} - %> - -<%= link_to_remote (l(:label_next) + ' »'), - {:update => "content", :url => { :year => (@month==12 ? @year+1 : @year), :month =>(@month==12 ? 1 : @month+1) }}, - {:href => url_for(:action => 'calendar', :year => (@month==12 ? @year+1 : @year), :month =>(@month==12 ? 1 : @month+1))} - %> -  -
    -
    -<%= image_tag 'arrow_from' %>  <%= l(:text_tip_task_begin_day) %>
    -<%= image_tag 'arrow_to' %>  <%= l(:text_tip_task_end_day) %>
    -<%= image_tag 'arrow_bw' %>  <%= l(:text_tip_task_begin_end_day) %>
    \ No newline at end of file diff --git a/redmine/app/views/projects/changelog.rhtml b/redmine/app/views/projects/changelog.rhtml deleted file mode 100644 index 081456413..000000000 --- a/redmine/app/views/projects/changelog.rhtml +++ /dev/null @@ -1,28 +0,0 @@ -

    <%=l(:label_change_log)%>

    - -
    - -
    -<%= start_form_tag %> -<%=l(:label_tracker_plural)%>
    -<% @trackers.each do |tracker| %> - <%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %> - <%= tracker.name %>
    -<% end %> -

    <%= submit_tag l(:button_apply), :class => 'button-small' %>

    -<%= end_form_tag %> -
    - -<% ver_id = nil - @fixed_issues.each do |issue| %> - <% unless ver_id == issue.fixed_version_id %> - <% if ver_id %><% end %> -

    <%= l(:label_version) %>: <%= issue.fixed_version.name %>

    -

    <%= format_date(issue.fixed_version.effective_date) %>
    - <%=h issue.fixed_version.description %>

    -
      - <% ver_id = issue.fixed_version_id - end %> -
    • <%= link_to issue.long_id, :controller => 'issues', :action => 'show', :id => issue %> [<%= issue.tracker.name %>]: <%= issue.subject %>
    • -<% end %> -
    \ No newline at end of file diff --git a/redmine/app/views/projects/destroy.rhtml b/redmine/app/views/projects/destroy.rhtml deleted file mode 100644 index d11705be4..000000000 --- a/redmine/app/views/projects/destroy.rhtml +++ /dev/null @@ -1,14 +0,0 @@ -

    <%=l(:label_confirmation)%>

    -
    -
    -

    <%= @project.name %>
    -<%=l(:text_project_destroy_confirmation)%>

    - -

    - <%= start_form_tag({:controller => 'projects', :action => 'destroy', :id => @project}) %> - <%= hidden_field_tag "confirm", 1 %> - <%= submit_tag l(:button_delete) %> - <%= end_form_tag %> -

    -
    -
    \ No newline at end of file diff --git a/redmine/app/views/projects/export_issues_pdf.rfpdf b/redmine/app/views/projects/export_issues_pdf.rfpdf deleted file mode 100644 index 2e0acf54b..000000000 --- a/redmine/app/views/projects/export_issues_pdf.rfpdf +++ /dev/null @@ -1,11 +0,0 @@ -<% pdf=IfpdfHelper::IFPDF.new - pdf.AliasNbPages - pdf.footer_date = format_date(Date.today) - pdf.AddPage - @issues.each {|i| - render :partial => 'issues/pdf', :locals => { :pdf => pdf, :issue => i } - pdf.AddPage - } -%> - -<%= pdf.Output %> \ No newline at end of file diff --git a/redmine/app/views/projects/gantt.rfpdf b/redmine/app/views/projects/gantt.rfpdf deleted file mode 100644 index 545abb483..000000000 --- a/redmine/app/views/projects/gantt.rfpdf +++ /dev/null @@ -1,168 +0,0 @@ -<% -pdf=IfpdfHelper::IFPDF.new -pdf.AliasNbPages -pdf.footer_date = format_date(Date.today) -pdf.AddPage("L") -pdf.SetFont('Arial','B',12) -pdf.SetX(15) -pdf.Cell(70, 20, @project.name) -pdf.Ln -pdf.SetFont('Arial','B',9) - -subject_width = 70 -header_heigth = 5 - -headers_heigth = header_heigth -show_weeks = false -show_days = false - -if @months < 7 - show_weeks = true - headers_heigth = 2*header_heigth - if @months < 3 - show_days = true - headers_heigth = 3*header_heigth - end -end - -g_width = 210 -zoom = (g_width) / (@date_to - @date_from + 1) -g_height = 120 -t_height = g_height + headers_heigth - -y_start = pdf.GetY - - -# -# Months headers -# -month_f = @date_from -left = subject_width -height = header_heigth -@months.times do - width = ((month_f >> 1) - month_f) * zoom - pdf.SetY(y_start) - pdf.SetX(left) - pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C") - left = left + width - month_f = month_f >> 1 -end - -# -# Weeks headers -# -if show_weeks - left = subject_width - height = header_heigth - if @date_from.cwday == 1 - # @date_from is monday - week_f = @date_from - else - # find next monday after @date_from - week_f = @date_from + (7 - @date_from.cwday + 1) - width = (7 - @date_from.cwday + 1) * zoom-1 - pdf.SetY(y_start + header_heigth) - pdf.SetX(left) - pdf.Cell(width + 1, height, "", "LTR") - left = left + width+1 - end - while week_f < @date_to - width = (week_f + 6 <= @date_to) ? 7 * zoom : (@date_to - week_f + 1) * zoom - pdf.SetY(y_start + header_heigth) - pdf.SetX(left) - pdf.Cell(width, height, week_f.cweek.to_s, "LTR", 0, "C") - left = left + width - week_f = week_f+7 - end -end - -# -# Days headers -# -if show_days - left = subject_width - height = header_heigth - wday = @date_from.cwday - pdf.SetFont('Arial','B',7) - (@date_to - @date_from + 1).to_i.times do - width = zoom - pdf.SetY(y_start + 2 * header_heigth) - pdf.SetX(left) - pdf.Cell(width, height, day_name(wday)[0,1], "LTR", 0, "C") - left = left + width - wday = wday + 1 - wday = 1 if wday > 7 - end -end - -pdf.SetY(y_start) -pdf.SetX(15) -pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1) - - -# -# Tasks -# -top = headers_heigth + y_start -pdf.SetFont('Arial','B',7) -@issues.each do |i| - pdf.SetY(top) - pdf.SetX(15) - pdf.Cell(subject_width-15, 5, "#{i.tracker.name} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR") - - pdf.SetY(top) - pdf.SetX(subject_width) - pdf.Cell(g_width, 5, "", "LR") - - i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from ) - i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to ) - - i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor - i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date ) - i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date ) - - i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today - - i_left = ((i_start_date - @date_from)*zoom) - i_width = ((i_end_date - i_start_date + 1)*zoom) - d_width = ((i_done_date - i_start_date)*zoom) - l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date - l_width ||= 0 - - pdf.SetY(top+1.5) - pdf.SetX(subject_width + i_left) - pdf.SetFillColor(200,200,200) - pdf.Cell(i_width, 2, "", 0, 0, "", 1) - - if l_width > 0 - pdf.SetY(top+1.5) - pdf.SetX(subject_width + i_left) - pdf.SetFillColor(255,100,100) - pdf.Cell(l_width, 2, "", 0, 0, "", 1) - end - if d_width > 0 - pdf.SetY(top+1.5) - pdf.SetX(subject_width + i_left) - pdf.SetFillColor(100,100,255) - pdf.Cell(d_width, 2, "", 0, 0, "", 1) - end - - pdf.SetY(top+1.5) - pdf.SetX(subject_width + i_left + i_width) - pdf.Cell(30, 2, "#{i.status.name} #{i.done_ratio}%") - - top = top + 5 - pdf.SetDrawColor(200, 200, 200) - pdf.Line(15, top, subject_width+g_width, top) - if pdf.GetY() > 180 - pdf.AddPage("L") - top = 20 - pdf.Line(15, top, subject_width+g_width, top) - end - pdf.SetDrawColor(0, 0, 0) -end - -pdf.Line(15, top, subject_width+g_width, top) - -%> -<%= pdf.Output %> \ No newline at end of file diff --git a/redmine/app/views/projects/gantt.rhtml b/redmine/app/views/projects/gantt.rhtml deleted file mode 100644 index 78d3ac20a..000000000 --- a/redmine/app/views/projects/gantt.rhtml +++ /dev/null @@ -1,241 +0,0 @@ -

    <%= l(:label_gantt_chart) %>

    -
    - -<%= l(:label_export_to) %>  <%= link_to 'PDF', :zoom => @zoom, :year => @year_from, :month => @month_from, :months => @months, :output => 'pdf' %> - -
    - - - - - - -
    -<%= start_form_tag %> - -<%= l(:label_months_from) %> -<%= select_month(@month_from, :prefix => "month", :discard_type => true) %> -<%= select_year(@year_from, :prefix => "year", :discard_type => true) %> -<%= hidden_field_tag 'zoom', @zoom %> -<%= submit_tag l(:button_submit), :class => "button-small" %> -<%= end_form_tag %> - -<%= if @zoom < 4 - link_to image_tag('zoom_in'), {:zoom => (@zoom+1), :year => @year_from, :month => @month_from, :months => @months} - else - image_tag 'zoom_in_g' - end %> -<%= if @zoom > 1 - link_to image_tag('zoom_out'), :zoom => (@zoom-1), :year => @year_from, :month => @month_from, :months => @months - else - image_tag 'zoom_out_g' - end %> -
    -
    - - - -<% zoom = 1 -@zoom.times { zoom = zoom * 2 } - -subject_width = 260 -header_heigth = 18 - -headers_heigth = header_heigth -show_weeks = false -show_days = false - -if @zoom >1 - show_weeks = true - headers_heigth = 2*header_heigth - if @zoom > 2 - show_days = true - headers_heigth = 3*header_heigth - end -end - -g_width = (@date_to - @date_from + 1)*zoom -g_height = [(20 * @issues.length + 6), 206].max -t_height = g_height + headers_heigth -%> - - - - - - -
    - -
    -
    -
    -<% -# -# Tasks subjects -# -top = headers_heigth + 8 -@issues.each do |i| %> -
    - <%= link_to "#{i.tracker.name} ##{i.id}", :controller => 'issues', :action => 'show', :id => i %>: - <%= i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %> -
    -<% top = top + 20 -end %> -
    -
    - -
    -
     
    -<% -# -# Months headers -# -month_f = @date_from -left = 0 -height = (show_weeks ? header_heigth : header_heigth + g_height) -@months.times do - width = ((month_f >> 1) - month_f) * zoom - 1 - %> -
    - <%= link_to "#{month_f.year}-#{month_f.month}", :year => month_f.year, :month => month_f.month, :zoom => @zoom, :months => @months %> -
    - <% - left = left + width + 1 - month_f = month_f >> 1 -end %> - -<% -# -# Weeks headers -# -if show_weeks - left = 0 - height = (show_days ? header_heigth-1 : header_heigth-1 + g_height) - if @date_from.cwday == 1 - # @date_from is monday - week_f = @date_from - else - # find next monday after @date_from - week_f = @date_from + (7 - @date_from.cwday + 1) - width = (7 - @date_from.cwday + 1) * zoom-1 - %> -
     
    - <% - left = left + width+1 - end %> - <% - while week_f < @date_to - width = (week_f + 6 <= @date_to) ? 7 * zoom -1 : (@date_to - week_f + 1) * zoom-1 - %> -
    - <%= week_f.cweek %> -
    - <% - left = left + width+1 - week_f = week_f+7 - end -end %> - -<% -# -# Days headers -# -if show_days - left = 0 - height = g_height + header_heigth - 1 - wday = @date_from.cwday - (@date_to - @date_from + 1).to_i.times do - width = zoom - 1 - %> -
    5 %>" class="m_bg"> - <%= day_name(wday)[0,1] %> -
    - <% - left = left + width+1 - wday = wday + 1 - wday = 1 if wday > 7 - end -end %> - -<% -# -# Today red line -# -if Date.today >= @date_from and Date.today <= @date_to %> -
     
    -<% end %> - -<% -# -# Tasks -# -top = headers_heigth + 12 -@issues.each do |i| %> - <% - i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from ) - i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to ) - - i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor - i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date ) - i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date ) - - i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today - - i_left = ((i_start_date - @date_from)*zoom).floor - i_width = ((i_end_date - i_start_date + 1)*zoom).floor - d_width = ((i_done_date - i_start_date)*zoom).floor - l_width = ((i_late_date - i_start_date+1)*zoom).floor if i_late_date - l_width ||= 0 - %> -
     
    - <% if l_width > 0 %> -
     
    - <% end %> - <% if d_width > 0 %> -
     
    - <% end %> -
    - <%= i.status.name %> - <%= (i.done_ratio).to_i %>% -
    - <% top = top + 20 -end %> -
    -
    - - - - - - -
    <%= link_to ('« ' + l(:label_previous)), :year => (@date_from << @months).year, :month => (@date_from << @months).month, :zoom => @zoom, :months => @months %> -<%= link_to (l(:label_next) + ' »'), :year => (@date_from >> @months).year, :month => (@date_from >> @months).month, :zoom => @zoom, :months => @months %>
    \ No newline at end of file diff --git a/redmine/app/views/projects/list.rhtml b/redmine/app/views/projects/list.rhtml deleted file mode 100644 index 0137086d9..000000000 --- a/redmine/app/views/projects/list.rhtml +++ /dev/null @@ -1,20 +0,0 @@ -

    <%=l(:label_public_projects)%>

    - - - - <%= sort_header_tag('name', :caption => l(:label_project)) %> - - <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> - - -<% for project in @projects %> - "> - -<% end %> -
    <%=l(:field_description)%>
    <%= link_to project.name, :action => 'show', :id => project %> - <%= project.description %> - <%= format_date(project.created_on) %> -
    - -<%= pagination_links_full @project_pages %> -[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ] \ No newline at end of file diff --git a/redmine/app/views/projects/list_documents.rhtml b/redmine/app/views/projects/list_documents.rhtml deleted file mode 100644 index e6cf2b828..000000000 --- a/redmine/app/views/projects/list_documents.rhtml +++ /dev/null @@ -1,23 +0,0 @@ -

    <%=l(:label_document_plural)%>

    - -<% if @documents.empty? %>

    <%= l(:label_no_data) %>

    <% end %> - -<% documents = @documents.group_by {|d| d.category } %> -<% documents.each do |category, docs| %> -

    <%= category.name %>

    -
      -<% docs.each do |d| %> -
    • - <%= link_to d.title, :controller => 'documents', :action => 'show', :id => d %> -
      - <%= truncate d.description, 250 %>
      - <%= format_time(d.created_on) %>
        -
    • - -<% end %> -
    -<% end %> - -

    -<%= link_to_if_authorized '» ' + l(:label_document_new), :controller => 'projects', :action => 'add_document', :id => @project %> -

    diff --git a/redmine/app/views/projects/list_files.rhtml b/redmine/app/views/projects/list_files.rhtml deleted file mode 100644 index 5fe65e6a6..000000000 --- a/redmine/app/views/projects/list_files.rhtml +++ /dev/null @@ -1,46 +0,0 @@ -

    <%=l(:label_attachment_plural)%>

    - -<% delete_allowed = authorize_for('versions', 'destroy_file') %> - - - - - - - - - - <% if delete_allowed %><% end %> - - -<% for version in @versions %> - <% unless version.attachments.empty? %> - - <% for file in version.attachments %> - "> - - - - - - - <% if delete_allowed %> - - <% end %> - - <% end - reset_cycle %> - <% end %> -<% end %> -
    <%=l(:field_version)%><%=l(:field_filename)%><%=l(:label_date)%><%=l(:field_filesize)%>D/LMD5
    <%= image_tag 'package' %> <%= version.name %>
    <%= link_to file.filename, :controller => 'versions', :action => 'download', :id => version, :attachment_id => file %><%= format_date(file.created_on) %><%= human_size(file.filesize) %><%= file.downloads %><%= file.digest %> - <%= start_form_tag :controller => 'versions', :action => 'destroy_file', :id => version, :attachment_id => file %> - <%= submit_tag l(:button_delete), :class => "button-small" %> - <%= end_form_tag %> -
    - -
    -

    -<%= link_to_if_authorized '» ' + l(:label_attachment_new), :controller => 'projects', :action => 'add_file', :id => @project %> -

    - - diff --git a/redmine/app/views/projects/list_issues.rhtml b/redmine/app/views/projects/list_issues.rhtml deleted file mode 100644 index e7e3ceeda..000000000 --- a/redmine/app/views/projects/list_issues.rhtml +++ /dev/null @@ -1,76 +0,0 @@ -

    <%=l(:label_issue_plural)%>

    -
    - -<%= l(:label_export_to) %>  -<%= link_to 'CSV', :action => 'export_issues_csv', :id => @project %>, -<%= link_to 'PDF', :action => 'export_issues_pdf', :id => @project %> - -
    - -<%= start_form_tag :action => 'list_issues' %> - - - - - - - - - - - - - -
    <%=l(:field_status)%>:
    <%= search_filter_tag 'status_id', :class => 'select-small' %>
    <%=l(:field_tracker)%>:
    <%= search_filter_tag 'tracker_id', :class => 'select-small' %>
    <%=l(:field_priority)%>:
    <%= search_filter_tag 'priority_id', :class => 'select-small' %>
    <%=l(:field_category)%>:
    <%= search_filter_tag 'category_id', :class => 'select-small' %>
    <%=l(:field_fixed_version)%>:
    <%= search_filter_tag 'fixed_version_id', :class => 'select-small' %>
    <%=l(:field_author)%>:
    <%= search_filter_tag 'author_id', :class => 'select-small' %>
    <%=l(:field_assigned_to)%>:
    <%= search_filter_tag 'assigned_to_id', :class => 'select-small' %>
    <%=l(:label_subproject_plural)%>:
    <%= search_filter_tag 'subproject_id', :class => 'select-small' %>
    - <%= hidden_field_tag 'set_filter', 1 %> - <%= submit_tag l(:button_apply), :class => 'button-small' %> - - <%= link_to l(:button_clear), :action => 'list_issues', :id => @project, :set_filter => 1 %> -
    -<%= end_form_tag %> - -   - - - - - -
    <%= check_all_links 'issues_form' %> - <%= l(:label_per_page) %>: - <%= start_form_tag %> - <%= select_tag 'per_page', options_for_select(@results_per_page_options, @results_per_page), :class => 'select-small'%> - <%= submit_tag l(:button_apply), :class => 'button-small'%> - <%= end_form_tag %> -
    -<%= start_form_tag({:controller => 'projects', :action => 'move_issues', :id => @project}, :id => 'issues_form' ) %> - - - - - <%= sort_header_tag('issues.id', :caption => '#') %> - <%= sort_header_tag('issue_statuses.name', :caption => l(:field_status)) %> - <%= sort_header_tag('issues.tracker_id', :caption => l(:field_tracker)) %> - - <%= sort_header_tag('users.lastname', :caption => l(:field_author)) %> - <%= sort_header_tag('issues.created_on', :caption => l(:field_created_on)) %> - <%= sort_header_tag('issues.updated_on', :caption => l(:field_updated_on)) %> - - <% for issue in @issues %> - "> - - - - - - - - - - <% end %> -
    <%=l(:field_subject)%>
    <%= check_box_tag "issue_ids[]", issue.id %><%= link_to issue.long_id, :controller => 'issues', :action => 'show', :id => issue %><%= issue.status.name %><%= issue.tracker.name %><%= link_to issue.subject, :controller => 'issues', :action => 'show', :id => issue %><%= issue.author.display_name %><%= format_time(issue.created_on) %><%= format_time(issue.updated_on) %>
    -

    -<%= pagination_links_full @issue_pages %> -[ <%= @issue_pages.current.first_item %> - <%= @issue_pages.current.last_item %> / <%= @issue_count %> ] -

    -<%= submit_tag l(:button_move) %> -<%= end_form_tag %> \ No newline at end of file diff --git a/redmine/app/views/projects/list_members.rhtml b/redmine/app/views/projects/list_members.rhtml deleted file mode 100644 index 655abb280..000000000 --- a/redmine/app/views/projects/list_members.rhtml +++ /dev/null @@ -1,11 +0,0 @@ -

    <%=l(:label_member_plural)%>

    - -<% members = @members.group_by {|m| m.role } %> -<% members.each do |role, member| %> -

    <%= role.name %>

    -
      -<% member.each do |m| %> -
    • <%= link_to m.user.display_name, :controller => 'account', :action => 'show', :id => m.user %> (<%= format_date m.created_on %>)
    • -<% end %> -
    -<% end %> diff --git a/redmine/app/views/projects/list_news.rhtml b/redmine/app/views/projects/list_news.rhtml deleted file mode 100644 index 6880de32f..000000000 --- a/redmine/app/views/projects/list_news.rhtml +++ /dev/null @@ -1,18 +0,0 @@ -

    <%=l(:label_news_plural)%>

    - -<% if @news.empty? %>

    <%= l(:label_no_data) %>

    <% end %> - -
      -<% for news in @news %> -
    • <%= link_to news.title, :controller => 'news', :action => 'show', :id => news %>
      - <% unless news.summary.empty? %><%= news.summary %>
      <% end %> - <%= news.author.name %>, <%= format_time(news.created_on) %>
        -
    • -<% end %> -
    - - -<%= pagination_links_full @news_pages %> -

    -<%= link_to_if_authorized '» ' + l(:label_news_new), :controller => 'projects', :action => 'add_news', :id => @project %> -

    diff --git a/redmine/app/views/projects/move_issues.rhtml b/redmine/app/views/projects/move_issues.rhtml deleted file mode 100644 index 380d47fd5..000000000 --- a/redmine/app/views/projects/move_issues.rhtml +++ /dev/null @@ -1,24 +0,0 @@ -

    <%=l(:button_move)%>

    - - -<%= start_form_tag({:action => 'move_issues', :id => @project}, :class => "tabular") %> - -
    -

    -<% for issue in @issues %> - <%= link_to issue.long_id, :controller => 'issues', :action => 'show', :id => issue %> - <%= issue.subject %> - <%= hidden_field_tag "issue_ids[]", issue.id %>
    -<% end %> -(<%= @issues.length%> <%= lwr(:label_issue, @issues.length)%>)

    - -  - - -

    -<%= select_tag "new_project_id", options_from_collection_for_select(@projects, "id", "name", @project.id) %>

    - -

    -<%= select_tag "new_tracker_id", options_from_collection_for_select(@trackers, "id", "name") %>

    -
    -<%= submit_tag l(:button_move) %> -<%= end_form_tag %> diff --git a/redmine/app/views/projects/settings.rhtml b/redmine/app/views/projects/settings.rhtml deleted file mode 100644 index 3f9cba0a0..000000000 --- a/redmine/app/views/projects/settings.rhtml +++ /dev/null @@ -1,118 +0,0 @@ -

    <%=l(:label_settings)%>

    - -<% if authorize_for('projects', 'edit') %> - <% labelled_tabular_form_for :project, @project, :url => { :action => "edit", :id => @project } do |f| %> - <%= render :partial => 'form', :locals => { :f => f } %> - <%= submit_tag l(:button_save) %> - <% end %> -
      -<% end %> - -
    -

    <%=l(:label_member_plural)%>

    -<%= error_messages_for 'member' %> - -<% for member in @project.members.find(:all, :include => :user) %> - <% unless member.new_record? %> - - - - - - <% end %> -<% end %> -
    <%= member.user.display_name %> - <% if authorize_for('members', 'edit') %> - <%= start_form_tag :controller => 'members', :action => 'edit', :id => member %> - - <%= submit_tag l(:button_change), :class => "button-small" %> - <%= end_form_tag %> - <% end %> - - <% if authorize_for('members', 'destroy') %> - <%= start_form_tag :controller => 'members', :action => 'destroy', :id => member %> - <%= submit_tag l(:button_delete), :class => "button-small" %> - <%= end_form_tag %> - <% end %> -
    -<% if authorize_for('projects', 'add_member') %> -
    -
    - <%= start_form_tag :controller => 'projects', :action => 'add_member', :id => @project %> - - - <%= submit_tag l(:button_add) %> - <%= end_form_tag %> -<% end %> -
    - -
    -

    <%=l(:label_version_plural)%>

    - -<% for version in @project.versions %> - - - - - - -<% end %> -
    <%=h version.name %><%= format_date(version.effective_date) %><%=h version.description %>    - <%= link_to_if_authorized l(:button_edit), :controller => 'versions', :action => 'edit', :id => version %> - <% if authorize_for('versions', 'destroy') %> -   - <%= start_form_tag :controller => 'versions', :action => 'destroy', :id => version %> - <%= submit_tag l(:button_delete), :class => "button-small" %> - <%= end_form_tag %> - <% end %> -
    -<% if authorize_for('projects', 'add_version') %> -
    - <%= link_to l(:label_version_new), :controller => 'projects', :action => 'add_version', :id => @project %> -<% end %> -
    - - -
    -

    <%=l(:label_issue_category_plural)%>

    - -<% for @category in @project.issue_categories %> - <% unless @category.new_record? %> - - - - - - <% end %> -<% end %> -
    - <%= start_form_tag :controller => 'issue_categories', :action => 'edit', :id => @category %> - <%= text_field 'category', 'name', :size => 25 %> - - <% if authorize_for('issue_categories', 'edit') %> - <%= submit_tag l(:button_save), :class => "button-small" %> - <%= end_form_tag %> - <% end %> - - <% if authorize_for('issue_categories', 'destroy') %> - <%= start_form_tag :controller => 'issue_categories', :action => 'destroy', :id => @category %> - <%= submit_tag l(:button_delete), :class => "button-small" %> - <%= end_form_tag %> - <% end %> -
    -<% if authorize_for('projects', 'add_issue_category') %> -
    - <%= start_form_tag :action => 'add_issue_category', :id => @project %> -
    - <%= error_messages_for 'issue_category' %> - <%= text_field 'issue_category', 'name', :size => 25 %> - <%= submit_tag l(:button_create) %> - <%= end_form_tag %> -<% end %> -
    diff --git a/redmine/app/views/projects/show.rhtml b/redmine/app/views/projects/show.rhtml deleted file mode 100644 index 79e36a586..000000000 --- a/redmine/app/views/projects/show.rhtml +++ /dev/null @@ -1,72 +0,0 @@ -

    <%=l(:label_overview)%>

    - -
    - <%= simple_format(auto_link(@project.description)) %> -
      - <% unless @project.homepage.empty? %>
    • <%=l(:field_homepage)%>: <%= auto_link @project.homepage %>
    • <% end %> -
    • <%=l(:field_created_on)%>: <%= format_date(@project.created_on) %>
    • - <% for custom_value in @custom_values %> - <% if !custom_value.value.empty? %> -
    • <%= custom_value.custom_field.name%>: <%= show_value(custom_value) %>
    • - <% end %> - <% end %> -
    - -
    -

    <%= image_tag "tracker" %> <%=l(:label_tracker_plural)%>

    -
      - <% for tracker in @trackers %> -
    • <%= link_to tracker.name, :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "tracker_id" => tracker.id %>: - <%= issue_count = Issue.count(:conditions => ["project_id=? and tracker_id=? and issue_statuses.is_closed=?", @project.id, tracker.id, false], :include => :status) %> - <%= lwr(:label_open_issues, issue_count) %> -
    • - <% end %> -
    - <% if authorize_for 'projects', 'add_issue' %> - » <%=l(:label_issue_new)%>: -
      - <% @trackers.each do |tracker| %> -
    • <%= link_to tracker.name, :controller => 'projects', :action => 'add_issue', :id => @project, :tracker_id => tracker %>
    • - <% end %> -
    - <% end %> -
    [ <%= link_to l(:label_issue_view_all), :controller => 'projects', :action => 'list_issues', :id => @project, :set_filter => 1 %> ]
    -
    -
    - -
    -
    -

    <%= image_tag "users" %> <%=l(:label_member_plural)%>

    - <% for member in @members %> - <%= link_to_user member.user %> (<%= member.role.name %>)
    - <% end %> -
    - - <% if @subprojects %> -
    -

    <%= image_tag "projects" %> <%=l(:label_subproject_plural)%>

    - <% for subproject in @subprojects %> - <%= link_to subproject.name, :action => 'show', :id => subproject %>
    - <% end %> -
    - <% end %> - -
    -

    <%=l(:label_news_latest)%>

    - <% for news in @news %> -

    <%= news.title %> (<%= link_to_user news.author %> <%= format_time(news.created_on) %>)
    - <%= news.summary %> - [<%= link_to l(:label_read), :controller => 'news', :action => 'show', :id => news %>]

    -
    - <% end %> -
    [ <%= link_to l(:label_news_view_all), :controller => 'projects', :action => 'list_news', :id => @project %> ]
    -
    -
    - - - - - - diff --git a/redmine/app/views/reports/_details.rhtml b/redmine/app/views/reports/_details.rhtml deleted file mode 100644 index be4c82e77..000000000 --- a/redmine/app/views/reports/_details.rhtml +++ /dev/null @@ -1,47 +0,0 @@ -<% if @statuses.empty? or rows.empty? %> -

    <%=l(:label_no_data)%>

    -<% else %> -<% col_width = 70 / (@statuses.length+3) %> - - - -<% for status in @statuses %> - -<% end %> - - - - - -<% for row in rows %> -"> - - <% for status in @statuses %> - - <% end %> - - - -<% end %> - -
    <%= status.name %><%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to row.name, :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "#{field_name}" => row.id %><%= link_to (aggregate data, { field_name => row.id, "status_id" => status.id }), - :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "status_id" => status.id, - "#{field_name}" => row.id %><%= link_to (aggregate data, { field_name => row.id, "closed" => 0 }), - :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "#{field_name}" => row.id, - "status_id" => "O" %><%= link_to (aggregate data, { field_name => row.id, "closed" => 1 }), - :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "#{field_name}" => row.id, - "status_id" => "C" %><%= link_to (aggregate data, { field_name => row.id }), - :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "#{field_name}" => row.id, - "status_id" => "A" %>
    -<% end - reset_cycle %> \ No newline at end of file diff --git a/redmine/app/views/reports/_simple.rhtml b/redmine/app/views/reports/_simple.rhtml deleted file mode 100644 index 3be1281c5..000000000 --- a/redmine/app/views/reports/_simple.rhtml +++ /dev/null @@ -1,36 +0,0 @@ -<% if @statuses.empty? or rows.empty? %> -

    <%=l(:label_no_data)%>

    -<% else %> - - - - - - - - -<% for row in rows %> -"> - - - - -<% end %> - -
    <%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to row.name, :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "#{field_name}" => row.id %><%= link_to (aggregate data, { field_name => row.id, "closed" => 0 }), - :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "#{field_name}" => row.id, - "status_id" => "O" %><%= link_to (aggregate data, { field_name => row.id, "closed" => 1 }), - :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "#{field_name}" => row.id, - "status_id" => "C" %><%= link_to (aggregate data, { field_name => row.id }), - :controller => 'projects', :action => 'list_issues', :id => @project, - :set_filter => 1, - "#{field_name}" => row.id, - "status_id" => "A" %>
    -<% end - reset_cycle %> \ No newline at end of file diff --git a/redmine/app/views/reports/issue_report.rhtml b/redmine/app/views/reports/issue_report.rhtml deleted file mode 100644 index 4927186a9..000000000 --- a/redmine/app/views/reports/issue_report.rhtml +++ /dev/null @@ -1,20 +0,0 @@ -

    <%=l(:label_report_plural)%>

    - -
    -

    <%=l(:field_tracker)%>  <%= link_to image_tag('details'), :detail => 'author' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => "tracker_id", :rows => @trackers } %> -
    -

    <%=l(:field_priority)%>  <%= link_to image_tag('details'), :detail => 'priority' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_priority, :field_name => "priority_id", :rows => @priorities } %> -
    -

    <%=l(:field_author)%>  <%= link_to image_tag('details'), :detail => 'author' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => "author_id", :rows => @authors } %> -
    -
    - -
    -

    <%=l(:field_category)%>  <%= link_to image_tag('details'), :detail => 'category' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_category, :field_name => "category_id", :rows => @categories } %> -
    -
    - diff --git a/redmine/app/views/reports/issue_report_details.rhtml b/redmine/app/views/reports/issue_report_details.rhtml deleted file mode 100644 index e37d38649..000000000 --- a/redmine/app/views/reports/issue_report_details.rhtml +++ /dev/null @@ -1,7 +0,0 @@ -

    <%=l(:label_report_plural)%>

    - -

    <%=@report_title%>

    -<%= render :partial => 'details', :locals => { :data => @data, :field_name => @field, :rows => @rows } %> -
    -<%= link_to l(:button_back), :action => 'issue_report' %> - diff --git a/redmine/app/views/roles/_form.rhtml b/redmine/app/views/roles/_form.rhtml deleted file mode 100644 index e0ab1c099..000000000 --- a/redmine/app/views/roles/_form.rhtml +++ /dev/null @@ -1,20 +0,0 @@ -<%= error_messages_for 'role' %> -
    - -

    <%= f.text_field :name, :required => true %>

    - -<%=l(:label_permissions)%>: -<% permissions = @permissions.group_by {|p| p.group_id } %> -<% permissions.keys.sort.each do |group_id| %> -
    <%= l(Permission::GROUPS[group_id]) %> -<% permissions[group_id].each do |p| %> -
    <%= check_box_tag "permission_ids[]", p.id, (@role.permissions.include? p) %> - <%= l(p.description.to_sym) %> -
    -<% end %> -
    -<% end %> -
    -<%= check_all_links 'role_form' %> - -
    diff --git a/redmine/app/views/roles/edit.rhtml b/redmine/app/views/roles/edit.rhtml deleted file mode 100644 index ffe117cef..000000000 --- a/redmine/app/views/roles/edit.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_role)%>

    - -<% labelled_tabular_form_for :role, @role, :url => { :action => 'edit' }, :html => {:id => 'role_form'} do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> diff --git a/redmine/app/views/roles/list.rhtml b/redmine/app/views/roles/list.rhtml deleted file mode 100644 index 169b3d1c0..000000000 --- a/redmine/app/views/roles/list.rhtml +++ /dev/null @@ -1,21 +0,0 @@ -

    <%=l(:label_role_plural)%>

    - - - - - - - -<% for role in @roles %> - "> - - -<% end %> -
    <%=l(:label_role)%>
    <%= link_to role.name, :action => 'edit', :id => role %> - <%= button_to l(:button_delete), { :action => 'destroy', :id => role }, :confirm => l(:text_are_you_sure), :class => "button-small" %> -
    - -<%= pagination_links_full @role_pages %> -
    - -<%= link_to '» ' + l(:label_role_new), :action => 'new' %> diff --git a/redmine/app/views/roles/new.rhtml b/redmine/app/views/roles/new.rhtml deleted file mode 100644 index a73c36cb1..000000000 --- a/redmine/app/views/roles/new.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_role_new)%>

    - -<% labelled_tabular_form_for :role, @role, :url => { :action => 'new' }, :html => {:id => 'role_form'} do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_create) %> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/roles/workflow.rhtml b/redmine/app/views/roles/workflow.rhtml deleted file mode 100644 index ee5b3a278..000000000 --- a/redmine/app/views/roles/workflow.rhtml +++ /dev/null @@ -1,71 +0,0 @@ -

    <%=l(:label_workflow)%>

    - -

    <%=l(:text_workflow_edit)%>:

    - -<%= start_form_tag ({:action => 'workflow'}, :method => 'get') %> -
    -


    -

    -
    - -
    -


    - - -<%= submit_tag l(:button_edit) %> -

    -
    -<%= end_form_tag %> - - - -<% unless @tracker.nil? or @role.nil? %> -
    - <%= form_tag ({:action => 'workflow', :role_id => @role, :tracker_id => @tracker }, :id => 'workflow_form' ) %> - - - - - - - - <% for new_status in @statuses %> - - <% end %> - - - <% for old_status in @statuses %> - - - - - <% for new_status in @statuses %> - - <% end %> - - - <% end %> -
    <%=l(:label_current_status)%><%=l(:label_new_statuses_allowed)%>
    <%= new_status.name %>
     
    <%= old_status.name %> - - checked="checked"<%end%> - <%if old_status==new_status%>disabled<%end%> - > -
    -
    -

    -<%=l(:button_check_all)%> | -<%=l(:button_uncheck_all)%> -

    -
    -<%= submit_tag l(:button_save) %> -<%= end_form_tag %> - -<% end %> -
    \ No newline at end of file diff --git a/redmine/app/views/trackers/_form.rhtml b/redmine/app/views/trackers/_form.rhtml deleted file mode 100644 index 625c0d636..000000000 --- a/redmine/app/views/trackers/_form.rhtml +++ /dev/null @@ -1,7 +0,0 @@ -<%= error_messages_for 'tracker' %> -
    - -

    <%= f.text_field :name, :required => true %>

    -

    <%= f.check_box :is_in_chlog %>

    - -
    diff --git a/redmine/app/views/trackers/edit.rhtml b/redmine/app/views/trackers/edit.rhtml deleted file mode 100644 index d8411099c..000000000 --- a/redmine/app/views/trackers/edit.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_tracker)%>

    - -<% labelled_tabular_form_for :tracker, @tracker, :url => { :action => 'edit' } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/trackers/list.rhtml b/redmine/app/views/trackers/list.rhtml deleted file mode 100644 index 8d4a5c595..000000000 --- a/redmine/app/views/trackers/list.rhtml +++ /dev/null @@ -1,22 +0,0 @@ -

    <%=l(:label_tracker_plural)%>

    - - - - - - - -<% for tracker in @trackers %> - "> - - - -<% end %> -
    <%=l(:label_tracker)%>
    <%= link_to tracker.name, :action => 'edit', :id => tracker %> - <%= button_to l(:button_delete), { :action => 'destroy', :id => tracker }, :confirm => l(:text_are_you_sure), :class => "button-small" %> -
    - -<%= pagination_links_full @tracker_pages %> -
    - -<%= link_to '» ' + l(:label_tracker_new), :action => 'new' %> diff --git a/redmine/app/views/trackers/new.rhtml b/redmine/app/views/trackers/new.rhtml deleted file mode 100644 index b318a5dc4..000000000 --- a/redmine/app/views/trackers/new.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_tracker_new)%>

    - -<% labelled_tabular_form_for :tracker, @tracker, :url => { :action => 'new' } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_create) %> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/users/_form.rhtml b/redmine/app/views/users/_form.rhtml deleted file mode 100644 index 089d4d23c..000000000 --- a/redmine/app/views/users/_form.rhtml +++ /dev/null @@ -1,30 +0,0 @@ -<%= error_messages_for 'user' %> - - -
    -

    <%=l(:label_information_plural)%>

    -

    <%= f.text_field :login, :required => true, :size => 25 %>

    -

    <%= f.text_field :firstname, :required => true %>

    -

    <%= f.text_field :lastname, :required => true %>

    -

    <%= f.text_field :mail, :required => true %>

    -

    <%= f.select :language, lang_options_for_select %>

    - -<% for @custom_value in @custom_values %> -

    <%= custom_field_tag_with_label @custom_value %>

    -<% end %> - -

    <%= f.check_box :admin %>

    -

    <%= f.check_box :mail_notification %>

    -
    - -
    -

    <%=l(:label_authentication)%>

    -<% unless @auth_sources.empty? %> -

    <%= f.select :auth_source_id, [[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] } %>

    -<% end %> -

    -<%= password_field_tag 'password', nil, :size => 25 %>

    -

    -<%= password_field_tag 'password_confirmation', nil, :size => 25 %>

    -
    - diff --git a/redmine/app/views/users/add.rhtml b/redmine/app/views/users/add.rhtml deleted file mode 100644 index d4c6a15f4..000000000 --- a/redmine/app/views/users/add.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_user_new)%>

    - -<% labelled_tabular_form_for :user, @user, :url => { :action => "add" } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_create) %> -<% end %> \ No newline at end of file diff --git a/redmine/app/views/users/edit.rhtml b/redmine/app/views/users/edit.rhtml deleted file mode 100644 index 2332b70ad..000000000 --- a/redmine/app/views/users/edit.rhtml +++ /dev/null @@ -1,6 +0,0 @@ -

    <%=l(:label_user)%>

    - -<% labelled_tabular_form_for :user, @user, :url => { :action => "edit" } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> diff --git a/redmine/app/views/users/list.rhtml b/redmine/app/views/users/list.rhtml deleted file mode 100644 index 9f4438138..000000000 --- a/redmine/app/views/users/list.rhtml +++ /dev/null @@ -1,46 +0,0 @@ -

    <%=l(:label_user_plural)%>

    - - - - <%= sort_header_tag('login', :caption => l(:field_login)) %> - <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %> - <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %> - - <%= sort_header_tag('admin', :caption => l(:field_admin)) %> - <%= sort_header_tag('status', :caption => l(:field_status)) %> - <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> - <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on)) %> - - -<% for user in @users %> - "> - - - - - - - - - - -<% end %> -
    <%=l(:field_mail)%>
    <%= link_to user.login, :action => 'edit', :id => user %><%= user.firstname %><%= user.lastname %><%= user.mail %><%= image_tag 'true' if user.admin? %><%= image_tag 'locked' if user.locked? %><%= image_tag 'user_new' if user.registered? %><%= format_time(user.created_on) %><%= format_time(user.last_login_on) unless user.last_login_on.nil? %> - <%= start_form_tag :action => 'edit', :id => user %> - <% if user.locked? %> - <%= hidden_field_tag 'user[status]', User::STATUS_ACTIVE %> - <%= submit_tag l(:button_unlock), :class => "button-small" %> - <% else %> - <%= hidden_field_tag 'user[status]', User::STATUS_LOCKED %> - <%= submit_tag l(:button_lock), :class => "button-small" %> - <% end %> - <%= end_form_tag %> -
    - -

    <%= pagination_links_full @user_pages %> -[ <%= @user_pages.current.first_item %> - <%= @user_pages.current.last_item %> / <%= @user_count %> ] -

    - -

    -<%= link_to '» ' + l(:label_user_new), :action => 'add' %> -

    \ No newline at end of file diff --git a/redmine/app/views/versions/_form.rhtml b/redmine/app/views/versions/_form.rhtml deleted file mode 100644 index 3d0eb0a2d..000000000 --- a/redmine/app/views/versions/_form.rhtml +++ /dev/null @@ -1,9 +0,0 @@ -<%= error_messages_for 'version' %> - -
    - -

    <%= f.text_field :name, :size => 20, :required => true %>

    -

    <%= f.text_field :description, :size => 60 %>

    -

    <%= f.text_field :effective_date, :size => 10, :required => true %><%= calendar_for('version_effective_date') %>

    - -
    \ No newline at end of file diff --git a/redmine/app/views/versions/edit.rhtml b/redmine/app/views/versions/edit.rhtml deleted file mode 100644 index 1556ebba1..000000000 --- a/redmine/app/views/versions/edit.rhtml +++ /dev/null @@ -1,7 +0,0 @@ -

    <%=l(:label_version)%>

    - -<% labelled_tabular_form_for :version, @version, :url => { :action => 'edit' } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> - diff --git a/redmine/app/views/welcome/index.rhtml b/redmine/app/views/welcome/index.rhtml deleted file mode 100644 index abee85691..000000000 --- a/redmine/app/views/welcome/index.rhtml +++ /dev/null @@ -1,30 +0,0 @@ -

    <%= $RDM_WELCOME_TITLE || l(:label_home) %>

    - -
    - <% if $RDM_WELCOME_TEXT %>

    <%= $RDM_WELCOME_TEXT %>


    <% end %> -
    -

    <%=l(:label_news_latest)%>

    - <% for news in @news %> -

    - <%= news.title %> (<%= link_to_user news.author %> <%= format_time(news.created_on) %> - <%= news.project.name %>)
    - <% unless news.summary.empty? %><%= news.summary %>
    <% end %> - [<%= link_to l(:label_read), :controller => 'news', :action => 'show', :id => news %>] -

    -
    - <% end %> -
    -
    - -
    -
    -

    <%=l(:label_project_latest)%>

    -
      - <% for project in @projects %> -
    • - <%= link_to project.name, :controller => 'projects', :action => 'show', :id => project %> (<%= format_time(project.created_on) %>)
      - <%= project.description %> -
    • - <% end %> -
    -
    -
    diff --git a/redmine/config/boot.rb b/redmine/config/boot.rb deleted file mode 100644 index 9fcd50fe3..000000000 --- a/redmine/config/boot.rb +++ /dev/null @@ -1,19 +0,0 @@ -# Don't change this file. Configuration is done in config/environment.rb and config/environments/*.rb - -unless defined?(RAILS_ROOT) - root_path = File.join(File.dirname(__FILE__), '..') - unless RUBY_PLATFORM =~ /mswin32/ - require 'pathname' - root_path = Pathname.new(root_path).cleanpath(true).to_s - end - RAILS_ROOT = root_path -end - -if File.directory?("#{RAILS_ROOT}/vendor/rails") - require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" -else - require 'rubygems' - require 'initializer' -end - -Rails::Initializer.run(:set_load_path) diff --git a/redmine/config/config_custom.example.rb b/redmine/config/config_custom.example.rb deleted file mode 100644 index 689d9daec..000000000 --- a/redmine/config/config_custom.example.rb +++ /dev/null @@ -1,65 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -# To set your own configuration, rename this file to config_custom.rb -# and edit parameters below -# Don't forget to restart the application after any change. - - -# Application host name -# Used to provide absolute links in mail notifications -# $RDM_HOST_NAME = "somenet.foo" - -# File storage path -# Directory used to store uploaded files -# #{RAILS_ROOT} represents application's home directory -# $RDM_STORAGE_PATH = "#{RAILS_ROOT}/files" - -# Set $RDM_LOGIN_REQUIRED to true if you want to force users to login -# to access any page of the application -# $RDM_LOGIN_REQUIRED = false - -# Uncomment to disable user self-registration -# $RDM_SELF_REGISTRATION = false - -# Default langage ('en', 'es', 'de', 'fr' are available) -# $RDM_DEFAULT_LANG = 'en' - -# Email adress used to send mail notifications -# $RDM_MAIL_FROM = "redmine@somenet.foo" - -# Page title -# $RDM_HEADER_TITLE = "Title" - -# Page sub-title -# $RDM_HEADER_SUBTITLE = "Sub title" - -# Welcome page title -# $RDM_WELCOME_TITLE = "Welcome" - -# Welcome page text -# $RDM_WELCOME_TEXT = "" - -# Signature displayed in footer -# Email adresses will be automatically displayed as a mailto link -# $RDM_FOOTER_SIG = "admin@somenet.foo" - -# Textile formatting (only available if RedCloth is installed) -# Textile formatting is automativaly disabled if RedCloth is not available -# Set to true to manually disable. -# $RDM_TEXTILE_DISABLED = true diff --git a/redmine/config/database.yml b/redmine/config/database.yml deleted file mode 100644 index cfb6f13df..000000000 --- a/redmine/config/database.yml +++ /dev/null @@ -1,69 +0,0 @@ -# MySQL (default setup). Versions 4.1 and 5.0 are recommended. -# -# Get the fast C bindings: -# gem install mysql -# (on OS X: gem install mysql -- --include=/usr/local/lib) -# And be sure to use new-style password hashing: -# http://dev.mysql.com/doc/refman/5.0/en/old-client.html - -production: - adapter: mysql - database: redmine - host: localhost - username: root - password: - -development: - adapter: mysql - database: redmine_development - host: localhost - username: root - password: - -development_pgsql: - adapter: postgresql - database: redmine - host: localhost - username: postgres - password: "postgres" - -development_oracle: - adapter: oci - host: 192.168.0.14 - username: rails - password: "rails" - -development_sqlserver: - adapter: sqlserver - host: localhost,1157 - database: redmine - -test: - adapter: mysql - database: redmine_test - host: localhost - username: root - password: - -test_pgsql: - adapter: postgresql - database: redmine - host: localhost - username: postgres - password: "postgres" - -test_oracle: - adapter: oci - host: 192.168.0.14 - username: rails_test - password: "rails" - -test_sqlserver: - adapter: sqlserver - host: localhost,1157 - database: redmine_test - -demo: - adapter: sqlite3 - dbfile: db/redmine_demo.db - diff --git a/redmine/config/environment.rb b/redmine/config/environment.rb deleted file mode 100644 index 359293b6e..000000000 --- a/redmine/config/environment.rb +++ /dev/null @@ -1,140 +0,0 @@ -# Be sure to restart your web server when you modify this file. - -# Uncomment below to force Rails into production mode when -# you don't control web/app server and can't set it the proper way -# ENV['RAILS_ENV'] ||= 'production' - -# Bootstrap the Rails environment, frameworks, and default configuration -require File.join(File.dirname(__FILE__), 'boot') - -Rails::Initializer.run do |config| - # Settings in config/environments/* take precedence those specified here - - # Skip frameworks you're not going to use - # config.frameworks -= [ :action_web_service, :action_mailer ] - - # Add additional load paths for your own custom dirs - # config.load_paths += %W( #{RAILS_ROOT}/extras ) - - # Force all environments to use the same logger level - # (by default production uses :info, the others :debug) - # config.log_level = :debug - - # Use the database for sessions instead of the file system - # (create the session table with 'rake create_sessions_table') - # config.action_controller.session_store = :active_record_store - - # Enable page/fragment caching by setting a file-based store - # (remember to create the caching directory and make it readable to the application) - # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" - - # Activate observers that should always be running - # config.active_record.observers = :cacher, :garbage_collector - - # Make Active Record use UTC-base instead of local time - # config.active_record.default_timezone = :utc - - # Use Active Record's schema dumper instead of SQL when creating the test database - # (enables use of different database adapters for development and test environments) - # config.active_record.schema_format = :ruby - - # See Rails::Configuration for more options - - # SMTP server configuration - config.action_mailer.server_settings = { - :address => "127.0.0.1", - :port => 25, - :domain => "somenet.foo", - :authentication => :login, - :user_name => "redmine", - :password => "redmine", - } - - config.action_mailer.perform_deliveries = true - - # Tell ActionMailer not to deliver emails to the real world. - # The :test delivery method accumulates sent emails in the - # ActionMailer::Base.deliveries array. - #config.action_mailer.delivery_method = :test - config.action_mailer.delivery_method = :smtp -end - -# Add new inflection rules using the following format -# (all these examples are active by default): -# Inflector.inflections do |inflect| -# inflect.plural /^(ox)$/i, '\1en' -# inflect.singular /^(ox)en/i, '\1' -# inflect.irregular 'person', 'people' -# inflect.uncountable %w( fish sheep ) -# end - -if File.exist? File.join(File.dirname(__FILE__), 'config_custom.rb') - begin - print "=> Loading config_custom.rb... " - require File.join(File.dirname(__FILE__), 'config_custom') - puts "done." - rescue Exception => detail - puts - puts detail - puts detail.backtrace.join("\n") - puts "=> Error in config_custom.rb. Check your configuration." - exit - end -end - -# IMPORTANT !!! DO NOT MODIFY PARAMETERS HERE -# Instead, rename config_custom.example.rb to config_custom.rb -# and set your own configuration in that file -# Parameters defined in config_custom.rb override those defined below - -# application host name -$RDM_HOST_NAME ||= "localhost:3000" -# file storage path -$RDM_STORAGE_PATH ||= "#{RAILS_ROOT}/files" -# if RDM_LOGIN_REQUIRED is set to true, login is required to access the application -$RDM_LOGIN_REQUIRED ||= false -# default langage -$RDM_DEFAULT_LANG ||= 'en' -# email sender adress -$RDM_MAIL_FROM ||= "redmine@somenet.foo" - -# page title -$RDM_HEADER_TITLE ||= "redMine" -# page sub-title -$RDM_HEADER_SUBTITLE ||= "Project management" -# footer signature -$RDM_FOOTER_SIG = "admin@somenet.foo" - -# textile formatting -# automaticaly disabled if 'textile' method is not defined (RedCloth unavailable) -$RDM_TEXTILE_DISABLED = true unless ActionView::Helpers::TextHelper.method_defined? "textilize" - -# application name -RDM_APP_NAME = "redMine" -# application version -RDM_APP_VERSION = "0.3.0" - -ActiveRecord::Errors.default_error_messages = { - :inclusion => "activerecord_error_inclusion", - :exclusion => "activerecord_error_exclusion", - :invalid => "activerecord_error_invalid", - :confirmation => "activerecord_error_confirmation", - :accepted => "activerecord_error_accepted", - :empty => "activerecord_error_empty", - :blank => "activerecord_error_blank", - :too_long => "activerecord_error_too_long", - :too_short => "activerecord_error_too_short", - :wrong_length => "activerecord_error_wrong_length", - :taken => "activerecord_error_taken", - :not_a_number => "activerecord_error_not_a_number" -} - -ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" } - -GLoc.set_config :default_language => $RDM_DEFAULT_LANG -GLoc.clear_strings -GLoc.set_kcode -GLoc.load_localized_strings -GLoc.set_config(:raise_string_not_found_errors => false) - - diff --git a/redmine/config/environments/demo.rb b/redmine/config/environments/demo.rb deleted file mode 100644 index 52aef32f1..000000000 --- a/redmine/config/environments/demo.rb +++ /dev/null @@ -1,21 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# The production environment is meant for finished, "live" apps. -# Code is not reloaded between requests -config.cache_classes = true - -# Use a different logger for distributed setups -# config.logger = SyslogLogger.new -config.log_level = :info - -# Full error reports are disabled and caching is turned on -config.action_controller.consider_all_requests_local = false -config.action_controller.perform_caching = true - -# Enable serving of images, stylesheets, and javascripts from an asset server -# config.action_controller.asset_host = "http://assets.example.com" - -# Disable mail delivery -config.action_mailer.perform_deliveries = false -config.action_mailer.raise_delivery_errors = false - diff --git a/redmine/config/environments/development.rb b/redmine/config/environments/development.rb deleted file mode 100644 index 04b779200..000000000 --- a/redmine/config/environments/development.rb +++ /dev/null @@ -1,19 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# In the development environment your application's code is reloaded on -# every request. This slows down response time but is perfect for development -# since you don't have to restart the webserver when you make code changes. -config.cache_classes = false - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Enable the breakpoint server that script/breakpointer connects to -config.breakpoint_server = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false diff --git a/redmine/config/environments/development_oracle.rb b/redmine/config/environments/development_oracle.rb deleted file mode 100644 index 04b779200..000000000 --- a/redmine/config/environments/development_oracle.rb +++ /dev/null @@ -1,19 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# In the development environment your application's code is reloaded on -# every request. This slows down response time but is perfect for development -# since you don't have to restart the webserver when you make code changes. -config.cache_classes = false - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Enable the breakpoint server that script/breakpointer connects to -config.breakpoint_server = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false diff --git a/redmine/config/environments/development_pgsql.rb b/redmine/config/environments/development_pgsql.rb deleted file mode 100644 index 04b779200..000000000 --- a/redmine/config/environments/development_pgsql.rb +++ /dev/null @@ -1,19 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# In the development environment your application's code is reloaded on -# every request. This slows down response time but is perfect for development -# since you don't have to restart the webserver when you make code changes. -config.cache_classes = false - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Enable the breakpoint server that script/breakpointer connects to -config.breakpoint_server = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false diff --git a/redmine/config/environments/development_sqlserver.rb b/redmine/config/environments/development_sqlserver.rb deleted file mode 100644 index 04b779200..000000000 --- a/redmine/config/environments/development_sqlserver.rb +++ /dev/null @@ -1,19 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# In the development environment your application's code is reloaded on -# every request. This slows down response time but is perfect for development -# since you don't have to restart the webserver when you make code changes. -config.cache_classes = false - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Enable the breakpoint server that script/breakpointer connects to -config.breakpoint_server = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false diff --git a/redmine/config/environments/production.rb b/redmine/config/environments/production.rb deleted file mode 100644 index 4cd4e086b..000000000 --- a/redmine/config/environments/production.rb +++ /dev/null @@ -1,20 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# The production environment is meant for finished, "live" apps. -# Code is not reloaded between requests -config.cache_classes = true - -# Use a different logger for distributed setups -# config.logger = SyslogLogger.new - - -# Full error reports are disabled and caching is turned on -config.action_controller.consider_all_requests_local = false -config.action_controller.perform_caching = true - -# Enable serving of images, stylesheets, and javascripts from an asset server -# config.action_controller.asset_host = "http://assets.example.com" - -# Disable delivery errors if you bad email addresses should just be ignored -config.action_mailer.raise_delivery_errors = false - diff --git a/redmine/config/environments/test.rb b/redmine/config/environments/test.rb deleted file mode 100644 index 9ba9ae0f8..000000000 --- a/redmine/config/environments/test.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# The test environment is used exclusively to run your application's -# test suite. You never need to work with it otherwise. Remember that -# your test database is "scratch space" for the test suite and is wiped -# and recreated between test runs. Don't rely on the data there! -config.cache_classes = true - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -config.action_mailer.delivery_method = :test diff --git a/redmine/config/environments/test_oracle.rb b/redmine/config/environments/test_oracle.rb deleted file mode 100644 index 35bb19bee..000000000 --- a/redmine/config/environments/test_oracle.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# The test environment is used exclusively to run your application's -# test suite. You never need to work with it otherwise. Remember that -# your test database is "scratch space" for the test suite and is wiped -# and recreated between test runs. Don't rely on the data there! -config.cache_classes = true - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -config.action_mailer.delivery_method = :test \ No newline at end of file diff --git a/redmine/config/environments/test_pgsql.rb b/redmine/config/environments/test_pgsql.rb deleted file mode 100644 index 35bb19bee..000000000 --- a/redmine/config/environments/test_pgsql.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# The test environment is used exclusively to run your application's -# test suite. You never need to work with it otherwise. Remember that -# your test database is "scratch space" for the test suite and is wiped -# and recreated between test runs. Don't rely on the data there! -config.cache_classes = true - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -config.action_mailer.delivery_method = :test \ No newline at end of file diff --git a/redmine/config/environments/test_sqlserver.rb b/redmine/config/environments/test_sqlserver.rb deleted file mode 100644 index 35bb19bee..000000000 --- a/redmine/config/environments/test_sqlserver.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# The test environment is used exclusively to run your application's -# test suite. You never need to work with it otherwise. Remember that -# your test database is "scratch space" for the test suite and is wiped -# and recreated between test runs. Don't rely on the data there! -config.cache_classes = true - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -config.action_mailer.delivery_method = :test \ No newline at end of file diff --git a/redmine/config/help.yml b/redmine/config/help.yml deleted file mode 100644 index b02a06fb1..000000000 --- a/redmine/config/help.yml +++ /dev/null @@ -1,63 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -# available languages for help pages -langs: - - en - - fr - -# mapping between controller/action and help pages -# if action is not defined here, 'index' page will be displayed -pages: - # administration - admin: - index: ch01.html - mail_options: ch01s08.html - info: ch01s09.html - users: - index: ch01s01.html - roles: - index: ch01s02.html - workflow: ch01s06.html - trackers: - index: ch01s03.html - issue_statuses: - index: ch01s05.html - # projects - projects: - index: ch02.html - add: ch02s08.html - show: ch02s01.html - add_document: ch02s06.html - list_documents: ch02s06.html - add_issue: ch02s02.html - list_issues: ch02s02.html - add_news: ch02s05.html - list_news: ch02s05.html - add_file: ch02s07.html - list_files: ch02s07.html - changelog: ch02s04.html - issues: - index: ch02s02.html - documents: - index: ch02s06.html - news: - index: ch02s05.html - versions: - index: ch02s08.html - reports: - index: ch02s03.html \ No newline at end of file diff --git a/redmine/config/routes.rb b/redmine/config/routes.rb deleted file mode 100644 index 2559159f1..000000000 --- a/redmine/config/routes.rb +++ /dev/null @@ -1,24 +0,0 @@ -ActionController::Routing::Routes.draw do |map| - # Add your own custom routes here. - # The priority is based upon order of creation: first created -> highest priority. - - # Here's a sample route: - # map.connect 'products/:id', :controller => 'catalog', :action => 'view' - # Keep in mind you can assign values other than :controller and :action - - # You can have the root of your site routed by hooking up '' - # -- just remember to delete public/index.html. - map.connect '', :controller => "welcome" - - map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow' - map.connect 'help/:ctrl/:page', :controller => 'help' - map.connect ':controller/:action/:id/:sort_key/:sort_order' - - # Allow downloading Web Service WSDL as a file with an extension - # instead of a file named 'wsdl' - map.connect ':controller/service.wsdl', :action => 'wsdl' - - - # Install the default route as the lowest priority. - map.connect ':controller/:action/:id' -end diff --git a/redmine/db/migrate/001_setup.rb b/redmine/db/migrate/001_setup.rb deleted file mode 100644 index ee22c148b..000000000 --- a/redmine/db/migrate/001_setup.rb +++ /dev/null @@ -1,317 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Setup < ActiveRecord::Migration - def self.up - create_table "attachments", :force => true do |t| - t.column "container_id", :integer, :default => 0, :null => false - t.column "container_type", :string, :limit => 30, :default => "", :null => false - t.column "filename", :string, :default => "", :null => false - t.column "disk_filename", :string, :default => "", :null => false - t.column "filesize", :integer, :default => 0, :null => false - t.column "content_type", :string, :limit => 60, :default => "" - t.column "digest", :string, :limit => 40, :default => "", :null => false - t.column "downloads", :integer, :default => 0, :null => false - t.column "author_id", :integer, :default => 0, :null => false - t.column "created_on", :timestamp - end - - create_table "auth_sources", :force => true do |t| - t.column "type", :string, :limit => 30, :default => "", :null => false - t.column "name", :string, :limit => 60, :default => "", :null => false - t.column "host", :string, :limit => 60 - t.column "port", :integer - t.column "account", :string, :limit => 60 - t.column "account_password", :string, :limit => 60 - t.column "base_dn", :string, :limit => 255 - t.column "attr_login", :string, :limit => 30 - t.column "attr_firstname", :string, :limit => 30 - t.column "attr_lastname", :string, :limit => 30 - t.column "attr_mail", :string, :limit => 30 - t.column "onthefly_register", :boolean, :default => false, :null => false - end - - create_table "custom_fields", :force => true do |t| - t.column "type", :string, :limit => 30, :default => "", :null => false - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "field_format", :string, :limit => 30, :default => "", :null => false - t.column "possible_values", :text, :default => "" - t.column "regexp", :string, :default => "" - t.column "min_length", :integer, :default => 0, :null => false - t.column "max_length", :integer, :default => 0, :null => false - t.column "is_required", :boolean, :default => false, :null => false - t.column "is_for_all", :boolean, :default => false, :null => false - end - - create_table "custom_fields_projects", :id => false, :force => true do |t| - t.column "custom_field_id", :integer, :default => 0, :null => false - t.column "project_id", :integer, :default => 0, :null => false - end - - create_table "custom_fields_trackers", :id => false, :force => true do |t| - t.column "custom_field_id", :integer, :default => 0, :null => false - t.column "tracker_id", :integer, :default => 0, :null => false - end - - create_table "custom_values", :force => true do |t| - t.column "customized_type", :string, :limit => 30, :default => "", :null => false - t.column "customized_id", :integer, :default => 0, :null => false - t.column "custom_field_id", :integer, :default => 0, :null => false - t.column "value", :text, :default => "", :null => false - end - - create_table "documents", :force => true do |t| - t.column "project_id", :integer, :default => 0, :null => false - t.column "category_id", :integer, :default => 0, :null => false - t.column "title", :string, :limit => 60, :default => "", :null => false - t.column "description", :text, :default => "" - t.column "created_on", :timestamp - end - - add_index "documents", ["project_id"], :name => "documents_project_id" - - create_table "enumerations", :force => true do |t| - t.column "opt", :string, :limit => 4, :default => "", :null => false - t.column "name", :string, :limit => 30, :default => "", :null => false - end - - create_table "issue_categories", :force => true do |t| - t.column "project_id", :integer, :default => 0, :null => false - t.column "name", :string, :limit => 30, :default => "", :null => false - end - - add_index "issue_categories", ["project_id"], :name => "issue_categories_project_id" - - create_table "issue_histories", :force => true do |t| - t.column "issue_id", :integer, :default => 0, :null => false - t.column "status_id", :integer, :default => 0, :null => false - t.column "author_id", :integer, :default => 0, :null => false - t.column "notes", :text, :default => "" - t.column "created_on", :timestamp - end - - add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" - - create_table "issue_statuses", :force => true do |t| - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "is_closed", :boolean, :default => false, :null => false - t.column "is_default", :boolean, :default => false, :null => false - t.column "html_color", :string, :limit => 6, :default => "FFFFFF", :null => false - end - - create_table "issues", :force => true do |t| - t.column "tracker_id", :integer, :default => 0, :null => false - t.column "project_id", :integer, :default => 0, :null => false - t.column "subject", :string, :default => "", :null => false - t.column "description", :text, :default => "", :null => false - t.column "due_date", :date - t.column "category_id", :integer - t.column "status_id", :integer, :default => 0, :null => false - t.column "assigned_to_id", :integer - t.column "priority_id", :integer, :default => 0, :null => false - t.column "fixed_version_id", :integer - t.column "author_id", :integer, :default => 0, :null => false - t.column "lock_version", :integer, :default => 0, :null => false - t.column "created_on", :timestamp - t.column "updated_on", :timestamp - end - - add_index "issues", ["project_id"], :name => "issues_project_id" - - create_table "members", :force => true do |t| - t.column "user_id", :integer, :default => 0, :null => false - t.column "project_id", :integer, :default => 0, :null => false - t.column "role_id", :integer, :default => 0, :null => false - t.column "created_on", :timestamp - end - - create_table "news", :force => true do |t| - t.column "project_id", :integer - t.column "title", :string, :limit => 60, :default => "", :null => false - t.column "summary", :string, :limit => 255, :default => "" - t.column "description", :text, :default => "", :null => false - t.column "author_id", :integer, :default => 0, :null => false - t.column "created_on", :timestamp - end - - add_index "news", ["project_id"], :name => "news_project_id" - - create_table "permissions", :force => true do |t| - t.column "controller", :string, :limit => 30, :default => "", :null => false - t.column "action", :string, :limit => 30, :default => "", :null => false - t.column "description", :string, :limit => 60, :default => "", :null => false - t.column "is_public", :boolean, :default => false, :null => false - t.column "sort", :integer, :default => 0, :null => false - t.column "mail_option", :boolean, :default => false, :null => false - t.column "mail_enabled", :boolean, :default => false, :null => false - end - - create_table "permissions_roles", :id => false, :force => true do |t| - t.column "permission_id", :integer, :default => 0, :null => false - t.column "role_id", :integer, :default => 0, :null => false - end - - add_index "permissions_roles", ["role_id"], :name => "permissions_roles_role_id" - - create_table "projects", :force => true do |t| - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "description", :string, :default => "", :null => false - t.column "homepage", :string, :limit => 60, :default => "" - t.column "is_public", :boolean, :default => true, :null => false - t.column "parent_id", :integer - t.column "projects_count", :integer, :default => 0 - t.column "created_on", :timestamp - t.column "updated_on", :timestamp - end - - create_table "roles", :force => true do |t| - t.column "name", :string, :limit => 30, :default => "", :null => false - end - - create_table "tokens", :force => true do |t| - t.column "user_id", :integer, :default => 0, :null => false - t.column "action", :string, :limit => 30, :default => "", :null => false - t.column "value", :string, :limit => 40, :default => "", :null => false - t.column "created_on", :datetime, :null => false - end - - create_table "trackers", :force => true do |t| - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "is_in_chlog", :boolean, :default => false, :null => false - end - - create_table "users", :force => true do |t| - t.column "login", :string, :limit => 30, :default => "", :null => false - t.column "hashed_password", :string, :limit => 40, :default => "", :null => false - t.column "firstname", :string, :limit => 30, :default => "", :null => false - t.column "lastname", :string, :limit => 30, :default => "", :null => false - t.column "mail", :string, :limit => 60, :default => "", :null => false - t.column "mail_notification", :boolean, :default => true, :null => false - t.column "admin", :boolean, :default => false, :null => false - t.column "status", :integer, :default => 1, :null => false - t.column "last_login_on", :datetime - t.column "language", :string, :limit => 2, :default => "" - t.column "auth_source_id", :integer - t.column "created_on", :timestamp - t.column "updated_on", :timestamp - end - - create_table "versions", :force => true do |t| - t.column "project_id", :integer, :default => 0, :null => false - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "description", :string, :default => "" - t.column "effective_date", :date, :null => false - t.column "created_on", :timestamp - t.column "updated_on", :timestamp - end - - add_index "versions", ["project_id"], :name => "versions_project_id" - - create_table "workflows", :force => true do |t| - t.column "tracker_id", :integer, :default => 0, :null => false - t.column "old_status_id", :integer, :default => 0, :null => false - t.column "new_status_id", :integer, :default => 0, :null => false - t.column "role_id", :integer, :default => 0, :null => false - end - - # project - Permission.create :controller => "projects", :action => "show", :description => "label_overview", :sort => 100, :is_public => true - Permission.create :controller => "projects", :action => "changelog", :description => "label_change_log", :sort => 105, :is_public => true - Permission.create :controller => "reports", :action => "issue_report", :description => "label_report_plural", :sort => 110, :is_public => true - Permission.create :controller => "projects", :action => "settings", :description => "label_settings", :sort => 150 - Permission.create :controller => "projects", :action => "edit", :description => "button_edit", :sort => 151 - # members - Permission.create :controller => "projects", :action => "list_members", :description => "button_list", :sort => 200, :is_public => true - Permission.create :controller => "projects", :action => "add_member", :description => "button_add", :sort => 220 - Permission.create :controller => "members", :action => "edit", :description => "button_edit", :sort => 221 - Permission.create :controller => "members", :action => "destroy", :description => "button_delete", :sort => 222 - # versions - Permission.create :controller => "projects", :action => "add_version", :description => "button_add", :sort => 320 - Permission.create :controller => "versions", :action => "edit", :description => "button_edit", :sort => 321 - Permission.create :controller => "versions", :action => "destroy", :description => "button_delete", :sort => 322 - # issue categories - Permission.create :controller => "projects", :action => "add_issue_category", :description => "button_add", :sort => 420 - Permission.create :controller => "issue_categories", :action => "edit", :description => "button_edit", :sort => 421 - Permission.create :controller => "issue_categories", :action => "destroy", :description => "button_delete", :sort => 422 - # issues - Permission.create :controller => "projects", :action => "list_issues", :description => "button_list", :sort => 1000, :is_public => true - Permission.create :controller => "projects", :action => "export_issues_csv", :description => "label_export_csv", :sort => 1001, :is_public => true - Permission.create :controller => "issues", :action => "show", :description => "button_view", :sort => 1005, :is_public => true - Permission.create :controller => "issues", :action => "download", :description => "button_download", :sort => 1010, :is_public => true - Permission.create :controller => "projects", :action => "add_issue", :description => "button_add", :sort => 1050, :mail_option => 1, :mail_enabled => 1 - Permission.create :controller => "issues", :action => "edit", :description => "button_edit", :sort => 1055 - Permission.create :controller => "issues", :action => "change_status", :description => "label_change_status", :sort => 1060, :mail_option => 1, :mail_enabled => 1 - Permission.create :controller => "issues", :action => "destroy", :description => "button_delete", :sort => 1065 - Permission.create :controller => "issues", :action => "add_attachment", :description => "label_attachment_new", :sort => 1070 - Permission.create :controller => "issues", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1075 - # news - Permission.create :controller => "projects", :action => "list_news", :description => "button_list", :sort => 1100, :is_public => true - Permission.create :controller => "news", :action => "show", :description => "button_view", :sort => 1101, :is_public => true - Permission.create :controller => "projects", :action => "add_news", :description => "button_add", :sort => 1120 - Permission.create :controller => "news", :action => "edit", :description => "button_edit", :sort => 1121 - Permission.create :controller => "news", :action => "destroy", :description => "button_delete", :sort => 1122 - # documents - Permission.create :controller => "projects", :action => "list_documents", :description => "button_list", :sort => 1200, :is_public => true - Permission.create :controller => "documents", :action => "show", :description => "button_view", :sort => 1201, :is_public => true - Permission.create :controller => "documents", :action => "download", :description => "button_download", :sort => 1202, :is_public => true - Permission.create :controller => "projects", :action => "add_document", :description => "button_add", :sort => 1220 - Permission.create :controller => "documents", :action => "edit", :description => "button_edit", :sort => 1221 - Permission.create :controller => "documents", :action => "destroy", :description => "button_delete", :sort => 1222 - Permission.create :controller => "documents", :action => "add_attachment", :description => "label_attachment_new", :sort => 1223 - Permission.create :controller => "documents", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1224 - # files - Permission.create :controller => "projects", :action => "list_files", :description => "button_list", :sort => 1300, :is_public => true - Permission.create :controller => "versions", :action => "download", :description => "button_download", :sort => 1301, :is_public => true - Permission.create :controller => "projects", :action => "add_file", :description => "button_add", :sort => 1320 - Permission.create :controller => "versions", :action => "destroy_file", :description => "button_delete", :sort => 1322 - - # create default administrator account - user = User.create :firstname => "redMine", :lastname => "Admin", :mail => "admin@somenet.foo", :mail_notification => true, :language => "en" - user.login = "admin" - user.password = "admin" - user.admin = true - user.save - - - end - - def self.down - drop_table :attachments - drop_table :auth_sources - drop_table :custom_fields - drop_table :custom_fields_projects - drop_table :custom_fields_trackers - drop_table :custom_values - drop_table :documents - drop_table :enumerations - drop_table :issue_categories - drop_table :issue_histories - drop_table :issue_statuses - drop_table :issues - drop_table :members - drop_table :news - drop_table :permissions - drop_table :permissions_roles - drop_table :projects - drop_table :roles - drop_table :trackers - drop_table :tokens - drop_table :users - drop_table :versions - drop_table :workflows - end -end diff --git a/redmine/db/migrate/002_issue_move.rb b/redmine/db/migrate/002_issue_move.rb deleted file mode 100644 index d1acf7ee2..000000000 --- a/redmine/db/migrate/002_issue_move.rb +++ /dev/null @@ -1,9 +0,0 @@ -class IssueMove < ActiveRecord::Migration - def self.up - Permission.create :controller => "projects", :action => "move_issues", :description => "button_move", :sort => 1061, :mail_option => 0, :mail_enabled => 0 - end - - def self.down - Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'move_issues']).destroy - end -end diff --git a/redmine/db/migrate/003_issue_add_note.rb b/redmine/db/migrate/003_issue_add_note.rb deleted file mode 100644 index 9f20039b0..000000000 --- a/redmine/db/migrate/003_issue_add_note.rb +++ /dev/null @@ -1,9 +0,0 @@ -class IssueAddNote < ActiveRecord::Migration - def self.up - Permission.create :controller => "issues", :action => "add_note", :description => "label_add_note", :sort => 1057, :mail_option => 1, :mail_enabled => 0 - end - - def self.down - Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'add_note']).destroy - end -end diff --git a/redmine/db/migrate/004_export_pdf.rb b/redmine/db/migrate/004_export_pdf.rb deleted file mode 100644 index 66045553f..000000000 --- a/redmine/db/migrate/004_export_pdf.rb +++ /dev/null @@ -1,11 +0,0 @@ -class ExportPdf < ActiveRecord::Migration - def self.up - Permission.create :controller => "projects", :action => "export_issues_pdf", :description => "label_export_pdf", :sort => 1002, :is_public => true, :mail_option => 0, :mail_enabled => 0 - Permission.create :controller => "issues", :action => "export_pdf", :description => "label_export_pdf", :sort => 1015, :is_public => true, :mail_option => 0, :mail_enabled => 0 - end - - def self.down - Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'export_issues_pdf']).destroy - Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'export_pdf']).destroy - end -end diff --git a/redmine/db/migrate/005_issue_start_date.rb b/redmine/db/migrate/005_issue_start_date.rb deleted file mode 100644 index 3d1693fc6..000000000 --- a/redmine/db/migrate/005_issue_start_date.rb +++ /dev/null @@ -1,11 +0,0 @@ -class IssueStartDate < ActiveRecord::Migration - def self.up - add_column :issues, :start_date, :date - add_column :issues, :done_ratio, :integer, :default => 0, :null => false - end - - def self.down - remove_column :issues, :start_date - remove_column :issues, :done_ratio - end -end diff --git a/redmine/db/migrate/006_calendar_and_activity.rb b/redmine/db/migrate/006_calendar_and_activity.rb deleted file mode 100644 index 5d8474fc2..000000000 --- a/redmine/db/migrate/006_calendar_and_activity.rb +++ /dev/null @@ -1,13 +0,0 @@ -class CalendarAndActivity < ActiveRecord::Migration - def self.up - Permission.create :controller => "projects", :action => "activity", :description => "label_activity", :sort => 160, :is_public => true, :mail_option => 0, :mail_enabled => 0 - Permission.create :controller => "projects", :action => "calendar", :description => "label_calendar", :sort => 165, :is_public => true, :mail_option => 0, :mail_enabled => 0 - Permission.create :controller => "projects", :action => "gantt", :description => "label_gantt", :sort => 166, :is_public => true, :mail_option => 0, :mail_enabled => 0 - end - - def self.down - Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'activity']).destroy - Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'calendar']).destroy - Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'gantt']).destroy - end -end diff --git a/redmine/db/migrate/007_create_journals.rb b/redmine/db/migrate/007_create_journals.rb deleted file mode 100644 index 6170b5bd3..000000000 --- a/redmine/db/migrate/007_create_journals.rb +++ /dev/null @@ -1,54 +0,0 @@ -class CreateJournals < ActiveRecord::Migration - - # model removed, but needed for data migration - class IssueHistory < ActiveRecord::Base; belongs_to :issue; end - - def self.up - create_table :journals, :force => true do |t| - t.column "journalized_id", :integer, :default => 0, :null => false - t.column "journalized_type", :string, :limit => 30, :default => "", :null => false - t.column "user_id", :integer, :default => 0, :null => false - t.column "notes", :text - t.column "created_on", :datetime, :null => false - end - create_table :journal_details, :force => true do |t| - t.column "journal_id", :integer, :default => 0, :null => false - t.column "property", :string, :limit => 30, :default => "", :null => false - t.column "prop_key", :string, :limit => 30, :default => "", :null => false - t.column "old_value", :string - t.column "value", :string - end - - # indexes - add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id" - add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id" - - Permission.create :controller => "issues", :action => "history", :description => "label_history", :sort => 1006, :is_public => true, :mail_option => 0, :mail_enabled => 0 - - # data migration - IssueHistory.find(:all, :include => :issue).each {|h| - j = Journal.new(:journalized => h.issue, :user_id => h.author_id, :notes => h.notes, :created_on => h.created_on) - j.details << JournalDetail.new(:property => 'attr', :prop_key => 'status_id', :value => h.status_id) - j.save - } - - drop_table :issue_histories - end - - def self.down - drop_table :journal_details - drop_table :journals - - create_table "issue_histories", :force => true do |t| - t.column "issue_id", :integer, :default => 0, :null => false - t.column "status_id", :integer, :default => 0, :null => false - t.column "author_id", :integer, :default => 0, :null => false - t.column "notes", :text, :default => "" - t.column "created_on", :timestamp - end - - add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" - - Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'history']).destroy - end -end diff --git a/redmine/db/migrate/008_create_user_preferences.rb b/redmine/db/migrate/008_create_user_preferences.rb deleted file mode 100644 index 80ae1cdf9..000000000 --- a/redmine/db/migrate/008_create_user_preferences.rb +++ /dev/null @@ -1,12 +0,0 @@ -class CreateUserPreferences < ActiveRecord::Migration - def self.up - create_table :user_preferences do |t| - t.column "user_id", :integer, :default => 0, :null => false - t.column "others", :text - end - end - - def self.down - drop_table :user_preferences - end -end diff --git a/redmine/db/migrate/009_add_hide_mail_pref.rb b/redmine/db/migrate/009_add_hide_mail_pref.rb deleted file mode 100644 index a22eafd93..000000000 --- a/redmine/db/migrate/009_add_hide_mail_pref.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddHideMailPref < ActiveRecord::Migration - def self.up - add_column :user_preferences, :hide_mail, :boolean, :default => false - end - - def self.down - remove_column :user_preferences, :hide_mail - end -end diff --git a/redmine/doc/CHANGELOG b/redmine/doc/CHANGELOG deleted file mode 100644 index 145d848c0..000000000 --- a/redmine/doc/CHANGELOG +++ /dev/null @@ -1,96 +0,0 @@ -== redMine changelog - -redMine - project management software -Copyright (C) 2006 Jean-Philippe Lang -http://redmine.org/ - - -== xx/xx/2006 v0.x.x - -* "my page" is now customizable -* improved issues change history -* new functionality: move an issue to another project or tracker -* new functionality: add a note to an issue -* new report: project activity -* "start date" and "% done" fields added on issues -* project calendar added -* gantt chart added (exportable to pdf) -* single/multiple issues pdf export added -* issues reports improvements -* multiple file upload for issues attachments -* textile formating of issue and news descritions (RedCloth required) -* integration of DotClear jstoolbar for textile formatting -* calendar date picker for date fields (LGPL DHTML Calendar http://sourceforge.net/projects/jscalendar) -* new filter in issues list: Author -* ajaxified paginators -* option to set number of results per page on issues list -* localized csv separator (comma/semicolon) -* csv output encoded to ISO-8859-1 -* user custom field displayed on account/show -* default configuration improved (default roles, trackers, status, permissions and workflows) -* fixed: custom fields not in csv exports -* fixed: project settings now displayed according to user's permissions - -== 10/08/2006 v0.3.0 - -* user authentication against multiple LDAP (optional) -* token based "lost password" functionality -* user self-registration functionality (optional) -* custom fields now available for issues, users and projects -* new custom field format "text" (displayed as a textarea field) -* project & administration drop down menus in navigation bar for quicker access -* text formatting is preserved for long text fields (issues, projects and news descriptions) -* urls and emails are turned into clickable links in long text fields -* "due date" field added on issues -* tracker selection filter added on change log -* Localization plugin replaced with GLoc 1.1.0 (iconv required) -* error messages internationalization -* german translation added (thanks to Karim Trott) -* data locking for issues to prevent update conflicts (using ActiveRecord builtin optimistic locking) -* new filter in issues list: "Fixed version" -* active filters are displayed with colored background on issues list -* custom configuration is now defined in config/config_custom.rb -* user object no more stored in session (only user_id) -* news summary field is no longer required -* tables and forms redesign -* Fixed: boolean custom field not working -* Fixed: error messages for custom fields are not displayed -* Fixed: invalid custom fields should have a red border -* Fixed: custom fields values are not validated on issue update -* Fixed: unable to choose an empty value for 'List' custom fields -* Fixed: no issue categories sorting -* Fixed: incorrect versions sorting - - -== 07/12/2006 - v0.2.2 - -* Fixed: bug in "issues list" - - -== 07/09/2006 - v0.2.1 - -* new databases supported: Oracle, PostgreSQL, SQL Server -* projects/subprojects hierarchy (1 level of subprojects only) -* environment information display in admin/info -* more filter options in issues list (rev6) -* default language based on browser settings (Accept-Language HTTP header) -* issues list exportable to CSV (rev6) -* simple_format and auto_link on long text fields -* more data validations -* Fixed: error when all mail notifications are unchecked in admin/mail_options -* Fixed: all project news are displayed on project summary -* Fixed: Can't change user password in users/edit -* Fixed: Error on tables creation with PostgreSQL (rev5) -* Fixed: SQL error in "issue reports" view with PostgreSQL (rev5) - - -== 06/25/2006 - v0.1.0 - -* multiple users/multiple projects -* role based access control -* issue tracking system -* fully customizable workflow -* documents/files repository -* email notifications on issue creation and update -* multilanguage support (except for error messages):english, french, spanish -* online manual in french (unfinished) \ No newline at end of file diff --git a/redmine/doc/COPYING b/redmine/doc/COPYING deleted file mode 100644 index 82fa1daad..000000000 --- a/redmine/doc/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program 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. - - This program 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 this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/redmine/doc/INSTALL b/redmine/doc/INSTALL deleted file mode 100644 index 9e29b6ddc..000000000 --- a/redmine/doc/INSTALL +++ /dev/null @@ -1,74 +0,0 @@ -== redMine installation - -redMine - project management software -Copyright (C) 2006 Jean-Philippe Lang -http://redmine.org/ - - -== Requirements - -* Ruby on Rails 1.1 -* Iconv -* a database (see compatibility below) -* (recommended) Apache/Lighttpd with FCGI support - -Optional: -* RedCloth (for textile formatting) -* Net::LDAP for Ruby (for LDAP authentication) - -Supported databases: -* MySQL (tested with MySQL 5) -* PostgreSQL (tested with PostgreSQL 8.1) -* Oracle (tested with Oracle 10g) -* SQL Server (tested with SQL Server 2005) -* SQLite (tested with SQLite 3) - - -== Upgrade - -Due to major database changes, there is no migration support from beta 0.2.0. -Next releases (0.3.0+) will be provided with upgrade support. - - -== Installation - -1. Uncompress program archive: - tar zxvf - -2. Create an empty database: "redmine" for example - -3. Configure database parameters in config/database.yml - for "production" environment (default database is MySQL) - -4. Create the database structure. Under application main directory: - rake migrate RAILS_ENV="production" - It will create tables and default configuration data - -5. Insert default configuration data in database: - rake load_default_data RAILS_ENV="production" - This step is optional, as you can define your own configuration - (roles, trackers, statuses, workflows, enumerations) from sratch - -6. Test the installation by running WEBrick web server: - ruby script/server -e production - - Once WEBrick has started, point your browser to http://localhost:3000/ - You should now see the application welcome page - -7. Use default administrator account to log in: - login: admin - password: admin - -8. Setup Apache or Lighttpd with fastcgi for best performance. - - -== Configuration - -A sample configuration file is provided: "config/config_custom.example.rb" -Rename it to config_custom.rb and edit parameters. -Don't forget to restart the application after any change. - - -config.action_mailer.server_settings: SMTP server configuration -config.action_mailer.perform_deliveries: set to false to disable mail delivering - diff --git a/redmine/doc/README b/redmine/doc/README deleted file mode 100644 index 42a0bc18e..000000000 --- a/redmine/doc/README +++ /dev/null @@ -1,58 +0,0 @@ -== redMine - -redMine - project management software -Copyright (C) 2006 Jean-Philippe Lang -http://redmine.org/ - -== License - -This program 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. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -== Main features - -redMine is a project management software written using Ruby on Rails. - -* multiple users/projects -* fully customizable role based access control -* issue tracking system -* fully customizable workflow -* documents/files repository -* email notifications -* custom fields for projects, users and issues -* multilanguage support -* multiple LDAP authentication support -* user self-registration support - - -== User documentation - -User documentation for redMine is written using DocBook XML format. -It's also avaible as HTML files in /public/manual (contextual help) - - -== Versioning - -redMine versioning scheme is major.minor.revision -Versions before 1.0.0 must be considered as beta versions and upgrading support -may not be provided for these versions. - - -== Credits - -* Jean-Francois Boutier (spanish translation) -* Andreas Viklund (open source XHTML layout, http://andreasviklund.com/) -* Karim Trott (german translation) - diff --git a/redmine/doc/docbook/en/redmine-userdoc-en.xml b/redmine/doc/docbook/en/redmine-userdoc-en.xml deleted file mode 100644 index c290bb85d..000000000 --- a/redmine/doc/docbook/en/redmine-userdoc-en.xml +++ /dev/null @@ -1,429 +0,0 @@ - - - - RedMine Documentation - - Administration -
    - Users - These screens allow you to manage the application users. -
    - Users’ List - - - Users’ List - - - - - - - The Lock/Unlock buttons allow you to lock/unlock the user accounts. - A user having a locked account cannot log in and access the application. -
    -
    - User Creation or Modification - In modification mode, please leave the Password field blank in order to keep the user’s password unchanged. - A user designated as administrator has unrestricted access to the application and to all projects. - - - - Administrator - : designate the user as the administrator of the application. - - - - - E-mail notifications - : activate or de-activate automatic e-mail notifications for this user - - - - - Locked - : de-activates the user’s account - - - - -
    -
    -
    - Roles and Permissions - 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. - On the new or edit Role screen, check off the actions authorized for the Role. -
    -
    - Trackers - Trackers allow the sorting of Issues and can define specific workflows. -
    -
    - Customized fields - Customized fields allow you to add additional information in Projects, Issues or Users. A customized field can be of one the following types: - - - - Integer - : positive or negative number - - - - - String - : a string of characters - one single line of input. - - - - - Text - : a string of characters with multiple lines of input. Differs from String Format by providing multiple lines of input instead of a single line. - - - - - Date - : date - - - - - Boolean - : true or false (check if necessary) - - - - - List - : value to select from a predefined list (aka: scroll list or select box) - - - - Validation elements can be defined: - - - - Required - : A required field must have input in the forms - - - - - For all the projects - : field automatically associated to all of the projects - - - - - Min - max length - : minimum and maximum length for the input fields (0 means that there is no restriction) - - - - - Regular Expression - : regular expressions may provide validation of the input value - - Examples: - - ^\[A-Z]{4}\d+$ - : 4 capital letters followed by one or several digits - - - ^[^0-9]*$ - : characters only - no digits - - - - - Possible values - : possible values for the fields of "List" type. Values are separated by the character | - - - - -
    - Fields for Projects - - - - - Required - : required field - - - - -
    -
    - Fields for Issues - - - - - For all projects - : field automatically associated to all project Issues - - 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). - - - -
    -
    - Field for Users - - - - - Required - : required field - - - - -
    -
    -
    - Issue status - These screens allow you to define the different possible Issue statuses. - - - - Closed - : indicates Issue is considered as closed - - - - - Default - : status applied by default to new Issue requests (only one status can be Default status) - - - - - Color - : HTML color code (6 characters) representing the displayed status - - - - -
    -
    - Workflow - The workflow allows to define changes the various project members are allowed to make on the Issues, according to their type. - 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. - - 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. - - - - Example of a workflow configuration - - - - - - - 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. -
    -
    - Enumerations - 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: - - - Issue Priorities - - - Document Categories - - - -
    -
    - E-mail notifications - This screen allows you to select the actions that will generate an e-mail notification for project members. - Note: E-mail sending must be activated in the application configuration if you want to make any notifications. -
    -
    - Authentication - By default, redMine refers to its own database to authenticate users, by a specific password. - 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. - 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’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. - -
    - LDAP statement - - - - - Name - : reference display name - - - - - Host - : LDAP server host name - - - - - Port - : connection port to the LDAP server - - - - - Account - : DN of the connection account to LDAP (please leave it blank if the directory authorizes anonymous read access) - - - - - Password - : password of the connection account - - - - - Base DN - : Basic DN used for user search in the directory - - - - - LDAP screen - : User search screen in the directory (optional) - - - - - LDAP features - : - - - - - Identifier - : LDAP feature name used as user identifier (e.g.: uid) - - - - - First name - : LDAP feature name including the user’s first name (ex: givenName) - - - - - Last name - : LDAP feature name including the user’s last name (ex: familyName) - - - - - E-mail - : LDAP feature name including the user’s e-mail address (ex: mail) - - - - - - - The features" - First name - ", " - Last name - " and " - E-mail - " are not used except when the accounts are created on the fly. - -
    -
    -
    - Information - Displays application and environment information. -
    -
    - - Projects -
    - Project preview - The preview presents the general project information, its main members, the latest announcements, as well as an synthesis of Issue requests open by tracker. - -
    -
    - Issue management - -
    - Issue list - 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). - Once applied, a screen is valid during the entire session. You can re-define it or delete it by clicking Cancel. - - - Request list - - - - - - - -
    -
    -
    - Reports - 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. -
    -
    - Change log - 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. -
    -
    - News - Allows you to inform users on project activity. -
    -
    - Documents - Documents are grouped by categories (see Value Lists). A document can contain several files (for example: revisions or successive versions). -
    -
    - Files - This module allows you to display various folders (sources, binaires, ...) for each version of the application. -
    -
    - Settings - -
    - Project features - - - - - Public - : if it’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’s not a public project, only the project members have access to it, according to their role. - - - - - Customized fields - : Select the customized fields that you want to use. Only the administrator can define new customized fields. - - - - -
    -
    - Members - 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. -
    -
    - Versions - 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). -
    -
    - Request categories - Issue categories allow you to organize Issues. Categories can correspond to different project modules. -
    -
    -
    -
    \ No newline at end of file diff --git a/redmine/doc/docbook/fr/redmine-userdoc-fr.xml b/redmine/doc/docbook/fr/redmine-userdoc-fr.xml deleted file mode 100644 index ba52da2c4..000000000 --- a/redmine/doc/docbook/fr/redmine-userdoc-fr.xml +++ /dev/null @@ -1,553 +0,0 @@ - - - - Documentation redMine - - - Administration - -
    - Utilisateurs - - Ces écrans vous permettent de gérer les utilisateurs de - l'application. - -
    - Liste des utilisateurs - - - - - Liste des utilisateurs - - - - - - - - - Les boutons Lock/Unlock vous permettent de - vérouiller/dévérouiller les comptes utilisateurs. - - Un utilisateur dont le compte est vérouillé ne peut plus - s'identifier pour accéder à l'application. -
    - -
    - Création ou modification d'un utilisateur - - En mode modification, laissez le champ Password vide pour - laisser le mot de passe de l'utilisateur inchangé. - - Un utilisateur déclaré comme administrateur dispose de toutes - les permissions sur l'application et sur tous les projets. - - - - Administrateur: déclare l'utilisateur - comme administrateur de l'application. - - - - Notifications par mail: permet - d'activer ou non l'envoi automatique de notifications par mail - pour cet utilisateur - - - - Vérouillé: désactive le compte de - l'utilisateur - - - - -
    -
    - -
    - Rôles et permissions - - Les rôles permettent de définir les permissions des différents - membres d'un projet. Chaque membre d'un projet dispose d'un rôle unique - au sein d'un projet. Un utilisateur peut avoir différents rôles au sein - de différents projets. - - Sur l'écran d'édition du rôle, cochez les actions que vous - souhaitez autoriser pour le rôle. -
    - -
    - Trackers - - Les trackers permettent de typer les demandes et de définir des - workflows spécifiques pour chacun de ces types. -
    - -
    - Champs personnalisés - - Les champs personnalisés vous permettent d'ajouter des - informations supplémentaires sur les projets, les demandes ou les - utilisateurs. Un champ personnalisé peut être de l'un des types - suivants: - - - - Entier: entier positif ou négatif - - - - Chaîne: chaîne de caractère - - - - Date: date - - - - Booléen: booléen (case à cocher) - - - - Liste: valeur à sélectionnée parmi une - liste prédéfinie (liste déroulante) - - - - Des éléments de validation peuvent être définis: - - - - Obligatoire: champ dont la saisie est - obligatoire sur les demandes - - - - Pour tous les projects: champ - automatiquement associé à l'ensemble des projets - - - - Min - max length: longueurs minimales et - maximales pour les champs en saisie libre (0 signifie qu'il n'y a - pas de restriction) - - - - Expression régulière: expression - régulière permettant de valider la valeur saisie - - Exemples: - - ^\[A-Z]{4}\d+$ : 4 lettres majuscules suivies - d'un ou plusieurs chiffres - - ^[^0-9]*$ : chaîne ne comportant pas de - chiffres - - - - Valeurs possibles: valeurs possibles pour - les champs de type "Liste". Les valeurs sont séparées par le - caractère | - - - - - -
    - Champs pour les projets - - - - - - Obligatoire: champ dont la saisie est - obligatoire - - - - -
    - -
    - Champs pour les demandes - - - - - - Pour tous les projects: champ - automatiquement associé aux demandes de l'ensemble des - projets - - Si cette option n'est pas activée, chaque projet pourra - choisir d'utiliser ou non le champ pour ses demandes (voir - configuration du projet). - - - - -
    - -
    - Champs pour les utilisateurs - - - - - - Obligatoire: champ dont la saisie est - obligatoire - - - - -
    -
    - -
    - Statut des demandes - - Ces écrans vous permettent de définir les différents statuts - possibles des demandes. - - - - Demande fermée: indique que le statut - correspond à une demande considérée comme fermée - - - - Statut par défaut: statut appliqué par - défaut aux nouvelles demandes (seul un statut peut être déclaré - comme statut par défaut) - - - - Couleur: code couleur HTML (6 caractères) - représentant le statut à l'affichage - - - - -
    - -
    - Workflow - - Le workflow permet de définir les changements que les différents - membres d'un projet sont autorisés à effectuer sur les demandes, en - fonction de leur type. - - Sélectionnez le rôle et le tracker pour lesquels vous souhaitez - modifier le workflow, puis cliquez sur Edit. L'écran vous permet alors - de modifier, pour le rôle et le tracker choisi, les changements - autorisés. Les lignes représentent les statuts initiaux des demandes. - Les colonnes représentent les statuts autorisés à être appliqués. - - Remarque: pour qu'un rôle puisse changer le statut des - demandes, la permission doit lui être explicitement donnée - indépendemment de la configuration du workflow. - - - - - Exemple de configuration d'un workflow - - - - - - - - - Dans l'exemple ci-dessus, les demandes de type Bug au statut - Nouveau pourront être passées au statut Assignée ou Résolue par le rôle - Développeur. Celles au statut Assignée pourront être passées au statut - Résolue. Le statut de toutes les autres demandes de type Bug ne pourra - pas être modifié par le Développeur. -
    - -
    - Listes de valeurs - - Les listes de valeurs utilisées par l'application (exemple: les - priorités des demandes) peuvent être personnalisées. Cet écran vous - permet de définir les valeurs possibles pour chacune des listes - suivantes: - - - - Priorités des demandes - - - - Catégories de documents - - - - -
    - -
    - Notifications par mail - - Cet écran vous permet de sélectionner les actions qui donneront - lieu à une notification par mail aux membres du projet. - - Remarque: l'envoi de mails doit être activé dans la configuration - de l'application si souhaitez effectuer des notifications. -
    - -
    - Authentification - - Par défaut, redMine s'appuie sur sa propre base de données pour - authentifier les utilisateurs, à l'aide d'un mot de passe - spécifique. - - Si vous disposez déjà d'un ou plusieurs référentiels externes - d'utilisateurs (annuaires LDAP), vous pouvez les déclarer afin qu'ils - soient utilisés pour l'authentification sur redMine. Cela permet aux - utilisateurs d'accéder à redMine avec leurs identifiants et mots de - passe habituels. - - Pour chaque référentiel déclaré, vous pouvez spécifier si les - comptes peuvent être créés à la volée dans redMine. Si c'est le cas, les - comptes utilisateurs sont automatiquement créés à la première connexion - de l'utilisateur (sans droits spécifiques sur les projets), à partir des - informations disponibles dans le référentiel. Sinon, l'administrateur - doit au préalable créer le compte de l'utilisateur dans redMine. - - - -
    - Déclaration d'un annuaire LDAP - - - - - - Nom: nom d'affichage du - référentiel - - - - Hôte: nom d'hôte du serveur LDAP - - - - Port: port de connexion au serveur - LDAP - - - - Compte: DN du compte de connexion au - LDAP (laisser vide si l'annuaire autorise l'accès anonyme en - lecture) - - - - Mot de passe: mot de passe du compte de - connexion - - - - Base DN: DN de base utilisé pour la - recherche des utilisateur dans l'annuaire - - - - Filtre LDAP: Filtre de recherche des - utilisateurs dans l'annuaire (optionnel) - - - - Attributs LDAP: - - - - Identifiant: nom de l'attribut LDAP - utilisé comme identifiant de l'utilisateur (ex: uid) - - - - Prénom: nom de l'attribut LDAP - contenant le prénom de l'utilisateur (ex: givenName) - - - - Nom: nom de l'attribut LDAP - contenant le nom de l'utilisateur (ex: sn) - - - - Email: nom de l'attribut LDAP - contenant l'adresse mail de l'utilisateur (ex: mail) - - - - - - Les attributs "Prénom", - "Nom" et "Email" ne sont - utilisés que lorsque les comptes sont créés à la volée. -
    -
    - -
    - Informations - - Affiche des informations relatives à l'application et à son - environnement. -
    -
    - - - Projets - -
    - Aperçu du projet - - L'aperçu vous présente les informations générales relatives au - projet, les principaux membres, les dernières annonces, ainsi qu'une - synthèse du nombre de demandes ouvertes par tracker. - - -
    - -
    - Gestion des demandes - - - -
    - Liste des demandes - - Par défaut, l'ensemble des demandes ouvertes du projet sont - affichées. Différents filtres vous permettent de sélectionner les - demandes à afficher. Si le projet comporte des sous-projets, vous avez - la possibilité d'afficher également les demandes relatives aux - sous-projets (non affichées par défaut). - - Une fois appliqué, un filtre reste valable durant toute votre - session. Vous pouvez le redéfinir, ou le supprimer en cliquant sur - Annuler. - - - - - Liste des demandes - - - - - - - - - -
    -
    - -
    - Rapports - - Cet écran présente la synthèse du nombre de demandes par statut et - selon différents critères (tracker, priorité, catégorie). Des liens - directs permettent d'accéder à la liste détaillée des demandes pour - chaque critère. -
    - -
    - Historique - - Cette page présente l'ensemble des demandes résolues dans chacune - des versions du projet. Certains types de demande peuvent être exclus de - cet affichage. -
    - -
    - Annonces - - Les nouvelles vous permettent d'informer les utilisateurs sur - l'activité du projet. -
    - -
    - Documents - - Les documents sont groupés par catégories (voir Listes de - valeurs). Un document peut contenir plusieurs fichiers (exemple: - révisions ou versions successives). -
    - -
    - Fichiers - - Ce module vous permet de publier les différents fichiers (sources, - binaires, ...) pour chaque version de l'application. -
    - -
    - Configuration du projet - - - -
    - Propriétés du projet - - - - - - Public: 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ès, en fonction de leur rôle. - - - - Champs personnalisés: sélectionner les - champs personnalisés que vous souhaitez utiliser pour les demandes - du projet. Seul l'administrateur peut définir de nouveaux champs - personnalisés. - - - - -
    - -
    - Membres - - Cet écran vous permet de définir les membres du projet ainsi que - leurs rôles respectifs. Un utilisateur ne peut avoir qu'un rôle au - sein d'un projet donné. Le rôle d'un membre détermine les permissions - dont il bénéficie sur le projet. -
    - -
    - Versions - - 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érentes versions de l'application (voir - Fichiers). -
    - -
    - Catégories des demandes - - Les catégories de demande vous permettent de typer les demandes. - Les catégories peuvent par exemple correspondre aux différents modules - du projet. -
    -
    -
    -
    \ No newline at end of file diff --git a/redmine/files/delete.me b/redmine/files/delete.me deleted file mode 100644 index 18beddaa8..000000000 --- a/redmine/files/delete.me +++ /dev/null @@ -1 +0,0 @@ -default directory for uploaded files \ No newline at end of file diff --git a/redmine/lang/de.yml b/redmine/lang/de.yml deleted file mode 100644 index 7eaa3d05a..000000000 --- a/redmine/lang/de.yml +++ /dev/null @@ -1,320 +0,0 @@ -_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' - -actionview_datehelper_select_day_prefix: -actionview_datehelper_select_month_names: January,February,March,April,May,June,July,August,September,October,November,December -actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec -actionview_datehelper_select_month_prefix: -actionview_datehelper_select_year_prefix: -actionview_datehelper_time_in_words_day: 1 day -actionview_datehelper_time_in_words_day_plural: %d days -actionview_datehelper_time_in_words_hour_about: about an hour -actionview_datehelper_time_in_words_hour_about_plural: about %d hours -actionview_datehelper_time_in_words_hour_about_single: about an hour -actionview_datehelper_time_in_words_minute: 1 minute -actionview_datehelper_time_in_words_minute_half: half a minute -actionview_datehelper_time_in_words_minute_less_than: less than a minute -actionview_datehelper_time_in_words_minute_plural: %d minutes -actionview_datehelper_time_in_words_minute_single: 1 minute -actionview_datehelper_time_in_words_second_less_than: less than a second -actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds -actionview_instancetag_blank_option: Bitte auserwählt - -activerecord_error_inclusion: ist nicht in der Liste eingeschlossen -activerecord_error_exclusion: ist reserviert -activerecord_error_invalid: ist unzulässig -activerecord_error_confirmation: bringt nicht Bestätigung zusammen -activerecord_error_accepted: muß angenommen werden -activerecord_error_empty: kann nicht leer sein -activerecord_error_blank: kann nicht leer sein -activerecord_error_too_long: ist zu lang -activerecord_error_too_short: ist zu kurz -activerecord_error_wrong_length: ist die falsche Länge -activerecord_error_taken: ist bereits genommen worden -activerecord_error_not_a_number: ist nicht eine Zahl -activerecord_error_not_a_date: ist nicht ein gültiges Datum -activerecord_error_greater_than_start_date: muß als grösser sein beginnen Datum - -general_fmt_age: %d yr -general_fmt_age_plural: %d yrs -general_fmt_date: %%b %%d, %%Y (%%a) -general_fmt_datetime: %%b %%d, %%Y (%%a), %%I:%%M %%p -general_fmt_datetime_short: %%b %%d, %%I:%%M %%p -general_fmt_time: %%I:%%M %%p -general_text_No: 'Nein' -general_text_Yes: 'Ja' -general_text_no: 'nein' -general_text_yes: 'ja' -general_lang_de: 'Deutsch' -general_csv_separator: ';' -general_day_names: Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag,Sonntag - -notice_account_updated: Konto wurde erfolgreich aktualisiert. -notice_account_invalid_creditentials: Unzulässiger Benutzer oder Passwort -notice_account_password_updated: Passwort wurde erfolgreich aktualisiert. -notice_account_wrong_password: Falsches Passwort -notice_account_register_done: Konto wurde erfolgreich verursacht. -notice_account_unknown_email: Unbekannter Benutzer. -notice_can_t_change_password: Dieses Konto verwendet eine externe Authentisierung Quelle. Unmöglich, das Kennwort zu ändern. -notice_account_lost_email_sent: Ein email mit Anweisungen, ein neues Kennwort zu wählen ist dir geschickt worden. -notice_account_activated: Dein Konto ist aktiviert worden. Du kannst jetzt einloggen. -notice_successful_create: Erfolgreiche Kreation. -notice_successful_update: Erfolgreiches Update. -notice_successful_delete: Erfolgreiche Auslassung. -notice_successful_connection: Erfolgreicher Anschluß. -notice_file_not_found: Erbetene Akte besteht nicht oder ist gelöscht worden. -notice_locking_conflict: Data have been updated by another user. - -mail_subject_lost_password: Dein redMine Kennwort -mail_subject_register: redMine Kontoaktivierung - -gui_validation_error: 1 Störung -gui_validation_error_plural: %d Störungen - -field_name: Name -field_description: Beschreibung -field_summary: Zusammenfassung -field_is_required: Erforderlich -field_firstname: Vorname -field_lastname: Nachname -field_mail: Email -field_filename: Datei -field_filesize: Grootte -field_downloads: Downloads -field_author: Autor -field_created_on: Angelegt -field_updated_on: aktualisiert -field_field_format: Format -field_is_for_all: Für alle Projekte -field_possible_values: Mögliche Werte -field_regexp: Regulärer Ausdruck -field_min_length: Minimale Länge -field_max_length: Maximale Länge -field_value: Wert -field_category: Kategorie -field_title: Títel -field_project: Projekt -field_issue: Antrag -field_status: Status -field_notes: Anmerkungen -field_is_closed: Problem erledigt -field_is_default: Rückstellung status -field_html_color: Farbe -field_tracker: Tracker -field_subject: Thema -field_due_date: Abgabedatum -field_assigned_to: Zugewiesen an -field_priority: Priorität -field_fixed_version: Erledigt in Version -field_user: Benutzer -field_role: Rolle -field_homepage: Startseite -field_is_public: Öffentlich -field_parent: Subprojekt von -field_is_in_chlog: Ansicht der Issues in der Historie -field_login: Mitgliedsname -field_mail_notification: Mailbenachrichtigung -field_admin: Administrator -field_locked: Gesperrt -field_last_login_on: Letzte Anmeldung -field_language: Sprache -field_effective_date: Datum -field_password: Passwort -field_new_password: Neues Passwort -field_password_confirmation: Bestätigung -field_version: Version -field_type: Typ -field_host: Host -field_port: Port -field_account: Konto -field_base_dn: Base DN -field_attr_login: Mitgliedsnameattribut -field_attr_firstname: Vornamensattribut -field_attr_lastname: Namenattribut -field_attr_mail: Emailattribut -field_onthefly: On-the-fly Benutzerkreation -field_start_date: Beginn -field_done_ratio: %% Getan -field_hide_mail: Mein email address verstecken - -label_user: Benutzer -label_user_plural: Benutzer -label_user_new: Neuer Benutzer -label_project: Projekt -label_project_new: Neues Projekt -label_project_plural: Projekte -label_project_latest: Neueste Projekte -label_issue: Antrag -label_issue_new: Neue Antrag -label_issue_plural: Anträge -label_issue_view_all: Alle Anträge ansehen -label_document: Dokument -label_document_new: Neues Dokument -label_document_plural: Dokumente -label_role: Rolle -label_role_plural: Rollen -label_role_new: Neue Rolle -label_role_and_permissions: Rollen und Rechte -label_member: Mitglied -label_member_new: Neues Mitglied -label_member_plural: Mitglieder -label_tracker: Tracker -label_tracker_plural: Tracker -label_tracker_new: Neuer Tracker -label_workflow: Workflow -label_issue_status: Antrag Status -label_issue_status_plural: Antrag Stati -label_issue_status_new: Neuer Status -label_issue_category: Antrag Kategorie -label_issue_category_plural: Antrag Kategorien -label_issue_category_new: Neue Kategorie -label_custom_field: Benutzerdefiniertes Feld -label_custom_field_plural: Benutzerdefinierte Felder -label_custom_field_new: Neues Feld -label_enumerations: Enumerationen -label_enumeration_new: Neuer Wert -label_information: Information -label_information_plural: Informationen -label_please_login: Anmelden -label_register: Anmelden -label_password_lost: Passwort vergessen -label_home: Hauptseite -label_my_page: Meine Seite -label_my_account: Mein Konto -label_my_projects: Meine Projekte -label_administration: Administration -label_login: Einloggen -label_logout: Abmelden -label_help: Hilfe -label_reported_issues: Gemeldete Issues -label_assigned_to_me_issues: Mir zugewiesen -label_last_login: Letzte Anmeldung -label_last_updates: Letztes aktualisiertes -label_last_updates_plural: %d Letztes aktualisiertes -label_registered_on: Angemeldet am -label_activity: Aktivität -label_new: Neue -label_logged_as: Angemeldet als -label_environment: Environment -label_authentication: Authentisierung -label_auth_source: Authentisierung Modus -label_auth_source_new: Neuer Authentisierung Modus -label_auth_source_plural: Authentisierung Modi -label_subproject: Vorprojekt von -label_subproject_plural: Vorprojekte -label_min_max_length: Min - Max Länge -label_list: Liste -label_date: Date -label_integer: Zahl -label_boolean: Boolesch -label_string: Text -label_text: Langer Text -label_attribute: Attribut -label_attribute_plural: Attribute -label_download: %d Herunterlade -label_download_plural: %d Herunterlade -label_no_data: Nichts anzuzeigen -label_change_status: Statuswechsel -label_history: Historie -label_attachment: Datei -label_attachment_new: Neue Datei -label_attachment_delete: Löschungakten -label_attachment_plural: Dateien -label_report: Bericht -label_report_plural: Berichte -label_news: Neuigkeit -label_news_new: Neuigkeite addieren -label_news_plural: Neuigkeiten -label_news_latest: Letzte Neuigkeiten -label_news_view_all: Alle Neuigkeiten anzeigen -label_change_log: Change log -label_settings: Konfiguration -label_overview: Übersicht -label_version: Version -label_version_new: Neue Version -label_version_plural: Versionen -label_confirmation: Bestätigung -label_export_to: Export zu -label_read: Lesen... -label_public_projects: Öffentliche Projekte -label_open_issues: Geöffnet -label_open_issues_plural: Geöffnet -label_closed_issues: Geschlossen -label_closed_issues_plural: Geschlossen -label_total: Gesamtzahl -label_permissions: Berechtigungen -label_current_status: Gegenwärtiger Status -label_new_statuses_allowed: Neue Status gewährten -label_all: Alle -label_none: Kein -label_next: Weiter -label_previous: Zurück -label_used_by: Benutzt von -label_details: Details... -label_add_note: Eine Anmerkung addieren -label_per_page: Pro Seite -label_calendar: Kalender -label_months_from: Monate von -label_gantt_chart: Gantt Diagramm -label_internal: Intern -label_last_changes: %d änderungen des Letzten -label_change_view_all: Alle änderungen ansehen -label_personalize_page: Diese Seite personifizieren - -button_login: Einloggen -button_submit: Einreichen -button_save: Speichern -button_check_all: Alles auswählen -button_uncheck_all: Alles abwählen -button_delete: Löschen -button_create: Anlegen -button_test: Testen -button_edit: Bearbeiten -button_add: Hinzufügen -button_change: Wechseln -button_apply: Anwenden -button_clear: Zurücksetzen -button_lock: Verriegeln -button_unlock: Entriegeln -button_download: Fernzuladen -button_list: Aufzulisten -button_view: Siehe -button_move: Bewegen -button_back: Rückkehr -button_cancel: Annullieren - -text_select_mail_notifications: Aktionen für die Mailbenachrichtigung aktiviert werden soll. -text_regexp_info: eg. ^[A-Z0-9]+$ -text_min_max_length_info: 0 heisst keine Beschränkung -text_possible_values_info: Werte trennten sich mit | -text_project_destroy_confirmation: Sind sie sicher, daß sie das Projekt löschen wollen ? -text_workflow_edit: Auswahl Workflow zum Bearbeiten -text_are_you_sure: Sind sie sicher ? -text_journal_changed: geändert von %s zu %s -text_journal_set_to: gestellt zu %s -text_journal_deleted: gelöscht -text_tip_task_begin_day: Aufgabe, die an diesem Tag beginnt -text_tip_task_end_day: Aufgabe, die an diesem Tag beendet -text_tip_task_begin_end_day: Aufgabe, die an diesem Tag beginnt und beendet - -default_role_manager: Manager -default_role_developper: Developer -default_role_reporter: Reporter -default_tracker_bug: Fehler -default_tracker_feature: Feature -default_tracker_support: Support -default_issue_status_new: Neu -default_issue_status_assigned: Zugewiesen -default_issue_status_resolved: Gelöst -default_issue_status_feedback: Feedback -default_issue_status_closed: Erledigt -default_issue_status_rejected: Abgewiesen -default_doc_category_user: Benutzerdokumentation -default_doc_category_tech: Technische Dokumentation -default_priority_low: Niedrig -default_priority_normal: Normal -default_priority_high: Hoch -default_priority_urgent: Dringend -default_priority_immediate: Sofort - -enumeration_issue_priorities: Issue-Prioritäten -enumeration_doc_categories: Dokumentenkategorien diff --git a/redmine/lang/en.yml b/redmine/lang/en.yml deleted file mode 100644 index a3aad0467..000000000 --- a/redmine/lang/en.yml +++ /dev/null @@ -1,320 +0,0 @@ -_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' - -actionview_datehelper_select_day_prefix: -actionview_datehelper_select_month_names: January,February,March,April,May,June,July,August,September,October,November,December -actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec -actionview_datehelper_select_month_prefix: -actionview_datehelper_select_year_prefix: -actionview_datehelper_time_in_words_day: 1 day -actionview_datehelper_time_in_words_day_plural: %d days -actionview_datehelper_time_in_words_hour_about: about an hour -actionview_datehelper_time_in_words_hour_about_plural: about %d hours -actionview_datehelper_time_in_words_hour_about_single: about an hour -actionview_datehelper_time_in_words_minute: 1 minute -actionview_datehelper_time_in_words_minute_half: half a minute -actionview_datehelper_time_in_words_minute_less_than: less than a minute -actionview_datehelper_time_in_words_minute_plural: %d minutes -actionview_datehelper_time_in_words_minute_single: 1 minute -actionview_datehelper_time_in_words_second_less_than: less than a second -actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds -actionview_instancetag_blank_option: Please select - -activerecord_error_inclusion: is not included in the list -activerecord_error_exclusion: is reserved -activerecord_error_invalid: is invalid -activerecord_error_confirmation: doesn't match confirmation -activerecord_error_accepted: must be accepted -activerecord_error_empty: can't be empty -activerecord_error_blank: can't be blank -activerecord_error_too_long: is too long -activerecord_error_too_short: is too short -activerecord_error_wrong_length: is the wrong length -activerecord_error_taken: has already been taken -activerecord_error_not_a_number: is not a number -activerecord_error_not_a_date: is not a valid date -activerecord_error_greater_than_start_date: must be greater than start date - -general_fmt_age: %d yr -general_fmt_age_plural: %d yrs -general_fmt_date: %%m/%%d/%%Y -general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p -general_fmt_datetime_short: %%b %%d, %%I:%%M %%p -general_fmt_time: %%I:%%M %%p -general_text_No: 'No' -general_text_Yes: 'Yes' -general_text_no: 'no' -general_text_yes: 'yes' -general_lang_en: 'English' -general_csv_separator: ',' -general_day_names: Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday - -notice_account_updated: Account was successfully updated. -notice_account_invalid_creditentials: Invalid user or password -notice_account_password_updated: Password was successfully updated. -notice_account_wrong_password: Wrong password -notice_account_register_done: Account was successfully created. -notice_account_unknown_email: Unknown user. -notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. -notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. -notice_account_activated: Your account has been activated. You can now log in. -notice_successful_create: Successful creation. -notice_successful_update: Successful update. -notice_successful_delete: Successful deletion. -notice_successful_connection: Successful connection. -notice_file_not_found: Requested file doesn't exist or has been deleted. -notice_locking_conflict: Data have been updated by another user. - -mail_subject_lost_password: Your redMine password -mail_subject_register: redMine account activation - -gui_validation_error: 1 error -gui_validation_error_plural: %d errors - -field_name: Name -field_description: Description -field_summary: Summary -field_is_required: Required -field_firstname: Firstname -field_lastname: Lastname -field_mail: Email -field_filename: File -field_filesize: Size -field_downloads: Downloads -field_author: Author -field_created_on: Created -field_updated_on: Updated -field_field_format: Format -field_is_for_all: For all projects -field_possible_values: Possible values -field_regexp: Regular expression -field_min_length: Minimum length -field_max_length: Maximum length -field_value: Value -field_category: Category -field_title: Title -field_project: Project -field_issue: Issue -field_status: Status -field_notes: Notes -field_is_closed: Issue closed -field_is_default: Default status -field_html_color: Color -field_tracker: Tracker -field_subject: Subject -field_due_date: Due date -field_assigned_to: Assigned to -field_priority: Priority -field_fixed_version: Fixed version -field_user: User -field_role: Role -field_homepage: Homepage -field_is_public: Public -field_parent: Subproject of -field_is_in_chlog: Issues displayed in changelog -field_login: Login -field_mail_notification: Mail notifications -field_admin: Administrator -field_locked: Locked -field_last_login_on: Last connection -field_language: Language -field_effective_date: Date -field_password: Password -field_new_password: New password -field_password_confirmation: Confirmation -field_version: Version -field_type: Type -field_host: Host -field_port: Port -field_account: Account -field_base_dn: Base DN -field_attr_login: Login attribute -field_attr_firstname: Firstname attribute -field_attr_lastname: Lastname attribute -field_attr_mail: Email attribute -field_onthefly: On-the-fly user creation -field_start_date: Start -field_done_ratio: %% Done -field_hide_mail: Hide my email address - -label_user: User -label_user_plural: Users -label_user_new: New user -label_project: Project -label_project_new: New project -label_project_plural: Projects -label_project_latest: Latest projects -label_issue: Issue -label_issue_new: New issue -label_issue_plural: Issues -label_issue_view_all: View all issues -label_document: Document -label_document_new: New document -label_document_plural: Documents -label_role: Role -label_role_plural: Roles -label_role_new: New role -label_role_and_permissions: Roles and permissions -label_member: Member -label_member_new: New member -label_member_plural: Members -label_tracker: Tracker -label_tracker_plural: Trackers -label_tracker_new: New tracker -label_workflow: Workflow -label_issue_status: Issue status -label_issue_status_plural: Issue statuses -label_issue_status_new: New status -label_issue_category: Issue category -label_issue_category_plural: Issue categories -label_issue_category_new: New category -label_custom_field: Custom field -label_custom_field_plural: Custom fields -label_custom_field_new: New custom field -label_enumerations: Enumerations -label_enumeration_new: New value -label_information: Information -label_information_plural: Information -label_please_login: Please login -label_register: Register -label_password_lost: Lost password -label_home: Home -label_my_page: My page -label_my_account: My account -label_my_projects: My projects -label_administration: Administration -label_login: Login -label_logout: Logout -label_help: Help -label_reported_issues: Reported issues -label_assigned_to_me_issues: Issues assigned to me -label_last_login: Last connection -label_last_updates: Last updated -label_last_updates_plural: %d last updated -label_registered_on: Registered on -label_activity: Activity -label_new: New -label_logged_as: Logged as -label_environment: Environment -label_authentication: Authentication -label_auth_source: Authentication mode -label_auth_source_new: New authentication mode -label_auth_source_plural: Authentication modes -label_subproject: Subproject -label_subproject_plural: Subprojects -label_min_max_length: Min - Max length -label_list: List -label_date: Date -label_integer: Integer -label_boolean: Boolean -label_string: Text -label_text: Long text -label_attribute: Attribute -label_attribute_plural: Attributes -label_download: %d Download -label_download_plural: %d Downloads -label_no_data: No data to display -label_change_status: Change status -label_history: History -label_attachment: File -label_attachment_new: New file -label_attachment_delete: Delete file -label_attachment_plural: Files -label_report: Report -label_report_plural: Reports -label_news: News -label_news_new: Add news -label_news_plural: News -label_news_latest: Latest news -label_news_view_all: View all news -label_change_log: Change log -label_settings: Settings -label_overview: Overview -label_version: Version -label_version_new: New version -label_version_plural: Versions -label_confirmation: Confirmation -label_export_to: Export to -label_read: Read... -label_public_projects: Public projects -label_open_issues: Open -label_open_issues_plural: Open -label_closed_issues: Closed -label_closed_issues_plural: Closed -label_total: Total -label_permissions: Permissions -label_current_status: Current status -label_new_statuses_allowed: New statuses allowed -label_all: All -label_none: None -label_next: Next -label_previous: Previous -label_used_by: Used by -label_details: Details... -label_add_note: Add a note -label_per_page: Per page -label_calendar: Calendar -label_months_from: months from -label_gantt_chart: Gantt chart -label_internal: Internal -label_last_changes: last %d changes -label_change_view_all: View all changes -label_personalize_page: Personalize this page - -button_login: Login -button_submit: Submit -button_save: Save -button_check_all: Check all -button_uncheck_all: Uncheck all -button_delete: Delete -button_create: Create -button_test: Test -button_edit: Edit -button_add: Add -button_change: Change -button_apply: Apply -button_clear: Clear -button_lock: Lock -button_unlock: Unlock -button_download: Download -button_list: List -button_view: View -button_move: Move -button_back: Back -button_cancel: Cancel - -text_select_mail_notifications: Select actions for which mail notifications should be sent. -text_regexp_info: eg. ^[A-Z0-9]+$ -text_min_max_length_info: 0 means no restriction -text_possible_values_info: values separated with | -text_project_destroy_confirmation: Are you sure you want to delete this project and all related data ? -text_workflow_edit: Select a role and a tracker to edit the workflow -text_are_you_sure: Are you sure ? -text_journal_changed: changed from %s to %s -text_journal_set_to: set to %s -text_journal_deleted: deleted -text_tip_task_begin_day: task beginning this day -text_tip_task_end_day: task ending this day -text_tip_task_begin_end_day: task beginning and ending this day - -default_role_manager: Manager -default_role_developper: Developer -default_role_reporter: Reporter -default_tracker_bug: Bug -default_tracker_feature: Feature -default_tracker_support: Support -default_issue_status_new: New -default_issue_status_assigned: Assigned -default_issue_status_resolved: Resolved -default_issue_status_feedback: Feedback -default_issue_status_closed: Closed -default_issue_status_rejected: Rejected -default_doc_category_user: User documentation -default_doc_category_tech: Technical documentation -default_priority_low: Low -default_priority_normal: Normal -default_priority_high: High -default_priority_urgent: Urgent -default_priority_immediate: Immediate - -enumeration_issue_priorities: Issue priorities -enumeration_doc_categories: Document categories diff --git a/redmine/lang/es.yml b/redmine/lang/es.yml deleted file mode 100644 index f87a31133..000000000 --- a/redmine/lang/es.yml +++ /dev/null @@ -1,320 +0,0 @@ -_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' - -actionview_datehelper_select_day_prefix: -actionview_datehelper_select_month_names: Enero,Febrero,Marzo,Abril,Mayo,Junio,Julio,Agosto,Septiembre,Octubre,Noviembre,Diciembre -actionview_datehelper_select_month_names_abbr: Ene,Feb,Mar,Abr,Mayo,Jun,Jul,Ago,Sep,Oct,Nov,Dic -actionview_datehelper_select_month_prefix: -actionview_datehelper_select_year_prefix: -actionview_datehelper_time_in_words_day: 1 day -actionview_datehelper_time_in_words_day_plural: %d days -actionview_datehelper_time_in_words_hour_about: about an hour -actionview_datehelper_time_in_words_hour_about_plural: about %d hours -actionview_datehelper_time_in_words_hour_about_single: about an hour -actionview_datehelper_time_in_words_minute: 1 minute -actionview_datehelper_time_in_words_minute_half: half a minute -actionview_datehelper_time_in_words_minute_less_than: less than a minute -actionview_datehelper_time_in_words_minute_plural: %d minutes -actionview_datehelper_time_in_words_minute_single: 1 minute -actionview_datehelper_time_in_words_second_less_than: less than a second -actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds -actionview_instancetag_blank_option: Please select - -activerecord_error_inclusion: is not included in the list -activerecord_error_exclusion: is reserved -activerecord_error_invalid: is invalid -activerecord_error_confirmation: doesn't match confirmation -activerecord_error_accepted: must be accepted -activerecord_error_empty: can't be empty -activerecord_error_blank: can't be blank -activerecord_error_too_long: is too long -activerecord_error_too_short: is too short -activerecord_error_wrong_length: is the wrong length -activerecord_error_taken: has already been taken -activerecord_error_not_a_number: is not a number -activerecord_error_not_a_date: no es una fecha válida -activerecord_error_greater_than_start_date: debe ser la fecha mayor que del comienzo - -general_fmt_age: %d año -general_fmt_age_plural: %d años -general_fmt_date: %%d/%%m/%%Y -general_fmt_datetime: %%d/%%m/%%Y %%H:%%M -general_fmt_datetime_short: %%d/%%m %%H:%%M -general_fmt_time: %%H:%%M -general_text_No: 'No' -general_text_Yes: 'Sí' -general_text_no: 'no' -general_text_yes: 'sí' -general_lang_es: 'Español' -general_csv_separator: ';' -general_day_names: Lunes,Martes,Miércoles,Jueves,Viernes,Sábado,Domingo - -notice_account_updated: Account was successfully updated. -notice_account_invalid_creditentials: Invalid user or password -notice_account_password_updated: Password was successfully updated. -notice_account_wrong_password: Wrong password -notice_account_register_done: Account was successfully created. -notice_account_unknown_email: Unknown user. -notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. -notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. -notice_account_activated: Your account has been activated. You can now log in. -notice_successful_create: Successful creation. -notice_successful_update: Successful update. -notice_successful_delete: Successful deletion. -notice_successful_connection: Successful connection. -notice_file_not_found: Requested file doesn't exist or has been deleted. -notice_locking_conflict: Data have been updated by another user. - -mail_subject_lost_password: Tu contraseña del redMine -mail_subject_register: Activación de la cuenta del redMine - -gui_validation_error: 1 error -gui_validation_error_plural: %d errores - -field_name: Nombre -field_description: Descripción -field_summary: Resumen -field_is_required: Obligatorio -field_firstname: Nombre -field_lastname: Apellido -field_mail: Email -field_filename: Fichero -field_filesize: Tamaño -field_downloads: Telecargas -field_author: Autor -field_created_on: Creado -field_updated_on: Actualizado -field_field_format: Formato -field_is_for_all: Para todos los proyectos -field_possible_values: Valores posibles -field_regexp: Expresión regular -field_min_length: Longitud mínima -field_max_length: Longitud máxima -field_value: Valor -field_category: Categoría -field_title: Título -field_project: Proyecto -field_issue: Petición -field_status: Estatuto -field_notes: Notas -field_is_closed: Petición resuelta -field_is_default: Estatuto por defecto -field_html_color: Color -field_tracker: Tracker -field_subject: Tema -field_due_date: Fecha debida -field_assigned_to: Asignado a -field_priority: Prioridad -field_fixed_version: Versión corregida -field_user: Usuario -field_role: Papel -field_homepage: Sitio web -field_is_public: Público -field_parent: Proyecto secundario de -field_is_in_chlog: Consultar las peticiones en el histórico -field_login: Identificador -field_mail_notification: Notificación por mail -field_admin: Administrador -field_locked: Cerrado -field_last_login_on: Última conexión -field_language: Lengua -field_effective_date: Fecha -field_password: Contraseña -field_new_password: Nueva contraseña -field_password_confirmation: Confirmación -field_version: Versión -field_type: Tipo -field_host: Anfitrión -field_port: Puerto -field_account: Cuenta -field_base_dn: Base DN -field_attr_login: Cualidad del identificador -field_attr_firstname: Cualidad del nombre -field_attr_lastname: Cualidad del apellido -field_attr_mail: Cualidad del Email -field_onthefly: Creación del usuario On-the-fly -field_start_date: Comienzo -field_done_ratio: %% Realizado -field_hide_mail: Ocultar mi email address - -label_user: Usuario -label_user_plural: Usuarios -label_user_new: Nuevo usuario -label_project: Proyecto -label_project_new: Nuevo proyecto -label_project_plural: Proyectos -label_project_latest: Los proyectos más últimos -label_issue: Petición -label_issue_new: Nueva petición -label_issue_plural: Peticiones -label_issue_view_all: Ver todas las peticiones -label_document: Documento -label_document_new: Nuevo documento -label_document_plural: Documentos -label_role: Papel -label_role_plural: Papeles -label_role_new: Nuevo papel -label_role_and_permissions: Papeles y permisos -label_member: Miembro -label_member_new: Nuevo miembro -label_member_plural: Miembros -label_tracker: Tracker -label_tracker_plural: Trackers -label_tracker_new: Nuevo tracker -label_workflow: Workflow -label_issue_status: Estatuto de petición -label_issue_status_plural: Estatutos de las peticiones -label_issue_status_new: Nuevo estatuto -label_issue_category: Categoría de las peticiones -label_issue_category_plural: Categorías de las peticiones -label_issue_category_new: Nueva categoría -label_custom_field: Campo personalizado -label_custom_field_plural: Campos personalizados -label_custom_field_new: Nuevo campo personalizado -label_enumerations: Listas de valores -label_enumeration_new: Nuevo valor -label_information: Informacion -label_information_plural: Informaciones -label_please_login: Conexión -label_register: Registrar -label_password_lost: ¿Olvidaste la contraseña? -label_home: Acogida -label_my_page: Mi página -label_my_account: Mi cuenta -label_my_projects: Mis proyectos -label_administration: Administración -label_login: Conexión -label_logout: Desconexión -label_help: Ayuda -label_reported_issues: Peticiones registradas -label_assigned_to_me_issues: Peticiones que me están asignadas -label_last_login: Última conexión -label_last_updates: Actualizado -label_last_updates_plural: %d Actualizados -label_registered_on: Inscrito el -label_activity: Actividad -label_new: Nuevo -label_logged_as: Conectado como -label_environment: Environment -label_authentication: Autentificación -label_auth_source: Modo de la autentificación -label_auth_source_new: Nuevo modo de la autentificación -label_auth_source_plural: Modos de la autentificación -label_subproject: Proyecto secundario -label_subproject_plural: Proyectos secundarios -label_min_max_length: Longitud mín - máx -label_list: Lista -label_date: Fecha -label_integer: Número -label_boolean: Boleano -label_string: Texto -label_text: Texto largo -label_attribute: Cualidad -label_attribute_plural: Cualidades -label_download: %d Telecarga -label_download_plural: %d Telecargas -label_no_data: Ningunos datos a exhibir -label_change_status: Cambiar el estatuto -label_history: Histórico -label_attachment: Fichero -label_attachment_new: Nuevo fichero -label_attachment_delete: Suprimir el fichero -label_attachment_plural: Ficheros -label_report: Informe -label_report_plural: Informes -label_news: Noticia -label_news_new: Nueva noticia -label_news_plural: Noticias -label_news_latest: Últimas noticias -label_news_view_all: Ver todas las noticias -label_change_log: Cambios -label_settings: Configuración -label_overview: Vistazo -label_version: Versión -label_version_new: Nueva versión -label_version_plural: Versiónes -label_confirmation: Confirmación -label_export_to: Exportar a -label_read: Leer... -label_public_projects: Proyectos publicos -label_open_issues: Abierta -label_open_issues_plural: Abiertas -label_closed_issues: Cerrada -label_closed_issues_plural: Cerradas -label_total: Total -label_permissions: Permisos -label_current_status: Estado actual -label_new_statuses_allowed: Nuevos estatutos autorizados -label_all: Todos -label_none: Ninguno -label_next: Próximo -label_previous: Precedente -label_used_by: Utilizado por -label_details: Detalles... -label_add_note: Agregar una nota -label_per_page: Por la página -label_calendar: Calendario -label_months_from: meses de -label_gantt_chart: Diagrama de Gantt -label_internal: Interno -label_last_changes: %d cambios del último -label_change_view_all: Ver todos los cambios -label_personalize_page: Personalizar esta página - -button_login: Conexión -button_submit: Someter -button_save: Validar -button_check_all: Seleccionar todo -button_uncheck_all: No seleccionar nada -button_delete: Suprimir -button_create: Crear -button_test: Testar -button_edit: Modificar -button_add: Añadir -button_change: Cambiar -button_apply: Aplicar -button_clear: Anular -button_lock: Bloquear -button_unlock: Desbloquear -button_download: Telecargar -button_list: Listar -button_view: Ver -button_move: Mover -button_back: Atrás -button_cancel: Cancelar - -text_select_mail_notifications: Seleccionar las actividades que necesitan la activación de la notificación por mail. -text_regexp_info: eg. ^[A-Z0-9]+$ -text_min_max_length_info: 0 para ninguna restricción -text_possible_values_info: Los valores se separaron con | -text_project_destroy_confirmation: ¿ Estás seguro de querer eliminar el proyecto ? -text_workflow_edit: Seleccionar un workflow para actualizar -text_are_you_sure: ¿ Estás seguro ? -text_journal_changed: cambiado de %s a %s -text_journal_set_to: fijado a %s -text_journal_deleted: suprimido -text_tip_task_begin_day: tarea que comienza este día -text_tip_task_end_day: tarea que termina este día -text_tip_task_begin_end_day: tarea que comienza y termina este día - -default_role_manager: Manager -default_role_developper: Desarrollador -default_role_reporter: Informador -default_tracker_bug: Anomalía -default_tracker_feature: Evolución -default_tracker_support: Asistencia -default_issue_status_new: Nuevo -default_issue_status_assigned: Asignada -default_issue_status_resolved: Resuelta -default_issue_status_feedback: Comentario -default_issue_status_closed: Cerrada -default_issue_status_rejected: Rechazada -default_doc_category_user: Documentación del usuario -default_doc_category_tech: Documentación tecnica -default_priority_low: Bajo -default_priority_normal: Normal -default_priority_high: Alto -default_priority_urgent: Urgente -default_priority_immediate: Ahora - -enumeration_issue_priorities: Prioridad de las peticiones -enumeration_doc_categories: Categorías del documento diff --git a/redmine/lang/fr.yml b/redmine/lang/fr.yml deleted file mode 100644 index 8e7829b19..000000000 --- a/redmine/lang/fr.yml +++ /dev/null @@ -1,321 +0,0 @@ -_gloc_rule_default: '|n| n<=1 ? "" : "_plural" ' - -actionview_datehelper_select_day_prefix: -actionview_datehelper_select_month_names: Janvier,Février,Mars,Avril,Mai,Juin,Juillet,Août,Septembre,Octobre,Novembre,Décembre -actionview_datehelper_select_month_names_abbr: Jan,Fév,Mars,Avril,Mai,Juin,Juil,Août,Sept,Oct,Nov,Déc -actionview_datehelper_select_month_prefix: -actionview_datehelper_select_year_prefix: -actionview_datehelper_time_in_words_day: 1 jour -actionview_datehelper_time_in_words_day_plural: %d jours -actionview_datehelper_time_in_words_hour_about: about an hour -actionview_datehelper_time_in_words_hour_about_plural: about %d hours -actionview_datehelper_time_in_words_hour_about_single: about an hour -actionview_datehelper_time_in_words_minute: 1 minute -actionview_datehelper_time_in_words_minute_half: 30 secondes -actionview_datehelper_time_in_words_minute_less_than: moins d'une minute -actionview_datehelper_time_in_words_minute_plural: %d minutes -actionview_datehelper_time_in_words_minute_single: 1 minute -actionview_datehelper_time_in_words_second_less_than: moins d'une seconde -actionview_datehelper_time_in_words_second_less_than_plural: moins de %d secondes -actionview_instancetag_blank_option: Choisir - -activerecord_error_inclusion: n'est pas inclus dans la liste -activerecord_error_exclusion: est reservé -activerecord_error_invalid: est invalide -activerecord_error_confirmation: ne correspond pas à la confirmation -activerecord_error_accepted: doit être accepté -activerecord_error_empty: doit être renseigné -activerecord_error_blank: doit être renseigné -activerecord_error_too_long: est trop long -activerecord_error_too_short: est trop court -activerecord_error_wrong_length: n'est pas de la bonne longueur -activerecord_error_taken: est déjà utilisé -activerecord_error_not_a_number: n'est pas un nombre -activerecord_error_not_a_date: n'est pas une date valide -activerecord_error_greater_than_start_date: doit être postérieur à la date de début - -general_fmt_age: %d an -general_fmt_age_plural: %d ans -general_fmt_date: %%d/%%m/%%Y -general_fmt_datetime: %%d/%%m/%%Y %%H:%%M -general_fmt_datetime_short: %%d/%%m %%H:%%M -general_fmt_time: %%H:%%M -general_text_No: 'Non' -general_text_Yes: 'Oui' -general_text_no: 'non' -general_text_yes: 'oui' -general_lang_fr: 'Français' -general_csv_separator: ';' -general_day_names: Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche - -notice_account_updated: Le compte a été mis à jour avec succès. -notice_account_invalid_creditentials: Identifiant ou mot de passe invalide. -notice_account_password_updated: Mot de passe mis à jour avec succès. -notice_account_wrong_password: Mot de passe incorrect -notice_account_register_done: Un message contenant les instructions pour activer votre compte vous a été envoyé. -notice_account_unknown_email: Aucun compte ne correspond à cette adresse. -notice_can_t_change_password: Ce compte utilise une authentification externe. Impossible de changer le mot de passe. -notice_account_lost_email_sent: Un message contenant les instructions pour choisir un nouveau mot de passe vous a été envoyé. -notice_account_activated: Votre compte a été activé. Vous pouvez à présent vous connecter. -notice_successful_create: Création effectuée avec succès. -notice_successful_update: Mise à jour effectuée avec succès. -notice_successful_delete: Suppression effectuée avec succès. -notice_successful_connection: Connection réussie. -notice_file_not_found: Le fichier demandé n'existe pas ou a été supprimé. -notice_locking_conflict: Les données ont été mises à jour par un autre utilisateur. Mise à jour impossible. - -mail_subject_lost_password: Votre mot de passe redMine -mail_subject_register: Activation de votre compte redMine - -gui_validation_error: 1 erreur -gui_validation_error_plural: %d erreurs - -field_name: Nom -field_description: Description -field_summary: Résumé -field_is_required: Obligatoire -field_firstname: Prénom -field_lastname: Nom -field_mail: Email -field_filename: Fichier -field_filesize: Taille -field_downloads: Téléchargements -field_author: Auteur -field_created_on: Créé -field_updated_on: Mis à jour -field_field_format: Format -field_is_for_all: Pour tous les projets -field_possible_values: Valeurs possibles -field_regexp: Expression régulière -field_min_length: Longueur minimum -field_max_length: Longueur maximum -field_value: Valeur -field_category: Catégorie -field_title: Titre -field_project: Projet -field_issue: Demande -field_status: Statut -field_notes: Notes -field_is_closed: Demande fermée -field_is_default: Statut par défaut -field_html_color: Couleur -field_tracker: Tracker -field_subject: Sujet -field_due_date: Date d'échéance -field_assigned_to: Assigné à -field_priority: Priorité -field_fixed_version: Version corrigée -field_user: Utilisateur -field_role: Rôle -field_homepage: Site web -field_is_public: Public -field_parent: Sous-projet de -field_is_in_chlog: Demandes affichées dans l'historique -field_login: Identifiant -field_mail_notification: Notifications par mail -field_admin: Administrateur -field_locked: Verrouillé -field_last_login_on: Dernière connexion -field_language: Langue -field_effective_date: Date -field_password: Mot de passe -field_new_password: Nouveau mot de passe -field_password_confirmation: Confirmation -field_version: Version -field_type: Type -field_host: Hôte -field_port: Port -field_account: Compte -field_base_dn: Base DN -field_attr_login: Attribut Identifiant -field_attr_firstname: Attribut Prénom -field_attr_lastname: Attribut Nom -field_attr_mail: Attribut Email -field_onthefly: Création des utilisateurs à la volée -field_start_date: Début -field_done_ratio: %% Réalisé -field_auth_source: Mode d'authentification -field_hide_mail: Cacher mon adresse mail - -label_user: Utilisateur -label_user_plural: Utilisateurs -label_user_new: Nouvel utilisateur -label_project: Projet -label_project_new: Nouveau projet -label_project_plural: Projets -label_project_latest: Derniers projets -label_issue: Demande -label_issue_new: Nouvelle demande -label_issue_plural: Demandes -label_issue_view_all: Voir toutes les demandes -label_document: Document -label_document_new: Nouveau document -label_document_plural: Documents -label_role: Rôle -label_role_plural: Rôles -label_role_new: Nouveau rôle -label_role_and_permissions: Rôles et permissions -label_member: Membre -label_member_new: Nouveau membre -label_member_plural: Membres -label_tracker: Tracker -label_tracker_plural: Trackers -label_tracker_new: Nouveau tracker -label_workflow: Workflow -label_issue_status: Statut de demandes -label_issue_status_plural: Statuts de demandes -label_issue_status_new: Nouveau statut -label_issue_category: Catégorie de demandes -label_issue_category_plural: Catégories de demandes -label_issue_category_new: Nouvelle catégorie -label_custom_field: Champ personnalisé -label_custom_field_plural: Champs personnalisés -label_custom_field_new: Nouveau champ personnalisé -label_enumerations: Listes de valeurs -label_enumeration_new: Nouvelle valeur -label_information: Information -label_information_plural: Informations -label_please_login: Identification -label_register: S'enregistrer -label_password_lost: Mot de passe perdu -label_home: Accueil -label_my_page: Ma page -label_my_account: Mon compte -label_my_projects: Mes projets -label_administration: Administration -label_login: Connexion -label_logout: Déconnexion -label_help: Aide -label_reported_issues: Demandes soumises -label_assigned_to_me_issues: Demandes qui me sont assignées -label_last_login: Dernière connexion -label_last_updates: Dernière mise à jour -label_last_updates_plural: %d dernières mises à jour -label_registered_on: Inscrit le -label_activity: Activité -label_new: Nouveau -label_logged_as: Connecté en tant que -label_environment: Environnement -label_authentication: Authentification -label_auth_source: Mode d'authentification -label_auth_source_new: Nouveau mode d'authentification -label_auth_source_plural: Modes d'authentification -label_subproject: Sous-projet -label_subproject_plural: Sous-projets -label_min_max_length: Longueurs mini - maxi -label_list: Liste -label_date: Date -label_integer: Entier -label_boolean: Booléen -label_string: Texte -label_text: Texte long -label_attribute: Attribut -label_attribute_plural: Attributs -label_download: %d Téléchargement -label_download_plural: %d Téléchargements -label_no_data: Aucune donnée à afficher -label_change_status: Changer le statut -label_history: Historique -label_attachment: Fichier -label_attachment_new: Nouveau fichier -label_attachment_delete: Supprimer le fichier -label_attachment_plural: Fichiers -label_report: Rapport -label_report_plural: Rapports -label_news: Annonce -label_news_new: Nouvelle annonce -label_news_plural: Annonces -label_news_latest: Dernières annonces -label_news_view_all: Voir toutes les annonces -label_change_log: Historique -label_settings: Configuration -label_overview: Aperçu -label_version: Version -label_version_new: Nouvelle version -label_version_plural: Versions -label_confirmation: Confirmation -label_export_to: Exporter en -label_read: Lire... -label_public_projects: Projets publics -label_open_issues: Ouverte -label_open_issues_plural: Ouvertes -label_closed_issues: Fermée -label_closed_issues_plural: Fermées -label_total: Total -label_permissions: Permissions -label_current_status: Statut actuel -label_new_statuses_allowed: Nouveaux statuts autorisés -label_all: Tous -label_none: Aucun -label_next: Suivant -label_previous: Précédent -label_used_by: Utilisé par -label_details: Détails... -label_add_note: Ajouter une note -label_per_page: Par page -label_calendar: Calendrier -label_months_from: mois depuis -label_gantt_chart: Diagramme de Gantt -label_internal: Interne -label_last_changes: %d derniers changements -label_change_view_all: Voir tous les changements -label_personalize_page: Personnaliser cette page - -button_login: Connexion -button_submit: Soumettre -button_save: Sauvegarder -button_check_all: Tout cocher -button_uncheck_all: Tout décocher -button_delete: Supprimer -button_create: Créer -button_test: Tester -button_edit: Modifier -button_add: Ajouter -button_change: Changer -button_apply: Appliquer -button_clear: Effacer -button_lock: Verrouiller -button_unlock: Déverrouiller -button_download: Télécharger -button_list: Lister -button_view: Voir -button_move: Déplacer -button_back: Retour -button_cancel: Annuler - -text_select_mail_notifications: Sélectionner les actions pour lesquelles la notification par mail doit être activée. -text_regexp_info: ex. ^[A-Z0-9]+$ -text_min_max_length_info: 0 pour aucune restriction -text_possible_values_info: valeurs séparées par | -text_project_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce projet et tout ce qui lui est rattaché ? -text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow -text_are_you_sure: Etes-vous sûr ? -text_journal_changed: changé de %s à %s -text_journal_set_to: mis à %s -text_journal_deleted: supprimé -text_tip_task_begin_day: tâche commençant ce jour -text_tip_task_end_day: tâche finissant ce jour -text_tip_task_begin_end_day: tâche commençant et finissant ce jour - -default_role_manager: Manager -default_role_developper: Développeur -default_role_reporter: Rapporteur -default_tracker_bug: Anomalie -default_tracker_feature: Evolution -default_tracker_support: Assistance -default_issue_status_new: Nouveau -default_issue_status_assigned: Assigné -default_issue_status_resolved: Résolu -default_issue_status_feedback: Commentaire -default_issue_status_closed: Fermé -default_issue_status_rejected: Rejeté -default_doc_category_user: Documentation utilisateur -default_doc_category_tech: Documentation technique -default_priority_low: Bas -default_priority_normal: Normal -default_priority_high: Haut -default_priority_urgent: Urgent -default_priority_immediate: Immédiat - -enumeration_issue_priorities: Priorités des demandes -enumeration_doc_categories: Catégories des documents diff --git a/redmine/lib/tasks/extract_fixtures.rake b/redmine/lib/tasks/extract_fixtures.rake deleted file mode 100644 index 49834e5ab..000000000 --- a/redmine/lib/tasks/extract_fixtures.rake +++ /dev/null @@ -1,24 +0,0 @@ -desc 'Create YAML test fixtures from data in an existing database. -Defaults to development database. Set RAILS_ENV to override.' - -task :extract_fixtures => :environment do - sql = "SELECT * FROM %s" - skip_tables = ["schema_info"] - ActiveRecord::Base.establish_connection - (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name| - i = "000" - File.open("#{RAILS_ROOT}/#{table_name}.yml", 'w' ) do |file| - data = ActiveRecord::Base.connection.select_all(sql % table_name) - file.write data.inject({}) { |hash, record| - - # cast extracted values - ActiveRecord::Base.connection.columns(table_name).each { |col| - record[col.name] = col.type_cast(record[col.name]) if record[col.name] - } - - hash["#{table_name}_#{i.succ!}"] = record - hash - }.to_yaml - end - end -end \ No newline at end of file diff --git a/redmine/lib/tasks/load_default_data.rake b/redmine/lib/tasks/load_default_data.rake deleted file mode 100644 index d672802db..000000000 --- a/redmine/lib/tasks/load_default_data.rake +++ /dev/null @@ -1,88 +0,0 @@ -desc 'Load default configuration data (using default language)' - -task :load_default_data => :environment do - include GLoc - set_language_if_valid($RDM_DEFAULT_LANG) - -begin - # check that no data already exists - if Role.find(:first) - raise "Some roles are already defined." - end - if Tracker.find(:first) - raise "Some trackers are already defined." - end - if IssueStatus.find(:first) - raise "Some statuses are already defined." - end - if Enumeration.find(:first) - raise "Some enumerations are already defined." - end - - puts "Loading default configuration for language: #{current_language}" - - # roles - manager = Role.create :name => l(:default_role_manager) - manager.permissions = Permission.find(:all, :conditions => ["is_public=?", false]) - - developper = Role.create :name => l(:default_role_developper) - perms = [150, 320, 321, 322, 420, 421, 422, 1050, 1060, 1070, 1075, 1220, 1221, 1222, 1223, 1224, 1320, 1322, 1061, 1057] - developper.permissions = Permission.find(:all, :conditions => ["sort IN (#{perms.join(',')})"]) - - reporter = Role.create :name => l(:default_role_reporter) - perms = [1050, 1060, 1070, 1057] - reporter.permissions = Permission.find(:all, :conditions => ["sort IN (#{perms.join(',')})"]) - - # trackers - Tracker.create(:name => l(:default_tracker_bug), :is_in_chlog => true) - Tracker.create(:name => l(:default_tracker_feature), :is_in_chlog => true) - Tracker.create(:name => l(:default_tracker_support), :is_in_chlog => false) - - # issue statuses - new = IssueStatus.create(:name => l(:default_issue_status_new), :is_closed => false, :is_default => true, :html_color => 'F98787') - assigned = IssueStatus.create(:name => l(:default_issue_status_assigned), :is_closed => false, :is_default => false, :html_color => 'C0C0FF') - resolved = IssueStatus.create(:name => l(:default_issue_status_resolved), :is_closed => false, :is_default => false, :html_color => '88E0B3') - feedback = IssueStatus.create(:name => l(:default_issue_status_feedback), :is_closed => false, :is_default => false, :html_color => 'F3A4F4') - closed = IssueStatus.create(:name => l(:default_issue_status_closed), :is_closed => true, :is_default => false, :html_color => 'DBDBDB') - rejected = IssueStatus.create(:name => l(:default_issue_status_rejected), :is_closed => true, :is_default => false, :html_color => 'F5C28B') - - # workflow - Tracker.find(:all).each { |t| - IssueStatus.find(:all).each { |os| - IssueStatus.find(:all).each { |ns| - Workflow.create(:tracker_id => t.id, :role_id => manager.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns - } - } - } - - Tracker.find(:all).each { |t| - [new, assigned, resolved, feedback].each { |os| - [assigned, resolved, feedback, closed].each { |ns| - Workflow.create(:tracker_id => t.id, :role_id => developper.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns - } - } - } - - Tracker.find(:all).each { |t| - [new, assigned, resolved, feedback].each { |os| - [closed].each { |ns| - Workflow.create(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns - } - } - Workflow.create(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => resolved.id, :new_status_id => feedback.id) - } - - # enumerations - Enumeration.create(:opt => "DCAT", :name => l(:default_doc_category_user)) - Enumeration.create(:opt => "DCAT", :name => l(:default_doc_category_tech)) - Enumeration.create(:opt => "IPRI", :name => l(:default_priority_low)) - Enumeration.create(:opt => "IPRI", :name => l(:default_priority_normal)) - Enumeration.create(:opt => "IPRI", :name => l(:default_priority_high)) - Enumeration.create(:opt => "IPRI", :name => l(:default_priority_urgent)) - Enumeration.create(:opt => "IPRI", :name => l(:default_priority_immediate)) - -rescue => error - puts "Error: " + error - puts "Default configuration can't be loaded." -end -end \ No newline at end of file diff --git a/redmine/log/delete.me b/redmine/log/delete.me deleted file mode 100644 index 18beddaa8..000000000 --- a/redmine/log/delete.me +++ /dev/null @@ -1 +0,0 @@ -default directory for uploaded files \ No newline at end of file diff --git a/redmine/public/.htaccess b/redmine/public/.htaccess deleted file mode 100644 index d3c998345..000000000 --- a/redmine/public/.htaccess +++ /dev/null @@ -1,40 +0,0 @@ -# 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 "

    Application error

    Rails application failed to start properly" \ No newline at end of file diff --git a/redmine/public/404.html b/redmine/public/404.html deleted file mode 100644 index ddf424b09..000000000 --- a/redmine/public/404.html +++ /dev/null @@ -1,23 +0,0 @@ - - -redMine 404 error - - -

    Page not found

    -

    The page you were trying to access doesn't exist or has been removed.

    -

    Back

    - - \ No newline at end of file diff --git a/redmine/public/500.html b/redmine/public/500.html deleted file mode 100644 index 93eb0f128..000000000 --- a/redmine/public/500.html +++ /dev/null @@ -1,24 +0,0 @@ - - -redMine 500 error - - -

    Internal error

    -

    An error occurred on the page you were trying to access.
    - If you continue to experience problems please contact your redMine administrator for assistance.

    -

    Back

    - - \ No newline at end of file diff --git a/redmine/public/dispatch.cgi b/redmine/public/dispatch.cgi deleted file mode 100644 index 9730473f2..000000000 --- a/redmine/public/dispatch.cgi +++ /dev/null @@ -1,10 +0,0 @@ -#!/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/redmine/public/dispatch.fcgi b/redmine/public/dispatch.fcgi deleted file mode 100644 index f934b3002..000000000 --- a/redmine/public/dispatch.fcgi +++ /dev/null @@ -1,24 +0,0 @@ -#!/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/redmine/public/dispatch.rb b/redmine/public/dispatch.rb deleted file mode 100644 index 9730473f2..000000000 --- a/redmine/public/dispatch.rb +++ /dev/null @@ -1,10 +0,0 @@ -#!/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/redmine/public/favicon.ico b/redmine/public/favicon.ico deleted file mode 100644 index e69de29bb..000000000 diff --git a/redmine/public/images/add.png b/redmine/public/images/add.png deleted file mode 100644 index 90032e9d8..000000000 Binary files a/redmine/public/images/add.png and /dev/null differ diff --git a/redmine/public/images/admin.png b/redmine/public/images/admin.png deleted file mode 100644 index 0c190984f..000000000 Binary files a/redmine/public/images/admin.png and /dev/null differ diff --git a/redmine/public/images/alert.png b/redmine/public/images/alert.png deleted file mode 100644 index ba107e83b..000000000 Binary files a/redmine/public/images/alert.png and /dev/null differ diff --git a/redmine/public/images/arrow_bw.png b/redmine/public/images/arrow_bw.png deleted file mode 100644 index 52dfc96f0..000000000 Binary files a/redmine/public/images/arrow_bw.png and /dev/null differ diff --git a/redmine/public/images/arrow_from.png b/redmine/public/images/arrow_from.png deleted file mode 100644 index 4d5eeb9ea..000000000 Binary files a/redmine/public/images/arrow_from.png and /dev/null differ diff --git a/redmine/public/images/arrow_to.png b/redmine/public/images/arrow_to.png deleted file mode 100644 index 4f969716f..000000000 Binary files a/redmine/public/images/arrow_to.png and /dev/null differ diff --git a/redmine/public/images/attachment.png b/redmine/public/images/attachment.png deleted file mode 100644 index eea26921b..000000000 Binary files a/redmine/public/images/attachment.png and /dev/null differ diff --git a/redmine/public/images/bulletgreen.png b/redmine/public/images/bulletgreen.png deleted file mode 100644 index abe41592b..000000000 Binary files a/redmine/public/images/bulletgreen.png and /dev/null differ diff --git a/redmine/public/images/bulletred.png b/redmine/public/images/bulletred.png deleted file mode 100644 index 26a121057..000000000 Binary files a/redmine/public/images/bulletred.png and /dev/null differ diff --git a/redmine/public/images/calendar.png b/redmine/public/images/calendar.png deleted file mode 100644 index aa269da38..000000000 Binary files a/redmine/public/images/calendar.png and /dev/null differ diff --git a/redmine/public/images/close.png b/redmine/public/images/close.png deleted file mode 100644 index 3501ed4d5..000000000 Binary files a/redmine/public/images/close.png and /dev/null differ diff --git a/redmine/public/images/close_hl.png b/redmine/public/images/close_hl.png deleted file mode 100644 index a433f7515..000000000 Binary files a/redmine/public/images/close_hl.png and /dev/null differ diff --git a/redmine/public/images/delete.png b/redmine/public/images/delete.png deleted file mode 100644 index 2ed33bdf3..000000000 Binary files a/redmine/public/images/delete.png and /dev/null differ diff --git a/redmine/public/images/details.png b/redmine/public/images/details.png deleted file mode 100644 index 7c813b04a..000000000 Binary files a/redmine/public/images/details.png and /dev/null differ diff --git a/redmine/public/images/dir.png b/redmine/public/images/dir.png deleted file mode 100644 index d078094ac..000000000 Binary files a/redmine/public/images/dir.png and /dev/null differ diff --git a/redmine/public/images/dir_new.png b/redmine/public/images/dir_new.png deleted file mode 100644 index 2d29814f2..000000000 Binary files a/redmine/public/images/dir_new.png and /dev/null differ diff --git a/redmine/public/images/dir_open.png b/redmine/public/images/dir_open.png deleted file mode 100644 index a248cba3c..000000000 Binary files a/redmine/public/images/dir_open.png and /dev/null differ diff --git a/redmine/public/images/document.png b/redmine/public/images/document.png deleted file mode 100644 index 34fde6eb3..000000000 Binary files a/redmine/public/images/document.png and /dev/null differ diff --git a/redmine/public/images/edit_small.png b/redmine/public/images/edit_small.png deleted file mode 100644 index dea7c92ea..000000000 Binary files a/redmine/public/images/edit_small.png and /dev/null differ diff --git a/redmine/public/images/file_new.png b/redmine/public/images/file_new.png deleted file mode 100644 index 9a12ca732..000000000 Binary files a/redmine/public/images/file_new.png and /dev/null differ diff --git a/redmine/public/images/gantt.png b/redmine/public/images/gantt.png deleted file mode 100644 index 2673d23d2..000000000 Binary files a/redmine/public/images/gantt.png and /dev/null differ diff --git a/redmine/public/images/help.png b/redmine/public/images/help.png deleted file mode 100644 index da8feb993..000000000 Binary files a/redmine/public/images/help.png and /dev/null differ diff --git a/redmine/public/images/home.png b/redmine/public/images/home.png deleted file mode 100644 index 7a12add6a..000000000 Binary files a/redmine/public/images/home.png and /dev/null differ diff --git a/redmine/public/images/issues.png b/redmine/public/images/issues.png deleted file mode 100644 index e6948bff7..000000000 Binary files a/redmine/public/images/issues.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_br.png b/redmine/public/images/jstoolbar/bt_br.png deleted file mode 100644 index f8211a997..000000000 Binary files a/redmine/public/images/jstoolbar/bt_br.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_code.png b/redmine/public/images/jstoolbar/bt_code.png deleted file mode 100644 index 52924abf7..000000000 Binary files a/redmine/public/images/jstoolbar/bt_code.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_del.png b/redmine/public/images/jstoolbar/bt_del.png deleted file mode 100644 index c6f3a8b40..000000000 Binary files a/redmine/public/images/jstoolbar/bt_del.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_em.png b/redmine/public/images/jstoolbar/bt_em.png deleted file mode 100644 index f08de4f30..000000000 Binary files a/redmine/public/images/jstoolbar/bt_em.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_ins.png b/redmine/public/images/jstoolbar/bt_ins.png deleted file mode 100644 index f6697db51..000000000 Binary files a/redmine/public/images/jstoolbar/bt_ins.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_link.png b/redmine/public/images/jstoolbar/bt_link.png deleted file mode 100644 index 9b3acbae5..000000000 Binary files a/redmine/public/images/jstoolbar/bt_link.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_ol.png b/redmine/public/images/jstoolbar/bt_ol.png deleted file mode 100644 index 2dfaec7c7..000000000 Binary files a/redmine/public/images/jstoolbar/bt_ol.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_quote.png b/redmine/public/images/jstoolbar/bt_quote.png deleted file mode 100644 index 25b2b8abe..000000000 Binary files a/redmine/public/images/jstoolbar/bt_quote.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_strong.png b/redmine/public/images/jstoolbar/bt_strong.png deleted file mode 100644 index 7e200d3f6..000000000 Binary files a/redmine/public/images/jstoolbar/bt_strong.png and /dev/null differ diff --git a/redmine/public/images/jstoolbar/bt_ul.png b/redmine/public/images/jstoolbar/bt_ul.png deleted file mode 100644 index 6e20851ec..000000000 Binary files a/redmine/public/images/jstoolbar/bt_ul.png and /dev/null differ diff --git a/redmine/public/images/loading.gif b/redmine/public/images/loading.gif deleted file mode 100644 index 085ccaeca..000000000 Binary files a/redmine/public/images/loading.gif and /dev/null differ diff --git a/redmine/public/images/locked.png b/redmine/public/images/locked.png deleted file mode 100644 index 5199dfe22..000000000 Binary files a/redmine/public/images/locked.png and /dev/null differ diff --git a/redmine/public/images/login.png b/redmine/public/images/login.png deleted file mode 100644 index 7e0c62d9c..000000000 Binary files a/redmine/public/images/login.png and /dev/null differ diff --git a/redmine/public/images/mailer.png b/redmine/public/images/mailer.png deleted file mode 100644 index 8008bb84b..000000000 Binary files a/redmine/public/images/mailer.png and /dev/null differ diff --git a/redmine/public/images/notes.png b/redmine/public/images/notes.png deleted file mode 100644 index d26b1d577..000000000 Binary files a/redmine/public/images/notes.png and /dev/null differ diff --git a/redmine/public/images/options.png b/redmine/public/images/options.png deleted file mode 100644 index a907c20f1..000000000 Binary files a/redmine/public/images/options.png and /dev/null differ diff --git a/redmine/public/images/package.png b/redmine/public/images/package.png deleted file mode 100644 index 634d13d9f..000000000 Binary files a/redmine/public/images/package.png and /dev/null differ diff --git a/redmine/public/images/projects.png b/redmine/public/images/projects.png deleted file mode 100644 index b42347a92..000000000 Binary files a/redmine/public/images/projects.png and /dev/null differ diff --git a/redmine/public/images/rails.png b/redmine/public/images/rails.png deleted file mode 100644 index b8441f182..000000000 Binary files a/redmine/public/images/rails.png and /dev/null differ diff --git a/redmine/public/images/rails_powered.png b/redmine/public/images/rails_powered.png deleted file mode 100644 index 5255e62de..000000000 Binary files a/redmine/public/images/rails_powered.png and /dev/null differ diff --git a/redmine/public/images/rails_small.png b/redmine/public/images/rails_small.png deleted file mode 100644 index aff4b7a84..000000000 Binary files a/redmine/public/images/rails_small.png and /dev/null differ diff --git a/redmine/public/images/role.png b/redmine/public/images/role.png deleted file mode 100644 index ad36d1ca8..000000000 Binary files a/redmine/public/images/role.png and /dev/null differ diff --git a/redmine/public/images/rss.png b/redmine/public/images/rss.png deleted file mode 100644 index 89ce35f80..000000000 Binary files a/redmine/public/images/rss.png and /dev/null differ diff --git a/redmine/public/images/sort_asc.png b/redmine/public/images/sort_asc.png deleted file mode 100644 index 05dfa15f4..000000000 Binary files a/redmine/public/images/sort_asc.png and /dev/null differ diff --git a/redmine/public/images/sort_desc.png b/redmine/public/images/sort_desc.png deleted file mode 100644 index f82d53917..000000000 Binary files a/redmine/public/images/sort_desc.png and /dev/null differ diff --git a/redmine/public/images/tracker.png b/redmine/public/images/tracker.png deleted file mode 100644 index f29cfb2af..000000000 Binary files a/redmine/public/images/tracker.png and /dev/null differ diff --git a/redmine/public/images/true.png b/redmine/public/images/true.png deleted file mode 100644 index 9afc0b52a..000000000 Binary files a/redmine/public/images/true.png and /dev/null differ diff --git a/redmine/public/images/user.png b/redmine/public/images/user.png deleted file mode 100644 index 89d591c0b..000000000 Binary files a/redmine/public/images/user.png and /dev/null differ diff --git a/redmine/public/images/user_new.png b/redmine/public/images/user_new.png deleted file mode 100644 index c7c718822..000000000 Binary files a/redmine/public/images/user_new.png and /dev/null differ diff --git a/redmine/public/images/user_page.png b/redmine/public/images/user_page.png deleted file mode 100644 index 940a7b8e1..000000000 Binary files a/redmine/public/images/user_page.png and /dev/null differ diff --git a/redmine/public/images/users.png b/redmine/public/images/users.png deleted file mode 100644 index 3b9fc5aa9..000000000 Binary files a/redmine/public/images/users.png and /dev/null differ diff --git a/redmine/public/images/workflow.png b/redmine/public/images/workflow.png deleted file mode 100644 index 868332fed..000000000 Binary files a/redmine/public/images/workflow.png and /dev/null differ diff --git a/redmine/public/images/zoom_in.png b/redmine/public/images/zoom_in.png deleted file mode 100644 index d9abe7f52..000000000 Binary files a/redmine/public/images/zoom_in.png and /dev/null differ diff --git a/redmine/public/images/zoom_in_g.png b/redmine/public/images/zoom_in_g.png deleted file mode 100644 index 72b271c5e..000000000 Binary files a/redmine/public/images/zoom_in_g.png and /dev/null differ diff --git a/redmine/public/images/zoom_out.png b/redmine/public/images/zoom_out.png deleted file mode 100644 index 906e4a4e5..000000000 Binary files a/redmine/public/images/zoom_out.png and /dev/null differ diff --git a/redmine/public/images/zoom_out_g.png b/redmine/public/images/zoom_out_g.png deleted file mode 100644 index 7f2416be2..000000000 Binary files a/redmine/public/images/zoom_out_g.png and /dev/null differ diff --git a/redmine/public/javascripts/application.js b/redmine/public/javascripts/application.js deleted file mode 100644 index 46649130e..000000000 --- a/redmine/public/javascripts/application.js +++ /dev/null @@ -1,20 +0,0 @@ -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/redmine/public/javascripts/calendar/calendar-setup.js b/redmine/public/javascripts/calendar/calendar-setup.js deleted file mode 100644 index f2b485430..000000000 --- a/redmine/public/javascripts/calendar/calendar-setup.js +++ /dev/null @@ -1,200 +0,0 @@ -/* 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/redmine/public/javascripts/calendar/calendar.js b/redmine/public/javascripts/calendar/calendar.js deleted file mode 100644 index 9088e0e89..000000000 --- a/redmine/public/javascripts/calendar/calendar.js +++ /dev/null @@ -1,1806 +0,0 @@ -/* 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 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 = "
    " + text + "
    "; - 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("×", 1, 200).ttip = Calendar._TT["CLOSE"]; - } - - row = Calendar.createElement("tr", thead); - row.className = "headrow"; - - this._nav_py = hh("«", 1, -2); - this._nav_py.ttip = Calendar._TT["PREV_YEAR"]; - - this._nav_pm = hh("‹", 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("›", 1, 1); - this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"]; - - this._nav_ny = hh("»", 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"] || " "; - - 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 = " "; - - 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 = " "; - 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/redmine/public/javascripts/calendar/lang/calendar-de.js b/redmine/public/javascripts/calendar/lang/calendar-de.js deleted file mode 100644 index 59fb983bf..000000000 --- a/redmine/public/javascripts/calendar/lang/calendar-de.js +++ /dev/null @@ -1,128 +0,0 @@ -// ** I18N - -// Calendar DE language -// Author: Jack (tR), -// 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/redmine/public/javascripts/calendar/lang/calendar-en.js b/redmine/public/javascripts/calendar/lang/calendar-en.js deleted file mode 100644 index 0dbde793d..000000000 --- a/redmine/public/javascripts/calendar/lang/calendar-en.js +++ /dev/null @@ -1,127 +0,0 @@ -// ** I18N - -// Calendar EN language -// Author: Mihai Bazon, -// 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/redmine/public/javascripts/calendar/lang/calendar-es.js b/redmine/public/javascripts/calendar/lang/calendar-es.js deleted file mode 100644 index 11d0b53d5..000000000 --- a/redmine/public/javascripts/calendar/lang/calendar-es.js +++ /dev/null @@ -1,129 +0,0 @@ -// ** I18N - -// Calendar ES (spanish) language -// Author: Mihai Bazon, -// Updater: Servilio Afre Puentes -// 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/redmine/public/javascripts/calendar/lang/calendar-fr.js b/redmine/public/javascripts/calendar/lang/calendar-fr.js deleted file mode 100644 index fb0cb2380..000000000 --- a/redmine/public/javascripts/calendar/lang/calendar-fr.js +++ /dev/null @@ -1,129 +0,0 @@ -// ** I18N - -// Calendar EN language -// Author: Mihai Bazon, -// 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, 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/redmine/public/javascripts/controls.js b/redmine/public/javascripts/controls.js deleted file mode 100644 index 9742b6918..000000000 --- a/redmine/public/javascripts/controls.js +++ /dev/null @@ -1,750 +0,0 @@ -// 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, - ''); - 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 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("
  • " + elem.substr(0, entry.length) + "" + - elem.substr(entry.length) + "
  • "); - 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("
  • " + elem.substr(0, foundPos) + "" + - elem.substr(foundPos, entry.length) + "" + elem.substr( - foundPos + entry.length) + "
  • "); - 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 "
      " + ret.join('') + "
    "; - } - }, 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(/
    /i); - }, - convertHTMLLineBreaks: function(string) { - return string.replace(/
    /gi, "\n").replace(//gi, "\n").replace(/<\/p>/gi, "\n").replace(/

    /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/redmine/public/javascripts/dragdrop.js b/redmine/public/javascripts/dragdrop.js deleted file mode 100644 index 92d1f7316..000000000 --- a/redmine/public/javascripts/dragdrop.js +++ /dev/null @@ -1,584 +0,0 @@ -// 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/redmine/public/javascripts/effects.js b/redmine/public/javascripts/effects.js deleted file mode 100644 index 414398ce4..000000000 --- a/redmine/public/javascripts/effects.js +++ /dev/null @@ -1,854 +0,0 @@ -// 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.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/redmine/public/javascripts/jstoolbar.js b/redmine/public/javascripts/jstoolbar.js deleted file mode 100644 index cf9454619..000000000 --- a/redmine/public/javascripts/jstoolbar.js +++ /dev/null @@ -1,440 +0,0 @@ -/* ***** 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/redmine/public/javascripts/menu.js b/redmine/public/javascripts/menu.js deleted file mode 100644 index bf5612dd5..000000000 --- a/redmine/public/javascripts/menu.js +++ /dev/null @@ -1,556 +0,0 @@ -//***************************************************************************** -// 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-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/redmine/public/javascripts/prototype.js b/redmine/public/javascripts/prototype.js deleted file mode 100644 index e9ccd3c88..000000000 --- a/redmine/public/javascripts/prototype.js +++ /dev/null @@ -1,1785 +0,0 @@ -/* Prototype JavaScript framework, version 1.4.0 - * (c) 2005 Sam Stephenson - * - * 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: '(?:)((\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 '#'; - } -} - -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 '#'; - } -} - -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 = '' + this.content + '
    '; - 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/redmine/public/manual/en/ch01.html b/redmine/public/manual/en/ch01.html deleted file mode 100644 index aa86147eb..000000000 --- a/redmine/public/manual/en/ch01.html +++ /dev/null @@ -1,3 +0,0 @@ - - - Chapter 1. AdministrationredMine home

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s01.html b/redmine/public/manual/en/ch01s01.html deleted file mode 100644 index 9f83e7d3c..000000000 --- a/redmine/public/manual/en/ch01s01.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 1. UsersredMine home

    1. Users

    These screens allow you to manage the application users.

    1.1. Users’ List

    The Lock/Unlock buttons allow you to lock/unlock the user accounts.

    A user having a locked account cannot log in and access the application.

    1.2. User Creation or Modification

    In modification mode, please leave the Password field blank in order to keep the user’s password unchanged.

    A user designated as administrator has unrestricted access to the application and to all projects.

    • Administrator : designate the user as the administrator of the application.

    • E-mail notifications : activate or de-activate automatic e-mail notifications for this user

    • Locked : de-activates the user’s account

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s02.html b/redmine/public/manual/en/ch01s02.html deleted file mode 100644 index 06ba75673..000000000 --- a/redmine/public/manual/en/ch01s02.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 2. Roles and PermissionsredMine home

    2. Roles and Permissions

    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.

    On the new or edit Role screen, check off the actions authorized for the Role.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s03.html b/redmine/public/manual/en/ch01s03.html deleted file mode 100644 index 9253ce104..000000000 --- a/redmine/public/manual/en/ch01s03.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 3. TrackersredMine home

    3. Trackers

    Trackers allow the sorting of Issues and can define specific workflows.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s04.html b/redmine/public/manual/en/ch01s04.html deleted file mode 100644 index 425e084f3..000000000 --- a/redmine/public/manual/en/ch01s04.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 4. Customized fieldsredMine home

    4. Customized fields

    Customized fields allow you to add additional information in Projects, Issues or Users. A customized field can be of one the following types:

    • Integer : positive or negative number

    • String : a string of characters - one single line of input.

    • Text : a string of characters with multiple lines of input. Differs from String Format by providing multiple lines of input instead of a single line.

    • Date : date

    • Boolean : true or false (check if necessary)

    • List : value to select from a predefined list (aka: scroll list or select box)

    Validation elements can be defined:

    • Required : A required field must have input in the forms

    • For all the projects : field automatically associated to all of the projects

    • Min - max length : minimum and maximum length for the input fields (0 means that there is no restriction)

    • Regular Expression : regular expressions may provide validation of the input value

      Examples:

      ^\[A-Z]{4}\d+$ : 4 capital letters followed by one or several digits

      ^[^0-9]*$ : characters only - no digits

    • Possible values : possible values for the fields of "List" type. Values are separated by the character |

    4.1. Fields for Projects

    • Required : required field

    4.2. Fields for Issues

    • For all projects : field automatically associated to all project Issues

      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).

    4.3. Field for Users

    • Required : required field

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s05.html b/redmine/public/manual/en/ch01s05.html deleted file mode 100644 index 75a4dd308..000000000 --- a/redmine/public/manual/en/ch01s05.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 5. Issue statusredMine home

    5. Issue status

    These screens allow you to define the different possible Issue statuses.

    • Closed : indicates Issue is considered as closed

    • Default : status applied by default to new Issue requests (only one status can be Default status)

    • Color : HTML color code (6 characters) representing the displayed status

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s06.html b/redmine/public/manual/en/ch01s06.html deleted file mode 100644 index e7d688f33..000000000 --- a/redmine/public/manual/en/ch01s06.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 6. WorkflowredMine home

    6. Workflow

    The workflow allows to define changes the various project members are allowed to make on the Issues, according to their type.

    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.

    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.

    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.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s07.html b/redmine/public/manual/en/ch01s07.html deleted file mode 100644 index 7b95d8a63..000000000 --- a/redmine/public/manual/en/ch01s07.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 7. EnumerationsredMine home

    7. Enumerations

    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:

    • Issue Priorities

    • Document Categories

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s08.html b/redmine/public/manual/en/ch01s08.html deleted file mode 100644 index 3a2ecf28d..000000000 --- a/redmine/public/manual/en/ch01s08.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 8. E-mail notificationsredMine home

    8. E-mail notifications

    This screen allows you to select the actions that will generate an e-mail notification for project members.

    Note: E-mail sending must be activated in the application configuration if you want to make any notifications.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s09.html b/redmine/public/manual/en/ch01s09.html deleted file mode 100644 index 599c6017b..000000000 --- a/redmine/public/manual/en/ch01s09.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 9. AuthenticationredMine home

    9. Authentication

    By default, redMine refers to its own database to authenticate users, by a specific password.

    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.

    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’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.

    9.1. LDAP statement

    • Name : reference display name

    • Host : LDAP server host name

    • Port : connection port to the LDAP server

    • Account : DN of the connection account to LDAP (please leave it blank if the directory authorizes anonymous read access)

    • Password : password of the connection account

    • Base DN : Basic DN used for user search in the directory

    • LDAP screen : User search screen in the directory (optional)

    • LDAP features :

      • Identifier : LDAP feature name used as user identifier (e.g.: uid)

      • First name : LDAP feature name including the user’s first name (ex: givenName)

      • Last name : LDAP feature name including the user’s last name (ex: familyName)

      • E-mail : LDAP feature name including the user’s e-mail address (ex: mail)

    The features" First name ", " Last name " and " E-mail " are not used except when the accounts are created on the fly.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch01s10.html b/redmine/public/manual/en/ch01s10.html deleted file mode 100644 index 5cdb85b9a..000000000 --- a/redmine/public/manual/en/ch01s10.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 10. InformationredMine home

    10. Information

    Displays application and environment information.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch02.html b/redmine/public/manual/en/ch02.html deleted file mode 100644 index b97b78d9e..000000000 --- a/redmine/public/manual/en/ch02.html +++ /dev/null @@ -1,3 +0,0 @@ - - - Chapter 2. ProjectsredMine home \ No newline at end of file diff --git a/redmine/public/manual/en/ch02s01.html b/redmine/public/manual/en/ch02s01.html deleted file mode 100644 index 63cdde630..000000000 --- a/redmine/public/manual/en/ch02s01.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 1. Project previewredMine home

    1. Project preview

    The preview presents the general project information, its main members, the latest announcements, as well as an synthesis of Issue requests open by tracker.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch02s02.html b/redmine/public/manual/en/ch02s02.html deleted file mode 100644 index 4354ce4c8..000000000 --- a/redmine/public/manual/en/ch02s02.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 2. Issue managementredMine home

    2. Issue management

    2.1. Issue list

    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).

    Once applied, a screen is valid during the entire session. You can re-define it or delete it by clicking Cancel.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch02s03.html b/redmine/public/manual/en/ch02s03.html deleted file mode 100644 index 351e1c916..000000000 --- a/redmine/public/manual/en/ch02s03.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 3. ReportsredMine home

    3. Reports

    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.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch02s04.html b/redmine/public/manual/en/ch02s04.html deleted file mode 100644 index 14da5dc73..000000000 --- a/redmine/public/manual/en/ch02s04.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 4. Change logredMine home

    4. Change log

    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.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch02s05.html b/redmine/public/manual/en/ch02s05.html deleted file mode 100644 index 3a8334df2..000000000 --- a/redmine/public/manual/en/ch02s05.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 5. NewsredMine home

    5. News

    Allows you to inform users on project activity.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch02s06.html b/redmine/public/manual/en/ch02s06.html deleted file mode 100644 index 71ced3400..000000000 --- a/redmine/public/manual/en/ch02s06.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 6. DocumentsredMine home

    6. Documents

    Documents are grouped by categories (see Value Lists). A document can contain several files (for example: revisions or successive versions).

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch02s07.html b/redmine/public/manual/en/ch02s07.html deleted file mode 100644 index b7eacb6a3..000000000 --- a/redmine/public/manual/en/ch02s07.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 7. FilesredMine home

    7. Files

    This module allows you to display various folders (sources, binaires, ...) for each version of the application.

    \ No newline at end of file diff --git a/redmine/public/manual/en/ch02s08.html b/redmine/public/manual/en/ch02s08.html deleted file mode 100644 index f9d19e8ce..000000000 --- a/redmine/public/manual/en/ch02s08.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 8. SettingsredMine home

    8. Settings

    8.1. Project features

    • Public : if it’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’s not a public project, only the project members have access to it, according to their role.

    • Customized fields : Select the customized fields that you want to use. Only the administrator can define new customized fields.

    8.2. Members

    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.

    8.3. Versions

    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).

    8.4. Request categories

    Issue categories allow you to organize Issues. Categories can correspond to different project modules.

    \ No newline at end of file diff --git a/redmine/public/manual/en/html.css b/redmine/public/manual/en/html.css deleted file mode 100644 index c1b2a6fca..000000000 --- a/redmine/public/manual/en/html.css +++ /dev/null @@ -1,55 +0,0 @@ -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/redmine/public/manual/en/index.html b/redmine/public/manual/en/index.html deleted file mode 100644 index f1f64aa45..000000000 --- a/redmine/public/manual/en/index.html +++ /dev/null @@ -1,3 +0,0 @@ - - - RedMine DocumentationredMine home \ No newline at end of file diff --git a/redmine/public/manual/en/resources/issues_list.png b/redmine/public/manual/en/resources/issues_list.png deleted file mode 100644 index 47eab0fca..000000000 Binary files a/redmine/public/manual/en/resources/issues_list.png and /dev/null differ diff --git a/redmine/public/manual/en/resources/users_list.png b/redmine/public/manual/en/resources/users_list.png deleted file mode 100644 index 0c9ef86ec..000000000 Binary files a/redmine/public/manual/en/resources/users_list.png and /dev/null differ diff --git a/redmine/public/manual/en/resources/workflow.png b/redmine/public/manual/en/resources/workflow.png deleted file mode 100644 index 04e79d61e..000000000 Binary files a/redmine/public/manual/en/resources/workflow.png and /dev/null differ diff --git a/redmine/public/manual/fr/ch01.html b/redmine/public/manual/fr/ch01.html deleted file mode 100644 index 567c5368a..000000000 --- a/redmine/public/manual/fr/ch01.html +++ /dev/null @@ -1,3 +0,0 @@ - - - Chapter 1. Administration \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s01.html b/redmine/public/manual/fr/ch01s01.html deleted file mode 100644 index c08192b8b..000000000 --- a/redmine/public/manual/fr/ch01s01.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 1. Utilisateurs

    1. Utilisateurs

    Ces écrans vous permettent de gérer les utilisateurs de l'application.

    1.1. Liste des utilisateurs

    Les boutons Lock/Unlock vous permettent de vérouiller/dévérouiller les comptes utilisateurs.

    Un utilisateur dont le compte est vérouillé ne peut plus s'identifier pour accéder à l'application.

    1.2. Création ou modification d'un utilisateur

    En mode modification, laissez le champ Password vide pour laisser le mot de passe de l'utilisateur inchangé.

    Un utilisateur déclaré comme administrateur dispose de toutes les permissions sur l'application et sur tous les projets.

    • Administrateur: déclare l'utilisateur comme administrateur de l'application.

    • Notifications par mail: permet d'activer ou non l'envoi automatique de notifications par mail pour cet utilisateur

    • Vérouillé: désactive le compte de l'utilisateur

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s02.html b/redmine/public/manual/fr/ch01s02.html deleted file mode 100644 index 2b448d1a8..000000000 --- a/redmine/public/manual/fr/ch01s02.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 2. Rôles et permissions

    2. Rôles et permissions

    Les rôles permettent de définir les permissions des différents membres d'un projet. Chaque membre d'un projet dispose d'un rôle unique au sein d'un projet. Un utilisateur peut avoir différents rôles au sein de différents projets.

    Sur l'écran d'édition du rôle, cochez les actions que vous souhaitez autoriser pour le rôle.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s03.html b/redmine/public/manual/fr/ch01s03.html deleted file mode 100644 index 4e03eed49..000000000 --- a/redmine/public/manual/fr/ch01s03.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 3. Trackers

    3. Trackers

    Les trackers permettent de typer les demandes et de définir des workflows spécifiques pour chacun de ces types.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s04.html b/redmine/public/manual/fr/ch01s04.html deleted file mode 100644 index 53fae1e24..000000000 --- a/redmine/public/manual/fr/ch01s04.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 4. Champs personnalisés

    4. Champs personnalisés

    Les champs personnalisés vous permettent d'ajouter des informations supplémentaires sur les projets, les demandes ou les utilisateurs. Un champ personnalisé peut être de l'un des types suivants:

    • Entier: entier positif ou négatif

    • Chaîne: chaîne de caractère

    • Date: date

    • Booléen: booléen (case à cocher)

    • Liste: valeur à sélectionnée parmi une liste prédéfinie (liste déroulante)

    Des éléments de validation peuvent être définis:

    • Obligatoire: champ dont la saisie est obligatoire sur les demandes

    • Pour tous les projects: champ automatiquement associé à l'ensemble des projets

    • Min - max length: longueurs minimales et maximales pour les champs en saisie libre (0 signifie qu'il n'y a pas de restriction)

    • Expression régulière: expression régulière permettant de valider la valeur saisie

      Exemples:

      ^\[A-Z]{4}\d+$ : 4 lettres majuscules suivies d'un ou plusieurs chiffres

      ^[^0-9]*$ : chaîne ne comportant pas de chiffres

    • Valeurs possibles: valeurs possibles pour les champs de type "Liste". Les valeurs sont séparées par le caractère |

    4.1. Champs pour les projets

    • Obligatoire: champ dont la saisie est obligatoire

    4.2. Champs pour les demandes

    • Pour tous les projects: champ automatiquement associé aux demandes de l'ensemble des projets

      Si cette option n'est pas activée, chaque projet pourra choisir d'utiliser ou non le champ pour ses demandes (voir configuration du projet).

    4.3. Champs pour les utilisateurs

    • Obligatoire: champ dont la saisie est obligatoire

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s05.html b/redmine/public/manual/fr/ch01s05.html deleted file mode 100644 index 67212eb4e..000000000 --- a/redmine/public/manual/fr/ch01s05.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 5. Statut des demandes

    5. Statut des demandes

    Ces écrans vous permettent de définir les différents statuts possibles des demandes.

    • Demande fermée: indique que le statut correspond à une demande considérée comme fermée

    • Statut par défaut: statut appliqué par défaut aux nouvelles demandes (seul un statut peut être déclaré comme statut par défaut)

    • Couleur: code couleur HTML (6 caractères) représentant le statut à l'affichage

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s06.html b/redmine/public/manual/fr/ch01s06.html deleted file mode 100644 index 335d27aba..000000000 --- a/redmine/public/manual/fr/ch01s06.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 6. Workflow

    6. Workflow

    Le workflow permet de définir les changements que les différents membres d'un projet sont autorisés à effectuer sur les demandes, en fonction de leur type.

    Sélectionnez le rôle et le tracker pour lesquels vous souhaitez modifier le workflow, puis cliquez sur Edit. L'écran vous permet alors de modifier, pour le rôle et le tracker choisi, les changements autorisés. Les lignes représentent les statuts initiaux des demandes. Les colonnes représentent les statuts autorisés à être appliqués.

    Remarque: pour qu'un rôle puisse changer le statut des demandes, la permission doit lui être explicitement donnée indépendemment de la configuration du workflow.

    Dans l'exemple ci-dessus, les demandes de type Bug au statut Nouveau pourront être passées au statut Assignée ou Résolue par le rôle Développeur. Celles au statut Assignée pourront être passées au statut Résolue. Le statut de toutes les autres demandes de type Bug ne pourra pas être modifié par le Développeur.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s07.html b/redmine/public/manual/fr/ch01s07.html deleted file mode 100644 index 4b8be47d3..000000000 --- a/redmine/public/manual/fr/ch01s07.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 7. Listes de valeurs

    7. Listes de valeurs

    Les listes de valeurs utilisées par l'application (exemple: les priorités des demandes) peuvent être personnalisées. Cet écran vous permet de définir les valeurs possibles pour chacune des listes suivantes:

    • Priorités des demandes

    • Catégories de documents

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s08.html b/redmine/public/manual/fr/ch01s08.html deleted file mode 100644 index db3133c68..000000000 --- a/redmine/public/manual/fr/ch01s08.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 8. Notifications par mail

    8. Notifications par mail

    Cet écran vous permet de sélectionner les actions qui donneront lieu à une notification par mail aux membres du projet.

    Remarque: l'envoi de mails doit être activé dans la configuration de l'application si souhaitez effectuer des notifications.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s09.html b/redmine/public/manual/fr/ch01s09.html deleted file mode 100644 index 7fb82b2a1..000000000 --- a/redmine/public/manual/fr/ch01s09.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 9. Authentification

    9. Authentification

    Par défaut, redMine s'appuie sur sa propre base de données pour authentifier les utilisateurs, à l'aide d'un mot de passe spécifique.

    Si vous disposez déjà d'un ou plusieurs référentiels externes d'utilisateurs (annuaires LDAP), vous pouvez les déclarer afin qu'ils soient utilisés pour l'authentification sur redMine. Cela permet aux utilisateurs d'accéder à redMine avec leurs identifiants et mots de passe habituels.

    Pour chaque référentiel déclaré, vous pouvez spécifier si les comptes peuvent être créés à la volée dans redMine. Si c'est le cas, les comptes utilisateurs sont automatiquement créés à la première connexion de l'utilisateur (sans droits spécifiques sur les projets), à partir des informations disponibles dans le référentiel. Sinon, l'administrateur doit au préalable créer le compte de l'utilisateur dans redMine.

    9.1. Déclaration d'un annuaire LDAP

    • Nom: nom d'affichage du référentiel

    • Hôte: nom d'hôte du serveur LDAP

    • Port: port de connexion au serveur LDAP

    • Compte: DN du compte de connexion au LDAP (laisser vide si l'annuaire autorise l'accès anonyme en lecture)

    • Mot de passe: mot de passe du compte de connexion

    • Base DN: DN de base utilisé pour la recherche des utilisateur dans l'annuaire

    • Filtre LDAP: Filtre de recherche des utilisateurs dans l'annuaire (optionnel)

    • Attributs LDAP:

      • Identifiant: nom de l'attribut LDAP utilisé comme identifiant de l'utilisateur (ex: uid)

      • Prénom: nom de l'attribut LDAP contenant le prénom de l'utilisateur (ex: givenName)

      • Nom: nom de l'attribut LDAP contenant le nom de l'utilisateur (ex: sn)

      • Email: nom de l'attribut LDAP contenant l'adresse mail de l'utilisateur (ex: mail)

    Les attributs "Prénom", "Nom" et "Email" ne sont utilisés que lorsque les comptes sont créés à la volée.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch01s10.html b/redmine/public/manual/fr/ch01s10.html deleted file mode 100644 index ab1cd4540..000000000 --- a/redmine/public/manual/fr/ch01s10.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 10. Informations

    10. Informations

    Affiche des informations relatives à l'application et à son environnement.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02.html b/redmine/public/manual/fr/ch02.html deleted file mode 100644 index 1fbca1b09..000000000 --- a/redmine/public/manual/fr/ch02.html +++ /dev/null @@ -1,3 +0,0 @@ - - - Chapter 2. Projets \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02s01.html b/redmine/public/manual/fr/ch02s01.html deleted file mode 100644 index 8509f6dea..000000000 --- a/redmine/public/manual/fr/ch02s01.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 1. Aperçu du projet

    1. Aperçu du projet

    L'aperçu vous présente les informations générales relatives au projet, les principaux membres, les dernières annonces, ainsi qu'une synthèse du nombre de demandes ouvertes par tracker.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02s02.html b/redmine/public/manual/fr/ch02s02.html deleted file mode 100644 index ba79d555f..000000000 --- a/redmine/public/manual/fr/ch02s02.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 2. Gestion des demandes

    2. Gestion des demandes

    2.1. Liste des demandes

    Par défaut, l'ensemble des demandes ouvertes du projet sont affichées. Différents filtres vous permettent de sélectionner les demandes à afficher. Si le projet comporte des sous-projets, vous avez la possibilité d'afficher également les demandes relatives aux sous-projets (non affichées par défaut).

    Une fois appliqué, un filtre reste valable durant toute votre session. Vous pouvez le redéfinir, ou le supprimer en cliquant sur Annuler.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02s03.html b/redmine/public/manual/fr/ch02s03.html deleted file mode 100644 index 1e3aa8906..000000000 --- a/redmine/public/manual/fr/ch02s03.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 3. Rapports

    3. Rapports

    Cet écran présente la synthèse du nombre de demandes par statut et selon différents critères (tracker, priorité, catégorie). Des liens directs permettent d'accéder à la liste détaillée des demandes pour chaque critère.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02s04.html b/redmine/public/manual/fr/ch02s04.html deleted file mode 100644 index d75c67318..000000000 --- a/redmine/public/manual/fr/ch02s04.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 4. Historique

    4. Historique

    Cette page présente l'ensemble des demandes résolues dans chacune des versions du projet. Certains types de demande peuvent être exclus de cet affichage.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02s05.html b/redmine/public/manual/fr/ch02s05.html deleted file mode 100644 index b3b39eacf..000000000 --- a/redmine/public/manual/fr/ch02s05.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 5. Annonces

    5. Annonces

    Les nouvelles vous permettent d'informer les utilisateurs sur l'activité du projet.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02s06.html b/redmine/public/manual/fr/ch02s06.html deleted file mode 100644 index 9a78b9f31..000000000 --- a/redmine/public/manual/fr/ch02s06.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 6. Documents

    6. Documents

    Les documents sont groupés par catégories (voir Listes de valeurs). Un document peut contenir plusieurs fichiers (exemple: révisions ou versions successives).

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02s07.html b/redmine/public/manual/fr/ch02s07.html deleted file mode 100644 index 38f0a0400..000000000 --- a/redmine/public/manual/fr/ch02s07.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 7. Fichiers

    7. Fichiers

    Ce module vous permet de publier les différents fichiers (sources, binaires, ...) pour chaque version de l'application.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/ch02s08.html b/redmine/public/manual/fr/ch02s08.html deleted file mode 100644 index 67d12305a..000000000 --- a/redmine/public/manual/fr/ch02s08.html +++ /dev/null @@ -1,3 +0,0 @@ - - - 8. Configuration du projet

    8. Configuration du projet

    8.1. Propriétés du projet

    • Public: 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ès, en fonction de leur rôle.

    • Champs personnalisés: sélectionner les champs personnalisés que vous souhaitez utiliser pour les demandes du projet. Seul l'administrateur peut définir de nouveaux champs personnalisés.

    8.2. Membres

    Cet écran vous permet de définir les membres du projet ainsi que leurs rôles respectifs. Un utilisateur ne peut avoir qu'un rôle au sein d'un projet donné. Le rôle d'un membre détermine les permissions dont il bénéficie sur le projet.

    8.3. Versions

    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érentes versions de l'application (voir Fichiers).

    8.4. Catégories des demandes

    Les catégories de demande vous permettent de typer les demandes. Les catégories peuvent par exemple correspondre aux différents modules du projet.

    \ No newline at end of file diff --git a/redmine/public/manual/fr/html.css b/redmine/public/manual/fr/html.css deleted file mode 100644 index c1b2a6fca..000000000 --- a/redmine/public/manual/fr/html.css +++ /dev/null @@ -1,55 +0,0 @@ -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/redmine/public/manual/fr/index.html b/redmine/public/manual/fr/index.html deleted file mode 100644 index 8d69ced1a..000000000 --- a/redmine/public/manual/fr/index.html +++ /dev/null @@ -1,3 +0,0 @@ - - - Documentation redMine \ No newline at end of file diff --git a/redmine/public/manual/fr/resources/issues_list.png b/redmine/public/manual/fr/resources/issues_list.png deleted file mode 100644 index 47eab0fca..000000000 Binary files a/redmine/public/manual/fr/resources/issues_list.png and /dev/null differ diff --git a/redmine/public/manual/fr/resources/users_list.png b/redmine/public/manual/fr/resources/users_list.png deleted file mode 100644 index 0c9ef86ec..000000000 Binary files a/redmine/public/manual/fr/resources/users_list.png and /dev/null differ diff --git a/redmine/public/manual/fr/resources/workflow.png b/redmine/public/manual/fr/resources/workflow.png deleted file mode 100644 index 04e79d61e..000000000 Binary files a/redmine/public/manual/fr/resources/workflow.png and /dev/null differ diff --git a/redmine/public/robots.txt b/redmine/public/robots.txt deleted file mode 100644 index 4ab9e89fe..000000000 --- a/redmine/public/robots.txt +++ /dev/null @@ -1 +0,0 @@ -# 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/redmine/public/stylesheets/application.css b/redmine/public/stylesheets/application.css deleted file mode 100644 index 13c1f6e34..000000000 --- a/redmine/public/stylesheets/application.css +++ /dev/null @@ -1,484 +0,0 @@ -/* 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/redmine/public/stylesheets/calendar.css b/redmine/public/stylesheets/calendar.css deleted file mode 100644 index f460d5cb0..000000000 --- a/redmine/public/stylesheets/calendar.css +++ /dev/null @@ -1,231 +0,0 @@ -/* 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 containing navigation buttons */ - background: #467aa7; - color: #fff; -} - -.calendar thead .daynames { /* Row containing the day names */ - background: #bdf; -} - -.calendar thead .name { /* Cells 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 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 */ - background: #80b0da; - padding: 1px 3px 1px 1px; - border: 1px solid #bbb; -} - -.calendar tbody td.active { /* Active (pressed) cells */ - 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 in footer (only one right now) */ - text-align: center; - background: #556; - color: #fff; -} - -.calendar tfoot .ttip { /* Tooltip (status bar) cell */ - 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/redmine/public/stylesheets/jstoolbar.css b/redmine/public/stylesheets/jstoolbar.css deleted file mode 100644 index efdf3d264..000000000 --- a/redmine/public/stylesheets/jstoolbar.css +++ /dev/null @@ -1,79 +0,0 @@ -.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/redmine/public/stylesheets/menu.css b/redmine/public/stylesheets/menu.css deleted file mode 100644 index b7084c2e7..000000000 --- a/redmine/public/stylesheets/menu.css +++ /dev/null @@ -1,39 +0,0 @@ -/*========== 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/redmine/public/stylesheets/rails.css b/redmine/public/stylesheets/rails.css deleted file mode 100644 index 3f7b6ca41..000000000 --- a/redmine/public/stylesheets/rails.css +++ /dev/null @@ -1,57 +0,0 @@ - -.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%; -} diff --git a/redmine/script/about b/redmine/script/about deleted file mode 100644 index 7b07d46a3..000000000 --- a/redmine/script/about +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/about' \ No newline at end of file diff --git a/redmine/script/breakpointer b/redmine/script/breakpointer deleted file mode 100644 index 64af76edd..000000000 --- a/redmine/script/breakpointer +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/breakpointer' \ No newline at end of file diff --git a/redmine/script/console b/redmine/script/console deleted file mode 100644 index 42f28f7d6..000000000 --- a/redmine/script/console +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/console' \ No newline at end of file diff --git a/redmine/script/destroy b/redmine/script/destroy deleted file mode 100644 index fa0e6fcd0..000000000 --- a/redmine/script/destroy +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/destroy' \ No newline at end of file diff --git a/redmine/script/generate b/redmine/script/generate deleted file mode 100644 index ef976e09f..000000000 --- a/redmine/script/generate +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/generate' \ No newline at end of file diff --git a/redmine/script/performance/benchmarker b/redmine/script/performance/benchmarker deleted file mode 100644 index c842d35d3..000000000 --- a/redmine/script/performance/benchmarker +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/performance/benchmarker' diff --git a/redmine/script/performance/profiler b/redmine/script/performance/profiler deleted file mode 100644 index d855ac8b1..000000000 --- a/redmine/script/performance/profiler +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/performance/profiler' diff --git a/redmine/script/plugin b/redmine/script/plugin deleted file mode 100644 index 26ca64c06..000000000 --- a/redmine/script/plugin +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/plugin' \ No newline at end of file diff --git a/redmine/script/process/reaper b/redmine/script/process/reaper deleted file mode 100644 index c77f04535..000000000 --- a/redmine/script/process/reaper +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/reaper' diff --git a/redmine/script/process/spawner b/redmine/script/process/spawner deleted file mode 100644 index 7118f3983..000000000 --- a/redmine/script/process/spawner +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/spawner' diff --git a/redmine/script/process/spinner b/redmine/script/process/spinner deleted file mode 100644 index 6816b32ef..000000000 --- a/redmine/script/process/spinner +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/spinner' diff --git a/redmine/script/runner b/redmine/script/runner deleted file mode 100644 index ccc30f9d2..000000000 --- a/redmine/script/runner +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/runner' \ No newline at end of file diff --git a/redmine/script/server b/redmine/script/server deleted file mode 100644 index dfabcb881..000000000 --- a/redmine/script/server +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/server' \ No newline at end of file diff --git a/redmine/test/fixtures/attachments.yml b/redmine/test/fixtures/attachments.yml deleted file mode 100644 index 6c352e1e3..000000000 --- a/redmine/test/fixtures/attachments.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -attachments_001: - created_on: 2006-07-19 21:07:27 +02:00 - downloads: 0 - content_type: text/plain - disk_filename: 060719210727_error281.txt - container_id: 3 - digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 - id: 1 - container_type: Issue - filesize: 28 - filename: error281.txt - author_id: 2 diff --git a/redmine/test/fixtures/auth_sources.yml b/redmine/test/fixtures/auth_sources.yml deleted file mode 100644 index 086c00f62..000000000 --- a/redmine/test/fixtures/auth_sources.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- {} - diff --git a/redmine/test/fixtures/custom_fields.yml b/redmine/test/fixtures/custom_fields.yml deleted file mode 100644 index fcf52c17a..000000000 --- a/redmine/test/fixtures/custom_fields.yml +++ /dev/null @@ -1,45 +0,0 @@ ---- -custom_fields_001: - name: Database - min_length: 0 - regexp: "" - is_for_all: false - type: IssueCustomField - max_length: 0 - possible_values: MySQL|PostgreSQL|Oracle - id: 1 - is_required: false - field_format: list -custom_fields_002: - name: Build - min_length: 1 - regexp: "" - is_for_all: true - type: IssueCustomField - max_length: 10 - possible_values: "" - id: 2 - is_required: false - field_format: string -custom_fields_003: - name: Development status - min_length: 0 - regexp: "" - is_for_all: false - type: ProjectCustomField - max_length: 0 - possible_values: Stable|Beta|Alpha|Planning - id: 3 - is_required: true - field_format: list -custom_fields_004: - name: Phone number - min_length: 0 - regexp: "" - is_for_all: false - type: UserCustomField - max_length: 0 - possible_values: "" - id: 4 - is_required: false - field_format: string diff --git a/redmine/test/fixtures/custom_fields_projects.yml b/redmine/test/fixtures/custom_fields_projects.yml deleted file mode 100644 index 086c00f62..000000000 --- a/redmine/test/fixtures/custom_fields_projects.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- {} - diff --git a/redmine/test/fixtures/custom_fields_trackers.yml b/redmine/test/fixtures/custom_fields_trackers.yml deleted file mode 100644 index cb06d2fcf..000000000 --- a/redmine/test/fixtures/custom_fields_trackers.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -custom_fields_trackers_001: - custom_field_id: 1 - tracker_id: 1 -custom_fields_trackers_002: - custom_field_id: 2 - tracker_id: 1 -custom_fields_trackers_003: - custom_field_id: 2 - tracker_id: 3 diff --git a/redmine/test/fixtures/custom_values.yml b/redmine/test/fixtures/custom_values.yml deleted file mode 100644 index 4a65619c4..000000000 --- a/redmine/test/fixtures/custom_values.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- -custom_values_006: - customized_type: Issue - custom_field_id: 2 - customized_id: 3 - id: 9 - value: "125" -custom_values_007: - customized_type: Project - custom_field_id: 3 - customized_id: 1 - id: 10 - value: Stable -custom_values_001: - customized_type: User - custom_field_id: 4 - customized_id: 3 - id: 2 - value: "" -custom_values_002: - customized_type: User - custom_field_id: 4 - customized_id: 4 - id: 3 - value: 01 23 45 67 89 -custom_values_003: - customized_type: User - custom_field_id: 4 - customized_id: 2 - id: 4 - value: "" -custom_values_004: - customized_type: Issue - custom_field_id: 2 - customized_id: 1 - id: 7 - value: "101" -custom_values_005: - customized_type: Issue - custom_field_id: 2 - customized_id: 2 - id: 8 - value: "" diff --git a/redmine/test/fixtures/documents.yml b/redmine/test/fixtures/documents.yml deleted file mode 100644 index 086c00f62..000000000 --- a/redmine/test/fixtures/documents.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- {} - diff --git a/redmine/test/fixtures/enumerations.yml b/redmine/test/fixtures/enumerations.yml deleted file mode 100644 index eeef99b5b..000000000 --- a/redmine/test/fixtures/enumerations.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -enumerations_001: - name: Uncategorized - id: 1 - opt: DCAT -enumerations_002: - name: User documentation - id: 2 - opt: DCAT -enumerations_003: - name: Technical documentation - id: 3 - opt: DCAT -enumerations_004: - name: Low - id: 4 - opt: IPRI -enumerations_005: - name: Normal - id: 5 - opt: IPRI -enumerations_006: - name: High - id: 6 - opt: IPRI -enumerations_007: - name: Urgent - id: 7 - opt: IPRI -enumerations_008: - name: Immediate - id: 8 - opt: IPRI diff --git a/redmine/test/fixtures/issue_categories.yml b/redmine/test/fixtures/issue_categories.yml deleted file mode 100644 index a994560d4..000000000 --- a/redmine/test/fixtures/issue_categories.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -issue_categories_001: - name: Printing - project_id: 1 - id: 1 -issue_categories_002: - name: Recipes - project_id: 1 - id: 2 diff --git a/redmine/test/fixtures/issue_statuses.yml b/redmine/test/fixtures/issue_statuses.yml deleted file mode 100644 index b5a509f39..000000000 --- a/redmine/test/fixtures/issue_statuses.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -issue_statuses_006: - name: Rejected - is_default: false - html_color: F5C28B - is_closed: true - id: 6 -issue_statuses_001: - name: New - is_default: true - html_color: F98787 - is_closed: false - id: 1 -issue_statuses_002: - name: Assigned - is_default: false - html_color: C0C0FF - is_closed: false - id: 2 -issue_statuses_003: - name: Resolved - is_default: false - html_color: 88E0B3 - is_closed: false - id: 3 -issue_statuses_004: - name: Feedback - is_default: false - html_color: F3A4F4 - is_closed: false - id: 4 -issue_statuses_005: - name: Closed - is_default: false - html_color: DBDBDB - is_closed: true - id: 5 diff --git a/redmine/test/fixtures/issues.yml b/redmine/test/fixtures/issues.yml deleted file mode 100644 index 5719a9bc9..000000000 --- a/redmine/test/fixtures/issues.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- -issues_001: - created_on: 2006-07-19 21:02:17 +02:00 - project_id: 1 - updated_on: 2006-07-19 21:04:30 +02:00 - priority_id: 4 - subject: Can't print recipes - id: 1 - fixed_version_id: - category_id: 1 - description: Unable to print recipes - tracker_id: 1 - assigned_to_id: - author_id: 2 - status_id: 1 -issues_002: - created_on: 2006-07-19 21:04:21 +02:00 - project_id: 1 - updated_on: 2006-07-19 21:09:50 +02:00 - priority_id: 5 - subject: Add ingredients categories - id: 2 - fixed_version_id: - category_id: - description: Ingredients should be classified by categories - tracker_id: 2 - assigned_to_id: 3 - author_id: 2 - status_id: 2 -issues_003: - created_on: 2006-07-19 21:07:27 +02:00 - project_id: 1 - updated_on: 2006-07-19 21:07:27 +02:00 - priority_id: 4 - subject: Error 281 when updating a recipe - id: 3 - fixed_version_id: - category_id: - description: Error 281 is encountered when saving a recipe - tracker_id: 1 - assigned_to_id: - author_id: 2 - status_id: 1 diff --git a/redmine/test/fixtures/members.yml b/redmine/test/fixtures/members.yml deleted file mode 100644 index 0626bdb18..000000000 --- a/redmine/test/fixtures/members.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -members_001: - created_on: 2006-07-19 19:35:33 +02:00 - project_id: 1 - role_id: 1 - id: 1 - user_id: 2 -members_002: - created_on: 2006-07-19 19:35:36 +02:00 - project_id: 1 - role_id: 2 - id: 2 - user_id: 3 diff --git a/redmine/test/fixtures/news.yml b/redmine/test/fixtures/news.yml deleted file mode 100644 index 1bef9184e..000000000 --- a/redmine/test/fixtures/news.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -news_001: - created_on: 2006-07-19 22:40:26 +02:00 - project_id: 1 - title: eCookbook first release ! - id: 1 - description: |- - eCookbook 1.0 has been released. - - Visit http://ecookbook.somenet.foo/ - summary: First version was released... - author_id: 2 -news_002: - created_on: 2006-07-19 22:42:58 +02:00 - project_id: 1 - title: 100,000 downloads for eCookbook - id: 2 - description: eCookbook 1.0 have downloaded 100,000 times - summary: eCookbook 1.0 have downloaded 100,000 times - author_id: 2 diff --git a/redmine/test/fixtures/permissions.yml b/redmine/test/fixtures/permissions.yml deleted file mode 100644 index 81350e1af..000000000 --- a/redmine/test/fixtures/permissions.yml +++ /dev/null @@ -1,379 +0,0 @@ ---- -permissions_041: - action: add_file - id: 41 - description: button_add - controller: projects - mail_enabled: false - mail_option: false - sort: 1320 - is_public: false -permissions_030: - action: destroy - id: 30 - description: button_delete - controller: news - mail_enabled: false - mail_option: false - sort: 1122 - is_public: false -permissions_019: - action: download - id: 19 - description: button_download - controller: issues - mail_enabled: false - mail_option: false - sort: 1010 - is_public: true -permissions_008: - action: edit - id: 8 - description: button_edit - controller: members - mail_enabled: false - mail_option: false - sort: 221 - is_public: false -permissions_042: - action: destroy_file - id: 42 - description: button_delete - controller: versions - mail_enabled: false - mail_option: false - sort: 1322 - is_public: false -permissions_031: - action: list_documents - id: 31 - description: button_list - controller: projects - mail_enabled: false - mail_option: false - sort: 1200 - is_public: true -permissions_020: - action: add_issue - id: 20 - description: button_add - controller: projects - mail_enabled: true - mail_option: true - sort: 1050 - is_public: false -permissions_009: - action: destroy - id: 9 - description: button_delete - controller: members - mail_enabled: false - mail_option: false - sort: 222 - is_public: false -permissions_032: - action: show - id: 32 - description: button_view - controller: documents - mail_enabled: false - mail_option: false - sort: 1201 - is_public: true -permissions_021: - action: edit - id: 21 - description: button_edit - controller: issues - mail_enabled: false - mail_option: false - sort: 1055 - is_public: false -permissions_010: - action: add_version - id: 10 - description: button_add - controller: projects - mail_enabled: false - mail_option: false - sort: 320 - is_public: false -permissions_033: - action: download - id: 33 - description: button_download - controller: documents - mail_enabled: false - mail_option: false - sort: 1202 - is_public: true -permissions_022: - action: change_status - id: 22 - description: label_change_status - controller: issues - mail_enabled: true - mail_option: true - sort: 1060 - is_public: false -permissions_011: - action: edit - id: 11 - description: button_edit - controller: versions - mail_enabled: false - mail_option: false - sort: 321 - is_public: false -permissions_034: - action: add_document - id: 34 - description: button_add - controller: projects - mail_enabled: false - mail_option: false - sort: 1220 - is_public: false -permissions_023: - action: destroy - id: 23 - description: button_delete - controller: issues - mail_enabled: false - mail_option: false - sort: 1065 - is_public: false -permissions_012: - action: destroy - id: 12 - description: button_delete - controller: versions - mail_enabled: false - mail_option: false - sort: 322 - is_public: false -permissions_001: - action: show - id: 1 - description: label_overview - controller: projects - mail_enabled: false - mail_option: false - sort: 100 - is_public: true -permissions_035: - action: edit - id: 35 - description: button_edit - controller: documents - mail_enabled: false - mail_option: false - sort: 1221 - is_public: false -permissions_024: - action: add_attachment - id: 24 - description: label_attachment_new - controller: issues - mail_enabled: false - mail_option: false - sort: 1070 - is_public: false -permissions_013: - action: add_issue_category - id: 13 - description: button_add - controller: projects - mail_enabled: false - mail_option: false - sort: 420 - is_public: false -permissions_002: - action: changelog - id: 2 - description: label_change_log - controller: projects - mail_enabled: false - mail_option: false - sort: 105 - is_public: true -permissions_036: - action: destroy - id: 36 - description: button_delete - controller: documents - mail_enabled: false - mail_option: false - sort: 1222 - is_public: false -permissions_025: - action: destroy_attachment - id: 25 - description: label_attachment_delete - controller: issues - mail_enabled: false - mail_option: false - sort: 1075 - is_public: false -permissions_014: - action: edit - id: 14 - description: button_edit - controller: issue_categories - mail_enabled: false - mail_option: false - sort: 421 - is_public: false -permissions_003: - action: issue_report - id: 3 - description: label_report_plural - controller: reports - mail_enabled: false - mail_option: false - sort: 110 - is_public: true -permissions_037: - action: add_attachment - id: 37 - description: label_attachment_new - controller: documents - mail_enabled: false - mail_option: false - sort: 1223 - is_public: false -permissions_026: - action: list_news - id: 26 - description: button_list - controller: projects - mail_enabled: false - mail_option: false - sort: 1100 - is_public: true -permissions_015: - action: destroy - id: 15 - description: button_delete - controller: issue_categories - mail_enabled: false - mail_option: false - sort: 422 - is_public: false -permissions_004: - action: settings - id: 4 - description: label_settings - controller: projects - mail_enabled: false - mail_option: false - sort: 150 - is_public: false -permissions_038: - action: destroy_attachment - id: 38 - description: label_attachment_delete - controller: documents - mail_enabled: false - mail_option: false - sort: 1224 - is_public: false -permissions_027: - action: show - id: 27 - description: button_view - controller: news - mail_enabled: false - mail_option: false - sort: 1101 - is_public: true -permissions_016: - action: list_issues - id: 16 - description: button_list - controller: projects - mail_enabled: false - mail_option: false - sort: 1000 - is_public: true -permissions_005: - action: edit - id: 5 - description: button_edit - controller: projects - mail_enabled: false - mail_option: false - sort: 151 - is_public: false -permissions_039: - action: list_files - id: 39 - description: button_list - controller: projects - mail_enabled: false - mail_option: false - sort: 1300 - is_public: true -permissions_028: - action: add_news - id: 28 - description: button_add - controller: projects - mail_enabled: false - mail_option: false - sort: 1120 - is_public: false -permissions_017: - action: export_issues_csv - id: 17 - description: label_export_csv - controller: projects - mail_enabled: false - mail_option: false - sort: 1001 - is_public: true -permissions_006: - action: list_members - id: 6 - description: button_list - controller: projects - mail_enabled: false - mail_option: false - sort: 200 - is_public: true -permissions_040: - action: download - id: 40 - description: button_download - controller: versions - mail_enabled: false - mail_option: false - sort: 1301 - is_public: true -permissions_029: - action: edit - id: 29 - description: button_edit - controller: news - mail_enabled: false - mail_option: false - sort: 1121 - is_public: false -permissions_018: - action: show - id: 18 - description: button_view - controller: issues - mail_enabled: false - mail_option: false - sort: 1005 - is_public: true -permissions_007: - action: add_member - id: 7 - description: button_add - controller: projects - mail_enabled: false - mail_option: false - sort: 220 - is_public: false diff --git a/redmine/test/fixtures/permissions_roles.yml b/redmine/test/fixtures/permissions_roles.yml deleted file mode 100644 index d4a054ecc..000000000 --- a/redmine/test/fixtures/permissions_roles.yml +++ /dev/null @@ -1,379 +0,0 @@ ---- -permissions_roles_075: - role_id: 3 - permission_id: 34 -permissions_roles_047: - role_id: 1 - permission_id: 15 -permissions_roles_102: - role_id: 2 - permission_id: 4 -permissions_roles_019: - role_id: 3 - permission_id: 30 -permissions_roles_048: - role_id: 2 - permission_id: 24 -permissions_roles_103: - role_id: 2 - permission_id: 27 -permissions_roles_076: - role_id: 2 - permission_id: 41 -permissions_roles_049: - role_id: 1 - permission_id: 3 -permissions_roles_104: - role_id: 2 - permission_id: 36 -permissions_roles_077: - role_id: 2 - permission_id: 7 -permissions_roles_105: - role_id: 2 - permission_id: 32 -permissions_roles_078: - role_id: 3 - permission_id: 38 -permissions_roles_106: - role_id: 2 - permission_id: 14 -permissions_roles_020: - role_id: 2 - permission_id: 9 -permissions_roles_079: - role_id: 2 - permission_id: 18 -permissions_roles_107: - role_id: 3 - permission_id: 40 -permissions_roles_021: - role_id: 1 - permission_id: 13 -permissions_roles_108: - role_id: 1 - permission_id: 29 -permissions_roles_050: - role_id: 2 - permission_id: 29 -permissions_roles_022: - role_id: 3 - permission_id: 4 -permissions_roles_109: - role_id: 3 - permission_id: 22 -permissions_roles_051: - role_id: 3 - permission_id: 37 -permissions_roles_023: - role_id: 1 - permission_id: 23 -permissions_roles_052: - role_id: 2 - permission_id: 33 -permissions_roles_024: - role_id: 1 - permission_id: 1 -permissions_roles_080: - role_id: 2 - permission_id: 13 -permissions_roles_053: - role_id: 2 - permission_id: 1 -permissions_roles_025: - role_id: 2 - permission_id: 10 -permissions_roles_081: - role_id: 3 - permission_id: 20 -permissions_roles_054: - role_id: 2 - permission_id: 12 -permissions_roles_026: - role_id: 1 - permission_id: 36 -permissions_roles_082: - role_id: 1 - permission_id: 39 -permissions_roles_110: - role_id: 3 - permission_id: 6 -permissions_roles_027: - role_id: 3 - permission_id: 31 -permissions_roles_083: - role_id: 1 - permission_id: 33 -permissions_roles_055: - role_id: 1 - permission_id: 38 -permissions_roles_111: - role_id: 3 - permission_id: 1 -permissions_roles_028: - role_id: 1 - permission_id: 24 -permissions_roles_084: - role_id: 3 - permission_id: 16 -permissions_roles_056: - role_id: 2 - permission_id: 5 -permissions_roles_029: - role_id: 1 - permission_id: 9 -permissions_roles_085: - role_id: 3 - permission_id: 27 -permissions_roles_057: - role_id: 1 - permission_id: 16 -permissions_roles_112: - role_id: 1 - permission_id: 20 -permissions_roles_086: - role_id: 3 - permission_id: 12 -permissions_roles_058: - role_id: 1 - permission_id: 26 -permissions_roles_113: - role_id: 2 - permission_id: 37 -permissions_roles_087: - role_id: 1 - permission_id: 5 -permissions_roles_059: - role_id: 3 - permission_id: 18 -permissions_roles_114: - role_id: 2 - permission_id: 20 -permissions_roles_115: - role_id: 2 - permission_id: 15 -permissions_roles_088: - role_id: 2 - permission_id: 3 -permissions_roles_001: - role_id: 2 - permission_id: 21 -permissions_roles_116: - role_id: 3 - permission_id: 23 -permissions_roles_030: - role_id: 1 - permission_id: 30 -permissions_roles_089: - role_id: 1 - permission_id: 28 -permissions_roles_002: - role_id: 3 - permission_id: 29 -permissions_roles_117: - role_id: 3 - permission_id: 28 -permissions_roles_031: - role_id: 2 - permission_id: 38 -permissions_roles_003: - role_id: 3 - permission_id: 41 -permissions_roles_118: - role_id: 1 - permission_id: 34 -permissions_roles_032: - role_id: 3 - permission_id: 9 -permissions_roles_004: - role_id: 2 - permission_id: 8 -permissions_roles_060: - role_id: 2 - permission_id: 2 -permissions_roles_119: - role_id: 1 - permission_id: 21 -permissions_roles_033: - role_id: 2 - permission_id: 28 -permissions_roles_005: - role_id: 3 - permission_id: 3 -permissions_roles_061: - role_id: 2 - permission_id: 40 -permissions_roles_006: - role_id: 3 - permission_id: 14 -permissions_roles_090: - role_id: 2 - permission_id: 26 -permissions_roles_062: - role_id: 1 - permission_id: 19 -permissions_roles_034: - role_id: 2 - permission_id: 11 -permissions_roles_007: - role_id: 1 - permission_id: 35 -permissions_roles_091: - role_id: 3 - permission_id: 35 -permissions_roles_063: - role_id: 2 - permission_id: 30 -permissions_roles_035: - role_id: 2 - permission_id: 23 -permissions_roles_008: - role_id: 2 - permission_id: 17 -permissions_roles_092: - role_id: 2 - permission_id: 31 -permissions_roles_064: - role_id: 3 - permission_id: 33 -permissions_roles_036: - role_id: 3 - permission_id: 5 -permissions_roles_120: - role_id: 3 - permission_id: 13 -permissions_roles_009: - role_id: 1 - permission_id: 12 -permissions_roles_093: - role_id: 2 - permission_id: 42 -permissions_roles_065: - role_id: 3 - permission_id: 26 -permissions_roles_037: - role_id: 1 - permission_id: 42 -permissions_roles_121: - role_id: 3 - permission_id: 2 -permissions_roles_094: - role_id: 3 - permission_id: 39 -permissions_roles_066: - role_id: 2 - permission_id: 6 -permissions_roles_038: - role_id: 1 - permission_id: 25 -permissions_roles_122: - role_id: 1 - permission_id: 7 -permissions_roles_095: - role_id: 2 - permission_id: 19 -permissions_roles_067: - role_id: 1 - permission_id: 17 -permissions_roles_039: - role_id: 3 - permission_id: 36 -permissions_roles_123: - role_id: 3 - permission_id: 24 -permissions_roles_096: - role_id: 1 - permission_id: 18 -permissions_roles_068: - role_id: 1 - permission_id: 32 -permissions_roles_124: - role_id: 1 - permission_id: 11 -permissions_roles_010: - role_id: 1 - permission_id: 8 -permissions_roles_069: - role_id: 3 - permission_id: 19 -permissions_roles_097: - role_id: 2 - permission_id: 35 -permissions_roles_125: - role_id: 2 - permission_id: 16 -permissions_roles_011: - role_id: 3 - permission_id: 42 -permissions_roles_098: - role_id: 1 - permission_id: 6 -permissions_roles_126: - role_id: 3 - permission_id: 7 -permissions_roles_012: - role_id: 3 - permission_id: 8 -permissions_roles_040: - role_id: 1 - permission_id: 2 -permissions_roles_099: - role_id: 3 - permission_id: 17 -permissions_roles_041: - role_id: 2 - permission_id: 39 -permissions_roles_013: - role_id: 1 - permission_id: 40 -permissions_roles_070: - role_id: 3 - permission_id: 11 -permissions_roles_042: - role_id: 1 - permission_id: 37 -permissions_roles_014: - role_id: 1 - permission_id: 22 -permissions_roles_071: - role_id: 1 - permission_id: 4 -permissions_roles_043: - role_id: 3 - permission_id: 32 -permissions_roles_015: - role_id: 2 - permission_id: 22 -permissions_roles_072: - role_id: 1 - permission_id: 27 -permissions_roles_044: - role_id: 1 - permission_id: 14 -permissions_roles_016: - role_id: 3 - permission_id: 15 -permissions_roles_073: - role_id: 2 - permission_id: 34 -permissions_roles_045: - role_id: 3 - permission_id: 10 -permissions_roles_100: - role_id: 1 - permission_id: 10 -permissions_roles_017: - role_id: 3 - permission_id: 25 -permissions_roles_074: - role_id: 2 - permission_id: 25 -permissions_roles_046: - role_id: 1 - permission_id: 31 -permissions_roles_101: - role_id: 3 - permission_id: 21 -permissions_roles_018: - role_id: 1 - permission_id: 41 diff --git a/redmine/test/fixtures/projects.yml b/redmine/test/fixtures/projects.yml deleted file mode 100644 index 9aa2f9abe..000000000 --- a/redmine/test/fixtures/projects.yml +++ /dev/null @@ -1,41 +0,0 @@ ---- -projects_001: - created_on: 2006-07-19 19:13:59 +02:00 - name: eCookbook - updated_on: 2006-07-19 22:53:01 +02:00 - projects_count: 2 - id: 1 - description: Recipes management application - homepage: http://ecookbook.somenet.foo/ - is_public: true - parent_id: -projects_002: - created_on: 2006-07-19 19:14:19 +02:00 - name: OnlineStore - updated_on: 2006-07-19 19:14:19 +02:00 - projects_count: 0 - id: 2 - description: E-commerce web site - homepage: "" - is_public: false - parent_id: -projects_003: - created_on: 2006-07-19 19:15:21 +02:00 - name: eCookbook Subproject 1 - updated_on: 2006-07-19 19:18:12 +02:00 - projects_count: 0 - id: 3 - description: eCookBook Subproject 1 - homepage: "" - is_public: true - parent_id: 1 -projects_004: - created_on: 2006-07-19 19:15:51 +02:00 - name: eCookbook Subproject 2 - updated_on: 2006-07-19 19:17:07 +02:00 - projects_count: 0 - id: 4 - description: eCookbook Subproject 2 - homepage: "" - is_public: true - parent_id: 1 diff --git a/redmine/test/fixtures/roles.yml b/redmine/test/fixtures/roles.yml deleted file mode 100644 index 4fc9881b4..000000000 --- a/redmine/test/fixtures/roles.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -roles_001: - name: Manager - id: 1 -roles_002: - name: Developer - id: 2 -roles_003: - name: Reporter - id: 3 diff --git a/redmine/test/fixtures/tokens.yml b/redmine/test/fixtures/tokens.yml deleted file mode 100644 index 977bafe6e..000000000 --- a/redmine/test/fixtures/tokens.yml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/redmine/test/fixtures/trackers.yml b/redmine/test/fixtures/trackers.yml deleted file mode 100644 index d4ea34ac8..000000000 --- a/redmine/test/fixtures/trackers.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -trackers_001: - name: Bug - id: 1 - is_in_chlog: true -trackers_002: - name: Feature request - id: 2 - is_in_chlog: true -trackers_003: - name: Support request - id: 3 - is_in_chlog: false diff --git a/redmine/test/fixtures/user_preferences.yml b/redmine/test/fixtures/user_preferences.yml deleted file mode 100644 index 8794d28ae..000000000 --- a/redmine/test/fixtures/user_preferences.yml +++ /dev/null @@ -1,5 +0,0 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html -first: - id: 1 -another: - id: 2 diff --git a/redmine/test/fixtures/users.yml b/redmine/test/fixtures/users.yml deleted file mode 100644 index ffa2fe42e..000000000 --- a/redmine/test/fixtures/users.yml +++ /dev/null @@ -1,61 +0,0 @@ ---- -users_004: - created_on: 2006-07-19 19:34:07 +02:00 - status: 1 - last_login_on: - language: en - hashed_password: 4e4aeb7baaf0706bd670263fef42dad15763b608 - updated_on: 2006-07-19 19:34:07 +02:00 - admin: false - mail: rhill@somenet.foo - lastname: Hill - firstname: Robert - id: 4 - auth_source_id: - mail_notification: true - login: rhill -users_001: - created_on: 2006-07-19 19:12:21 +02:00 - status: 1 - last_login_on: 2006-07-19 22:57:52 +02:00 - language: en - hashed_password: d033e22ae348aeb5660fc2140aec35850c4da997 - updated_on: 2006-07-19 22:57:52 +02:00 - admin: true - mail: admin@somenet.foo - lastname: Admin - firstname: redMine - id: 1 - auth_source_id: - mail_notification: true - login: admin -users_002: - created_on: 2006-07-19 19:32:09 +02:00 - status: 1 - last_login_on: 2006-07-19 22:42:15 +02:00 - language: en - hashed_password: a9a653d4151fa2c081ba1ffc2c2726f3b80b7d7d - updated_on: 2006-07-19 22:42:15 +02:00 - admin: false - mail: jsmith@somenet.foo - lastname: Smith - firstname: John - id: 2 - auth_source_id: - mail_notification: true - login: jsmith -users_003: - created_on: 2006-07-19 19:33:19 +02:00 - status: 1 - last_login_on: - language: en - hashed_password: 7feb7657aa7a7bf5aef3414a5084875f27192415 - updated_on: 2006-07-19 19:33:19 +02:00 - admin: false - mail: dlopper@somenet.foo - lastname: Lopper - firstname: Dave - id: 3 - auth_source_id: - mail_notification: true - login: dlopper diff --git a/redmine/test/fixtures/versions.yml b/redmine/test/fixtures/versions.yml deleted file mode 100644 index 89a738abd..000000000 --- a/redmine/test/fixtures/versions.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -versions_001: - created_on: 2006-07-19 21:00:07 +02:00 - name: "0.1" - project_id: 1 - updated_on: 2006-07-19 21:00:07 +02:00 - id: 1 - description: Beta - effective_date: 2006-07-01 -versions_002: - created_on: 2006-07-19 21:00:33 +02:00 - name: "1.0" - project_id: 1 - updated_on: 2006-07-19 21:00:33 +02:00 - id: 2 - description: Stable release - effective_date: 2006-07-19 diff --git a/redmine/test/fixtures/workflows.yml b/redmine/test/fixtures/workflows.yml deleted file mode 100644 index 47e95e6e3..000000000 --- a/redmine/test/fixtures/workflows.yml +++ /dev/null @@ -1,1621 +0,0 @@ ---- -workflows_189: - new_status_id: 5 - role_id: 1 - old_status_id: 2 - id: 189 - tracker_id: 3 -workflows_001: - new_status_id: 2 - role_id: 1 - old_status_id: 1 - id: 1 - tracker_id: 1 -workflows_002: - new_status_id: 3 - role_id: 1 - old_status_id: 1 - id: 2 - tracker_id: 1 -workflows_003: - new_status_id: 4 - role_id: 1 - old_status_id: 1 - id: 3 - tracker_id: 1 -workflows_110: - new_status_id: 6 - role_id: 1 - old_status_id: 4 - id: 110 - tracker_id: 2 -workflows_004: - new_status_id: 5 - role_id: 1 - old_status_id: 1 - id: 4 - tracker_id: 1 -workflows_030: - new_status_id: 5 - role_id: 1 - old_status_id: 6 - id: 30 - tracker_id: 1 -workflows_111: - new_status_id: 1 - role_id: 1 - old_status_id: 5 - id: 111 - tracker_id: 2 -workflows_005: - new_status_id: 6 - role_id: 1 - old_status_id: 1 - id: 5 - tracker_id: 1 -workflows_031: - new_status_id: 2 - role_id: 2 - old_status_id: 1 - id: 31 - tracker_id: 1 -workflows_112: - new_status_id: 2 - role_id: 1 - old_status_id: 5 - id: 112 - tracker_id: 2 -workflows_006: - new_status_id: 1 - role_id: 1 - old_status_id: 2 - id: 6 - tracker_id: 1 -workflows_032: - new_status_id: 3 - role_id: 2 - old_status_id: 1 - id: 32 - tracker_id: 1 -workflows_113: - new_status_id: 3 - role_id: 1 - old_status_id: 5 - id: 113 - tracker_id: 2 -workflows_220: - new_status_id: 6 - role_id: 2 - old_status_id: 2 - id: 220 - tracker_id: 3 -workflows_007: - new_status_id: 3 - role_id: 1 - old_status_id: 2 - id: 7 - tracker_id: 1 -workflows_033: - new_status_id: 4 - role_id: 2 - old_status_id: 1 - id: 33 - tracker_id: 1 -workflows_060: - new_status_id: 5 - role_id: 2 - old_status_id: 6 - id: 60 - tracker_id: 1 -workflows_114: - new_status_id: 4 - role_id: 1 - old_status_id: 5 - id: 114 - tracker_id: 2 -workflows_140: - new_status_id: 6 - role_id: 2 - old_status_id: 4 - id: 140 - tracker_id: 2 -workflows_221: - new_status_id: 1 - role_id: 2 - old_status_id: 3 - id: 221 - tracker_id: 3 -workflows_008: - new_status_id: 4 - role_id: 1 - old_status_id: 2 - id: 8 - tracker_id: 1 -workflows_034: - new_status_id: 5 - role_id: 2 - old_status_id: 1 - id: 34 - tracker_id: 1 -workflows_115: - new_status_id: 6 - role_id: 1 - old_status_id: 5 - id: 115 - tracker_id: 2 -workflows_141: - new_status_id: 1 - role_id: 2 - old_status_id: 5 - id: 141 - tracker_id: 2 -workflows_222: - new_status_id: 2 - role_id: 2 - old_status_id: 3 - id: 222 - tracker_id: 3 -workflows_223: - new_status_id: 4 - role_id: 2 - old_status_id: 3 - id: 223 - tracker_id: 3 -workflows_009: - new_status_id: 5 - role_id: 1 - old_status_id: 2 - id: 9 - tracker_id: 1 -workflows_035: - new_status_id: 6 - role_id: 2 - old_status_id: 1 - id: 35 - tracker_id: 1 -workflows_061: - new_status_id: 2 - role_id: 3 - old_status_id: 1 - id: 61 - tracker_id: 1 -workflows_116: - new_status_id: 1 - role_id: 1 - old_status_id: 6 - id: 116 - tracker_id: 2 -workflows_142: - new_status_id: 2 - role_id: 2 - old_status_id: 5 - id: 142 - tracker_id: 2 -workflows_250: - new_status_id: 6 - role_id: 3 - old_status_id: 2 - id: 250 - tracker_id: 3 -workflows_224: - new_status_id: 5 - role_id: 2 - old_status_id: 3 - id: 224 - tracker_id: 3 -workflows_036: - new_status_id: 1 - role_id: 2 - old_status_id: 2 - id: 36 - tracker_id: 1 -workflows_062: - new_status_id: 3 - role_id: 3 - old_status_id: 1 - id: 62 - tracker_id: 1 -workflows_117: - new_status_id: 2 - role_id: 1 - old_status_id: 6 - id: 117 - tracker_id: 2 -workflows_143: - new_status_id: 3 - role_id: 2 - old_status_id: 5 - id: 143 - tracker_id: 2 -workflows_170: - new_status_id: 6 - role_id: 3 - old_status_id: 4 - id: 170 - tracker_id: 2 -workflows_251: - new_status_id: 1 - role_id: 3 - old_status_id: 3 - id: 251 - tracker_id: 3 -workflows_225: - new_status_id: 6 - role_id: 2 - old_status_id: 3 - id: 225 - tracker_id: 3 -workflows_037: - new_status_id: 3 - role_id: 2 - old_status_id: 2 - id: 37 - tracker_id: 1 -workflows_063: - new_status_id: 4 - role_id: 3 - old_status_id: 1 - id: 63 - tracker_id: 1 -workflows_090: - new_status_id: 5 - role_id: 3 - old_status_id: 6 - id: 90 - tracker_id: 1 -workflows_118: - new_status_id: 3 - role_id: 1 - old_status_id: 6 - id: 118 - tracker_id: 2 -workflows_144: - new_status_id: 4 - role_id: 2 - old_status_id: 5 - id: 144 - tracker_id: 2 -workflows_252: - new_status_id: 2 - role_id: 3 - old_status_id: 3 - id: 252 - tracker_id: 3 -workflows_226: - new_status_id: 1 - role_id: 2 - old_status_id: 4 - id: 226 - tracker_id: 3 -workflows_038: - new_status_id: 4 - role_id: 2 - old_status_id: 2 - id: 38 - tracker_id: 1 -workflows_064: - new_status_id: 5 - role_id: 3 - old_status_id: 1 - id: 64 - tracker_id: 1 -workflows_091: - new_status_id: 2 - role_id: 1 - old_status_id: 1 - id: 91 - tracker_id: 2 -workflows_119: - new_status_id: 4 - role_id: 1 - old_status_id: 6 - id: 119 - tracker_id: 2 -workflows_145: - new_status_id: 6 - role_id: 2 - old_status_id: 5 - id: 145 - tracker_id: 2 -workflows_171: - new_status_id: 1 - role_id: 3 - old_status_id: 5 - id: 171 - tracker_id: 2 -workflows_253: - new_status_id: 4 - role_id: 3 - old_status_id: 3 - id: 253 - tracker_id: 3 -workflows_227: - new_status_id: 2 - role_id: 2 - old_status_id: 4 - id: 227 - tracker_id: 3 -workflows_039: - new_status_id: 5 - role_id: 2 - old_status_id: 2 - id: 39 - tracker_id: 1 -workflows_065: - new_status_id: 6 - role_id: 3 - old_status_id: 1 - id: 65 - tracker_id: 1 -workflows_092: - new_status_id: 3 - role_id: 1 - old_status_id: 1 - id: 92 - tracker_id: 2 -workflows_146: - new_status_id: 1 - role_id: 2 - old_status_id: 6 - id: 146 - tracker_id: 2 -workflows_172: - new_status_id: 2 - role_id: 3 - old_status_id: 5 - id: 172 - tracker_id: 2 -workflows_254: - new_status_id: 5 - role_id: 3 - old_status_id: 3 - id: 254 - tracker_id: 3 -workflows_228: - new_status_id: 3 - role_id: 2 - old_status_id: 4 - id: 228 - tracker_id: 3 -workflows_066: - new_status_id: 1 - role_id: 3 - old_status_id: 2 - id: 66 - tracker_id: 1 -workflows_093: - new_status_id: 4 - role_id: 1 - old_status_id: 1 - id: 93 - tracker_id: 2 -workflows_147: - new_status_id: 2 - role_id: 2 - old_status_id: 6 - id: 147 - tracker_id: 2 -workflows_173: - new_status_id: 3 - role_id: 3 - old_status_id: 5 - id: 173 - tracker_id: 2 -workflows_255: - new_status_id: 6 - role_id: 3 - old_status_id: 3 - id: 255 - tracker_id: 3 -workflows_229: - new_status_id: 5 - role_id: 2 - old_status_id: 4 - id: 229 - tracker_id: 3 -workflows_067: - new_status_id: 3 - role_id: 3 - old_status_id: 2 - id: 67 - tracker_id: 1 -workflows_148: - new_status_id: 3 - role_id: 2 - old_status_id: 6 - id: 148 - tracker_id: 2 -workflows_174: - new_status_id: 4 - role_id: 3 - old_status_id: 5 - id: 174 - tracker_id: 2 -workflows_256: - new_status_id: 1 - role_id: 3 - old_status_id: 4 - id: 256 - tracker_id: 3 -workflows_068: - new_status_id: 4 - role_id: 3 - old_status_id: 2 - id: 68 - tracker_id: 1 -workflows_094: - new_status_id: 5 - role_id: 1 - old_status_id: 1 - id: 94 - tracker_id: 2 -workflows_149: - new_status_id: 4 - role_id: 2 - old_status_id: 6 - id: 149 - tracker_id: 2 -workflows_175: - new_status_id: 6 - role_id: 3 - old_status_id: 5 - id: 175 - tracker_id: 2 -workflows_257: - new_status_id: 2 - role_id: 3 - old_status_id: 4 - id: 257 - tracker_id: 3 -workflows_069: - new_status_id: 5 - role_id: 3 - old_status_id: 2 - id: 69 - tracker_id: 1 -workflows_095: - new_status_id: 6 - role_id: 1 - old_status_id: 1 - id: 95 - tracker_id: 2 -workflows_176: - new_status_id: 1 - role_id: 3 - old_status_id: 6 - id: 176 - tracker_id: 2 -workflows_258: - new_status_id: 3 - role_id: 3 - old_status_id: 4 - id: 258 - tracker_id: 3 -workflows_096: - new_status_id: 1 - role_id: 1 - old_status_id: 2 - id: 96 - tracker_id: 2 -workflows_177: - new_status_id: 2 - role_id: 3 - old_status_id: 6 - id: 177 - tracker_id: 2 -workflows_259: - new_status_id: 5 - role_id: 3 - old_status_id: 4 - id: 259 - tracker_id: 3 -workflows_097: - new_status_id: 3 - role_id: 1 - old_status_id: 2 - id: 97 - tracker_id: 2 -workflows_178: - new_status_id: 3 - role_id: 3 - old_status_id: 6 - id: 178 - tracker_id: 2 -workflows_098: - new_status_id: 4 - role_id: 1 - old_status_id: 2 - id: 98 - tracker_id: 2 -workflows_179: - new_status_id: 4 - role_id: 3 - old_status_id: 6 - id: 179 - tracker_id: 2 -workflows_099: - new_status_id: 5 - role_id: 1 - old_status_id: 2 - id: 99 - tracker_id: 2 -workflows_100: - new_status_id: 6 - role_id: 1 - old_status_id: 2 - id: 100 - tracker_id: 2 -workflows_020: - new_status_id: 6 - role_id: 1 - old_status_id: 4 - id: 20 - tracker_id: 1 -workflows_101: - new_status_id: 1 - role_id: 1 - old_status_id: 3 - id: 101 - tracker_id: 2 -workflows_021: - new_status_id: 1 - role_id: 1 - old_status_id: 5 - id: 21 - tracker_id: 1 -workflows_102: - new_status_id: 2 - role_id: 1 - old_status_id: 3 - id: 102 - tracker_id: 2 -workflows_210: - new_status_id: 5 - role_id: 1 - old_status_id: 6 - id: 210 - tracker_id: 3 -workflows_022: - new_status_id: 2 - role_id: 1 - old_status_id: 5 - id: 22 - tracker_id: 1 -workflows_103: - new_status_id: 4 - role_id: 1 - old_status_id: 3 - id: 103 - tracker_id: 2 -workflows_023: - new_status_id: 3 - role_id: 1 - old_status_id: 5 - id: 23 - tracker_id: 1 -workflows_104: - new_status_id: 5 - role_id: 1 - old_status_id: 3 - id: 104 - tracker_id: 2 -workflows_130: - new_status_id: 6 - role_id: 2 - old_status_id: 2 - id: 130 - tracker_id: 2 -workflows_211: - new_status_id: 2 - role_id: 2 - old_status_id: 1 - id: 211 - tracker_id: 3 -workflows_024: - new_status_id: 4 - role_id: 1 - old_status_id: 5 - id: 24 - tracker_id: 1 -workflows_050: - new_status_id: 6 - role_id: 2 - old_status_id: 4 - id: 50 - tracker_id: 1 -workflows_105: - new_status_id: 6 - role_id: 1 - old_status_id: 3 - id: 105 - tracker_id: 2 -workflows_131: - new_status_id: 1 - role_id: 2 - old_status_id: 3 - id: 131 - tracker_id: 2 -workflows_212: - new_status_id: 3 - role_id: 2 - old_status_id: 1 - id: 212 - tracker_id: 3 -workflows_025: - new_status_id: 6 - role_id: 1 - old_status_id: 5 - id: 25 - tracker_id: 1 -workflows_051: - new_status_id: 1 - role_id: 2 - old_status_id: 5 - id: 51 - tracker_id: 1 -workflows_106: - new_status_id: 1 - role_id: 1 - old_status_id: 4 - id: 106 - tracker_id: 2 -workflows_132: - new_status_id: 2 - role_id: 2 - old_status_id: 3 - id: 132 - tracker_id: 2 -workflows_213: - new_status_id: 4 - role_id: 2 - old_status_id: 1 - id: 213 - tracker_id: 3 -workflows_240: - new_status_id: 5 - role_id: 2 - old_status_id: 6 - id: 240 - tracker_id: 3 -workflows_026: - new_status_id: 1 - role_id: 1 - old_status_id: 6 - id: 26 - tracker_id: 1 -workflows_052: - new_status_id: 2 - role_id: 2 - old_status_id: 5 - id: 52 - tracker_id: 1 -workflows_107: - new_status_id: 2 - role_id: 1 - old_status_id: 4 - id: 107 - tracker_id: 2 -workflows_133: - new_status_id: 4 - role_id: 2 - old_status_id: 3 - id: 133 - tracker_id: 2 -workflows_214: - new_status_id: 5 - role_id: 2 - old_status_id: 1 - id: 214 - tracker_id: 3 -workflows_241: - new_status_id: 2 - role_id: 3 - old_status_id: 1 - id: 241 - tracker_id: 3 -workflows_027: - new_status_id: 2 - role_id: 1 - old_status_id: 6 - id: 27 - tracker_id: 1 -workflows_053: - new_status_id: 3 - role_id: 2 - old_status_id: 5 - id: 53 - tracker_id: 1 -workflows_080: - new_status_id: 6 - role_id: 3 - old_status_id: 4 - id: 80 - tracker_id: 1 -workflows_108: - new_status_id: 3 - role_id: 1 - old_status_id: 4 - id: 108 - tracker_id: 2 -workflows_134: - new_status_id: 5 - role_id: 2 - old_status_id: 3 - id: 134 - tracker_id: 2 -workflows_160: - new_status_id: 6 - role_id: 3 - old_status_id: 2 - id: 160 - tracker_id: 2 -workflows_215: - new_status_id: 6 - role_id: 2 - old_status_id: 1 - id: 215 - tracker_id: 3 -workflows_242: - new_status_id: 3 - role_id: 3 - old_status_id: 1 - id: 242 - tracker_id: 3 -workflows_028: - new_status_id: 3 - role_id: 1 - old_status_id: 6 - id: 28 - tracker_id: 1 -workflows_054: - new_status_id: 4 - role_id: 2 - old_status_id: 5 - id: 54 - tracker_id: 1 -workflows_081: - new_status_id: 1 - role_id: 3 - old_status_id: 5 - id: 81 - tracker_id: 1 -workflows_109: - new_status_id: 5 - role_id: 1 - old_status_id: 4 - id: 109 - tracker_id: 2 -workflows_135: - new_status_id: 6 - role_id: 2 - old_status_id: 3 - id: 135 - tracker_id: 2 -workflows_161: - new_status_id: 1 - role_id: 3 - old_status_id: 3 - id: 161 - tracker_id: 2 -workflows_216: - new_status_id: 1 - role_id: 2 - old_status_id: 2 - id: 216 - tracker_id: 3 -workflows_243: - new_status_id: 4 - role_id: 3 - old_status_id: 1 - id: 243 - tracker_id: 3 -workflows_029: - new_status_id: 4 - role_id: 1 - old_status_id: 6 - id: 29 - tracker_id: 1 -workflows_055: - new_status_id: 6 - role_id: 2 - old_status_id: 5 - id: 55 - tracker_id: 1 -workflows_082: - new_status_id: 2 - role_id: 3 - old_status_id: 5 - id: 82 - tracker_id: 1 -workflows_136: - new_status_id: 1 - role_id: 2 - old_status_id: 4 - id: 136 - tracker_id: 2 -workflows_162: - new_status_id: 2 - role_id: 3 - old_status_id: 3 - id: 162 - tracker_id: 2 -workflows_217: - new_status_id: 3 - role_id: 2 - old_status_id: 2 - id: 217 - tracker_id: 3 -workflows_270: - new_status_id: 5 - role_id: 3 - old_status_id: 6 - id: 270 - tracker_id: 3 -workflows_244: - new_status_id: 5 - role_id: 3 - old_status_id: 1 - id: 244 - tracker_id: 3 -workflows_056: - new_status_id: 1 - role_id: 2 - old_status_id: 6 - id: 56 - tracker_id: 1 -workflows_137: - new_status_id: 2 - role_id: 2 - old_status_id: 4 - id: 137 - tracker_id: 2 -workflows_163: - new_status_id: 4 - role_id: 3 - old_status_id: 3 - id: 163 - tracker_id: 2 -workflows_190: - new_status_id: 6 - role_id: 1 - old_status_id: 2 - id: 190 - tracker_id: 3 -workflows_218: - new_status_id: 4 - role_id: 2 - old_status_id: 2 - id: 218 - tracker_id: 3 -workflows_245: - new_status_id: 6 - role_id: 3 - old_status_id: 1 - id: 245 - tracker_id: 3 -workflows_057: - new_status_id: 2 - role_id: 2 - old_status_id: 6 - id: 57 - tracker_id: 1 -workflows_083: - new_status_id: 3 - role_id: 3 - old_status_id: 5 - id: 83 - tracker_id: 1 -workflows_138: - new_status_id: 3 - role_id: 2 - old_status_id: 4 - id: 138 - tracker_id: 2 -workflows_164: - new_status_id: 5 - role_id: 3 - old_status_id: 3 - id: 164 - tracker_id: 2 -workflows_191: - new_status_id: 1 - role_id: 1 - old_status_id: 3 - id: 191 - tracker_id: 3 -workflows_219: - new_status_id: 5 - role_id: 2 - old_status_id: 2 - id: 219 - tracker_id: 3 -workflows_246: - new_status_id: 1 - role_id: 3 - old_status_id: 2 - id: 246 - tracker_id: 3 -workflows_058: - new_status_id: 3 - role_id: 2 - old_status_id: 6 - id: 58 - tracker_id: 1 -workflows_084: - new_status_id: 4 - role_id: 3 - old_status_id: 5 - id: 84 - tracker_id: 1 -workflows_139: - new_status_id: 5 - role_id: 2 - old_status_id: 4 - id: 139 - tracker_id: 2 -workflows_165: - new_status_id: 6 - role_id: 3 - old_status_id: 3 - id: 165 - tracker_id: 2 -workflows_192: - new_status_id: 2 - role_id: 1 - old_status_id: 3 - id: 192 - tracker_id: 3 -workflows_247: - new_status_id: 3 - role_id: 3 - old_status_id: 2 - id: 247 - tracker_id: 3 -workflows_059: - new_status_id: 4 - role_id: 2 - old_status_id: 6 - id: 59 - tracker_id: 1 -workflows_085: - new_status_id: 6 - role_id: 3 - old_status_id: 5 - id: 85 - tracker_id: 1 -workflows_166: - new_status_id: 1 - role_id: 3 - old_status_id: 4 - id: 166 - tracker_id: 2 -workflows_248: - new_status_id: 4 - role_id: 3 - old_status_id: 2 - id: 248 - tracker_id: 3 -workflows_086: - new_status_id: 1 - role_id: 3 - old_status_id: 6 - id: 86 - tracker_id: 1 -workflows_167: - new_status_id: 2 - role_id: 3 - old_status_id: 4 - id: 167 - tracker_id: 2 -workflows_193: - new_status_id: 4 - role_id: 1 - old_status_id: 3 - id: 193 - tracker_id: 3 -workflows_249: - new_status_id: 5 - role_id: 3 - old_status_id: 2 - id: 249 - tracker_id: 3 -workflows_087: - new_status_id: 2 - role_id: 3 - old_status_id: 6 - id: 87 - tracker_id: 1 -workflows_168: - new_status_id: 3 - role_id: 3 - old_status_id: 4 - id: 168 - tracker_id: 2 -workflows_194: - new_status_id: 5 - role_id: 1 - old_status_id: 3 - id: 194 - tracker_id: 3 -workflows_088: - new_status_id: 3 - role_id: 3 - old_status_id: 6 - id: 88 - tracker_id: 1 -workflows_169: - new_status_id: 5 - role_id: 3 - old_status_id: 4 - id: 169 - tracker_id: 2 -workflows_195: - new_status_id: 6 - role_id: 1 - old_status_id: 3 - id: 195 - tracker_id: 3 -workflows_089: - new_status_id: 4 - role_id: 3 - old_status_id: 6 - id: 89 - tracker_id: 1 -workflows_196: - new_status_id: 1 - role_id: 1 - old_status_id: 4 - id: 196 - tracker_id: 3 -workflows_197: - new_status_id: 2 - role_id: 1 - old_status_id: 4 - id: 197 - tracker_id: 3 -workflows_198: - new_status_id: 3 - role_id: 1 - old_status_id: 4 - id: 198 - tracker_id: 3 -workflows_199: - new_status_id: 5 - role_id: 1 - old_status_id: 4 - id: 199 - tracker_id: 3 -workflows_010: - new_status_id: 6 - role_id: 1 - old_status_id: 2 - id: 10 - tracker_id: 1 -workflows_011: - new_status_id: 1 - role_id: 1 - old_status_id: 3 - id: 11 - tracker_id: 1 -workflows_012: - new_status_id: 2 - role_id: 1 - old_status_id: 3 - id: 12 - tracker_id: 1 -workflows_200: - new_status_id: 6 - role_id: 1 - old_status_id: 4 - id: 200 - tracker_id: 3 -workflows_013: - new_status_id: 4 - role_id: 1 - old_status_id: 3 - id: 13 - tracker_id: 1 -workflows_120: - new_status_id: 5 - role_id: 1 - old_status_id: 6 - id: 120 - tracker_id: 2 -workflows_201: - new_status_id: 1 - role_id: 1 - old_status_id: 5 - id: 201 - tracker_id: 3 -workflows_040: - new_status_id: 6 - role_id: 2 - old_status_id: 2 - id: 40 - tracker_id: 1 -workflows_121: - new_status_id: 2 - role_id: 2 - old_status_id: 1 - id: 121 - tracker_id: 2 -workflows_202: - new_status_id: 2 - role_id: 1 - old_status_id: 5 - id: 202 - tracker_id: 3 -workflows_014: - new_status_id: 5 - role_id: 1 - old_status_id: 3 - id: 14 - tracker_id: 1 -workflows_041: - new_status_id: 1 - role_id: 2 - old_status_id: 3 - id: 41 - tracker_id: 1 -workflows_122: - new_status_id: 3 - role_id: 2 - old_status_id: 1 - id: 122 - tracker_id: 2 -workflows_203: - new_status_id: 3 - role_id: 1 - old_status_id: 5 - id: 203 - tracker_id: 3 -workflows_015: - new_status_id: 6 - role_id: 1 - old_status_id: 3 - id: 15 - tracker_id: 1 -workflows_230: - new_status_id: 6 - role_id: 2 - old_status_id: 4 - id: 230 - tracker_id: 3 -workflows_123: - new_status_id: 4 - role_id: 2 - old_status_id: 1 - id: 123 - tracker_id: 2 -workflows_204: - new_status_id: 4 - role_id: 1 - old_status_id: 5 - id: 204 - tracker_id: 3 -workflows_016: - new_status_id: 1 - role_id: 1 - old_status_id: 4 - id: 16 - tracker_id: 1 -workflows_042: - new_status_id: 2 - role_id: 2 - old_status_id: 3 - id: 42 - tracker_id: 1 -workflows_231: - new_status_id: 1 - role_id: 2 - old_status_id: 5 - id: 231 - tracker_id: 3 -workflows_070: - new_status_id: 6 - role_id: 3 - old_status_id: 2 - id: 70 - tracker_id: 1 -workflows_124: - new_status_id: 5 - role_id: 2 - old_status_id: 1 - id: 124 - tracker_id: 2 -workflows_150: - new_status_id: 5 - role_id: 2 - old_status_id: 6 - id: 150 - tracker_id: 2 -workflows_205: - new_status_id: 6 - role_id: 1 - old_status_id: 5 - id: 205 - tracker_id: 3 -workflows_017: - new_status_id: 2 - role_id: 1 - old_status_id: 4 - id: 17 - tracker_id: 1 -workflows_043: - new_status_id: 4 - role_id: 2 - old_status_id: 3 - id: 43 - tracker_id: 1 -workflows_232: - new_status_id: 2 - role_id: 2 - old_status_id: 5 - id: 232 - tracker_id: 3 -workflows_125: - new_status_id: 6 - role_id: 2 - old_status_id: 1 - id: 125 - tracker_id: 2 -workflows_151: - new_status_id: 2 - role_id: 3 - old_status_id: 1 - id: 151 - tracker_id: 2 -workflows_206: - new_status_id: 1 - role_id: 1 - old_status_id: 6 - id: 206 - tracker_id: 3 -workflows_018: - new_status_id: 3 - role_id: 1 - old_status_id: 4 - id: 18 - tracker_id: 1 -workflows_044: - new_status_id: 5 - role_id: 2 - old_status_id: 3 - id: 44 - tracker_id: 1 -workflows_071: - new_status_id: 1 - role_id: 3 - old_status_id: 3 - id: 71 - tracker_id: 1 -workflows_233: - new_status_id: 3 - role_id: 2 - old_status_id: 5 - id: 233 - tracker_id: 3 -workflows_126: - new_status_id: 1 - role_id: 2 - old_status_id: 2 - id: 126 - tracker_id: 2 -workflows_152: - new_status_id: 3 - role_id: 3 - old_status_id: 1 - id: 152 - tracker_id: 2 -workflows_207: - new_status_id: 2 - role_id: 1 - old_status_id: 6 - id: 207 - tracker_id: 3 -workflows_019: - new_status_id: 5 - role_id: 1 - old_status_id: 4 - id: 19 - tracker_id: 1 -workflows_045: - new_status_id: 6 - role_id: 2 - old_status_id: 3 - id: 45 - tracker_id: 1 -workflows_260: - new_status_id: 6 - role_id: 3 - old_status_id: 4 - id: 260 - tracker_id: 3 -workflows_234: - new_status_id: 4 - role_id: 2 - old_status_id: 5 - id: 234 - tracker_id: 3 -workflows_127: - new_status_id: 3 - role_id: 2 - old_status_id: 2 - id: 127 - tracker_id: 2 -workflows_153: - new_status_id: 4 - role_id: 3 - old_status_id: 1 - id: 153 - tracker_id: 2 -workflows_180: - new_status_id: 5 - role_id: 3 - old_status_id: 6 - id: 180 - tracker_id: 2 -workflows_208: - new_status_id: 3 - role_id: 1 - old_status_id: 6 - id: 208 - tracker_id: 3 -workflows_046: - new_status_id: 1 - role_id: 2 - old_status_id: 4 - id: 46 - tracker_id: 1 -workflows_072: - new_status_id: 2 - role_id: 3 - old_status_id: 3 - id: 72 - tracker_id: 1 -workflows_261: - new_status_id: 1 - role_id: 3 - old_status_id: 5 - id: 261 - tracker_id: 3 -workflows_235: - new_status_id: 6 - role_id: 2 - old_status_id: 5 - id: 235 - tracker_id: 3 -workflows_154: - new_status_id: 5 - role_id: 3 - old_status_id: 1 - id: 154 - tracker_id: 2 -workflows_181: - new_status_id: 2 - role_id: 1 - old_status_id: 1 - id: 181 - tracker_id: 3 -workflows_209: - new_status_id: 4 - role_id: 1 - old_status_id: 6 - id: 209 - tracker_id: 3 -workflows_047: - new_status_id: 2 - role_id: 2 - old_status_id: 4 - id: 47 - tracker_id: 1 -workflows_073: - new_status_id: 4 - role_id: 3 - old_status_id: 3 - id: 73 - tracker_id: 1 -workflows_128: - new_status_id: 4 - role_id: 2 - old_status_id: 2 - id: 128 - tracker_id: 2 -workflows_262: - new_status_id: 2 - role_id: 3 - old_status_id: 5 - id: 262 - tracker_id: 3 -workflows_236: - new_status_id: 1 - role_id: 2 - old_status_id: 6 - id: 236 - tracker_id: 3 -workflows_155: - new_status_id: 6 - role_id: 3 - old_status_id: 1 - id: 155 - tracker_id: 2 -workflows_048: - new_status_id: 3 - role_id: 2 - old_status_id: 4 - id: 48 - tracker_id: 1 -workflows_074: - new_status_id: 5 - role_id: 3 - old_status_id: 3 - id: 74 - tracker_id: 1 -workflows_129: - new_status_id: 5 - role_id: 2 - old_status_id: 2 - id: 129 - tracker_id: 2 -workflows_263: - new_status_id: 3 - role_id: 3 - old_status_id: 5 - id: 263 - tracker_id: 3 -workflows_237: - new_status_id: 2 - role_id: 2 - old_status_id: 6 - id: 237 - tracker_id: 3 -workflows_182: - new_status_id: 3 - role_id: 1 - old_status_id: 1 - id: 182 - tracker_id: 3 -workflows_049: - new_status_id: 5 - role_id: 2 - old_status_id: 4 - id: 49 - tracker_id: 1 -workflows_075: - new_status_id: 6 - role_id: 3 - old_status_id: 3 - id: 75 - tracker_id: 1 -workflows_156: - new_status_id: 1 - role_id: 3 - old_status_id: 2 - id: 156 - tracker_id: 2 -workflows_264: - new_status_id: 4 - role_id: 3 - old_status_id: 5 - id: 264 - tracker_id: 3 -workflows_238: - new_status_id: 3 - role_id: 2 - old_status_id: 6 - id: 238 - tracker_id: 3 -workflows_183: - new_status_id: 4 - role_id: 1 - old_status_id: 1 - id: 183 - tracker_id: 3 -workflows_076: - new_status_id: 1 - role_id: 3 - old_status_id: 4 - id: 76 - tracker_id: 1 -workflows_157: - new_status_id: 3 - role_id: 3 - old_status_id: 2 - id: 157 - tracker_id: 2 -workflows_265: - new_status_id: 6 - role_id: 3 - old_status_id: 5 - id: 265 - tracker_id: 3 -workflows_239: - new_status_id: 4 - role_id: 2 - old_status_id: 6 - id: 239 - tracker_id: 3 -workflows_077: - new_status_id: 2 - role_id: 3 - old_status_id: 4 - id: 77 - tracker_id: 1 -workflows_158: - new_status_id: 4 - role_id: 3 - old_status_id: 2 - id: 158 - tracker_id: 2 -workflows_184: - new_status_id: 5 - role_id: 1 - old_status_id: 1 - id: 184 - tracker_id: 3 -workflows_266: - new_status_id: 1 - role_id: 3 - old_status_id: 6 - id: 266 - tracker_id: 3 -workflows_078: - new_status_id: 3 - role_id: 3 - old_status_id: 4 - id: 78 - tracker_id: 1 -workflows_159: - new_status_id: 5 - role_id: 3 - old_status_id: 2 - id: 159 - tracker_id: 2 -workflows_185: - new_status_id: 6 - role_id: 1 - old_status_id: 1 - id: 185 - tracker_id: 3 -workflows_267: - new_status_id: 2 - role_id: 3 - old_status_id: 6 - id: 267 - tracker_id: 3 -workflows_079: - new_status_id: 5 - role_id: 3 - old_status_id: 4 - id: 79 - tracker_id: 1 -workflows_186: - new_status_id: 1 - role_id: 1 - old_status_id: 2 - id: 186 - tracker_id: 3 -workflows_268: - new_status_id: 3 - role_id: 3 - old_status_id: 6 - id: 268 - tracker_id: 3 -workflows_187: - new_status_id: 3 - role_id: 1 - old_status_id: 2 - id: 187 - tracker_id: 3 -workflows_269: - new_status_id: 4 - role_id: 3 - old_status_id: 6 - id: 269 - tracker_id: 3 -workflows_188: - new_status_id: 4 - role_id: 1 - old_status_id: 2 - id: 188 - tracker_id: 3 diff --git a/redmine/test/functional/my_controller_test.rb b/redmine/test/functional/my_controller_test.rb deleted file mode 100644 index 525c71b45..000000000 --- a/redmine/test/functional/my_controller_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'my_controller' - -# Re-raise errors caught by the controller. -class MyController; def rescue_action(e) raise e end; end - -class MyControllerTest < Test::Unit::TestCase - def setup - @controller = MyController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/redmine/test/functional/projects_controller_test.rb b/redmine/test/functional/projects_controller_test.rb deleted file mode 100644 index f20f8ad0f..000000000 --- a/redmine/test/functional/projects_controller_test.rb +++ /dev/null @@ -1,114 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require File.dirname(__FILE__) + '/../test_helper' -require 'projects_controller' - -# Re-raise errors caught by the controller. -class ProjectsController; def rescue_action(e) raise e end; end - -class ProjectsControllerTest < Test::Unit::TestCase - fixtures :projects, :permissions - - def setup - @controller = ProjectsController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - def test_index - get :index - assert_response :success - assert_template 'list' - end - - def test_list - get :list - assert_response :success - assert_template 'list' - assert_not_nil assigns(:projects) - end - - def test_show - get :show, :id => 1 - assert_response :success - assert_template 'show' - assert_not_nil assigns(:project) - end - - def test_list_members - get :list_members, :id => 1 - assert_response :success - assert_template 'list_members' - assert_not_nil assigns(:members) - end - - def test_list_documents - get :list_documents, :id => 1 - assert_response :success - assert_template 'list_documents' - assert_not_nil assigns(:documents) - end - - def test_list_issues - get :list_issues, :id => 1 - assert_response :success - assert_template 'list_issues' - assert_not_nil assigns(:issues) - end - - def test_list_issues_with_filter - get :list_issues, :id => 1, :set_filter => 1 - assert_response :success - assert_template 'list_issues' - assert_not_nil assigns(:issues) - end - - def test_list_issues_reset_filter - post :list_issues, :id => 1 - assert_response :success - assert_template 'list_issues' - assert_not_nil assigns(:issues) - end - - def test_export_issues_csv - get :export_issues_csv, :id => 1 - assert_response :success - assert_not_nil assigns(:issues) - end - - def test_list_news - get :list_news, :id => 1 - assert_response :success - assert_template 'list_news' - assert_not_nil assigns(:news) - end - - def test_list_files - get :list_files, :id => 1 - assert_response :success - assert_template 'list_files' - assert_not_nil assigns(:versions) - end - - def test_changelog - get :changelog, :id => 1 - assert_response :success - assert_template 'changelog' - assert_not_nil assigns(:fixed_issues) - end -end diff --git a/redmine/test/integration/account_test.rb b/redmine/test/integration/account_test.rb deleted file mode 100644 index 0d6f75d70..000000000 --- a/redmine/test/integration/account_test.rb +++ /dev/null @@ -1,100 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require "#{File.dirname(__FILE__)}/../test_helper" - -class AccountTest < ActionController::IntegrationTest - fixtures :users - - # Replace this with your real tests. - def test_login - get "my/page" - assert_redirected_to "account/login" - log_user('jsmith', 'jsmith') - - get "my/account" - assert_response :success - assert_template "my/account" - end - - def test_change_password - log_user('jsmith', 'jsmith') - get "my/account" - assert_response :success - assert_template "my/account" - - post "my/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello2" - assert_response :success - assert_template "my/account" - assert_tag :tag => "div", :attributes => { :class => "errorExplanation" } - - post "my/change_password", :password => 'jsmithZZ', :new_password => "hello", :new_password_confirmation => "hello" - assert_redirected_to "my/account" - assert_equal 'Wrong password', flash[:notice] - - post "my/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello" - assert_redirected_to "my/account" - log_user('jsmith', 'hello') - end - - def test_my_account - log_user('jsmith', 'jsmith') - get "my/account" - assert_response :success - assert_template "my/account" - - post "my/account", :user => {:firstname => "Joe", :login => "root", :admin => 1} - assert_response :success - assert_template "my/account" - user = User.find(2) - assert_equal "Joe", user.firstname - assert_equal "jsmith", user.login - assert_equal false, user.admin? - end - - def test_my_page - log_user('jsmith', 'jsmith') - get "my/page" - assert_response :success - assert_template "my/page" - end - - def test_lost_password - get "account/lost_password" - assert_response :success - assert_template "account/lost_password" - - post "account/lost_password", :mail => 'jsmith@somenet.foo' - assert_redirected_to "account/login" - - token = Token.find(:first) - assert_equal 'recovery', token.action - assert_equal 'jsmith@somenet.foo', token.user.mail - assert !token.expired? - - get "account/lost_password", :token => token.value - assert_response :success - assert_template "account/password_recovery" - - post "account/lost_password", :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'newpass' - assert_redirected_to "account/login" - assert_equal 'Password was successfully updated.', flash[:notice] - - log_user('jsmith', 'newpass') - assert_equal 0, Token.count - end -end diff --git a/redmine/test/integration/admin_test.rb b/redmine/test/integration/admin_test.rb deleted file mode 100644 index 0241ae8da..000000000 --- a/redmine/test/integration/admin_test.rb +++ /dev/null @@ -1,61 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require "#{File.dirname(__FILE__)}/../test_helper" - -class AdminTest < ActionController::IntegrationTest - fixtures :users - - def test_add_user - log_user("admin", "admin") - get "/users/add" - assert_response :success - assert_template "users/add" - post "/users/add", :user => { :login => "psmith", :firstname => "Paul", :lastname => "Smith", :mail => "psmith@somenet.foo", :language => "en" }, :password => "psmith09", :password_confirmation => "psmith09" - assert_redirected_to "users/list" - - user = User.find_by_login("psmith") - assert_kind_of User, user - logged_user = User.try_to_login("psmith", "psmith09") - assert_kind_of User, logged_user - assert_equal "Paul", logged_user.firstname - - post "users/edit", :id => user.id, :user => { :status => User::STATUS_LOCKED } - assert_redirected_to "users/list" - locked_user = User.try_to_login("psmith", "psmith09") - assert_equal nil, locked_user - end - - def test_add_project - log_user("admin", "admin") - get "projects/add" - assert_response :success - assert_template "projects/add" - post "projects/add", :project => { :name => "blog", :description => "weblog", :is_public => 1} - assert_redirected_to "admin/projects" - assert_equal 'Successful creation.', flash[:notice] - - project = Project.find_by_name("blog") - assert_kind_of Project, project - assert_equal "weblog", project.description - assert_equal true, project.is_public? - - get "admin/projects" - assert_response :success - assert_template "admin/projects" - end -end diff --git a/redmine/test/test_helper.rb b/redmine/test/test_helper.rb deleted file mode 100644 index 2e4f7dcd0..000000000 --- a/redmine/test/test_helper.rb +++ /dev/null @@ -1,55 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -ENV["RAILS_ENV"] ||= "test" -require File.expand_path(File.dirname(__FILE__) + "/../config/environment") -require 'test_help' - -class Test::Unit::TestCase - # Transactional fixtures accelerate your tests by wrapping each test method - # in a transaction that's rolled back on completion. This ensures that the - # test database remains unchanged so your fixtures don't have to be reloaded - # between every test method. Fewer database queries means faster tests. - # - # Read Mike Clark's excellent walkthrough at - # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting - # - # Every Active Record database supports transactions except MyISAM tables - # in MySQL. Turn off transactional fixtures in this case; however, if you - # don't care one way or the other, switching from MyISAM to InnoDB tables - # is recommended. - self.use_transactional_fixtures = true - - # Instantiated fixtures are slow, but give you @david where otherwise you - # would need people(:david). If you don't want to migrate your existing - # test cases which use the @david style and don't mind the speed hit (each - # instantiated fixtures translates to a database query per test method), - # then set this back to true. - self.use_instantiated_fixtures = false - - # Add more helper methods to be used by all tests here... - - def log_user(login, password) - get "/account/login" - assert_equal nil, session[:user_id] - assert_response :success - assert_template "account/login" - post "/account/login", :login => login, :password => password - assert_redirected_to "my/page" - assert_equal login, User.find(session[:user_id]).login - end -end diff --git a/redmine/test/unit/member_test.rb b/redmine/test/unit/member_test.rb deleted file mode 100644 index 079782306..000000000 --- a/redmine/test/unit/member_test.rb +++ /dev/null @@ -1,51 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require File.dirname(__FILE__) + '/../test_helper' - -class MemberTest < Test::Unit::TestCase - fixtures :users, :projects, :roles, :members - - def setup - @jsmith = Member.find(1) - end - - def test_create - member = Member.new(:project_id => 1, :user_id => 4, :role_id => 1) - assert member.save - end - - def test_update - assert_equal "eCookbook", @jsmith.project.name - assert_equal "Manager", @jsmith.role.name - assert_equal "jsmith", @jsmith.user.login - - @jsmith.role = Role.find(2) - assert @jsmith.save - end - - def test_validate - member = Member.new(:project_id => 1, :user_id => 2, :role_id =>2) - # same use can't have more than one role for a project - assert !member.save - end - - def test_destroy - @jsmith.destroy - assert_raise(ActiveRecord::RecordNotFound) { Member.find(@jsmith.id) } - end -end diff --git a/redmine/test/unit/project_test.rb b/redmine/test/unit/project_test.rb deleted file mode 100644 index 9c8f0c97e..000000000 --- a/redmine/test/unit/project_test.rb +++ /dev/null @@ -1,79 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require File.dirname(__FILE__) + '/../test_helper' - -class ProjectTest < Test::Unit::TestCase - fixtures :projects - - def setup - @ecookbook = Project.find(1) - @ecookbook_sub1 = Project.find(3) - end - - def test_truth - assert_kind_of Project, @ecookbook - assert_equal "eCookbook", @ecookbook.name - end - - def test_update - assert_equal "eCookbook", @ecookbook.name - @ecookbook.name = "eCook" - assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ") - @ecookbook.reload - assert_equal "eCook", @ecookbook.name - end - - def test_validate - @ecookbook.name = "" - assert !@ecookbook.save - assert_equal 1, @ecookbook.errors.count - assert_equal l(:activerecord_error_blank), @ecookbook.errors.on(:name) - end - - def test_public_projects - public_projects = Project.find(:all, :conditions => ["is_public=?", true]) - assert_equal 3, public_projects.length - assert_equal true, public_projects[0].is_public? - end - - def test_destroy - @ecookbook.destroy - assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) } - end - - def test_subproject_ok - sub = Project.find(2) - sub.parent = @ecookbook - assert sub.save - assert_equal @ecookbook.id, sub.parent.id - @ecookbook.reload - assert_equal 3, @ecookbook.projects_count - end - - def test_subproject_invalid - sub = Project.find(2) - sub.parent = @ecookbook_sub1 - assert !sub.save - end - - def test_subproject_invalid_2 - sub = @ecookbook - sub.parent = Project.find(2) - assert !sub.save - end -end diff --git a/redmine/test/unit/token_test.rb b/redmine/test/unit/token_test.rb deleted file mode 100644 index 1c3820e99..000000000 --- a/redmine/test/unit/token_test.rb +++ /dev/null @@ -1,10 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class TokenTest < Test::Unit::TestCase - fixtures :tokens - - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/redmine/test/unit/user_preference_test.rb b/redmine/test/unit/user_preference_test.rb deleted file mode 100644 index 4675a2652..000000000 --- a/redmine/test/unit/user_preference_test.rb +++ /dev/null @@ -1,10 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class UserPreferenceTest < Test::Unit::TestCase - fixtures :user_preferences - - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/redmine/test/unit/user_test.rb b/redmine/test/unit/user_test.rb deleted file mode 100644 index 211e6554c..000000000 --- a/redmine/test/unit/user_test.rb +++ /dev/null @@ -1,88 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require File.dirname(__FILE__) + '/../test_helper' - -class UserTest < Test::Unit::TestCase - fixtures :users - - def setup - @admin = User.find(1) - @jsmith = User.find(2) - end - - def test_truth - assert_kind_of User, @jsmith - end - - def test_create - user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo") - - user.login = "jsmith" - user.password, user.password_confirmation = "password", "password" - # login uniqueness - assert !user.save - assert_equal 1, user.errors.count - - user.login = "newuser" - user.password, user.password_confirmation = "passwd", "password" - # password confirmation - assert !user.save - assert_equal 1, user.errors.count - - user.password, user.password_confirmation = "password", "password" - assert user.save - end - - def test_update - assert_equal "admin", @admin.login - @admin.login = "john" - assert @admin.save, @admin.errors.full_messages.join("; ") - @admin.reload - assert_equal "john", @admin.login - end - - def test_validate - @admin.login = "" - assert !@admin.save - assert_equal 2, @admin.errors.count - end - - def test_password - user = User.try_to_login("admin", "admin") - assert_kind_of User, user - assert_equal "admin", user.login - user.password = "hello" - assert user.save - - user = User.try_to_login("admin", "hello") - assert_kind_of User, user - assert_equal "admin", user.login - assert_equal User.hash_password("hello"), user.hashed_password - end - - def test_lock - user = User.try_to_login("jsmith", "jsmith") - assert_equal @jsmith, user - - @jsmith.status = User::STATUS_LOCKED - assert @jsmith.save - - user = User.try_to_login("jsmith", "jsmith") - assert_equal nil, user - end -end diff --git a/redmine/vendor/plugins/gloc-1.1.0/CHANGELOG b/redmine/vendor/plugins/gloc-1.1.0/CHANGELOG deleted file mode 100644 index 6392d7cbe..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/CHANGELOG +++ /dev/null @@ -1,19 +0,0 @@ -== Version 1.1 (28 May 2006) - -* The charset for each and/or all languages can now be easily configured. -* Added a ActionController filter that auto-detects the client language. -* The rake task "sort" now merges lines that match 100%, and warns if duplicate keys are found. -* Rule support. Create flexible rules to handle issues such as pluralization. -* Massive speed and stability improvements to development mode. -* Added Russian strings. (Thanks to Evgeny Lineytsev) -* Complete RDoc documentation. -* Improved helpers. -* GLoc now configurable via get_config and set_config -* Added an option to tell GLoc to output various verbose information. -* More useful functions such as set_language_if_valid, similar_language -* GLoc's entire internal state can now be backed up and restored. - - -== Version 1.0 (17 April 2006) - -* Initial public release. diff --git a/redmine/vendor/plugins/gloc-1.1.0/MIT-LICENSE b/redmine/vendor/plugins/gloc-1.1.0/MIT-LICENSE deleted file mode 100644 index 081774a65..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/MIT-LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2005-2006 David Barri - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/README b/redmine/vendor/plugins/gloc-1.1.0/README deleted file mode 100644 index 66f8e5e9f..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/README +++ /dev/null @@ -1,208 +0,0 @@ -= About - -=== Preface -I originally started designing this on weekends and after work in 2005. We started to become very interested in Rails at work and I wanted to get some experience with ruby with before we started using it full-time. I didn't have very many ideas for anything interesting to create so, because we write a lot of multilingual webapps at my company, I decided to write a localization library. That way if my little hobby project developed into something decent, I could at least put it to good use. -And here we are in 2006, my little hobby project has come a long way and become quite a useful piece of software. Not only do I use it in production sites I write at work, but I also prefer it to other existing alternatives. Therefore I have decided to make it publicly available, and I hope that other developers will find it useful too. - -=== About -GLoc is a localization library. It doesn't aim to do everything l10n-related that you can imagine, but what it does, it does very well. It was originally designed as a Rails plugin, but can also be used for plain ruby projects. Here are a list of its main features: -* Lightweight and efficient. -* Uses file-based string bundles. Strings can also be set directly. -* Intelligent, cascading language configuration. -* Create flexible rules to handle issues such as pluralization. -* Includes a ActionController filter that auto-detects the client language. -* Works perfectly with Rails Engines and allows strings to be overridden just as easily as controllers, models, etc. -* Automatically localizes Rails functions such as distance_in_minutes, select_month etc -* Supports different charsets. You can even specify the encoding to use for each language seperately. -* Special Rails mods/helpers. - -=== What does GLoc mean? -If you're wondering about the name "GLoc", I'm sure you're not alone. -This project was originally just called "Localization" which was a bit too common, so when I decided to release it I decided to call it "Golly's Localization Library" instead (Golly is my nickname), and that was long and boring so I then abbreviated that to "GLoc". What a fun story!! - -=== Localization helpers -This also includes a few helpers for common situations such as displaying localized date, time, "yes" or "no", etc. - -=== Rails Localization -At the moment, unless you manually remove the require 'gloc-rails-text' line from init.rb, this plugin overrides certain Rails functions to provide multilingual versions. This automatically localizes functions such as select_date(), distance_of_time_in_words() and more... -The strings can be found in lang/*.yml. -NOTE: This is not complete. Timezones and countries are not currently localized. - - - - -= Usage - -=== Quickstart - -Windows users will need to first install iconv. http://wiki.rubyonrails.com/rails/pages/iconv - -* Create a dir "#{RAILS_ROOT}/lang" -* Create a file "#{RAILS_ROOT}/lang/en.yml" and write your strings. The format is "key: string". Save it as UTF-8. If you save it in a different encoding, add a key called file_charset (eg. "file_charset: iso-2022-jp") -* Put the following in config/environment.rb and change the values as you see fit. The following example is for an app that uses English and Japanese, with Japanese being the default. - GLoc.set_config :default_language => :ja - GLoc.clear_strings_except :en, :ja - GLoc.set_kcode - GLoc.load_localized_strings -* Add 'include GLoc' to all classes that will use localization. This is added to most Rails classes automatically. -* Optionally, you can set the language for models and controllers by simply inserting set_language :en in classes and/or methods. -* To use localized strings, replace text such as "Welcome" with l(:welcome_string_key), and "Hello #{name}." with l(:hello_string_key, name). (Of course the strings will need to exist in your string bundle.) - -There is more functionality provided by this plugin, that is not demonstrated above. Please read the API summary for details. - -=== API summary - -The following methods are added as both class methods and instance methods to modules/classes that include GLoc. They are also available as class methods of GLoc. - current_language # Returns the current language - l(symbol, *arguments) # Returns a localized string - ll(lang, symbol, *arguments) # Returns a localized string in a specific language - ltry(possible_key) # Returns a localized string if passed a Symbol, else returns the same argument passed - lwr(symbol, *arguments) # Uses the default rule to return a localized string. - lwr_(rule, symbol, *arguments) # Uses a specified rule to return a localized string. - l_has_string?(symbol) # Checks if a localized string exists - set_language(language) # Sets the language for the current class or class instance - set_language_if_valid(lang) # Sets the current language if the language passed is a valid language - -The GLoc module also defines the following class methods: - add_localized_strings(lang, symbol_hash, override=true) # Adds a hash of localized strings - backup_state(clear=false) # Creates a backup of GLoc's internal state and optionally clears everything too - clear_strings(*languages) # Removes localized strings from memory - clear_strings_except(*languages) # Removes localized strings from memory except for those of certain specified languages - get_charset(lang) # Returns the charset used to store localized strings in memory - get_config(key) # Returns a GLoc configuration value (see below) - load_localized_strings(dir=nil, override=true) # Loads localized strings from all YML files in a given directory - restore_state(state) # Restores a backup of GLoc's internal state - set_charset(new_charset, *langs) # Sets the charset used to internally store localized strings - set_config(hash) # Sets GLoc configuration values (see below) - set_kcode(charset=nil) # Sets the $KCODE global variable - similar_language(language) # Tries to find a valid language that is similar to the argument passed - valid_languages # Returns an array of (currently) valid languages (ie. languages for which localized data exists) - valid_language?(language) # Checks whether any localized strings are in memory for a given language - -GLoc uses the following configuration items. They can be accessed via get_config and set_config. - :default_cookie_name - :default_language - :default_param_name - :raise_string_not_found_errors - :verbose - -The GLoc module is automatically included in the following classes: - ActionController::Base - ActionMailer::Base - ActionView::Base - ActionView::Helpers::InstanceTag - ActiveRecord::Base - ActiveRecord::Errors - ApplicationHelper - Test::Unit::TestCase - -The GLoc module also defines the following controller filters: - autodetect_language_filter - -GLoc also makes the following change to Rails: -* Views for ActionMailer are now #{view_name}_#{language}.rb rather than just #{view_name}.rb -* All ActiveRecord validation class methods now accept a localized string key (symbol) as a :message value. -* ActiveRecord::Errors.add now accepts symbols as valid message values. At runtime these symbols are converted to localized strings using the current_language of the base record. -* ActiveRecord::Errors.add now accepts arrays as arguments so that printf-style strings can be generated at runtime. This also applies to the validates_* class methods. - Eg. validates_xxxxxx_of :name, :message => ['Your name must be at least %d characters.', MIN_LEN] - Eg. validates_xxxxxx_of :name, :message => [:user_error_validation_name_too_short, MIN_LEN] -* Instances of ActiveView inherit their current_language from the controller (or mailer) creating them. - -This plugin also adds the following rake tasks: - * gloc:sort - Sorts the keys in the lang ymls (also accepts a DIR argument) - -=== Cascading language configuration - -The language can be set at three levels: - 1. The default # GLoc.get_config :default_language - 2. Class level # class A; set_language :de; end - 3. Instance level # b= B.new; b.set_language :zh - -Instance level has the highest priority and the default has the lowest. - -Because GLoc is included at class level too, it becomes easy to associate languages with contexts. -For example: - class Student - set_language :en - def say_hello - puts "We say #{l :hello} but our teachers say #{Teacher.l :hello}" - end - end - -=== Rules - -There are often situations when depending on the value of one or more variables, the surrounding text -changes. The most common case of this is pluralization. Rather than hardcode these rules, they are -completely definable by the user so that the user can eaasily accomodate for more complicated grammatical -rules such as those found in Russian and Polish (or so I hear). To define a rule, simply include a string -in the string bundle whose key begins with "_gloc_rule_" and then write ruby code as the value. The ruby -code will be converted to a Proc when the string bundle is first read, and should return a prefix that will -be appended to the string key at runtime to point to a new string. Make sense? Probably not... Please look -at the following example and I am sure it will all make sense. - -Simple example (string bundle / en.yml) - _gloc_rule_default: ' |n| n==1 ? "_single" : "_plural" ' - man_count_plural: There are %d men. - man_count_single: There is 1 man. - -Simple example (code) - lwr(:man_count, 1) # => There is 1 man. - lwr(:man_count, 8) # => There are 8 men. - -To use rules other than the default simply call lwr_ instead of lwr, and specify the rule. - -Example #2 (string bundle / en.yml) - _gloc_rule_default: ' |n| n==1 ? "_single" : "_plural" ' - _gloc_rule_custom: ' |n| return "_none" if n==0; return "_heaps" if n>100; n==1 ? "_single" : "_plural" ' - man_count_none: There are no men. - man_count_heaps: There are heaps of men!! - man_count_plural: There are %d men. - man_count_single: There is 1 man. - -Example #2 (code) - lwr_(:custom, :man_count, 0) # => There are no men. - lwr_(:custom, :man_count, 1) # => There is 1 man. - lwr_(:custom, :man_count, 8) # => There are 8 men. - lwr_(:custom, :man_count, 150) # => There are heaps of men!! - - -=== Helpers - -GLoc includes the following helpers: - l_age(age) # Returns a localized version of an age. eg "3 years old" - l_date(date) # Returns a date in a localized format - l_datetime(date) # Returns a date+time in a localized format - l_datetime_short(date) # Returns a date+time in a localized short format. - l_lang_name(l,dl=nil) # Returns the name of a language (you must supply your own strings) - l_strftime(date,fmt) # Formats a date/time in a localized format. - l_time(date) # Returns a time in a localized format - l_YesNo(value) # Returns localized string of "Yes" or "No" depending on the arg - l_yesno(value) # Returns localized string of "yes" or "no" depending on the arg - -=== Rails localization - -Not all of Rails is covered but the following functions are: - distance_of_time_in_words - select_day - select_month - select_year - add_options - - - - -= FAQ - -==== How do I use it in engines? -Simply put this in your init_engine.rb - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') -That way your engines strings will be loaded when the engine is started. Just simply make sure that you load your application strings after you start your engines to safely override any engine strings. - -==== Why am I getting an Iconv::IllegalSequence error when calling GLoc.set_charset? -By default GLoc loads all of its default strings at startup. For example, calling set_charset 'iso-2022-jp' will cause this error because Russian strings are loaded by default, and the Russian strings use characters that cannot be expressed in the ISO-2022-JP charset. -Before calling set_charset you should call clear_strings_except to remove strings from any languages that you will not be using. -Alternatively, you can simply specify the language(s) as follows, set_charset 'iso-2022-jp', :ja. - -==== How do I make GLoc ignore StringNotFoundErrors? -Disable it as follows: - GLoc.set_config :raise_string_not_found_errors => false diff --git a/redmine/vendor/plugins/gloc-1.1.0/Rakefile b/redmine/vendor/plugins/gloc-1.1.0/Rakefile deleted file mode 100644 index a5b8fe762..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/Rakefile +++ /dev/null @@ -1,15 +0,0 @@ -Dir.glob("#{File.dirname(__FILE__)}/tasks/*.rake").each {|f| load f} - -task :default => 'gloc:sort' - -# RDoc task -require 'rake/rdoctask' -Rake::RDocTask.new() { |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = "GLoc Localization Library Documentation" - rdoc.options << '--line-numbers' << '--inline-source' - rdoc.rdoc_files.include('README', 'CHANGELOG') - rdoc.rdoc_files.include('lib/**/*.rb') - rdoc.rdoc_files.exclude('lib/gloc-dev.rb') - rdoc.rdoc_files.exclude('lib/gloc-config.rb') -} diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionController/Filters/ClassMethods.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionController/Filters/ClassMethods.html deleted file mode 100644 index fba33b5b5..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionController/Filters/ClassMethods.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - Module: ActionController::Filters::ClassMethods - - - - - - - - - - -
    - - - - - - - - - - -
    ModuleActionController::Filters::ClassMethods
    In: - - lib/gloc-rails.rb - -
    -
    -
    - - -
    - - - -
    - - - -
    - -
    -

    Methods

    - - -
    - -
    - - - - -
    - - - - - - - - - -
    -

    Public Instance methods

    - -
    - - - - -
    -

    -This filter attempts to auto-detect the clients desired language. It first -checks the params, then a cookie and then the HTTP_ACCEPT_LANGUAGE request -header. If a language is found to match or be similar to a currently valid -language, then it sets the current_language of the controller. -

    -
    -  class ExampleController < ApplicationController
    -    set_language :en
    -    autodetect_language_filter :except => 'monkey', :on_no_lang => :lang_not_autodetected_callback
    -    autodetect_language_filter :only => 'monkey', :check_cookie => 'monkey_lang', :check_accept_header => false
    -    ...
    -    def lang_not_autodetected_callback
    -      redirect_to somewhere
    -    end
    -  end
    -
    -

    -The args for this filter are exactly the same the arguments of -before_filter with the following exceptions: -

    -
      -
    • :check_params — If false, then params will not be checked -for a language. If a String, then this will value will be used as the name -of the param. - -
    • -
    • :check_cookie — If false, then the cookie will not be -checked for a language. If a String, then this will value will be used as -the name of the cookie. - -
    • -
    • :check_accept_header — If false, then HTTP_ACCEPT_LANGUAGE -will not be checked for a language. - -
    • -
    • :on_set_lang — You can specify the name of a callback -function to be called when the language is successfully detected and set. -The param must be a Symbol or a String which is the name of the function. -The callback function must accept one argument (the language) and must be -instance level. - -
    • -
    • :on_no_lang — You can specify the name of a callback -function to be called when the language couldn’t be detected -automatically. The param must be a Symbol or a String which is the name of -the function. The callback function must be instance level. - -
    • -
    -

    -You override the default names of the param or cookie by calling GLoc.set_config :default_param_name -=> ‘new_param_name‘ and GLoc.set_config :default_cookie_name -=> ‘new_cookie_name‘. -

    -

    [Source]

    -
    -
    -    # File lib/gloc-rails.rb, line 43
    -43:       def autodetect_language_filter(*args)
    -44:         options= args.last.is_a?(Hash) ? args.last : {}
    -45:         x= 'Proc.new { |c| l= nil;'
    -46:         # :check_params
    -47:         unless (v= options.delete(:check_params)) == false
    -48:           name= v ? ":#{v}" : 'GLoc.get_config(:default_param_name)'
    -49:           x << "l ||= GLoc.similar_language(c.params[#{name}]);"
    -50:         end
    -51:         # :check_cookie
    -52:         unless (v= options.delete(:check_cookie)) == false
    -53:           name= v ? ":#{v}" : 'GLoc.get_config(:default_cookie_name)'
    -54:           x << "l ||= GLoc.similar_language(c.send(:cookies)[#{name}]);"
    -55:         end
    -56:         # :check_accept_header
    -57:         unless options.delete(:check_accept_header) == false
    -58:           x << %<
    -59:               unless l
    -60:                 a= c.request.env['HTTP_ACCEPT_LANGUAGE'].split(/,|;/) rescue nil
    -61:                 a.each {|x| l ||= GLoc.similar_language(x)} if a
    -62:               end; >
    -63:         end
    -64:         # Set language
    -65:         x << 'ret= true;'
    -66:         x << 'if l; c.set_language(l); c.headers[\'Content-Language\']= l.to_s; '
    -67:         if options.has_key?(:on_set_lang)
    -68:           x << "ret= c.#{options.delete(:on_set_lang)}(l);"
    -69:         end
    -70:         if options.has_key?(:on_no_lang)
    -71:           x << "else; ret= c.#{options.delete(:on_no_lang)};"
    -72:         end
    -73:         x << 'end; ret }'
    -74:         
    -75:         # Create filter
    -76:         block= eval x
    -77:         before_filter(*args, &block)
    -78:       end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionMailer/Base.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionMailer/Base.html deleted file mode 100644 index 056b23d85..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionMailer/Base.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - Class: ActionMailer::Base - - - - - - - - - - -
    - - - - - - - - - - - - - - -
    ClassActionMailer::Base
    In: - - lib/gloc-rails.rb - -
    -
    Parent: - Object -
    -
    - - -
    - - - -
    - -
    -

    -In addition to including GLoc, -render_message is also overridden so that mail templates contain -the current language at the end of the file. Eg. deliver_hello -will render hello_en.rhtml. -

    - -
    - - -
    - - -
    - - - -
    -

    Included Modules

    - -
    - GLoc -
    -
    - -
    - - - -
    -

    External Aliases

    - -
    - - - - - - -
    render_message->render_message_without_gloc
    -
    -
    - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Base.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Base.html deleted file mode 100644 index 00767055d..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Base.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - Class: ActionView::Base - - - - - - - - - - -
    - - - - - - - - - - - - - - -
    ClassActionView::Base
    In: - - lib/gloc-rails.rb - -
    -
    Parent: - Object -
    -
    - - -
    - - - -
    - -
    -

    -initialize is overridden so that new instances of this class -inherit the current language of the controller. -

    - -
    - - -
    - -
    -

    Methods

    - -
    - new   -
    -
    - -
    - - - -
    -

    Included Modules

    - -
    - GLoc -
    -
    - -
    - - - -
    -

    External Aliases

    - -
    - - - - - - -
    initialize->initialize_without_gloc
    -
    -
    - - - - - - -
    -

    Public Class methods

    - -
    - - - - -
    -

    [Source]

    -
    -
    -     # File lib/gloc-rails.rb, line 109
    -109:     def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)
    -110:       initialize_without_gloc(base_path, assigns_for_first_render, controller)
    -111:       set_language controller.current_language unless controller.nil?
    -112:     end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/DateHelper.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/DateHelper.html deleted file mode 100644 index 84ca8fae3..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/DateHelper.html +++ /dev/null @@ -1,348 +0,0 @@ - - - - - - Module: ActionView::Helpers::DateHelper - - - - - - - - - - -
    - - - - - - - - - - -
    ModuleActionView::Helpers::DateHelper
    In: - - lib/gloc-rails-text.rb - -
    -
    -
    - - -
    - - - -
    - - - -
    - -
    -

    Methods

    - - -
    - -
    - - - - -
    - - -
    -

    Constants

    - -
    - - - - - - - - - - - - - - - - -
    LOCALIZED_HELPERS=true
    LOCALIZED_MONTHNAMES={}
    LOCALIZED_ABBR_MONTHNAMES={}
    -
    -
    - - - - - - - -
    -

    Public Instance methods

    - -
    - - - - -
    -

    -This method uses current_language to return a localized string. -

    -

    [Source]

    -
    -
    -    # File lib/gloc-rails-text.rb, line 16
    -16:       def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
    -17:         from_time = from_time.to_time if from_time.respond_to?(:to_time)
    -18:         to_time = to_time.to_time if to_time.respond_to?(:to_time)
    -19:         distance_in_minutes = (((to_time - from_time).abs)/60).round
    -20:         distance_in_seconds = ((to_time - from_time).abs).round
    -21: 
    -22:         case distance_in_minutes
    -23:           when 0..1
    -24:             return (distance_in_minutes==0) ? l(:actionview_datehelper_time_in_words_minute_less_than) : l(:actionview_datehelper_time_in_words_minute_single) unless include_seconds
    -25:             case distance_in_seconds
    -26:               when 0..5   then lwr(:actionview_datehelper_time_in_words_second_less_than, 5)
    -27:               when 6..10  then lwr(:actionview_datehelper_time_in_words_second_less_than, 10)
    -28:               when 11..20 then lwr(:actionview_datehelper_time_in_words_second_less_than, 20)
    -29:               when 21..40 then l(:actionview_datehelper_time_in_words_minute_half)
    -30:               when 41..59 then l(:actionview_datehelper_time_in_words_minute_less_than)
    -31:               else             l(:actionview_datehelper_time_in_words_minute)
    -32:             end
    -33:                                 
    -34:           when 2..45      then lwr(:actionview_datehelper_time_in_words_minute, distance_in_minutes)
    -35:           when 46..90     then l(:actionview_datehelper_time_in_words_hour_about_single)
    -36:           when 90..1440   then lwr(:actionview_datehelper_time_in_words_hour_about, (distance_in_minutes.to_f / 60.0).round)
    -37:           when 1441..2880 then lwr(:actionview_datehelper_time_in_words_day, 1)
    -38:           else                 lwr(:actionview_datehelper_time_in_words_day, (distance_in_minutes / 1440).round)
    -39:         end
    -40:       end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -This method has been modified so that a localized string can be appended to -the day numbers. -

    -

    [Source]

    -
    -
    -    # File lib/gloc-rails-text.rb, line 43
    -43:       def select_day(date, options = {})
    -44:         day_options = []
    -45:         prefix = l :actionview_datehelper_select_day_prefix
    -46: 
    -47:         1.upto(31) do |day|
    -48:           day_options << ((date && (date.kind_of?(Fixnum) ? date : date.day) == day) ?
    -49:             %(<option value="#{day}" selected="selected">#{day}#{prefix}</option>\n) :
    -50:             %(<option value="#{day}">#{day}#{prefix}</option>\n)
    -51:           )
    -52:         end
    -53: 
    -54:         select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
    -55:       end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -This method has been modified so that -

    -
      -
    • the month names are localized. - -
    • -
    • it uses options: :min_date, :max_date, -:start_month, :end_month - -
    • -
    • a localized string can be appended to the month numbers when the -:use_month_numbers option is specified. - -
    • -
    -

    [Source]

    -
    -
    -    # File lib/gloc-rails-text.rb, line 61
    -61:       def select_month(date, options = {})
    -62:         unless LOCALIZED_MONTHNAMES.has_key?(current_language)
    -63:           LOCALIZED_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names).split(',')
    -64:           LOCALIZED_ABBR_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names_abbr).split(',')
    -65:         end
    -66:         
    -67:         month_options = []
    -68:         month_names = options[:use_short_month] ? LOCALIZED_ABBR_MONTHNAMES[current_language] : LOCALIZED_MONTHNAMES[current_language]
    -69:         
    -70:         if options.has_key?(:min_date) && options.has_key?(:max_date)
    -71:           if options[:min_date].year == options[:max_date].year
    -72:             start_month, end_month = options[:min_date].month, options[:max_date].month
    -73:           end
    -74:         end
    -75:         start_month = (options[:start_month] || 1) unless start_month
    -76:         end_month = (options[:end_month] || 12) unless end_month
    -77:         prefix = l :actionview_datehelper_select_month_prefix
    -78: 
    -79:         start_month.upto(end_month) do |month_number|
    -80:           month_name = if options[:use_month_numbers]
    -81:             "#{month_number}#{prefix}"
    -82:           elsif options[:add_month_numbers]
    -83:             month_number.to_s + ' - ' + month_names[month_number]
    -84:           else
    -85:             month_names[month_number]
    -86:           end
    -87: 
    -88:           month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ?
    -89:             %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
    -90:             %(<option value="#{month_number}">#{month_name}</option>\n)
    -91:           )
    -92:         end
    -93: 
    -94:         select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
    -95:       end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -This method has been modified so that -

    -
      -
    • it uses options: :min_date, :max_date - -
    • -
    • a localized string can be appended to the years numbers. - -
    • -
    -

    [Source]

    -
    -
    -     # File lib/gloc-rails-text.rb, line 100
    -100:       def select_year(date, options = {})
    -101:         year_options = []
    -102:         y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year
    -103: 
    -104:         start_year = options.has_key?(:min_date) ? options[:min_date].year : (options[:start_year] || y-5)
    -105:         end_year = options.has_key?(:max_date) ? options[:max_date].year : (options[:end_year] || y+5)
    -106:         step_val = start_year < end_year ? 1 : -1
    -107:         prefix = l :actionview_datehelper_select_year_prefix
    -108: 
    -109:         start_year.step(end_year, step_val) do |year|
    -110:           year_options << ((date && (date.kind_of?(Fixnum) ? date : date.year) == year) ?
    -111:             %(<option value="#{year}" selected="selected">#{year}#{prefix}</option>\n) :
    -112:             %(<option value="#{year}">#{year}#{prefix}</option>\n)
    -113:           )
    -114:         end
    -115: 
    -116:         select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
    -117:       end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/InstanceTag.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/InstanceTag.html deleted file mode 100644 index a236e0e5d..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/InstanceTag.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - Class: ActionView::Helpers::InstanceTag - - - - - - - - - - -
    - - - - - - - - - - - - - - -
    ClassActionView::Helpers::InstanceTag
    In: - - lib/gloc-rails-text.rb - -
    - - lib/gloc-rails.rb - -
    -
    Parent: - Object -
    -
    - - -
    - - - -
    - -
    -

    -The private method add_options is overridden so that "Please -select" is localized. -

    - -
    - - -
    - -
    -

    Methods

    - - -
    - -
    - - - -
    -

    Included Modules

    - -
    - GLoc -
    -
    - -
    - - - - - - - - - -
    -

    Public Instance methods

    - -
    - - - - -
    -

    -Inherits the current language from the template object. -

    -

    [Source]

    -
    -
    -     # File lib/gloc-rails.rb, line 119
    -119:       def current_language
    -120:         @template_object.current_language
    -121:       end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Errors.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Errors.html deleted file mode 100644 index 9a16f608b..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Errors.html +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - Class: ActiveRecord::Errors - - - - - - - - - - -
    - - - - - - - - - - - - - - -
    ClassActiveRecord::Errors
    In: - - lib/gloc-rails.rb - -
    -
    Parent: - Object -
    -
    - - -
    - - - -
    - - - -
    - -
    -

    Methods

    - -
    - add   - current_language   -
    -
    - -
    - - - -
    -

    Included Modules

    - -
    - GLoc -
    -
    - -
    - - - -
    -

    External Aliases

    - -
    - - - - - - -
    add->add_without_gloc
    -
    -
    - - - - - - -
    -

    Public Instance methods

    - -
    - - - - -
    -

    -The GLoc version of this method provides two -extra features -

    -
      -
    • If msg is a string, it will be considered a GLoc string key. - -
    • -
    • If msg is an array, the first element will be considered the -string and the remaining elements will be considered arguments for the -string. Eg. [‘Hi %s.’,’John’] - -
    • -
    -

    [Source]

    -
    -
    -     # File lib/gloc-rails.rb, line 141
    -141:     def add(attribute, msg= @@default_error_messages[:invalid])
    -142:       if msg.is_a?(Array)
    -143:         args= msg.clone
    -144:         msg= args.shift
    -145:         args= nil if args.empty?
    -146:       end
    -147:       msg= ltry(msg)
    -148:       msg= msg % args unless args.nil?
    -149:       add_without_gloc(attribute, msg)
    -150:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Inherits the current language from the base record. -

    -

    [Source]

    -
    -
    -     # File lib/gloc-rails.rb, line 152
    -152:     def current_language
    -153:       @base.current_language
    -154:     end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Validations/ClassMethods.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Validations/ClassMethods.html deleted file mode 100644 index 145a74c2b..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Validations/ClassMethods.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - Module: ActiveRecord::Validations::ClassMethods - - - - - - - - - - -
    - - - - - - - - - - -
    ModuleActiveRecord::Validations::ClassMethods
    In: - - lib/gloc-rails.rb - -
    -
    -
    - - -
    - - - -
    - - - -
    - -
    -

    Methods

    - - -
    - -
    - - - - -
    - - - - - - - - - -
    -

    Public Instance methods

    - -
    - - - - -
    -

    -The default Rails version of this function creates an error message and -then passes it to ActiveRecord.Errors. The GLoc version of this method, sends an array to -ActiveRecord.Errors that will be turned into a -string by ActiveRecord.Errors which in turn -allows for the message of this validation function to be a GLoc string key. -

    -

    [Source]

    -
    -
    -     # File lib/gloc-rails.rb, line 164
    -164:       def validates_length_of(*attrs)
    -165:         # Merge given options with defaults.
    -166:         options = {
    -167:           :too_long     => ActiveRecord::Errors.default_error_messages[:too_long],
    -168:           :too_short    => ActiveRecord::Errors.default_error_messages[:too_short],
    -169:           :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]
    -170:         }.merge(DEFAULT_VALIDATION_OPTIONS)
    -171:         options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash)
    -172: 
    -173:         # Ensure that one and only one range option is specified.
    -174:         range_options = ALL_RANGE_OPTIONS & options.keys
    -175:         case range_options.size
    -176:           when 0
    -177:             raise ArgumentError, 'Range unspecified.  Specify the :within, :maximum, :minimum, or :is option.'
    -178:           when 1
    -179:             # Valid number of options; do nothing.
    -180:           else
    -181:             raise ArgumentError, 'Too many range options specified.  Choose only one.'
    -182:         end
    -183: 
    -184:         # Get range option and value.
    -185:         option = range_options.first
    -186:         option_value = options[range_options.first]
    -187: 
    -188:         case option
    -189:         when :within, :in
    -190:           raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range)
    -191: 
    -192:           too_short = [options[:too_short] , option_value.begin]
    -193:           too_long  = [options[:too_long]  , option_value.end  ]
    -194: 
    -195:           validates_each(attrs, options) do |record, attr, value|
    -196:             if value.nil? or value.split(//).size < option_value.begin
    -197:               record.errors.add(attr, too_short)
    -198:             elsif value.split(//).size > option_value.end
    -199:               record.errors.add(attr, too_long)
    -200:             end
    -201:           end
    -202:         when :is, :minimum, :maximum
    -203:           raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0
    -204: 
    -205:           # Declare different validations per option.
    -206:           validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
    -207:           message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
    -208: 
    -209:           message = [(options[:message] || options[message_options[option]]) , option_value]
    -210: 
    -211:           validates_each(attrs, options) do |record, attr, value|
    -212:             if value.kind_of?(String)
    -213:               record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value]
    -214:             else
    -215:               record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]
    -216:             end
    -217:           end
    -218:         end
    -219:       end
    -
    -
    -
    -
    - -
    - - -
    - validates_size_of(*attrs) -
    - -
    -

    -Alias for validates_length_of -

    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html deleted file mode 100644 index 8a25c7de8..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html +++ /dev/null @@ -1,774 +0,0 @@ - - - - - - Module: GLoc - - - - - - - - - - - - - -
    - - - -
    - -
    -

    -Copyright © 2005-2006 David Barri -

    - -
    - - -
    - - - -
    - - - -
    -

    Included Modules

    - - -
    - -
    - -
    -

    Classes and Modules

    - - Module GLoc::ClassMethods
    -Module GLoc::Helpers
    -Module GLoc::InstanceMethods
    - -
    - -
    -

    Constants

    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    LOCALIZED_STRINGS={}
    RULES={}
    LOWERCASE_LANGUAGES={}
    UTF_8='utf-8'
    SHIFT_JIS='sjis'
    EUC_JP='euc-jp'
    -
    -
    - -
    -

    External Aliases

    - -
    - - - - - - -
    clear_strings->_clear_strings
    -
    -
    - - - - - - -
    -

    Public Class methods

    - -
    - - - - -
    -

    -Adds a collection of localized strings to the in-memory string store. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 113
    -113:     def add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil)
    -114:       _verbose_msg {"Adding #{symbol_hash.size} #{lang} strings."}
    -115:       _add_localized_strings(lang, symbol_hash, override, strings_charset)
    -116:       _verbose_msg :stats
    -117:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Creates a backup of the internal state of GLoc (ie. -strings, langs, rules, config) and optionally clears everything. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 121
    -121:     def backup_state(clear=false)
    -122:       s= _get_internal_state_vars.map{|o| o.clone}
    -123:       _get_internal_state_vars.each{|o| o.clear} if clear
    -124:       s
    -125:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Removes all localized strings from memory, either of a certain language (or -languages), or entirely. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 129
    -129:     def clear_strings(*languages)
    -130:       if languages.empty?
    -131:         _verbose_msg {"Clearing all strings"}
    -132:         LOCALIZED_STRINGS.clear
    -133:         LOWERCASE_LANGUAGES.clear
    -134:       else
    -135:         languages.each {|l|
    -136:           _verbose_msg {"Clearing :#{l} strings"}
    -137:           l= l.to_sym
    -138:           LOCALIZED_STRINGS.delete l
    -139:           LOWERCASE_LANGUAGES.each_pair {|k,v| LOWERCASE_LANGUAGES.delete k if v == l}
    -140:         }
    -141:       end
    -142:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Removes all localized strings from memory, except for those of certain -specified languages. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 146
    -146:     def clear_strings_except(*languages)
    -147:       clear= (LOCALIZED_STRINGS.keys - languages)
    -148:       _clear_strings(*clear) unless clear.empty?
    -149:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Returns the default language -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 108
    -108:     def current_language
    -109:       GLoc::CONFIG[:default_language]
    -110:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Returns the charset used to store localized strings in memory. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 152
    -152:     def get_charset(lang)
    -153:       CONFIG[:internal_charset_per_lang][lang] || CONFIG[:internal_charset]
    -154:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Returns a GLoc configuration value. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 157
    -157:     def get_config(key)
    -158:       CONFIG[key]
    -159:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Loads the localized strings that are included in the GLoc library. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 162
    -162:     def load_gloc_default_localized_strings(override=false)
    -163:       GLoc.load_localized_strings "#{File.dirname(__FILE__)}/../lang", override
    -164:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Loads localized strings from all yml files in the specifed directory. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 167
    -167:     def load_localized_strings(dir=nil, override=true)
    -168:       _charset_required
    -169:       _get_lang_file_list(dir).each {|filename|
    -170:         
    -171:         # Load file
    -172:         raw_hash = YAML::load(File.read(filename))
    -173:         raw_hash={} unless raw_hash.kind_of?(Hash)
    -174:         filename =~ /([^\/\\]+)\.ya?ml$/
    -175:         lang = $1.to_sym
    -176:         file_charset = raw_hash['file_charset'] || UTF_8
    -177:   
    -178:         # Convert string keys to symbols
    -179:         dest_charset= get_charset(lang)
    -180:         _verbose_msg {"Reading file #{filename} [charset: #{file_charset} --> #{dest_charset}]"}
    -181:         symbol_hash = {}
    -182:         Iconv.open(dest_charset, file_charset) do |i|
    -183:           raw_hash.each {|key, value|
    -184:             symbol_hash[key.to_sym] = i.iconv(value)
    -185:           }
    -186:         end
    -187:   
    -188:         # Add strings to repos
    -189:         _add_localized_strings(lang, symbol_hash, override)
    -190:       }
    -191:       _verbose_msg :stats
    -192:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Restores a backup of GLoc’s internal state -that was made with backup_state. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 195
    -195:     def restore_state(state)
    -196:       _get_internal_state_vars.each do |o|
    -197:         o.clear
    -198:         o.send o.respond_to?(:merge!) ? :merge! : :concat, state.shift
    -199:       end
    -200:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Sets the charset used to internally store localized strings. You can set -the charset to use for a specific language or languages, or if none are -specified the charset for ALL localized strings will be set. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 205
    -205:     def set_charset(new_charset, *langs)
    -206:       CONFIG[:internal_charset_per_lang] ||= {}
    -207:       
    -208:       # Convert symbol shortcuts
    -209:       if new_charset.is_a?(Symbol)
    -210:         new_charset= case new_charset
    -211:           when :utf8, :utf_8 then UTF_8
    -212:           when :sjis, :shift_jis, :shiftjis then SHIFT_JIS
    -213:           when :eucjp, :euc_jp then EUC_JP
    -214:           else new_charset.to_s
    -215:           end
    -216:       end
    -217:       
    -218:       # Convert existing strings
    -219:       (langs.empty? ? LOCALIZED_STRINGS.keys : langs).each do |lang|
    -220:         cur_charset= get_charset(lang)
    -221:         if cur_charset && new_charset != cur_charset
    -222:           _verbose_msg {"Converting :#{lang} strings from #{cur_charset} to #{new_charset}"}
    -223:           Iconv.open(new_charset, cur_charset) do |i|
    -224:             bundle= LOCALIZED_STRINGS[lang]
    -225:             bundle.each_pair {|k,v| bundle[k]= i.iconv(v)}
    -226:           end
    -227:         end
    -228:       end
    -229:       
    -230:       # Set new charset value
    -231:       if langs.empty?
    -232:         _verbose_msg {"Setting GLoc charset for all languages to #{new_charset}"}
    -233:         CONFIG[:internal_charset]= new_charset
    -234:         CONFIG[:internal_charset_per_lang].clear
    -235:       else
    -236:         langs.each do |lang|
    -237:           _verbose_msg {"Setting GLoc charset for :#{lang} strings to #{new_charset}"}
    -238:           CONFIG[:internal_charset_per_lang][lang]= new_charset
    -239:         end
    -240:       end
    -241:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Sets GLoc configuration values. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 244
    -244:     def set_config(hash)
    -245:       CONFIG.merge! hash
    -246:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Sets the $KCODE global variable according to a specified charset, or else -the current default charset for the default language. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 250
    -250:     def set_kcode(charset=nil)
    -251:       _charset_required
    -252:       charset ||= get_charset(current_language)
    -253:       $KCODE= case charset
    -254:         when UTF_8 then 'u'
    -255:         when SHIFT_JIS then 's'
    -256:         when EUC_JP then 'e'
    -257:         else 'n'
    -258:         end
    -259:       _verbose_msg {"$KCODE set to #{$KCODE}"}
    -260:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Tries to find a valid language that is similar to the argument passed. Eg. -:en, :en_au, :EN_US are all similar languages. Returns nil if no -similar languages are found. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 265
    -265:     def similar_language(lang)
    -266:       return nil if lang.nil?
    -267:       return lang.to_sym if valid_language?(lang)
    -268:       # Check lowercase without dashes
    -269:       lang= lang.to_s.downcase.gsub('-','_')
    -270:       return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang)
    -271:       # Check without dialect
    -272:       if lang.to_s =~ /^([a-z]+?)[^a-z].*/
    -273:         lang= $1
    -274:         return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang)
    -275:       end
    -276:       # Check other dialects
    -277:       lang= "#{lang}_"
    -278:       LOWERCASE_LANGUAGES.keys.each {|k| return LOWERCASE_LANGUAGES[k] if k.starts_with?(lang)}
    -279:       # Nothing found
    -280:       nil
    -281:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Returns true if there are any localized strings for a specified -language. Note that although set_langauge nil is perfectly valid, -nil is not a valid language. -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 290
    -290:     def valid_language?(language)
    -291:       LOCALIZED_STRINGS.has_key? language.to_sym rescue false
    -292:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Returns an array of (currently) valid languages (ie. languages for which -localized data exists). -

    -

    [Source]

    -
    -
    -     # File lib/gloc.rb, line 284
    -284:     def valid_languages
    -285:       LOCALIZED_STRINGS.keys
    -286:     end
    -
    -
    -
    -
    - -

    Public Instance methods

    - -
    - - - - -
    -

    -Returns the instance-level current language, or if not set, returns the -class-level current language. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 77
    -77:   def current_language
    -78:     @gloc_language || self.class.current_language
    -79:   end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/ClassMethods.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/ClassMethods.html deleted file mode 100644 index ba1a28ad0..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/ClassMethods.html +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - Module: GLoc::ClassMethods - - - - - - - - - - -
    - - - - - - - - - - -
    ModuleGLoc::ClassMethods
    In: - - lib/gloc.rb - -
    -
    -
    - - -
    - - - -
    - -
    -

    -All classes/modules that include GLoc will also -gain these class methods. Notice that the GLoc::InstanceMethods module is also -included. -

    - -
    - - -
    - -
    -

    Methods

    - - -
    - -
    - - - -
    -

    Included Modules

    - - -
    - -
    - - - - - - - - - -
    -

    Public Instance methods

    - -
    - - - - -
    -

    -Returns the current language, or if not set, returns the GLoc current language. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 89
    -89:     def current_language
    -90:       @gloc_language || GLoc.current_language
    -91:     end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/Helpers.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/Helpers.html deleted file mode 100644 index f3fdf63e1..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/Helpers.html +++ /dev/null @@ -1,323 +0,0 @@ - - - - - - Module: GLoc::Helpers - - - - - - - - - - -
    - - - - - - - - - - -
    ModuleGLoc::Helpers
    In: - - lib/gloc-helpers.rb - -
    -
    -
    - - -
    - - - -
    - -
    -

    -These helper methods will be included in the InstanceMethods module. -

    - -
    - - -
    - -
    -

    Methods

    - -
    - l_YesNo   - l_age   - l_date   - l_datetime   - l_datetime_short   - l_lang_name   - l_strftime   - l_time   - l_yesno   -
    -
    - -
    - - - - -
    - - - - - - - - - -
    -

    Public Instance methods

    - -
    - - - - -
    -

    [Source]

    -
    -
    -    # File lib/gloc-helpers.rb, line 12
    -12:     def l_YesNo(value)         l(value ? :general_text_Yes : :general_text_No) end
    -
    -
    -
    -
    - -
    - - - - -
    -

    [Source]

    -
    -
    -   # File lib/gloc-helpers.rb, line 6
    -6:     def l_age(age)             lwr :general_fmt_age, age end
    -
    -
    -
    -
    - -
    - - - - -
    -

    [Source]

    -
    -
    -   # File lib/gloc-helpers.rb, line 7
    -7:     def l_date(date)           l_strftime date, :general_fmt_date end
    -
    -
    -
    -
    - -
    - - - - -
    -

    [Source]

    -
    -
    -   # File lib/gloc-helpers.rb, line 8
    -8:     def l_datetime(date)       l_strftime date, :general_fmt_datetime end
    -
    -
    -
    -
    - -
    - - - - -
    -

    [Source]

    -
    -
    -   # File lib/gloc-helpers.rb, line 9
    -9:     def l_datetime_short(date) l_strftime date, :general_fmt_datetime_short end
    -
    -
    -
    -
    - -
    - - - - -
    -

    [Source]

    -
    -
    -    # File lib/gloc-helpers.rb, line 15
    -15:     def l_lang_name(lang, display_lang=nil)
    -16:       ll display_lang || current_language, "general_lang_#{lang}"
    -17:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    [Source]

    -
    -
    -    # File lib/gloc-helpers.rb, line 10
    -10:     def l_strftime(date,fmt)   date.strftime l(fmt) end
    -
    -
    -
    -
    - -
    - - - - -
    -

    [Source]

    -
    -
    -    # File lib/gloc-helpers.rb, line 11
    -11:     def l_time(time)           l_strftime time, :general_fmt_time end
    -
    -
    -
    -
    - -
    - - - - -
    -

    [Source]

    -
    -
    -    # File lib/gloc-helpers.rb, line 13
    -13:     def l_yesno(value)         l(value ? :general_text_yes : :general_text_no) end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/InstanceMethods.html b/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/InstanceMethods.html deleted file mode 100644 index 4e15c9383..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/InstanceMethods.html +++ /dev/null @@ -1,364 +0,0 @@ - - - - - - Module: GLoc::InstanceMethods - - - - - - - - - - -
    - - - - - - - - - - -
    ModuleGLoc::InstanceMethods
    In: - - lib/gloc.rb - -
    -
    -
    - - -
    - - - -
    - -
    -

    -This module will be included in both instances and classes of GLoc includees. It is also included as class -methods in the GLoc module itself. -

    - -
    - - -
    - -
    -

    Methods

    - -
    - l   - l_has_string?   - ll   - ltry   - lwr   - lwr_   - set_language   - set_language_if_valid   -
    -
    - -
    - - - -
    -

    Included Modules

    - -
    - Helpers -
    -
    - -
    - - - - - - - - - -
    -

    Public Instance methods

    - -
    - - - - -
    -

    -Returns a localized string. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 18
    -18:     def l(symbol, *arguments)
    -19:       return GLoc._l(symbol,current_language,*arguments)
    -20:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Returns true if a localized string with the specified key exists. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 48
    -48:     def l_has_string?(symbol)
    -49:       return GLoc._l_has_string?(symbol,current_language)
    -50:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Returns a localized string in a specified language. This does not effect -current_language. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 24
    -24:     def ll(lang, symbol, *arguments)
    -25:       return GLoc._l(symbol,lang.to_sym,*arguments)
    -26:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Returns a localized string if the argument is a Symbol, else just returns -the argument. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 29
    -29:     def ltry(possible_key)
    -30:       possible_key.is_a?(Symbol) ? l(possible_key) : possible_key
    -31:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Uses the default GLoc rule to return a localized -string. See lwr_() for more info. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 35
    -35:     def lwr(symbol, *arguments)
    -36:       lwr_(:default, symbol, *arguments)
    -37:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Uses a rule to return a localized string. A rule is a function -that uses specified arguments to return a localization key prefix. The -prefix is appended to the localization key originally specified, to create -a new key which is then used to lookup a localized string. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 43
    -43:     def lwr_(rule, symbol, *arguments)
    -44:       GLoc._l("#{symbol}#{GLoc::_l_rule(rule,current_language).call(*arguments)}",current_language,*arguments)
    -45:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Sets the current language for this instance/class. Setting the language of -a class effects all instances unless the instance has its own language -defined. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 54
    -54:     def set_language(language)
    -55:       @gloc_language= language.nil? ? nil : language.to_sym
    -56:     end
    -
    -
    -
    -
    - -
    - - - - -
    -

    -Sets the current language if the language passed is a valid language. If -the language was valid, this method returns true else it will -return false. Note that nil is not a valid language. See -set_language(language) for more -info. -

    -

    [Source]

    -
    -
    -    # File lib/gloc.rb, line 62
    -62:     def set_language_if_valid(language)
    -63:       if GLoc.valid_language?(language)
    -64:         set_language(language)
    -65:         true
    -66:       else
    -67:         false
    -68:       end
    -69:     end
    -
    -
    -
    -
    - - -
    - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/created.rid b/redmine/vendor/plugins/gloc-1.1.0/doc/created.rid deleted file mode 100644 index eba9efa29..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/created.rid +++ /dev/null @@ -1 +0,0 @@ -Sun May 28 15:21:13 E. Australia Standard Time 2006 diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html deleted file mode 100644 index aec36c5bf..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - File: CHANGELOG - - - - - - - - - - -
    -

    CHANGELOG

    - - - - - - - - - -
    Path:CHANGELOG -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - -
    -

    Version 1.1 (28 May 2006)

    -
      -
    • The charset for each and/or all languages can now be easily configured. - -
    • -
    • Added a ActionController filter that auto-detects the client language. - -
    • -
    • The rake task "sort" now merges lines that match 100%, and warns -if duplicate keys are found. - -
    • -
    • Rule support. Create flexible rules to handle issues such as pluralization. - -
    • -
    • Massive speed and stability improvements to development mode. - -
    • -
    • Added Russian strings. (Thanks to Evgeny Lineytsev) - -
    • -
    • Complete RDoc documentation. - -
    • -
    • Improved helpers. - -
    • -
    • GLoc now configurable via get_config and -set_config - -
    • -
    • Added an option to tell GLoc to output -various verbose information. - -
    • -
    • More useful functions such as set_language_if_valid, similar_language - -
    • -
    • GLoc’s entire internal state can -now be backed up and restored. - -
    • -
    -

    Version 1.0 (17 April 2006)

    -
      -
    • Initial public release. - -
    • -
    - -
    - - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/README.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/README.html deleted file mode 100644 index d078659d2..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/README.html +++ /dev/null @@ -1,480 +0,0 @@ - - - - - - File: README - - - - - - - - - - -
    -

    README

    - - - - - - - - - -
    Path:README -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - -
    -

    About

    -

    Preface

    -

    -I originally started designing this on weekends and after work in 2005. We -started to become very interested in Rails at work and I wanted to get some -experience with ruby with before we started using it full-time. I -didn’t have very many ideas for anything interesting to create so, -because we write a lot of multilingual webapps at my company, I decided to -write a localization library. That way if my little hobby project developed -into something decent, I could at least put it to good use. And here we are -in 2006, my little hobby project has come a long way and become quite a -useful piece of software. Not only do I use it in production sites I write -at work, but I also prefer it to other existing alternatives. Therefore I -have decided to make it publicly available, and I hope that other -developers will find it useful too. -

    -

    About

    -

    -GLoc is a localization library. It -doesn’t aim to do everything l10n-related that you can imagine, but -what it does, it does very well. It was originally designed as a Rails -plugin, but can also be used for plain ruby projects. Here are a list of -its main features: -

    -
      -
    • Lightweight and efficient. - -
    • -
    • Uses file-based string bundles. Strings can also be set directly. - -
    • -
    • Intelligent, cascading language configuration. - -
    • -
    • Create flexible rules to handle issues such as pluralization. - -
    • -
    • Includes a ActionController filter that auto-detects the client language. - -
    • -
    • Works perfectly with Rails Engines and allows strings to be overridden just -as easily as controllers, models, etc. - -
    • -
    • Automatically localizes Rails functions such as distance_in_minutes, -select_month etc - -
    • -
    • Supports different charsets. You can even specify the encoding to use for -each language seperately. - -
    • -
    • Special Rails mods/helpers. - -
    • -
    -

    What does GLoc mean?

    -

    -If you’re wondering about the name "GLoc", I’m sure you’re not -alone. This project was originally just called "Localization" -which was a bit too common, so when I decided to release it I decided to -call it "Golly’s Localization Library" instead (Golly is my -nickname), and that was long and boring so I then abbreviated that to -"GLoc". What a fun story!! -

    -

    Localization helpers

    -

    -This also includes a few helpers for common situations such as displaying -localized date, time, "yes" or "no", etc. -

    -

    Rails Localization

    -

    -At the moment, unless you manually remove the require -‘gloc-rails-text’ line from init.rb, this plugin overrides -certain Rails functions to provide multilingual versions. This -automatically localizes functions such as select_date(), -distance_of_time_in_words() and more… The strings can be found in -lang/*.yml. NOTE: This is not complete. Timezones and countries are not -currently localized. -

    -

    Usage

    -

    Quickstart

    -

    -Windows users will need to first install iconv. wiki.rubyonrails.com/rails/pages/iconv -

    -
      -
    • Create a dir "#{RAILS_ROOT}/lang" - -
    • -
    • Create a file "#{RAILS_ROOT}/lang/en.yml" and write your strings. -The format is "key: string". Save it as UTF-8. If you save it in -a different encoding, add a key called file_charset (eg. -"file_charset: iso-2022-jp") - -
    • -
    • Put the following in config/environment.rb and change the values as you see -fit. The following example is for an app that uses English and Japanese, -with Japanese being the default. - -
      -  GLoc.set_config :default_language => :ja
      -  GLoc.clear_strings_except :en, :ja
      -  GLoc.set_kcode
      -  GLoc.load_localized_strings
      -
      -
    • -
    • Add ‘include GLoc’ to all -classes that will use localization. This is added to most Rails classes -automatically. - -
    • -
    • Optionally, you can set the language for models and controllers by simply -inserting set_language :en in classes and/or methods. - -
    • -
    • To use localized strings, replace text such as "Welcome" -with l(:welcome_string_key), and "Hello -#{name}." with l(:hello_string_key, name). (Of course -the strings will need to exist in your string bundle.) - -
    • -
    -

    -There is more functionality provided by this plugin, that is not -demonstrated above. Please read the API summary for details. -

    -

    API summary

    -

    -The following methods are added as both class methods and instance methods -to modules/classes that include GLoc. -They are also available as class methods of GLoc. -

    -
    -  current_language               # Returns the current language
    -  l(symbol, *arguments)          # Returns a localized string
    -  ll(lang, symbol, *arguments)   # Returns a localized string in a specific language
    -  ltry(possible_key)             # Returns a localized string if passed a Symbol, else returns the same argument passed
    -  lwr(symbol, *arguments)        # Uses the default rule to return a localized string.
    -  lwr_(rule, symbol, *arguments) # Uses a specified rule to return a localized string.
    -  l_has_string?(symbol)          # Checks if a localized string exists
    -  set_language(language)         # Sets the language for the current class or class instance
    -  set_language_if_valid(lang)    # Sets the current language if the language passed is a valid language
    -
    -

    -The GLoc module also defines the -following class methods: -

    -
    -  add_localized_strings(lang, symbol_hash, override=true) # Adds a hash of localized strings
    -  backup_state(clear=false)                               # Creates a backup of GLoc's internal state and optionally clears everything too
    -  clear_strings(*languages)                               # Removes localized strings from memory
    -  clear_strings_except(*languages)                        # Removes localized strings from memory except for those of certain specified languages
    -  get_charset(lang)                                       # Returns the charset used to store localized strings in memory
    -  get_config(key)                                         # Returns a GLoc configuration value (see below)
    -  load_localized_strings(dir=nil, override=true)          # Loads localized strings from all YML files in a given directory
    -  restore_state(state)                                    # Restores a backup of GLoc's internal state
    -  set_charset(new_charset, *langs)                        # Sets the charset used to internally store localized strings
    -  set_config(hash)                                        # Sets GLoc configuration values (see below)
    -  set_kcode(charset=nil)                                  # Sets the $KCODE global variable
    -  similar_language(language)                              # Tries to find a valid language that is similar to the argument passed
    -  valid_languages                                         # Returns an array of (currently) valid languages (ie. languages for which localized data exists)
    -  valid_language?(language)                               # Checks whether any localized strings are in memory for a given language
    -
    -

    -GLoc uses the following configuration -items. They can be accessed via get_config and -set_config. -

    -
    -  :default_cookie_name
    -  :default_language
    -  :default_param_name
    -  :raise_string_not_found_errors
    -  :verbose
    -
    -

    -The GLoc module is automatically -included in the following classes: -

    -
    -  ActionController::Base
    -  ActionMailer::Base
    -  ActionView::Base
    -  ActionView::Helpers::InstanceTag
    -  ActiveRecord::Base
    -  ActiveRecord::Errors
    -  ApplicationHelper
    -  Test::Unit::TestCase
    -
    -

    -The GLoc module also defines the -following controller filters: -

    -
    -  autodetect_language_filter
    -
    -

    -GLoc also makes the following change to -Rails: -

    -
      -
    • Views for ActionMailer are now #{view_name}_#{language}.rb rather than just -#{view_name}.rb - -
    • -
    • All ActiveRecord validation class methods now accept a localized string key -(symbol) as a :message value. - -
    • -
    • ActiveRecord::Errors.add -now accepts symbols as valid message values. At runtime these symbols are -converted to localized strings using the current_language of the base -record. - -
    • -
    • ActiveRecord::Errors.add -now accepts arrays as arguments so that printf-style strings can be -generated at runtime. This also applies to the validates_* class methods. - -
      -  Eg. validates_xxxxxx_of :name, :message => ['Your name must be at least %d characters.', MIN_LEN]
      -  Eg. validates_xxxxxx_of :name, :message => [:user_error_validation_name_too_short, MIN_LEN]
      -
      -
    • -
    • Instances of ActiveView inherit their current_language from the controller -(or mailer) creating them. - -
    • -
    -

    -This plugin also adds the following rake tasks: -

    -
    -  * gloc:sort - Sorts the keys in the lang ymls (also accepts a DIR argument)
    -
    -

    Cascading language configuration

    -

    -The language can be set at three levels: -

    -
    -  1. The default     # GLoc.get_config :default_language
    -  2. Class level     # class A; set_language :de; end
    -  3. Instance level  # b= B.new; b.set_language :zh
    -
    -

    -Instance level has the highest priority and the default has the lowest. -

    -

    -Because GLoc is included at class level -too, it becomes easy to associate languages with contexts. For example: -

    -
    -  class Student
    -    set_language :en
    -    def say_hello
    -      puts "We say #{l :hello} but our teachers say #{Teacher.l :hello}"
    -    end
    -  end
    -
    -

    Rules

    -

    -There are often situations when depending on the value of one or more -variables, the surrounding text changes. The most common case of this is -pluralization. Rather than hardcode these rules, they are completely -definable by the user so that the user can eaasily accomodate for more -complicated grammatical rules such as those found in Russian and Polish (or -so I hear). To define a rule, simply include a string in the string bundle -whose key begins with "gloc_rule" and then write ruby -code as the value. The ruby code will be converted to a Proc when the -string bundle is first read, and should return a prefix that will be -appended to the string key at runtime to point to a new string. Make sense? -Probably not… Please look at the following example and I am sure it -will all make sense. -

    -

    -Simple example (string bundle / en.yml) -

    -
    -  _gloc_rule_default: ' |n| n==1 ? "_single" : "_plural" '
    -  man_count_plural: There are %d men.
    -  man_count_single: There is 1 man.
    -
    -

    -Simple example (code) -

    -
    -  lwr(:man_count, 1)  # => There is 1 man.
    -  lwr(:man_count, 8)  # => There are 8 men.
    -
    -

    -To use rules other than the default simply call lwr_ instead of lwr, and -specify the rule. -

    -

    -Example 2 (string bundle / en.yml) -

    -
    -  _gloc_rule_default: ' |n| n==1 ? "_single" : "_plural" '
    -  _gloc_rule_custom: ' |n| return "_none" if n==0; return "_heaps" if n>100; n==1 ? "_single" : "_plural" '
    -  man_count_none: There are no men.
    -  man_count_heaps: There are heaps of men!!
    -  man_count_plural: There are %d men.
    -  man_count_single: There is 1 man.
    -
    -

    -Example 2 (code) -

    -
    -  lwr_(:custom, :man_count, 0)    # => There are no men.
    -  lwr_(:custom, :man_count, 1)    # => There is 1 man.
    -  lwr_(:custom, :man_count, 8)    # => There are 8 men.
    -  lwr_(:custom, :man_count, 150)  # => There are heaps of men!!
    -
    -

    Helpers

    -

    -GLoc includes the following helpers: -

    -
    -  l_age(age)             # Returns a localized version of an age. eg "3 years old"
    -  l_date(date)           # Returns a date in a localized format
    -  l_datetime(date)       # Returns a date+time in a localized format
    -  l_datetime_short(date) # Returns a date+time in a localized short format.
    -  l_lang_name(l,dl=nil)  # Returns the name of a language (you must supply your own strings)
    -  l_strftime(date,fmt)   # Formats a date/time in a localized format.
    -  l_time(date)           # Returns a time in a localized format
    -  l_YesNo(value)         # Returns localized string of "Yes" or "No" depending on the arg
    -  l_yesno(value)         # Returns localized string of "yes" or "no" depending on the arg
    -
    -

    Rails localization

    -

    -Not all of Rails is covered but the following functions are: -

    -
    -  distance_of_time_in_words
    -  select_day
    -  select_month
    -  select_year
    -  add_options
    -
    -

    FAQ

    -

    How do I use it in engines?

    -

    -Simply put this in your init_engine.rb -

    -
    -  GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang')
    -
    -

    -That way your engines strings will be loaded when the engine is started. -Just simply make sure that you load your application strings after you -start your engines to safely override any engine strings. -

    -

    Why am I getting an Iconv::IllegalSequence error when calling GLoc.set_charset?

    -

    -By default GLoc loads all of its default -strings at startup. For example, calling set_charset -‘iso-2022-jp’ will cause this error because Russian -strings are loaded by default, and the Russian strings use characters that -cannot be expressed in the ISO-2022-JP charset. Before calling -set_charset you should call clear_strings_except to -remove strings from any languages that you will not be using. -Alternatively, you can simply specify the language(s) as follows, -set_charset ‘iso-2022-jp’, :ja. -

    -

    How do I make GLoc ignore StringNotFoundErrors?

    -

    -Disable it as follows: -

    -
    -  GLoc.set_config :raise_string_not_found_errors => false
    -
    - -
    - - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html deleted file mode 100644 index 394b79d70..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - File: gloc-helpers.rb - - - - - - - - - - -
    -

    gloc-helpers.rb

    - - - - - - - - - -
    Path:lib/gloc-helpers.rb -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - -
    -

    -Copyright © 2005-2006 David Barri -

    - -
    - - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-internal_rb.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-internal_rb.html deleted file mode 100644 index 6d09fec7b..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-internal_rb.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - File: gloc-internal.rb - - - - - - - - - - -
    -

    gloc-internal.rb

    - - - - - - - - - -
    Path:lib/gloc-internal.rb -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - -
    -

    -Copyright © 2005-2006 David Barri -

    - -
    - -
    -

    Required files

    - -
    - iconv   - gloc-version   -
    -
    - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails-text_rb.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails-text_rb.html deleted file mode 100644 index 52a387218..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails-text_rb.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - File: gloc-rails-text.rb - - - - - - - - - - -
    -

    gloc-rails-text.rb

    - - - - - - - - - -
    Path:lib/gloc-rails-text.rb -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - -
    -

    -Copyright © 2005-2006 David Barri -

    - -
    - -
    -

    Required files

    - -
    - date   -
    -
    - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails_rb.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails_rb.html deleted file mode 100644 index 3ae73b87b..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails_rb.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - File: gloc-rails.rb - - - - - - - - - - -
    -

    gloc-rails.rb

    - - - - - - - - - -
    Path:lib/gloc-rails.rb -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - -
    -

    -Copyright © 2005-2006 David Barri -

    - -
    - -
    -

    Required files

    - -
    - gloc   -
    -
    - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html deleted file mode 100644 index 4b29e9d94..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - File: gloc-ruby.rb - - - - - - - - - - -
    -

    gloc-ruby.rb

    - - - - - - - - - -
    Path:lib/gloc-ruby.rb -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - -
    -

    -Copyright © 2005-2006 David Barri -

    - -
    - - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-version_rb.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-version_rb.html deleted file mode 100644 index 17f93aa43..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-version_rb.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - File: gloc-version.rb - - - - - - - - - - -
    -

    gloc-version.rb

    - - - - - - - - - -
    Path:lib/gloc-version.rb -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - - - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html b/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html deleted file mode 100644 index 9e68a89cd..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - File: gloc.rb - - - - - - - - - - -
    -

    gloc.rb

    - - - - - - - - - -
    Path:lib/gloc.rb -
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    -
    - - -
    - - - -
    - -
    -

    -Copyright © 2005-2006 David Barri -

    - -
    - -
    -

    Required files

    - -
    - yaml   - gloc-internal   - gloc-helpers   -
    -
    - -
    - - -
    - - - - -
    - - - - - - - - - - - -
    - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/fr_class_index.html b/redmine/vendor/plugins/gloc-1.1.0/doc/fr_class_index.html deleted file mode 100644 index 08e0418f3..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/fr_class_index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - Classes - - - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/fr_file_index.html b/redmine/vendor/plugins/gloc-1.1.0/doc/fr_file_index.html deleted file mode 100644 index 839e378d3..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/fr_file_index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - Files - - - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/fr_method_index.html b/redmine/vendor/plugins/gloc-1.1.0/doc/fr_method_index.html deleted file mode 100644 index 325ed3589..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/fr_method_index.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - Methods - - - - - -
    -

    Methods

    -
    - add (ActiveRecord::Errors)
    - add_localized_strings (GLoc)
    - autodetect_language_filter (ActionController::Filters::ClassMethods)
    - backup_state (GLoc)
    - clear_strings (GLoc)
    - clear_strings_except (GLoc)
    - current_language (GLoc::ClassMethods)
    - current_language (GLoc)
    - current_language (GLoc)
    - current_language (ActionView::Helpers::InstanceTag)
    - current_language (ActiveRecord::Errors)
    - distance_of_time_in_words (ActionView::Helpers::DateHelper)
    - get_charset (GLoc)
    - get_config (GLoc)
    - l (GLoc::InstanceMethods)
    - l_YesNo (GLoc::Helpers)
    - l_age (GLoc::Helpers)
    - l_date (GLoc::Helpers)
    - l_datetime (GLoc::Helpers)
    - l_datetime_short (GLoc::Helpers)
    - l_has_string? (GLoc::InstanceMethods)
    - l_lang_name (GLoc::Helpers)
    - l_strftime (GLoc::Helpers)
    - l_time (GLoc::Helpers)
    - l_yesno (GLoc::Helpers)
    - ll (GLoc::InstanceMethods)
    - load_gloc_default_localized_strings (GLoc)
    - load_localized_strings (GLoc)
    - ltry (GLoc::InstanceMethods)
    - lwr (GLoc::InstanceMethods)
    - lwr_ (GLoc::InstanceMethods)
    - new (ActionView::Base)
    - restore_state (GLoc)
    - select_day (ActionView::Helpers::DateHelper)
    - select_month (ActionView::Helpers::DateHelper)
    - select_year (ActionView::Helpers::DateHelper)
    - set_charset (GLoc)
    - set_config (GLoc)
    - set_kcode (GLoc)
    - set_language (GLoc::InstanceMethods)
    - set_language_if_valid (GLoc::InstanceMethods)
    - similar_language (GLoc)
    - valid_language? (GLoc)
    - valid_languages (GLoc)
    - validates_length_of (ActiveRecord::Validations::ClassMethods)
    - validates_size_of (ActiveRecord::Validations::ClassMethods)
    -
    -
    - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/index.html b/redmine/vendor/plugins/gloc-1.1.0/doc/index.html deleted file mode 100644 index f29103142..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - GLoc Localization Library Documentation - - - - - - - - - - - \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/doc/rdoc-style.css b/redmine/vendor/plugins/gloc-1.1.0/doc/rdoc-style.css deleted file mode 100644 index fbf7326af..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/doc/rdoc-style.css +++ /dev/null @@ -1,208 +0,0 @@ - -body { - font-family: Verdana,Arial,Helvetica,sans-serif; - font-size: 90%; - margin: 0; - margin-left: 40px; - padding: 0; - background: white; -} - -h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; } -h1 { font-size: 150%; } -h2,h3,h4 { margin-top: 1em; } - -a { background: #eef; color: #039; text-decoration: none; } -a:hover { background: #039; color: #eef; } - -/* Override the base stylesheet's Anchor inside a table cell */ -td > a { - background: transparent; - color: #039; - text-decoration: none; -} - -/* and inside a section title */ -.section-title > a { - background: transparent; - color: #eee; - text-decoration: none; -} - -/* === Structural elements =================================== */ - -div#index { - margin: 0; - margin-left: -40px; - padding: 0; - font-size: 90%; -} - - -div#index a { - margin-left: 0.7em; -} - -div#index .section-bar { - margin-left: 0px; - padding-left: 0.7em; - background: #ccc; - font-size: small; -} - - -div#classHeader, div#fileHeader { - width: auto; - color: white; - padding: 0.5em 1.5em 0.5em 1.5em; - margin: 0; - margin-left: -40px; - border-bottom: 3px solid #006; -} - -div#classHeader a, div#fileHeader a { - background: inherit; - color: white; -} - -div#classHeader td, div#fileHeader td { - background: inherit; - color: white; -} - - -div#fileHeader { - background: #057; -} - -div#classHeader { - background: #048; -} - - -.class-name-in-header { - font-size: 180%; - font-weight: bold; -} - - -div#bodyContent { - padding: 0 1.5em 0 1.5em; -} - -div#description { - padding: 0.5em 1.5em; - background: #efefef; - border: 1px dotted #999; -} - -div#description h1,h2,h3,h4,h5,h6 { - color: #125;; - background: transparent; -} - -div#validator-badges { - text-align: center; -} -div#validator-badges img { border: 0; } - -div#copyright { - color: #333; - background: #efefef; - font: 0.75em sans-serif; - margin-top: 5em; - margin-bottom: 0; - padding: 0.5em 2em; -} - - -/* === Classes =================================== */ - -table.header-table { - color: white; - font-size: small; -} - -.type-note { - font-size: small; - color: #DEDEDE; -} - -.xxsection-bar { - background: #eee; - color: #333; - padding: 3px; -} - -.section-bar { - color: #333; - border-bottom: 1px solid #999; - margin-left: -20px; -} - - -.section-title { - background: #79a; - color: #eee; - padding: 3px; - margin-top: 2em; - margin-left: -30px; - border: 1px solid #999; -} - -.top-aligned-row { vertical-align: top } -.bottom-aligned-row { vertical-align: bottom } - -/* --- Context section classes ----------------------- */ - -.context-row { } -.context-item-name { font-family: monospace; font-weight: bold; color: black; } -.context-item-value { font-size: small; color: #448; } -.context-item-desc { color: #333; padding-left: 2em; } - -/* --- Method classes -------------------------- */ -.method-detail { - background: #efefef; - padding: 0; - margin-top: 0.5em; - margin-bottom: 1em; - border: 1px dotted #ccc; -} -.method-heading { - color: black; - background: #ccc; - border-bottom: 1px solid #666; - padding: 0.2em 0.5em 0 0.5em; -} -.method-signature { color: black; background: inherit; } -.method-name { font-weight: bold; } -.method-args { font-style: italic; } -.method-description { padding: 0 0.5em 0 0.5em; } - -/* --- Source code sections -------------------- */ - -a.source-toggle { font-size: 90%; } -div.method-source-code { - background: #262626; - color: #ffdead; - margin: 1em; - padding: 0.5em; - border: 1px dashed #999; - overflow: hidden; -} - -div.method-source-code pre { color: #ffdead; overflow: hidden; } - -/* --- Ruby keyword styles --------------------- */ - -.standalone-code { background: #221111; color: #ffdead; overflow: hidden; } - -.ruby-constant { color: #7fffd4; background: transparent; } -.ruby-keyword { color: #00ffff; background: transparent; } -.ruby-ivar { color: #eedd82; background: transparent; } -.ruby-operator { color: #00ffee; background: transparent; } -.ruby-identifier { color: #ffdead; background: transparent; } -.ruby-node { color: #ffa07a; background: transparent; } -.ruby-comment { color: #b22222; font-weight: bold; background: transparent; } -.ruby-regexp { color: #ffa07a; background: transparent; } -.ruby-value { color: #7fffd4; background: transparent; } \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/init.rb b/redmine/vendor/plugins/gloc-1.1.0/init.rb deleted file mode 100644 index 9d99acd61..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/init.rb +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -require 'gloc' -require 'gloc-ruby' -require 'gloc-rails' -require 'gloc-rails-text' -require 'gloc-config' - -require 'gloc-dev' if ENV['RAILS_ENV'] == 'development' - -GLoc.load_gloc_default_localized_strings diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-config.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-config.rb deleted file mode 100644 index e85b041f5..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-config.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -module GLoc - - private - - CONFIG= {} unless const_defined?(:CONFIG) - unless CONFIG.frozen? - CONFIG[:default_language] ||= :en - CONFIG[:default_param_name] ||= 'lang' - CONFIG[:default_cookie_name] ||= 'lang' - CONFIG[:raise_string_not_found_errors]= true unless CONFIG.has_key?(:raise_string_not_found_errors) - CONFIG[:verbose] ||= false - end - -end diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb deleted file mode 100644 index cb12b4cb3..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -puts "GLoc v#{GLoc::VERSION} running in development mode. Strings can be modified at runtime." - -module GLoc - class << self - - alias :actual_add_localized_strings :add_localized_strings - def add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) - _verbose_msg {"dev::add_localized_strings #{lang}, [#{symbol_hash.size}], #{override}, #{strings_charset ? strings_charset : 'nil'}"} - STATE.push [:hash, lang, {}.merge(symbol_hash), override, strings_charset] - _force_refresh - end - - alias :actual_load_localized_strings :load_localized_strings - def load_localized_strings(dir=nil, override=true) - _verbose_msg {"dev::load_localized_strings #{dir ? dir : 'nil'}, #{override}"} - STATE.push [:dir, dir, override] - _get_lang_file_list(dir).each {|filename| FILES[filename]= nil} - end - - alias :actual_clear_strings :clear_strings - def clear_strings(*languages) - _verbose_msg {"dev::clear_strings #{languages.map{|l|l.to_s}.join(', ')}"} - STATE.push [:clear, languages.clone] - _force_refresh - end - - alias :actual_clear_strings_except :clear_strings_except - def clear_strings_except(*languages) - _verbose_msg {"dev::clear_strings_except #{languages.map{|l|l.to_s}.join(', ')}"} - STATE.push [:clear_except, languages.clone] - _force_refresh - end - - # Replace methods - [:_l, :_l_rule, :_l_has_string?, :similar_language, :valid_languages, :valid_language?].each do |m| - class_eval <<-EOB - alias :actual_#{m} :#{m} - def #{m}(*args) - _assert_gloc_strings_up_to_date - actual_#{m}(*args) - end - EOB - end - - #------------------------------------------------------------------------- - private - - STATE= [] - FILES= {} - - def _assert_gloc_strings_up_to_date - changed= @@force_refresh - - # Check if any lang files have changed - unless changed - FILES.each_pair {|f,mtime| - changed ||= (File.stat(f).mtime != mtime) - } - end - - return unless changed - puts "GLoc reloading strings..." - @@force_refresh= false - - # Update file timestamps - FILES.each_key {|f| - FILES[f]= File.stat(f).mtime - } - - # Reload strings - actual_clear_strings - STATE.each {|s| - case s[0] - when :dir then actual_load_localized_strings s[1], s[2] - when :hash then actual_add_localized_strings s[1], s[2], s[3], s[4] - when :clear then actual_clear_strings(*s[1]) - when :clear_except then actual_clear_strings_except(*s[1]) - else raise "Invalid state id: '#{s[0]}'" - end - } - _verbose_msg :stats - end - - @@force_refresh= false - def _force_refresh - @@force_refresh= true - end - - alias :super_get_internal_state_vars :_get_internal_state_vars - def _get_internal_state_vars - super_get_internal_state_vars + [ STATE, FILES ] - end - - end -end diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb deleted file mode 100644 index f2ceb8e3d..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -module GLoc - # These helper methods will be included in the InstanceMethods module. - module Helpers - def l_age(age) lwr :general_fmt_age, age end - def l_date(date) l_strftime date, :general_fmt_date end - def l_datetime(date) l_strftime date, :general_fmt_datetime end - def l_datetime_short(date) l_strftime date, :general_fmt_datetime_short end - def l_strftime(date,fmt) date.strftime l(fmt) end - def l_time(time) l_strftime time, :general_fmt_time end - def l_YesNo(value) l(value ? :general_text_Yes : :general_text_No) end - def l_yesno(value) l(value ? :general_text_yes : :general_text_no) end - - def l_lang_name(lang, display_lang=nil) - ll display_lang || current_language, "general_lang_#{lang}" - end - - end -end diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb deleted file mode 100644 index f16e90555..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -require 'iconv' -require 'gloc-version' - -module GLoc - class GLocError < StandardError #:nodoc: - end - class InvalidArgumentsError < GLocError #:nodoc: - end - class InvalidKeyError < GLocError #:nodoc: - end - class RuleNotFoundError < GLocError #:nodoc: - end - class StringNotFoundError < GLocError #:nodoc: - end - - class << self - private - - def _add_localized_data(lang, symbol_hash, override, target) #:nodoc: - lang= lang.to_sym - if override - target[lang] ||= {} - target[lang].merge!(symbol_hash) - else - symbol_hash.merge!(target[lang]) if target[lang] - target[lang]= symbol_hash - end - end - - def _add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) #:nodoc: - _charset_required - - # Convert all incoming strings to the gloc charset - if strings_charset - Iconv.open(get_charset(lang), strings_charset) do |i| - symbol_hash.each_pair {|k,v| symbol_hash[k]= i.iconv(v)} - end - end - - # Convert rules - rules= {} - old_kcode= $KCODE - begin - $KCODE= 'u' - Iconv.open(UTF_8, get_charset(lang)) do |i| - symbol_hash.each {|k,v| - if /^_gloc_rule_(.+)$/ =~ k.to_s - v= i.iconv(v) if v - v= '""' if v.nil? - rules[$1.to_sym]= eval "Proc.new do #{v} end" - end - } - end - ensure - $KCODE= old_kcode - end - rules.keys.each {|k| symbol_hash.delete "_gloc_rule_#{k}".to_sym} - - # Add new localized data - LOWERCASE_LANGUAGES[lang.to_s.downcase]= lang - _add_localized_data(lang, symbol_hash, override, LOCALIZED_STRINGS) - _add_localized_data(lang, rules, override, RULES) - end - - def _charset_required #:nodoc: - set_charset UTF_8 unless CONFIG[:internal_charset] - end - - def _get_internal_state_vars - [ CONFIG, LOCALIZED_STRINGS, RULES, LOWERCASE_LANGUAGES ] - end - - def _get_lang_file_list(dir) #:nodoc: - dir= File.join(RAILS_ROOT,'lang') if dir.nil? - Dir[File.join(dir,'*.{yaml,yml}')] - end - - def _l(symbol, language, *arguments) #:nodoc: - symbol= symbol.to_sym if symbol.is_a?(String) - raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol) - - translation= LOCALIZED_STRINGS[language][symbol] rescue nil - if translation.nil? - raise StringNotFoundError.new("There is no key called '#{symbol}' in the #{language} strings.") if CONFIG[:raise_string_not_found_errors] - translation= symbol.to_s - end - - begin - return translation % arguments - rescue => e - raise InvalidArgumentsError.new("Translation value #{translation.inspect} with arguments #{arguments.inspect} caused error '#{e.message}'") - end - end - - def _l_has_string?(symbol,lang) #:nodoc: - symbol= symbol.to_sym if symbol.is_a?(String) - LOCALIZED_STRINGS[lang].has_key?(symbol.to_sym) rescue false - end - - def _l_rule(symbol,lang) #:nodoc: - symbol= symbol.to_sym if symbol.is_a?(String) - raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol) - - r= RULES[lang][symbol] rescue nil - raise RuleNotFoundError.new("There is no rule called '#{symbol}' in the #{lang} rules.") if r.nil? - r - end - - def _verbose_msg(type=nil) - return unless CONFIG[:verbose] - x= case type - when :stats - x= valid_languages.map{|l| ":#{l}(#{LOCALIZED_STRINGS[l].size}/#{RULES[l].size})"}.sort.join(', ') - "Current stats -- #{x}" - else - yield - end - puts "[GLoc] #{x}" - end - - public :_l, :_l_has_string?, :_l_rule - end - - private - - unless const_defined?(:LOCALIZED_STRINGS) - LOCALIZED_STRINGS= {} - RULES= {} - LOWERCASE_LANGUAGES= {} - end - -end diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb deleted file mode 100644 index abbb7a190..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -require 'date' - -module ActionView #:nodoc: - module Helpers #:nodoc: - module DateHelper - - unless const_defined?(:LOCALIZED_HELPERS) - LOCALIZED_HELPERS= true - LOCALIZED_MONTHNAMES = {} - LOCALIZED_ABBR_MONTHNAMES = {} - end - - # This method uses current_language to return a localized string. - def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false) - from_time = from_time.to_time if from_time.respond_to?(:to_time) - to_time = to_time.to_time if to_time.respond_to?(:to_time) - distance_in_minutes = (((to_time - from_time).abs)/60).round - distance_in_seconds = ((to_time - from_time).abs).round - - case distance_in_minutes - when 0..1 - return (distance_in_minutes==0) ? l(:actionview_datehelper_time_in_words_minute_less_than) : l(:actionview_datehelper_time_in_words_minute_single) unless include_seconds - case distance_in_seconds - when 0..5 then lwr(:actionview_datehelper_time_in_words_second_less_than, 5) - when 6..10 then lwr(:actionview_datehelper_time_in_words_second_less_than, 10) - when 11..20 then lwr(:actionview_datehelper_time_in_words_second_less_than, 20) - when 21..40 then l(:actionview_datehelper_time_in_words_minute_half) - when 41..59 then l(:actionview_datehelper_time_in_words_minute_less_than) - else l(:actionview_datehelper_time_in_words_minute) - end - - when 2..45 then lwr(:actionview_datehelper_time_in_words_minute, distance_in_minutes) - when 46..90 then l(:actionview_datehelper_time_in_words_hour_about_single) - when 90..1440 then lwr(:actionview_datehelper_time_in_words_hour_about, (distance_in_minutes.to_f / 60.0).round) - when 1441..2880 then lwr(:actionview_datehelper_time_in_words_day, 1) - else lwr(:actionview_datehelper_time_in_words_day, (distance_in_minutes / 1440).round) - end - end - - # This method has been modified so that a localized string can be appended to the day numbers. - def select_day(date, options = {}) - day_options = [] - prefix = l :actionview_datehelper_select_day_prefix - - 1.upto(31) do |day| - day_options << ((date && (date.kind_of?(Fixnum) ? date : date.day) == day) ? - %(\n) : - %(\n) - ) - end - - select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled]) - end - - # This method has been modified so that - # * the month names are localized. - # * it uses options: :min_date, :max_date, :start_month, :end_month - # * a localized string can be appended to the month numbers when the :use_month_numbers option is specified. - def select_month(date, options = {}) - unless LOCALIZED_MONTHNAMES.has_key?(current_language) - LOCALIZED_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names).split(',') - LOCALIZED_ABBR_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names_abbr).split(',') - end - - month_options = [] - month_names = options[:use_short_month] ? LOCALIZED_ABBR_MONTHNAMES[current_language] : LOCALIZED_MONTHNAMES[current_language] - - if options.has_key?(:min_date) && options.has_key?(:max_date) - if options[:min_date].year == options[:max_date].year - start_month, end_month = options[:min_date].month, options[:max_date].month - end - end - start_month = (options[:start_month] || 1) unless start_month - end_month = (options[:end_month] || 12) unless end_month - prefix = l :actionview_datehelper_select_month_prefix - - start_month.upto(end_month) do |month_number| - month_name = if options[:use_month_numbers] - "#{month_number}#{prefix}" - elsif options[:add_month_numbers] - month_number.to_s + ' - ' + month_names[month_number] - else - month_names[month_number] - end - - month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ? - %(\n) : - %(\n) - ) - end - - select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled]) - end - - # This method has been modified so that - # * it uses options: :min_date, :max_date - # * a localized string can be appended to the years numbers. - def select_year(date, options = {}) - year_options = [] - y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year - - start_year = options.has_key?(:min_date) ? options[:min_date].year : (options[:start_year] || y-5) - end_year = options.has_key?(:max_date) ? options[:max_date].year : (options[:end_year] || y+5) - step_val = start_year < end_year ? 1 : -1 - prefix = l :actionview_datehelper_select_year_prefix - - start_year.step(end_year, step_val) do |year| - year_options << ((date && (date.kind_of?(Fixnum) ? date : date.year) == year) ? - %(\n) : - %(\n) - ) - end - - select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled]) - end - - end - - # The private method add_options is overridden so that "Please select" is localized. - class InstanceTag - private - - def add_options(option_tags, options, value = nil) - option_tags = "\n" + option_tags if options[:include_blank] - - if value.blank? && options[:prompt] - ("\n") + option_tags - else - option_tags - end - end - - end - end -end diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb deleted file mode 100644 index 0a35b90ab..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb +++ /dev/null @@ -1,230 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -require 'gloc' - -module ActionController #:nodoc: - class Base #:nodoc: - include GLoc - end - module Filters #:nodoc: - module ClassMethods - - # This filter attempts to auto-detect the clients desired language. - # It first checks the params, then a cookie and then the HTTP_ACCEPT_LANGUAGE - # request header. If a language is found to match or be similar to a currently - # valid language, then it sets the current_language of the controller. - # - # class ExampleController < ApplicationController - # set_language :en - # autodetect_language_filter :except => 'monkey', :on_no_lang => :lang_not_autodetected_callback - # autodetect_language_filter :only => 'monkey', :check_cookie => 'monkey_lang', :check_accept_header => false - # ... - # def lang_not_autodetected_callback - # redirect_to somewhere - # end - # end - # - # The args for this filter are exactly the same the arguments of - # before_filter with the following exceptions: - # * :check_params -- If false, then params will not be checked for a language. - # If a String, then this will value will be used as the name of the param. - # * :check_cookie -- If false, then the cookie will not be checked for a language. - # If a String, then this will value will be used as the name of the cookie. - # * :check_accept_header -- If false, then HTTP_ACCEPT_LANGUAGE will not be checked for a language. - # * :on_set_lang -- You can specify the name of a callback function to be called when the language - # is successfully detected and set. The param must be a Symbol or a String which is the name of the function. - # The callback function must accept one argument (the language) and must be instance level. - # * :on_no_lang -- You can specify the name of a callback function to be called when the language - # couldn't be detected automatically. The param must be a Symbol or a String which is the name of the function. - # The callback function must be instance level. - # - # You override the default names of the param or cookie by calling GLoc.set_config :default_param_name => 'new_param_name' - # and GLoc.set_config :default_cookie_name => 'new_cookie_name'. - def autodetect_language_filter(*args) - options= args.last.is_a?(Hash) ? args.last : {} - x= 'Proc.new { |c| l= nil;' - # :check_params - unless (v= options.delete(:check_params)) == false - name= v ? ":#{v}" : 'GLoc.get_config(:default_param_name)' - x << "l ||= GLoc.similar_language(c.params[#{name}]);" - end - # :check_cookie - unless (v= options.delete(:check_cookie)) == false - name= v ? ":#{v}" : 'GLoc.get_config(:default_cookie_name)' - x << "l ||= GLoc.similar_language(c.send(:cookies)[#{name}]);" - end - # :check_accept_header - unless options.delete(:check_accept_header) == false - x << %< - unless l - a= c.request.env['HTTP_ACCEPT_LANGUAGE'].split(/,|;/) rescue nil - a.each {|x| l ||= GLoc.similar_language(x)} if a - end; > - end - # Set language - x << 'ret= true;' - x << 'if l; c.set_language(l); c.headers[\'Content-Language\']= l.to_s; ' - if options.has_key?(:on_set_lang) - x << "ret= c.#{options.delete(:on_set_lang)}(l);" - end - if options.has_key?(:on_no_lang) - x << "else; ret= c.#{options.delete(:on_no_lang)};" - end - x << 'end; ret }' - - # Create filter - block= eval x - before_filter(*args, &block) - end - - end - end -end - -# ============================================================================== - -module ActionMailer #:nodoc: - # In addition to including GLoc, render_message is also overridden so - # that mail templates contain the current language at the end of the file. - # Eg. deliver_hello will render hello_en.rhtml. - class Base - include GLoc - private - alias :render_message_without_gloc :render_message - def render_message(method_name, body) - render_message_without_gloc("#{method_name}_#{current_language}", body) - end - end -end - -# ============================================================================== - -module ActionView #:nodoc: - # initialize is overridden so that new instances of this class inherit - # the current language of the controller. - class Base - include GLoc - - alias :initialize_without_gloc :initialize - def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil) - initialize_without_gloc(base_path, assigns_for_first_render, controller) - set_language controller.current_language unless controller.nil? - end - end - - module Helpers #:nodoc: - class InstanceTag - include GLoc - # Inherits the current language from the template object. - def current_language - @template_object.current_language - end - end - end -end - -# ============================================================================== - -module ActiveRecord #:nodoc: - class Base #:nodoc: - include GLoc - end - - class Errors - include GLoc - alias :add_without_gloc :add - # The GLoc version of this method provides two extra features - # * If msg is a string, it will be considered a GLoc string key. - # * If msg is an array, the first element will be considered - # the string and the remaining elements will be considered arguments for the - # string. Eg. ['Hi %s.','John'] - def add(attribute, msg= @@default_error_messages[:invalid]) - if msg.is_a?(Array) - args= msg.clone - msg= args.shift - args= nil if args.empty? - end - msg= ltry(msg) - msg= msg % args unless args.nil? - add_without_gloc(attribute, msg) - end - # Inherits the current language from the base record. - def current_language - @base.current_language - end - end - - module Validations #:nodoc: - module ClassMethods - # The default Rails version of this function creates an error message and then - # passes it to ActiveRecord.Errors. - # The GLoc version of this method, sends an array to ActiveRecord.Errors that will - # be turned into a string by ActiveRecord.Errors which in turn allows for the message - # of this validation function to be a GLoc string key. - def validates_length_of(*attrs) - # Merge given options with defaults. - options = { - :too_long => ActiveRecord::Errors.default_error_messages[:too_long], - :too_short => ActiveRecord::Errors.default_error_messages[:too_short], - :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length] - }.merge(DEFAULT_VALIDATION_OPTIONS) - options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash) - - # Ensure that one and only one range option is specified. - range_options = ALL_RANGE_OPTIONS & options.keys - case range_options.size - when 0 - raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.' - when 1 - # Valid number of options; do nothing. - else - raise ArgumentError, 'Too many range options specified. Choose only one.' - end - - # Get range option and value. - option = range_options.first - option_value = options[range_options.first] - - case option - when :within, :in - raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) - - too_short = [options[:too_short] , option_value.begin] - too_long = [options[:too_long] , option_value.end ] - - validates_each(attrs, options) do |record, attr, value| - if value.nil? or value.split(//).size < option_value.begin - record.errors.add(attr, too_short) - elsif value.split(//).size > option_value.end - record.errors.add(attr, too_long) - end - end - when :is, :minimum, :maximum - raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0 - - # Declare different validations per option. - validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } - message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } - - message = [(options[:message] || options[message_options[option]]) , option_value] - - validates_each(attrs, options) do |record, attr, value| - if value.kind_of?(String) - record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value] - else - record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] - end - end - end - end - - alias_method :validates_size_of, :validates_length_of - end - end -end - -# ============================================================================== - -module ApplicationHelper #:nodoc: - include GLoc -end diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb deleted file mode 100644 index f96ab6cf9..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -module Test # :nodoc: - module Unit # :nodoc: - class TestCase # :nodoc: - include GLoc -end; end; end diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-version.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-version.rb deleted file mode 100644 index 91afcf482..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc-version.rb +++ /dev/null @@ -1,12 +0,0 @@ -module GLoc - module VERSION #:nodoc: - MAJOR = 1 - MINOR = 1 - TINY = nil - - STRING= [MAJOR, MINOR, TINY].delete_if{|x|x.nil?}.join('.') - def self.to_s; STRING end - end -end - -puts "NOTICE: You are using a dev version of GLoc." if GLoc::VERSION::TINY == 'DEV' \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc.rb b/redmine/vendor/plugins/gloc-1.1.0/lib/gloc.rb deleted file mode 100644 index bcad0ed9b..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/lib/gloc.rb +++ /dev/null @@ -1,294 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -require 'yaml' -require 'gloc-internal' -require 'gloc-helpers' - -module GLoc - UTF_8= 'utf-8' - SHIFT_JIS= 'sjis' - EUC_JP= 'euc-jp' - - # This module will be included in both instances and classes of GLoc includees. - # It is also included as class methods in the GLoc module itself. - module InstanceMethods - include Helpers - - # Returns a localized string. - def l(symbol, *arguments) - return GLoc._l(symbol,current_language,*arguments) - end - - # Returns a localized string in a specified language. - # This does not effect current_language. - def ll(lang, symbol, *arguments) - return GLoc._l(symbol,lang.to_sym,*arguments) - end - - # Returns a localized string if the argument is a Symbol, else just returns the argument. - def ltry(possible_key) - possible_key.is_a?(Symbol) ? l(possible_key) : possible_key - end - - # Uses the default GLoc rule to return a localized string. - # See lwr_() for more info. - def lwr(symbol, *arguments) - lwr_(:default, symbol, *arguments) - end - - # Uses a rule to return a localized string. - # A rule is a function that uses specified arguments to return a localization key prefix. - # The prefix is appended to the localization key originally specified, to create a new key which - # is then used to lookup a localized string. - def lwr_(rule, symbol, *arguments) - GLoc._l("#{symbol}#{GLoc::_l_rule(rule,current_language).call(*arguments)}",current_language,*arguments) - end - - # Returns true if a localized string with the specified key exists. - def l_has_string?(symbol) - return GLoc._l_has_string?(symbol,current_language) - end - - # Sets the current language for this instance/class. - # Setting the language of a class effects all instances unless the instance has its own language defined. - def set_language(language) - @gloc_language= language.nil? ? nil : language.to_sym - end - - # Sets the current language if the language passed is a valid language. - # If the language was valid, this method returns true else it will return false. - # Note that nil is not a valid language. - # See set_language(language) for more info. - def set_language_if_valid(language) - if GLoc.valid_language?(language) - set_language(language) - true - else - false - end - end - end - - #--------------------------------------------------------------------------- - # Instance - - include ::GLoc::InstanceMethods - # Returns the instance-level current language, or if not set, returns the class-level current language. - def current_language - @gloc_language || self.class.current_language - end - - #--------------------------------------------------------------------------- - # Class - - # All classes/modules that include GLoc will also gain these class methods. - # Notice that the GLoc::InstanceMethods module is also included. - module ClassMethods - include ::GLoc::InstanceMethods - # Returns the current language, or if not set, returns the GLoc current language. - def current_language - @gloc_language || GLoc.current_language - end - end - - def self.included(target) #:nodoc: - super - class << target - include ::GLoc::ClassMethods - end - end - - #--------------------------------------------------------------------------- - # GLoc module - - class << self - include ::GLoc::InstanceMethods - - # Returns the default language - def current_language - GLoc::CONFIG[:default_language] - end - - # Adds a collection of localized strings to the in-memory string store. - def add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) - _verbose_msg {"Adding #{symbol_hash.size} #{lang} strings."} - _add_localized_strings(lang, symbol_hash, override, strings_charset) - _verbose_msg :stats - end - - # Creates a backup of the internal state of GLoc (ie. strings, langs, rules, config) - # and optionally clears everything. - def backup_state(clear=false) - s= _get_internal_state_vars.map{|o| o.clone} - _get_internal_state_vars.each{|o| o.clear} if clear - s - end - - # Removes all localized strings from memory, either of a certain language (or languages), - # or entirely. - def clear_strings(*languages) - if languages.empty? - _verbose_msg {"Clearing all strings"} - LOCALIZED_STRINGS.clear - LOWERCASE_LANGUAGES.clear - else - languages.each {|l| - _verbose_msg {"Clearing :#{l} strings"} - l= l.to_sym - LOCALIZED_STRINGS.delete l - LOWERCASE_LANGUAGES.each_pair {|k,v| LOWERCASE_LANGUAGES.delete k if v == l} - } - end - end - alias :_clear_strings :clear_strings - - # Removes all localized strings from memory, except for those of certain specified languages. - def clear_strings_except(*languages) - clear= (LOCALIZED_STRINGS.keys - languages) - _clear_strings(*clear) unless clear.empty? - end - - # Returns the charset used to store localized strings in memory. - def get_charset(lang) - CONFIG[:internal_charset_per_lang][lang] || CONFIG[:internal_charset] - end - - # Returns a GLoc configuration value. - def get_config(key) - CONFIG[key] - end - - # Loads the localized strings that are included in the GLoc library. - def load_gloc_default_localized_strings(override=false) - GLoc.load_localized_strings "#{File.dirname(__FILE__)}/../lang", override - end - - # Loads localized strings from all yml files in the specifed directory. - def load_localized_strings(dir=nil, override=true) - _charset_required - _get_lang_file_list(dir).each {|filename| - - # Load file - raw_hash = YAML::load(File.read(filename)) - raw_hash={} unless raw_hash.kind_of?(Hash) - filename =~ /([^\/\\]+)\.ya?ml$/ - lang = $1.to_sym - file_charset = raw_hash['file_charset'] || UTF_8 - - # Convert string keys to symbols - dest_charset= get_charset(lang) - _verbose_msg {"Reading file #{filename} [charset: #{file_charset} --> #{dest_charset}]"} - symbol_hash = {} - Iconv.open(dest_charset, file_charset) do |i| - raw_hash.each {|key, value| - symbol_hash[key.to_sym] = i.iconv(value) - } - end - - # Add strings to repos - _add_localized_strings(lang, symbol_hash, override) - } - _verbose_msg :stats - end - - # Restores a backup of GLoc's internal state that was made with backup_state. - def restore_state(state) - _get_internal_state_vars.each do |o| - o.clear - o.send o.respond_to?(:merge!) ? :merge! : :concat, state.shift - end - end - - # Sets the charset used to internally store localized strings. - # You can set the charset to use for a specific language or languages, - # or if none are specified the charset for ALL localized strings will be set. - def set_charset(new_charset, *langs) - CONFIG[:internal_charset_per_lang] ||= {} - - # Convert symbol shortcuts - if new_charset.is_a?(Symbol) - new_charset= case new_charset - when :utf8, :utf_8 then UTF_8 - when :sjis, :shift_jis, :shiftjis then SHIFT_JIS - when :eucjp, :euc_jp then EUC_JP - else new_charset.to_s - end - end - - # Convert existing strings - (langs.empty? ? LOCALIZED_STRINGS.keys : langs).each do |lang| - cur_charset= get_charset(lang) - if cur_charset && new_charset != cur_charset - _verbose_msg {"Converting :#{lang} strings from #{cur_charset} to #{new_charset}"} - Iconv.open(new_charset, cur_charset) do |i| - bundle= LOCALIZED_STRINGS[lang] - bundle.each_pair {|k,v| bundle[k]= i.iconv(v)} - end - end - end - - # Set new charset value - if langs.empty? - _verbose_msg {"Setting GLoc charset for all languages to #{new_charset}"} - CONFIG[:internal_charset]= new_charset - CONFIG[:internal_charset_per_lang].clear - else - langs.each do |lang| - _verbose_msg {"Setting GLoc charset for :#{lang} strings to #{new_charset}"} - CONFIG[:internal_charset_per_lang][lang]= new_charset - end - end - end - - # Sets GLoc configuration values. - def set_config(hash) - CONFIG.merge! hash - end - - # Sets the $KCODE global variable according to a specified charset, or else the - # current default charset for the default language. - def set_kcode(charset=nil) - _charset_required - charset ||= get_charset(current_language) - $KCODE= case charset - when UTF_8 then 'u' - when SHIFT_JIS then 's' - when EUC_JP then 'e' - else 'n' - end - _verbose_msg {"$KCODE set to #{$KCODE}"} - end - - # Tries to find a valid language that is similar to the argument passed. - # Eg. :en, :en_au, :EN_US are all similar languages. - # Returns nil if no similar languages are found. - def similar_language(lang) - return nil if lang.nil? - return lang.to_sym if valid_language?(lang) - # Check lowercase without dashes - lang= lang.to_s.downcase.gsub('-','_') - return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang) - # Check without dialect - if lang.to_s =~ /^([a-z]+?)[^a-z].*/ - lang= $1 - return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang) - end - # Check other dialects - lang= "#{lang}_" - LOWERCASE_LANGUAGES.keys.each {|k| return LOWERCASE_LANGUAGES[k] if k.starts_with?(lang)} - # Nothing found - nil - end - - # Returns an array of (currently) valid languages (ie. languages for which localized data exists). - def valid_languages - LOCALIZED_STRINGS.keys - end - - # Returns true if there are any localized strings for a specified language. - # Note that although set_langauge nil is perfectly valid, nil is not a valid language. - def valid_language?(language) - LOCALIZED_STRINGS.has_key? language.to_sym rescue false - end - end -end diff --git a/redmine/vendor/plugins/gloc-1.1.0/tasks/gloc.rake b/redmine/vendor/plugins/gloc-1.1.0/tasks/gloc.rake deleted file mode 100644 index 8da73779e..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/tasks/gloc.rake +++ /dev/null @@ -1,30 +0,0 @@ -namespace :gloc do - desc 'Sorts the keys in the lang ymls' - task :sort do - dir = ENV['DIR'] || '{.,vendor/plugins/*}/lang' - puts "Processing directory #{dir}" - files = Dir.glob(File.join(dir,'*.{yaml,yml}')) - puts 'No files found.' if files.empty? - files.each {|file| - puts "Sorting file: #{file}" - header = [] - content = IO.readlines(file) - content.each {|line| line.gsub!(/[\s\r\n\t]+$/,'')} - content.delete_if {|line| line==''} - tmp= [] - content.each {|x| tmp << x unless tmp.include?(x)} - content= tmp - header << content.shift if !content.empty? && content[0] =~ /^file_charset:/ - content.sort! - filebak = "#{file}.bak" - File.rename file, filebak - File.open(file, 'w') {|fout| fout << header.join("\n") << content.join("\n") << "\n"} - File.delete filebak - # Report duplicates - count= {} - content.map {|x| x.gsub(/:.+$/, '') }.each {|x| count[x] ||= 0; count[x] += 1} - count.delete_if {|k,v|v==1} - puts count.keys.sort.map{|x|" WARNING: Duplicate key '#{x}' (#{count[x]} occurances)"}.join("\n") unless count.empty? - } - end -end \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb b/redmine/vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb deleted file mode 100644 index 4cb232904..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -$LOAD_PATH.push File.join(File.dirname(__FILE__),'..','lib') -require "#{File.dirname(__FILE__)}/../../../../test/test_helper" -require "#{File.dirname(__FILE__)}/../init" - -class GLocRailsTestController < ActionController::Base - autodetect_language_filter :only => :auto, :on_set_lang => :called_when_set, :on_no_lang => :called_when_bad - autodetect_language_filter :only => :auto2, :check_accept_header => false, :check_params => 'xx' - autodetect_language_filter :only => :auto3, :check_cookie => false - autodetect_language_filter :only => :auto4, :check_cookie => 'qwe', :check_params => false - def rescue_action(e) raise e end - def auto; render :text => 'auto'; end - def auto2; render :text => 'auto'; end - def auto3; render :text => 'auto'; end - def auto4; render :text => 'auto'; end - attr_accessor :callback_set, :callback_bad - def called_when_set(l) @callback_set ||= 0; @callback_set += 1 end - def called_when_bad; @callback_bad ||= 0; @callback_bad += 1 end -end - -class GLocRailsTest < Test::Unit::TestCase - - def setup - @lstrings = GLoc::LOCALIZED_STRINGS.clone - @old_config= GLoc::CONFIG.clone - begin_new_request - end - - def teardown - GLoc.clear_strings - GLoc::LOCALIZED_STRINGS.merge! @lstrings - GLoc::CONFIG.merge! @old_config - end - - def begin_new_request - @controller = GLocRailsTestController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - def test_autodetect_language - GLoc::CONFIG[:default_language]= :def - GLoc::CONFIG[:default_param_name] = 'plang' - GLoc::CONFIG[:default_cookie_name] = 'clang' - GLoc.clear_strings - GLoc.add_localized_strings :en, :a => 'a' - GLoc.add_localized_strings :en_au, :a => 'a' - GLoc.add_localized_strings :en_US, :a => 'a' - GLoc.add_localized_strings :Ja, :a => 'a' - GLoc.add_localized_strings :ZH_HK, :a => 'a' - - # default - subtest_autodetect_language :def, nil, nil, nil - subtest_autodetect_language :def, 'its', 'all', 'bullshit,man;q=zxc' - # simple - subtest_autodetect_language :en_au, 'en_au', nil, nil - subtest_autodetect_language :en_US, nil, 'en_us', nil - subtest_autodetect_language :Ja, nil, nil, 'ja' - # priority - subtest_autodetect_language :Ja, 'ja', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5' - subtest_autodetect_language :en_US, 'why', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5' - subtest_autodetect_language :Ja, nil, nil, 'qwe_en,JA,zh,monkey_en;q=0.5' - # dashes to underscores in accept string - subtest_autodetect_language :en_au, 'monkey', nil, 'de,EN-Au' - # remove dialect - subtest_autodetect_language :en, nil, 'en-bullshit', nil - subtest_autodetect_language :en, 'monkey', nil, 'de,EN-NZ,ja' - # different dialect - subtest_autodetect_language :ZH_HK, 'zh', nil, 'de,EN-NZ,ja' - subtest_autodetect_language :ZH_HK, 'monkey', 'zh', 'de,EN-NZ,ja' - - # Check param/cookie names use defaults - GLoc::CONFIG[:default_param_name] = 'p_lang' - GLoc::CONFIG[:default_cookie_name] = 'c_lang' - # :check_params - subtest_autodetect_language :def, 'en_au', nil, nil - subtest_autodetect_language :en_au, {:p_lang => 'en_au'}, nil, nil - # :check_cookie - subtest_autodetect_language :def, nil, 'en_us', nil - subtest_autodetect_language :en_US, nil, {:c_lang => 'en_us'}, nil - GLoc::CONFIG[:default_param_name] = 'plang' - GLoc::CONFIG[:default_cookie_name] = 'clang' - - # autodetect_language_filter :only => :auto2, :check_accept_header => false, :check_params => 'xx' - subtest_autodetect_language :def, 'ja', nil, 'en_US', :auto2 - subtest_autodetect_language :Ja, {:xx => 'ja'}, nil, 'en_US', :auto2 - subtest_autodetect_language :en_au, 'ja', 'en_au', 'en_US', :auto2 - - # autodetect_language_filter :only => :auto3, :check_cookie => false - subtest_autodetect_language :Ja, 'ja', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5', :auto3 - subtest_autodetect_language :ZH_HK, 'hehe', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5', :auto3 - - # autodetect_language_filter :only => :auto4, :check_cookie => 'qwe', :check_params => false - subtest_autodetect_language :def, 'ja', 'en_us', nil, :auto4 - subtest_autodetect_language :ZH_HK, 'ja', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5', :auto4 - subtest_autodetect_language :en_US, 'ja', {:qwe => 'en_us'}, 'ja', :auto4 - end - - def subtest_autodetect_language(expected,params,cookie,accept, action=:auto) - begin_new_request - params= {'plang' => params} if params.is_a?(String) - params ||= {} - if cookie - cookie={'clang' => cookie} unless cookie.is_a?(Hash) - cookie.each_pair {|k,v| @request.cookies[k.to_s]= CGI::Cookie.new(k.to_s,v)} - end - @request.env['HTTP_ACCEPT_LANGUAGE']= accept - get action, params - assert_equal expected, @controller.current_language - if action == :auto - s,b = expected != :def ? [1,nil] : [nil,1] - assert_equal s, @controller.callback_set - assert_equal b, @controller.callback_bad - end - end - -end \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/gloc_test.rb b/redmine/vendor/plugins/gloc-1.1.0/test/gloc_test.rb deleted file mode 100644 index a39d5c41c..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/gloc_test.rb +++ /dev/null @@ -1,433 +0,0 @@ -# Copyright (c) 2005-2006 David Barri - -$LOAD_PATH.push File.join(File.dirname(__FILE__),'..','lib') -require 'gloc' -require 'gloc-ruby' -require 'gloc-config' -require 'gloc-rails-text' -require File.join(File.dirname(__FILE__),'lib','rails-time_ext') unless 3.respond_to?(:days) -require File.join(File.dirname(__FILE__),'lib','rails-string_ext') unless ''.respond_to?(:starts_with?) -#require 'gloc-dev' - -class LClass; include GLoc; end -class LClass2 < LClass; end -class LClass_en < LClass2; set_language :en; end -class LClass_ja < LClass2; set_language :ja; end -# class LClass_forced_au < LClass; set_language :en; force_language :en_AU; set_language :ja; end - -class GLocTest < Test::Unit::TestCase - include GLoc - include ActionView::Helpers::DateHelper - - def setup - @l1 = LClass.new - @l2 = LClass.new - @l3 = LClass.new - @l1.set_language :ja - @l2.set_language :en - @l3.set_language 'en_AU' - @gloc_state= GLoc.backup_state true - GLoc::CONFIG.merge!({ - :default_param_name => 'lang', - :default_cookie_name => 'lang', - :default_language => :ja, - :raise_string_not_found_errors => true, - :verbose => false, - }) - end - - def teardown - GLoc.restore_state @gloc_state - end - - #--------------------------------------------------------------------------- - - def test_basic - assert_localized_value [nil, @l1, @l2, @l3], nil, :in_both_langs - - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') - - assert_localized_value [nil, @l1], 'enにもjaにもある', :in_both_langs - assert_localized_value [nil, @l1], '日本語のみ', :ja_only - assert_localized_value [nil, @l1], nil, :en_only - - assert_localized_value @l2, 'This is in en+ja', :in_both_langs - assert_localized_value @l2, nil, :ja_only - assert_localized_value @l2, 'English only', :en_only - - assert_localized_value @l3, "Thiz in en 'n' ja", :in_both_langs - assert_localized_value @l3, nil, :ja_only - assert_localized_value @l3, 'Aussie English only bro', :en_only - - @l3.set_language :en - assert_localized_value @l3, 'This is in en+ja', :in_both_langs - assert_localized_value @l3, nil, :ja_only - assert_localized_value @l3, 'English only', :en_only - - assert_localized_value nil, 'enにもjaにもある', :in_both_langs - assert_localized_value nil, '日本語のみ', :ja_only - assert_localized_value nil, nil, :en_only - end - - def test_load_twice_with_override - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang2') - - assert_localized_value [nil, @l1], '更新された', :in_both_langs - assert_localized_value [nil, @l1], '日本語のみ', :ja_only - assert_localized_value [nil, @l1], nil, :en_only - assert_localized_value [nil, @l1], nil, :new_en - assert_localized_value [nil, @l1], '新たな日本語ストリング', :new_ja - - assert_localized_value @l2, 'This is in en+ja', :in_both_langs - assert_localized_value @l2, nil, :ja_only - assert_localized_value @l2, 'overriden dude', :en_only - assert_localized_value @l2, 'This is a new English string', :new_en - assert_localized_value @l2, nil, :new_ja - - assert_localized_value @l3, "Thiz in en 'n' ja", :in_both_langs - assert_localized_value @l3, nil, :ja_only - assert_localized_value @l3, 'Aussie English only bro', :en_only - end - - def test_load_twice_without_override - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang2'), false - - assert_localized_value [nil, @l1], 'enにもjaにもある', :in_both_langs - assert_localized_value [nil, @l1], '日本語のみ', :ja_only - assert_localized_value [nil, @l1], nil, :en_only - assert_localized_value [nil, @l1], nil, :new_en - assert_localized_value [nil, @l1], '新たな日本語ストリング', :new_ja - - assert_localized_value @l2, 'This is in en+ja', :in_both_langs - assert_localized_value @l2, nil, :ja_only - assert_localized_value @l2, 'English only', :en_only - assert_localized_value @l2, 'This is a new English string', :new_en - assert_localized_value @l2, nil, :new_ja - - assert_localized_value @l3, "Thiz in en 'n' ja", :in_both_langs - assert_localized_value @l3, nil, :ja_only - assert_localized_value @l3, 'Aussie English only bro', :en_only - end - - def test_add_localized_strings - assert_localized_value nil, nil, :add - assert_localized_value nil, nil, :ja_only - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') - assert_localized_value nil, nil, :add - assert_localized_value nil, '日本語のみ', :ja_only - GLoc.add_localized_strings 'en', {:ja_only => 'bullshit'}, true - GLoc.add_localized_strings 'en', {:ja_only => 'bullshit'}, false - assert_localized_value nil, nil, :add - assert_localized_value nil, '日本語のみ', :ja_only - GLoc.add_localized_strings 'ja', {:ja_only => 'bullshit', :add => '123'}, false - assert_localized_value nil, '123', :add - assert_localized_value nil, '日本語のみ', :ja_only - GLoc.add_localized_strings 'ja', {:ja_only => 'bullshit', :add => '234'} - assert_localized_value nil, '234', :add - assert_localized_value nil, 'bullshit', :ja_only - end - - def test_class_set_language - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') - - @l1 = LClass_ja.new - @l2 = LClass_en.new - @l3 = LClass_en.new - - assert_localized_value @l1, 'enにもjaにもある', :in_both_langs - assert_localized_value @l2, 'This is in en+ja', :in_both_langs - assert_localized_value @l3, 'This is in en+ja', :in_both_langs - - @l3.set_language 'en_AU' - - assert_localized_value @l1, 'enにもjaにもある', :in_both_langs - assert_localized_value @l2, 'This is in en+ja', :in_both_langs - assert_localized_value @l3, "Thiz in en 'n' ja", :in_both_langs - end - - def test_ll - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') - - assert_equal 'enにもjaにもある', ll('ja',:in_both_langs) - assert_equal 'enにもjaにもある', GLoc::ll('ja',:in_both_langs) - assert_equal 'enにもjaにもある', LClass_en.ll('ja',:in_both_langs) - assert_equal 'enにもjaにもある', LClass_ja.ll('ja',:in_both_langs) - - assert_equal 'This is in en+ja', ll('en',:in_both_langs) - assert_equal 'This is in en+ja', GLoc::ll('en',:in_both_langs) - assert_equal 'This is in en+ja', LClass_en.ll('en',:in_both_langs) - assert_equal 'This is in en+ja', LClass_ja.ll('en',:in_both_langs) - end - - def test_lsym - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') - assert_equal 'enにもjaにもある', LClass_ja.ltry(:in_both_langs) - assert_equal 'hello', LClass_ja.ltry('hello') - assert_equal nil, LClass_ja.ltry(nil) - end - -# def test_forced -# assert_equal :en_AU, LClass_forced_au.current_language -# a= LClass_forced_au.new -# a.set_language :ja -# assert_equal :en_AU, a.current_language -# a.force_language :ja -# assert_equal :ja, a.current_language -# assert_equal :en_AU, LClass_forced_au.current_language -# end - - def test_pluralization - GLoc.add_localized_strings :en, :_gloc_rule_default => %[|n| case n; when 0 then '_none'; when 1 then '_single'; else '_many'; end], :a_single => '%d man', :a_many => '%d men', :a_none => 'No men' - GLoc.add_localized_strings :en, :_gloc_rule_asd => %[|n| n<10 ? '_few' : '_heaps'], :a_few => 'a few men (%d)', :a_heaps=> 'soo many men' - set_language :en - - assert_equal 'No men', lwr(:a, 0) - assert_equal '1 man', lwr(:a, 1) - assert_equal '3 men', lwr(:a, 3) - assert_equal '20 men', lwr(:a, 20) - - assert_equal 'a few men (0)', lwr_(:asd, :a, 0) - assert_equal 'a few men (1)', lwr_(:asd, :a, 1) - assert_equal 'a few men (3)', lwr_(:asd, :a, 3) - assert_equal 'soo many men', lwr_(:asd, :a, 12) - assert_equal 'soo many men', lwr_(:asd, :a, 20) - - end - - def test_distance_in_words - load_default_strings - [ - [20.seconds, 'less than a minute', '1分以内', 'меньше минуты'], - [80.seconds, '1 minute', '1分', '1 минуту'], - [3.seconds, 'less than 5 seconds', '5秒以内', 'менее 5 секунд', true], - [9.seconds, 'less than 10 seconds', '10秒以内', 'менее 10 секунд', true], - [16.seconds, 'less than 20 seconds', '20秒以内', 'менее 20 секунд', true], - [35.seconds, 'half a minute', '約30秒', 'полминуты', true], - [50.seconds, 'less than a minute', '1分以内', 'меньше минуты', true], - [1.1.minutes, '1 minute', '1分', '1 минуту'], - [2.1.minutes, '2 minutes', '2分', '2 минуты'], - [4.1.minutes, '4 minutes', '4分', '4 минуты'], - [5.1.minutes, '5 minutes', '5分', '5 минут'], - [1.1.hours, 'about an hour', '約1時間', 'около часа'], - [3.1.hours, 'about 3 hours', '約3時間', 'около 3 часов'], - [9.1.hours, 'about 9 hours', '約9時間', 'около 9 часов'], - [1.1.days, '1 day', '1日間', '1 день'], - [2.1.days, '2 days', '2日間', '2 дня'], - [4.days, '4 days', '4日間', '4 дня'], - [6.days, '6 days', '6日間', '6 дней'], - [11.days, '11 days', '11日間', '11 дней'], - [12.days, '12 days', '12日間', '12 дней'], - [15.days, '15 days', '15日間', '15 дней'], - [20.days, '20 days', '20日間', '20 дней'], - [21.days, '21 days', '21日間', '21 день'], - [22.days, '22 days', '22日間', '22 дня'], - [25.days, '25 days', '25日間', '25 дней'], - ].each do |a| - t, en, ja, ru = a - inc_sec= (a.size == 5) ? a[-1] : false - set_language :en - assert_equal en, distance_of_time_in_words(t,0,inc_sec) - set_language :ja - assert_equal ja, distance_of_time_in_words(t,0,inc_sec) - set_language :ru - assert_equal ru, distance_of_time_in_words(t,0,inc_sec) - end - end - - def test_age - load_default_strings - [ - [1, '1 yr', '1歳', '1 год'], - [22, '22 yrs', '22歳', '22 года'], - [27, '27 yrs', '27歳', '27 лет'], - ].each do |a, en, ja, ru| - set_language :en - assert_equal en, l_age(a) - set_language :ja - assert_equal ja, l_age(a) - set_language :ru - assert_equal ru, l_age(a) - end - end - - def test_yesno - load_default_strings - set_language :en - assert_equal 'yes', l_yesno(true) - assert_equal 'no', l_yesno(false) - assert_equal 'Yes', l_YesNo(true) - assert_equal 'No', l_YesNo(false) - end - - def test_all_languages_have_values_for_helpers - load_default_strings - t= Time.local(2000, 9, 15, 11, 23, 57) - GLoc.valid_languages.each {|l| - set_language l - 0.upto(120) {|n| l_age(n)} - l_date(t) - l_datetime(t) - l_datetime_short(t) - l_time(t) - [true,false].each{|v| l_YesNo(v); l_yesno(v) } - } - end - - def test_similar_languages - GLoc.add_localized_strings :en, :a => 'a' - GLoc.add_localized_strings :en_AU, :a => 'a' - GLoc.add_localized_strings :ja, :a => 'a' - GLoc.add_localized_strings :zh_tw, :a => 'a' - - assert_equal :en, GLoc.similar_language(:en) - assert_equal :en, GLoc.similar_language('en') - assert_equal :ja, GLoc.similar_language(:ja) - assert_equal :ja, GLoc.similar_language('ja') - # lowercase + dashes to underscores - assert_equal :en, GLoc.similar_language('EN') - assert_equal :en, GLoc.similar_language(:EN) - assert_equal :en_AU, GLoc.similar_language(:EN_Au) - assert_equal :en_AU, GLoc.similar_language('eN-Au') - # remove dialect - assert_equal :ja, GLoc.similar_language(:ja_Au) - assert_equal :ja, GLoc.similar_language('JA-ASDF') - assert_equal :ja, GLoc.similar_language('jA_ASD_ZXC') - # different dialect - assert_equal :zh_tw, GLoc.similar_language('ZH') - assert_equal :zh_tw, GLoc.similar_language('ZH_HK') - assert_equal :zh_tw, GLoc.similar_language('ZH-BUL') - # non matching - assert_equal nil, GLoc.similar_language('WW') - assert_equal nil, GLoc.similar_language('WW_AU') - assert_equal nil, GLoc.similar_language('WW-AU') - assert_equal nil, GLoc.similar_language('eZ_en') - assert_equal nil, GLoc.similar_language('AU-ZH') - end - - def test_clear_strings_and_similar_langs - GLoc.add_localized_strings :en, :a => 'a' - GLoc.add_localized_strings :en_AU, :a => 'a' - GLoc.add_localized_strings :ja, :a => 'a' - GLoc.add_localized_strings :zh_tw, :a => 'a' - GLoc.clear_strings :en, :ja - assert_equal nil, GLoc.similar_language('ja') - assert_equal :en_AU, GLoc.similar_language('en') - assert_equal :zh_tw, GLoc.similar_language('ZH_HK') - GLoc.clear_strings - assert_equal nil, GLoc.similar_language('ZH_HK') - end - - def test_lang_name - GLoc.add_localized_strings :en, :general_lang_en => 'English', :general_lang_ja => 'Japanese' - GLoc.add_localized_strings :ja, :general_lang_en => '英語', :general_lang_ja => '日本語' - set_language :en - assert_equal 'Japanese', l_lang_name(:ja) - assert_equal 'English', l_lang_name('en') - set_language :ja - assert_equal '日本語', l_lang_name('ja') - assert_equal '英語', l_lang_name(:en) - end - - def test_charset_change_all - load_default_strings - GLoc.add_localized_strings :ja2, :a => 'a' - GLoc.valid_languages # Force refresh if in dev mode - GLoc.class_eval 'LOCALIZED_STRINGS[:ja2]= LOCALIZED_STRINGS[:ja].clone' - - [:ja, :ja2].each do |l| - set_language l - assert_equal 'はい', l_yesno(true) - assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase - end - - GLoc.set_charset 'sjis' - assert_equal 'sjis', GLoc.get_charset(:ja) - assert_equal 'sjis', GLoc.get_charset(:ja2) - - [:ja, :ja2].each do |l| - set_language l - assert_equal "82CD82A2", l_yesno(true).unpack('H*')[0].upcase - end - end - - def test_charset_change_single - load_default_strings - GLoc.add_localized_strings :ja2, :a => 'a' - GLoc.add_localized_strings :ja3, :a => 'a' - GLoc.valid_languages # Force refresh if in dev mode - GLoc.class_eval 'LOCALIZED_STRINGS[:ja2]= LOCALIZED_STRINGS[:ja].clone' - GLoc.class_eval 'LOCALIZED_STRINGS[:ja3]= LOCALIZED_STRINGS[:ja].clone' - - [:ja, :ja2, :ja3].each do |l| - set_language l - assert_equal 'はい', l_yesno(true) - assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase - end - - GLoc.set_charset 'sjis', :ja - assert_equal 'sjis', GLoc.get_charset(:ja) - assert_equal 'utf-8', GLoc.get_charset(:ja2) - assert_equal 'utf-8', GLoc.get_charset(:ja3) - - set_language :ja - assert_equal "82CD82A2", l_yesno(true).unpack('H*')[0].upcase - set_language :ja2 - assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase - set_language :ja3 - assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase - - GLoc.set_charset 'euc-jp', :ja, :ja3 - assert_equal 'euc-jp', GLoc.get_charset(:ja) - assert_equal 'utf-8', GLoc.get_charset(:ja2) - assert_equal 'euc-jp', GLoc.get_charset(:ja3) - - set_language :ja - assert_equal "A4CFA4A4", l_yesno(true).unpack('H*')[0].upcase - set_language :ja2 - assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase - set_language :ja3 - assert_equal "A4CFA4A4", l_yesno(true).unpack('H*')[0].upcase - end - - def test_set_language_if_valid - GLoc.add_localized_strings :en, :a => 'a' - GLoc.add_localized_strings :zh_tw, :a => 'a' - - assert set_language_if_valid('en') - assert_equal :en, current_language - - assert set_language_if_valid('zh_tw') - assert_equal :zh_tw, current_language - - assert !set_language_if_valid(nil) - assert_equal :zh_tw, current_language - - assert !set_language_if_valid('ja') - assert_equal :zh_tw, current_language - - assert set_language_if_valid(:en) - assert_equal :en, current_language - end - - #=========================================================================== - protected - - def assert_localized_value(objects,expected,key) - objects = [objects] unless objects.kind_of?(Array) - objects.each {|object| - o = object || GLoc - assert_equal !expected.nil?, o.l_has_string?(key) - if expected.nil? - assert_raise(GLoc::StringNotFoundError) {o.l(key)} - else - assert_equal expected, o.l(key) - end - } - end - - def load_default_strings - GLoc.load_localized_strings File.join(File.dirname(__FILE__),'..','lang') - end -end \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/lang/en.yaml b/redmine/vendor/plugins/gloc-1.1.0/test/lang/en.yaml deleted file mode 100644 index 325dc599e..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/lang/en.yaml +++ /dev/null @@ -1,2 +0,0 @@ -in_both_langs: This is in en+ja -en_only: English only \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml b/redmine/vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml deleted file mode 100644 index 307cc7859..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml +++ /dev/null @@ -1,2 +0,0 @@ -in_both_langs: Thiz in en 'n' ja -en_only: Aussie English only bro \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/lang/ja.yml b/redmine/vendor/plugins/gloc-1.1.0/test/lang/ja.yml deleted file mode 100644 index 64df03376..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/lang/ja.yml +++ /dev/null @@ -1,2 +0,0 @@ -in_both_langs: enにもjaにもある -ja_only: 日本語のみ \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/lang2/en.yml b/redmine/vendor/plugins/gloc-1.1.0/test/lang2/en.yml deleted file mode 100644 index e6467e7a0..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/lang2/en.yml +++ /dev/null @@ -1,2 +0,0 @@ -en_only: overriden dude -new_en: This is a new English string \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml b/redmine/vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml deleted file mode 100644 index 864b287d0..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml +++ /dev/null @@ -1,2 +0,0 @@ -in_both_langs: 更新された -new_ja: 新たな日本語ストリング \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/lib/rails-string_ext.rb b/redmine/vendor/plugins/gloc-1.1.0/test/lib/rails-string_ext.rb deleted file mode 100644 index 418d28db2..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/lib/rails-string_ext.rb +++ /dev/null @@ -1,23 +0,0 @@ -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module String #:nodoc: - # Additional string tests. - module StartsEndsWith - # Does the string start with the specified +prefix+? - def starts_with?(prefix) - prefix = prefix.to_s - self[0, prefix.length] == prefix - end - - # Does the string end with the specified +suffix+? - def ends_with?(suffix) - suffix = suffix.to_s - self[-suffix.length, suffix.length] == suffix - end - end - end - end -end -class String - include ActiveSupport::CoreExtensions::String::StartsEndsWith -end \ No newline at end of file diff --git a/redmine/vendor/plugins/gloc-1.1.0/test/lib/rails-time_ext.rb b/redmine/vendor/plugins/gloc-1.1.0/test/lib/rails-time_ext.rb deleted file mode 100644 index d8771e4e6..000000000 --- a/redmine/vendor/plugins/gloc-1.1.0/test/lib/rails-time_ext.rb +++ /dev/null @@ -1,76 +0,0 @@ -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Numeric #:nodoc: - # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years. - # - # If you need precise date calculations that doesn't just treat months as 30 days, then have - # a look at Time#advance. - # - # Some of these methods are approximations, Ruby's core - # Date[http://stdlib.rubyonrails.org/libdoc/date/rdoc/index.html] and - # Time[http://stdlib.rubyonrails.org/libdoc/time/rdoc/index.html] should be used for precision - # date and time arithmetic - module Time - def seconds - self - end - alias :second :seconds - - def minutes - self * 60 - end - alias :minute :minutes - - def hours - self * 60.minutes - end - alias :hour :hours - - def days - self * 24.hours - end - alias :day :days - - def weeks - self * 7.days - end - alias :week :weeks - - def fortnights - self * 2.weeks - end - alias :fortnight :fortnights - - def months - self * 30.days - end - alias :month :months - - def years - (self * 365.25.days).to_i - end - alias :year :years - - # Reads best without arguments: 10.minutes.ago - def ago(time = ::Time.now) - time - self - end - - # Reads best with argument: 10.minutes.until(time) - alias :until :ago - - # Reads best with argument: 10.minutes.since(time) - def since(time = ::Time.now) - time + self - end - - # Reads best without arguments: 10.minutes.from_now - alias :from_now :since - end - end - end -end - -class Numeric #:nodoc: - include ActiveSupport::CoreExtensions::Numeric::Time -end diff --git a/redmine/vendor/plugins/rfpdf/CHANGELOG b/redmine/vendor/plugins/rfpdf/CHANGELOG deleted file mode 100644 index 6822b8364..000000000 --- a/redmine/vendor/plugins/rfpdf/CHANGELOG +++ /dev/null @@ -1,13 +0,0 @@ -1.00 Added view template functionality -1.10 Added Chinese support -1.11 Added Japanese support -1.12 Added Korean support -1.13 Updated to fpdf.rb 1.53d. - Added makefont and fpdf_eps. - Handle \n at the beginning of a string in MultiCell. - Tried to fix clipping issue in MultiCell - still needs some work. -1.14 2006-09-26 -* Added support for @options_for_rfpdf hash for configuration: - * Added :filename option in this hash -If you're using the same settings for @options_for_rfpdf often, you might want to -put your assignment in a before_filter (perhaps overriding :filename, etc in your actions). diff --git a/redmine/vendor/plugins/rfpdf/MIT-LICENSE b/redmine/vendor/plugins/rfpdf/MIT-LICENSE deleted file mode 100644 index f39a79dc0..000000000 --- a/redmine/vendor/plugins/rfpdf/MIT-LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2006 4ssoM LLC - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND -NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/redmine/vendor/plugins/rfpdf/README b/redmine/vendor/plugins/rfpdf/README deleted file mode 100644 index 9db19075b..000000000 --- a/redmine/vendor/plugins/rfpdf/README +++ /dev/null @@ -1,99 +0,0 @@ -= RFPDF Template Plugin - -A template plugin allowing the inclusion of ERB-enabled RFPDF template files. - -== Example .rb method Usage - -In the controller, something like: - - def mypdf - pdf = FPDF.new() - - # - # Chinese - # - pdf.extend(PDF_Chinese) - pdf.AddPage - pdf.AddBig5Font - pdf.SetFont('Big5','',18) - pdf.Write(5, '²{®É®ð·Å 18 C Àã«× 83 %') - icBig5 = Iconv.new('Big5', 'UTF-8') - pdf.Write(15, icBig5.iconv("宋体 should be working")) - send_data pdf.Output, :filename => "something.pdf", :type => "application/pdf" - end - -== Example .rfdf Usage - -In the controller, something like: - - def mypdf - @options_for_rfpdf ||= {} - @options_for_rfpdf[:file_name] = "nice_looking.pdf" - end - -In the layout (make sure this is the only item in the layout): -<%= @content_for_layout %> - -In the view (mypdf.rfpdf): - -<% - pdf = FPDF.new() - # - # Chinese - # - pdf.extend(PDF_Chinese) - pdf.AddPage - pdf.AddBig5Font - pdf.SetFont('Big5','',18) - pdf.Write(5, '²{®É®ð·Å 18 C Àã«× 83 %') - icBig5 = Iconv.new('Big5', 'UTF-8') - pdf.Write(15, icBig5.iconv("宋体 should be working")) - - # - # Japanese - # - pdf.extend(PDF_Japanese) - pdf.AddSJISFont(); - pdf.AddPage(); - pdf.SetFont('SJIS','',18); - pdf.Write(5,'9ÉñåéÇÃåˆäJÉeÉXÉgÇåoǃPHP 3.0ÇÕ1998îN6åéÇ…åˆéÆÇ…ÉäÉäÅ[ÉXÇ≥ÇÍNjǵÇΩÅB'); - icSJIS = Iconv.new('SJIS', 'UTF-8') - pdf.Write(15, icSJIS.iconv("これはテキストである should be working")) - - # - # Korean - # - pdf.extend(PDF_Korean) - pdf.AddUHCFont(); - pdf.AddPage(); - pdf.SetFont('UHC','',18); - pdf.Write(5,'PHP 3.0Àº 1998³â 6¿ù¿¡ °ø½ÄÀûÀ¸·Î ¸±¸®ÁîµÇ¾ú´Ù. °ø°³ÀûÀÎ Å×½ºÆ® ÀÌÈľà 9°³¿ù¸¸À̾ú´Ù.'); - icUHC = Iconv.new('UHC', 'UTF-8') - pdf.Write(15, icUHC.iconv("이것은 원본 이다")) - - # - # English - # - pdf.AddPage(); - pdf.SetFont('Arial', '', 10) - pdf.Write(5, "should be working") -%> -<%= pdf.Output() %> - - -== Configuring - -You can configure Rfpdf by using an @options_for_rfpdf hash in your controllers. - -Here are a few options: - -:filename (default: action_name.pdf) - Filename of PDF to generate - -Note: If you're using the same settings for @options_for_rfpdf often, you might want to -put your assignment in a before_filter (perhaps overriding :filename, etc in your actions). - -== Problems - -Layouts and partials are currently not supported; just need -to wrap the PDF generation differently. diff --git a/redmine/vendor/plugins/rfpdf/init.rb b/redmine/vendor/plugins/rfpdf/init.rb deleted file mode 100644 index 7e51d9eba..000000000 --- a/redmine/vendor/plugins/rfpdf/init.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'rfpdf' - -ActionView::Base::register_template_handler 'rfpdf', RFPDF::View \ No newline at end of file diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf.rb deleted file mode 100644 index 9fc0683ef..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf.rb +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2006 4ssoM LLC -# -# The MIT License -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -$LOAD_PATH.unshift(File.dirname(__FILE__)) - -require 'rfpdf/errors' -require 'rfpdf/view' -require 'rfpdf/fpdf' -require 'rfpdf/rfpdf' -require 'rfpdf/chinese' -require 'rfpdf/japanese' -require 'rfpdf/korean' diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb deleted file mode 100644 index a04ccd18d..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb +++ /dev/null @@ -1,99 +0,0 @@ -# Translation of the bookmark class from the PHP FPDF script from Olivier Plathey -# Translated by Sylvain Lafleur and ?? with the help of Brian Ollenberger -# -# First added in 1.53b -# -# Usage is as follows: -# -# require 'fpdf' -# require 'bookmark' -# pdf = FPDF.new -# pdf.extend(PDF_Bookmark) -# -# This allows it to be combined with other extensions, such as the Chinese -# module. - -module PDF_Bookmark - def PDF_Bookmark.extend_object(o) - o.instance_eval('@outlines,@OutlineRoot=[],0') - super(o) - end - - def Bookmark(txt,level=0,y=0) - y=self.GetY() if y==-1 - @outlines.push({'t'=>txt,'l'=>level,'y'=>y,'p'=>self.PageNo()}) - end - - def putbookmarks - @nb=@outlines.size - return if @nb==0 - lru=[] - level=0 - @outlines.each_index do |i| - o=@outlines[i] - if o['l']>0 - parent=lru[o['l']-1] - # Set parent and last pointers - @outlines[i]['parent']=parent - @outlines[parent]['last']=i - if o['l']>level - # Level increasing: set first pointer - @outlines[parent]['first']=i - end - else - @outlines[i]['parent']=@nb - end - if o['l']<=level and i>0 - # Set prev and next pointers - prev=lru[o['l']] - @outlines[prev]['next']=i - @outlines[i]['prev']=prev - end - lru[o['l']]=i - level=o['l'] - end - # Outline items - n=@n+1 - @outlines.each_index do |i| - o=@outlines[i] - newobj - out('<>') - out('endobj') - end - # Outline root - newobj - @OutlineRoot=@n - out('<>') - out('endobj') - end - - def putresources - super - putbookmarks - end - - def putcatalog - super - if not @outlines.empty? - out('/Outlines '+@OutlineRoot.to_s+' 0 R') - out('/PageMode /UseOutlines') - end - end -end diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/chinese.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/chinese.rb deleted file mode 100644 index 731d582a2..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/chinese.rb +++ /dev/null @@ -1,473 +0,0 @@ -# Copyright (c) 2006 4ssoM LLC -# 1.12 contributed by Ed Moss. -# -# The MIT License -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# This is direct port of chinese.php -# -# Chinese PDF support. -# -# Usage is as follows: -# -# require 'fpdf' -# require 'chinese' -# pdf = FPDF.new -# pdf.extend(PDF_Chinese) -# -# This allows it to be combined with other extensions, such as the bookmark -# module. - -module PDF_Chinese - - Big5_widths={' '=>250,'!'=>250,'"'=>408,'#'=>668,''=>490,'%'=>875,'&'=>698,'\''=>250, - '('=>240,')'=>240,'*'=>417,'+'=>667,','=>250,'-'=>313,'.'=>250,'/'=>520,'0'=>500,'1'=>500, - '2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>250,''=>250, - '<'=>667,'='=>667,'>'=>667,'?'=>396,'@'=>921,'A'=>677,'B'=>615,'C'=>719,'D'=>760,'E'=>625, - 'F'=>552,'G'=>771,'H'=>802,'I'=>354,'J'=>354,'K'=>781,'L'=>604,'M'=>927,'N'=>750,'O'=>823, - 'P'=>563,'Q'=>823,'R'=>729,'S'=>542,'T'=>698,'U'=>771,'V'=>729,'W'=>948,'X'=>771,'Y'=>677, - 'Z'=>635,'['=>344,'\\'=>520,']'=>344,'^'=>469,'_'=>500,'`'=>250,'a'=>469,'b'=>521,'c'=>427, - 'd'=>521,'e'=>438,'f'=>271,'g'=>469,'h'=>531,'i'=>250,'j'=>250,'k'=>458,'l'=>240,'m'=>802, - 'n'=>531,'o'=>500,'p'=>521,'q'=>521,'r'=>365,'s'=>333,'t'=>292,'u'=>521,'v'=>458,'w'=>677, - 'x'=>479,'y'=>458,'z'=>427,'{'=>480,'|'=>496,'end'=>480,'~'=>667} - - GB_widths={' '=>207,'!'=>270,'"'=>342,'#'=>467,''=>462,'%'=>797,'&'=>710,'\''=>239, - '('=>374,')'=>374,'*'=>423,'+'=>605,','=>238,'-'=>375,'.'=>238,'/'=>334,'0'=>462,'1'=>462, - '2'=>462,'3'=>462,'4'=>462,'5'=>462,'6'=>462,'7'=>462,'8'=>462,'9'=>462,':'=>238,''=>238, - '<'=>605,'='=>605,'>'=>605,'?'=>344,'@'=>748,'A'=>684,'B'=>560,'C'=>695,'D'=>739,'E'=>563, - 'F'=>511,'G'=>729,'H'=>793,'I'=>318,'J'=>312,'K'=>666,'L'=>526,'M'=>896,'N'=>758,'O'=>772, - 'P'=>544,'Q'=>772,'R'=>628,'S'=>465,'T'=>607,'U'=>753,'V'=>711,'W'=>972,'X'=>647,'Y'=>620, - 'Z'=>607,'['=>374,'\\'=>333,']'=>374,'^'=>606,'_'=>500,'`'=>239,'a'=>417,'b'=>503,'c'=>427, - 'd'=>529,'e'=>415,'f'=>264,'g'=>444,'h'=>518,'i'=>241,'j'=>230,'k'=>495,'l'=>228,'m'=>793, - 'n'=>527,'o'=>524,'p'=>524,'q'=>504,'r'=>338,'s'=>336,'t'=>277,'u'=>517,'v'=>450,'w'=>652, - 'x'=>466,'y'=>452,'z'=>407,'{'=>370,'|'=>258,'end'=>370,'~'=>605} - - def AddCIDFont(family,style,name,cw,cMap,registry) -#ActionController::Base::logger.debug registry.to_a.join(":").to_s - fontkey=family.downcase+style.upcase - unless @fonts[fontkey].nil? - Error("Font already added: family style") - end - i=@fonts.length+1 - name=name.gsub(' ','') - @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw, 'CMap'=>cMap,'registry'=>registry} - end - - def AddCIDFonts(family,name,cw,cMap,registry) - AddCIDFont(family,'',name,cw,cMap,registry) - AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) - AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) - AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) - end - - def AddBig5Font(family='Big5',name='MSungStd-Light-Acro') - #Add Big5 font with proportional Latin - cw=Big5_widths - cMap='ETenms-B5-H' - registry={'ordering'=>'CNS1','supplement'=>0} -#ActionController::Base::logger.debug registry.to_a.join(":").to_s - AddCIDFonts(family,name,cw,cMap,registry) - end - - def AddBig5hwFont(family='Big5-hw',name='MSungStd-Light-Acro') - #Add Big5 font with half-witdh Latin - cw = {} - 32.upto(126) do |i| - cw[i.chr]=500 - end - cMap='ETen-B5-H' - registry={'ordering'=>'CNS1','supplement'=>0} - AddCIDFonts(family,name,cw,cMap,registry) - end - - def AddGBFont(family='GB',name='STSongStd-Light-Acro') - #Add GB font with proportional Latin - cw=GB_widths - cMap='GBKp-EUC-H' - registry={'ordering'=>'GB1','supplement'=>2} - AddCIDFonts(family,name,cw,cMap,registry) - end - - def AddGBhwFont(family='GB-hw',name='STSongStd-Light-Acro') - #Add GB font with half-width Latin - 32.upto(126) do |i| - cw[i.chr]=500 - end - cMap='GBK-EUC-H' - registry={'ordering'=>'GB1','supplement'=>2} - AddCIDFonts(family,name,cw,cMap,registry) - end - - def GetStringWidth(s) - if(@CurrentFont['type']=='Type0') - return GetMBStringWidth(s) - else - return super(s) - end - end - - def GetMBStringWidth(s) - #Multi-byte version of GetStringWidth() - l=0 - cw=@CurrentFont['cw'] - nb=s.length - i=0 - while(i0 and s[nb-1]=="\n") - nb-=1 - end - b=0 - if(border) - if(border==1) - border='LTRB' - b='LRT' - b2='LR' - else - b2='' - if(border.index('L').nil?) - b2+='L' - end - if(border.index('R').nil?) - b2+='R' - end - b=border.index('T').nil? ? b2+'T' : b2 - end - end - sep=-1 - i=0 - j=0 - l=0 - nl=1 - while(iwmax) - #Automatic line break - if(sep==-1 or i==j) - if(i==j) - i+=ascii ? 1 : 2 - end - Cell(w,h,s[j,i-j],b,2,align,fill) - else - Cell(w,h,s[j,sep-j],b,2,align,fill) - i=(s[sep]==' ') ? sep+1 : sep - end - sep=-1 - j=i - l=0 -# nl+=1 - if(border and nl==2) - b=b2 - end - else - i+=ascii ? 1 : 2 - end - end - #Last chunk - if(border and not border.index('B').nil?) - b+='B' - end - Cell(w,h,s[j,i-j],b,2,align,fill) - @x=@lMargin - end - - def Write(h,txt,link='') - if(@CurrentFont['type']=='Type0') - MBWrite(h,txt,link) - else - super(h,txt,link) - end - end - - def MBWrite(h,txt,link) - #Multi-byte version of Write() - cw=@CurrentFont['cw'] - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - s=txt.gsub("\r",'') - nb=s.length - sep=-1 - i=0 - j=0 - l=0 - nl=1 - while(iwmax) - #Automatic line break - if(sep==-1 or i==j) - if(@x>@lMargin) - #Move to next line - @x=@lMargin - @y+=h - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - i+=1 - nl+=1 - next - end - if(i==j) - i+=ascii ? 1 : 2 - end - Cell(w,h,s[j,i-j],0,2,'',0,link) - else - Cell(w,h,s[j,sep-j],0,2,'',0,link) - i=(s[sep]==' ') ? sep+1 : sep - end - sep=-1 - j=i - l=0 - if(nl==1) - @x=@lMargin - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - end - nl+=1 - else - i+=ascii ? 1 : 2 - end - end - #Last chunk - if(i!=j) - Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link) - end - end - -private - - def putfonts() - nf=@n - @diffs.each do |diff| - #Encodings - newobj() - out('<>') - out('endobj') - end - # mqr=get_magic_quotes_runtime() - # set_magic_quotes_runtime(0) - @FontFiles.each_pair do |file, info| - #Font file embedding - newobj() - @FontFiles[file]['n']=@n - if(defined('FPDF_FONTPATH')) - file=FPDF_FONTPATH+file - end - size=filesize(file) - if(!size) - Error('Font file not found') - end - out('<>') - f=fopen(file,'rb') - putstream(fread(f,size)) - fclose(f) - out('endobj') - end -# - # set_magic_quotes_runtime(mqr) -# - @fonts.each_pair do |k, font| - #Font objects - newobj() - @fonts[k]['n']=@n - out('<>') - out('endobj') - if(font['type']!='core') - #Widths - newobj() - cw=font['cw'] - s='[' - 32.upto(255) do |i| - s+=cw[i.chr]+' ' - end - out(s+']') - out('endobj') - #Descriptor - newobj() - s='<>') - out('endobj') - end - end - end - end - - def putType0(font) - #Type0 - out('/Subtype /Type0') - out('/BaseFont /'+font['name']+'-'+font['CMap']) - out('/Encoding /'+font['CMap']) - out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') - out('>>') - out('endobj') - #CIDFont - newobj() - out('<>') - out('/FontDescriptor '+(@n+1).to_s+' 0 R') - if(font['CMap']=='ETen-B5-H') - w='13648 13742 500' - elsif(font['CMap']=='GBK-EUC-H') - w='814 907 500 7716 [500]' - else - # ActionController::Base::logger.debug font['cw'].keys.sort.join(' ').to_s - # ActionController::Base::logger.debug font['cw'].values.join(' ').to_s - w='1 [' - font['cw'].keys.sort.each {|key| - w+=font['cw'][key].to_s + " " -# ActionController::Base::logger.debug key.to_s -# ActionController::Base::logger.debug font['cw'][key].to_s - } - w +=']' - end - out('/W ['+w+']>>') - out('endobj') - #Font descriptor - newobj() - out('<>') - out('endobj') - end -end diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/errors.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/errors.rb deleted file mode 100644 index 2be2dae16..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/errors.rb +++ /dev/null @@ -1,4 +0,0 @@ -module RFPDF - class GenerationError < StandardError #:nodoc: - end -end \ No newline at end of file diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb deleted file mode 100644 index ad52e9e62..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb +++ /dev/null @@ -1,1550 +0,0 @@ -# Ruby FPDF 1.53d -# FPDF 1.53 by Olivier Plathey ported to Ruby by Brian Ollenberger -# Copyright 2005 Brian Ollenberger -# Please retain this entire copyright notice. If you distribute any -# modifications, place an additional comment here that clearly indicates -# that it was modified. You may (but are not send any useful modifications that you make -# back to me at http://zeropluszero.com/software/fpdf/ - -# Bug fixes, examples, external fonts, JPEG support, and upgrade to version -# 1.53 contributed by Kim Shrier. -# -# Bookmark support contributed by Sylvain Lafleur. -# -# EPS support contributed by Thiago Jackiw, ported from the PHP version by Valentin Schmidt. -# -# Bookmarks contributed by Sylvain Lafleur. -# -# 1.53 contributed by Ed Moss -# Handle '\n' at the beginning of a string -# Bookmarks contributed by Sylvain Lafleur. - -require 'date' -require 'zlib' - -class FPDF - FPDF_VERSION = '1.53d' - - Charwidths = { - 'courier'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], - - 'courierB'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], - - 'courierI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], - - 'courierBI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], - - 'helvetica'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500], - - 'helveticaB'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556], - - 'helveticaI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500], - - 'helveticaBI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556], - - 'times'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500, 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 350, 500, 350, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 350, 611, 350, 350, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333, 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500, 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500], - - 'timesB'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500, 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 350, 667, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333, 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500], - - 'timesI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500, 920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722, 611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500, 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500, 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 350, 500, 350, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 350, 556, 350, 350, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 350, 389, 556, 250, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 333, 760, 333, 400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500, 611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500, 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444], - - 'timesBI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722, 611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500, 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500, 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 350, 611, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 389, 611, 250, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 333, 747, 333, 400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500, 667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444], - - 'symbol'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444, 549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722, 768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500, 500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549, 549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 750, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603, 400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658, 823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713, 768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603, 494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494, 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0], - - 'zapfdingbats'=>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933, 911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537, 577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831, 923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826, 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762, 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0, 390, 390, 317, 317, 276, 276, 509, 509, 410, 410, 234, 234, 334, 334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834, 873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874, 0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0] - } - - def initialize(orientation='P', unit='mm', format='A4') - # Initialization of properties - @page=0 - @n=2 - @buffer='' - @pages=[] - @OrientationChanges=[] - @state=0 - @fonts={} - @FontFiles={} - @diffs=[] - @images={} - @links=[] - @PageLinks={} - @InFooter=false - @FontFamily='' - @FontStyle='' - @FontSizePt=12 - @underline= false - @DrawColor='0 G' - @FillColor='0 g' - @TextColor='0 g' - @ColorFlag=false - @ws=0 - @offsets=[] - - # Standard fonts - @CoreFonts={} - @CoreFonts['courier']='Courier' - @CoreFonts['courierB']='Courier-Bold' - @CoreFonts['courierI']='Courier-Oblique' - @CoreFonts['courierBI']='Courier-BoldOblique' - @CoreFonts['helvetica']='Helvetica' - @CoreFonts['helveticaB']='Helvetica-Bold' - @CoreFonts['helveticaI']='Helvetica-Oblique' - @CoreFonts['helveticaBI']='Helvetica-BoldOblique' - @CoreFonts['times']='Times-Roman' - @CoreFonts['timesB']='Times-Bold' - @CoreFonts['timesI']='Times-Italic' - @CoreFonts['timesBI']='Times-BoldItalic' - @CoreFonts['symbol']='Symbol' - @CoreFonts['zapfdingbats']='ZapfDingbats' - - # Scale factor - if unit=='pt' - @k=1 - elsif unit=='mm' - @k=72/25.4 - elsif unit=='cm' - @k=72/2.54; - elsif unit=='in' - @k=72 - else - raise 'Incorrect unit: '+unit - end - - # Page format - if format.is_a? String - format.downcase! - if format=='a3' - format=[841.89,1190.55] - elsif format=='a4' - format=[595.28,841.89] - elsif format=='a5' - format=[420.94,595.28] - elsif format=='letter' - format=[612,792] - elsif format=='legal' - format=[612,1008] - else - raise 'Unknown page format: '+format - end - @fwPt,@fhPt=format - else - @fwPt=format[0]*@k - @fhPt=format[1]*@k - end - @fw=@fwPt/@k; - @fh=@fhPt/@k; - - # Page orientation - orientation.downcase! - if orientation=='p' or orientation=='portrait' - @DefOrientation='P' - @wPt=@fwPt - @hPt=@fhPt - elsif orientation=='l' or orientation=='landscape' - @DefOrientation='L' - @wPt=@fhPt - @hPt=@fwPt - else - raise 'Incorrect orientation: '+orientation - end - @CurOrientation=@DefOrientation - @w=@wPt/@k - @h=@hPt/@k - - # Page margins (1 cm) - margin=28.35/@k - SetMargins(margin,margin) - # Interior cell margin (1 mm) - @cMargin=margin/10 - # Line width (0.2 mm) - @LineWidth=0.567/@k - # Automatic page break - SetAutoPageBreak(true,2*margin) - # Full width display mode - SetDisplayMode('fullwidth') - # Enable compression - SetCompression(true) - # Set default PDF version number - @PDFVersion='1.3' - end - - def SetMargins(left, top, right=-1) - # Set left, top and right margins - @lMargin=left - @tMargin=top - right=left if right==-1 - @rMargin=right - end - - def SetLeftMargin(margin) - # Set left margin - @lMargin=margin - @x=margin if @page>0 and @x0 - # Page footer - @InFooter=true - self.Footer - @InFooter=false - # Close page - endpage - end - # Start new page - beginpage(orientation) - # Set line cap style to square - out('2 J') - # Set line width - @LineWidth=lw - out(sprintf('%.2f w',lw*@k)) - # Set font - SetFont(family,style,size) if family - # Set colors - @DrawColor=dc - out(dc) if dc!='0 G' - @FillColor=fc - out(fc) if fc!='0 g' - @TextColor=tc - @ColorFlag=cf - # Page header - self.Header - # Restore line width - if @LineWidth!=lw - @LineWidth=lw - out(sprintf('%.2f w',lw*@k)) - end - # Restore font - self.SetFont(family,style,size) if family - # Restore colors - if @DrawColor!=dc - @DrawColor=dc - out(dc) - end - if @FillColor!=fc - @FillColor=fc - out(fc) - end - @TextColor=tc - @ColorFlag=cf - end - - def Header - # To be implemented in your inherited class - end - - def Footer - # To be implemented in your inherited class - end - - def PageNo - # Get current page number - @page - end - - def SetDrawColor(r,g=-1,b=-1) - # Set color for all stroking operations - if (r==0 and g==0 and b==0) or g==-1 - @DrawColor=sprintf('%.3f G',r/255.0) - else - @DrawColor=sprintf('%.3f %.3f %.3f RG',r/255.0,g/255.0,b/255.0) - end - out(@DrawColor) if(@page>0) - end - - def SetFillColor(r,g=-1,b=-1) - # Set color for all filling operations - if (r==0 and g==0 and b==0) or g==-1 - @FillColor=sprintf('%.3f g',r/255.0) - else - @FillColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0) - end - @ColorFlag=(@FillColor!=@TextColor) - out(@FillColor) if(@page>0) - end - - def SetTextColor(r,g=-1,b=-1) - # Set color for text - if (r==0 and g==0 and b==0) or g==-1 - @TextColor=sprintf('%.3f g',r/255.0) - else - @TextColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0) - end - @ColorFlag=(@FillColor!=@TextColor) - end - - def GetStringWidth(s) - # Get width of a string in the current font - cw=@CurrentFont['cw'] - w=0 - s.each_byte do |c| - w=w+cw[c] - end - w*@FontSize/1000.0 - end - - def SetLineWidth(width) - # Set line width - @LineWidth=width - out(sprintf('%.2f w',width*@k)) if @page>0 - end - - def Line(x1, y1, x2, y2) - # Draw a line - out(sprintf('%.2f %.2f m %.2f %.2f l S', - x1*@k,(@h-y1)*@k,x2*@k,(@h-y2)*@k)) - end - - def Rect(x, y, w, h, style='') - # Draw a rectangle - if style=='F' - op='f' - elsif style=='FD' or style=='DF' - op='B' - else - op='S' - end - out(sprintf('%.2f %.2f %.2f %.2f re %s', x*@k,(@h-y)*@k,w*@k,-h*@k,op)) - end - - def AddFont(family, style='', file='') - # Add a TrueType or Type1 font - family = family.downcase - family = 'helvetica' if family == 'arial' - - style = style.upcase - style = 'BI' if style == 'IB' - - fontkey = family + style - - if @fonts.has_key?(fontkey) - self.Error("Font already added: #{family} #{style}") - end - - file = family.gsub(' ', '') + style.downcase + '.rb' if file == '' - - if self.class.const_defined? 'FPDF_FONTPATH' - if FPDF_FONTPATH[-1,1] == '/' - file = FPDF_FONTPATH + file - else - file = FPDF_FONTPATH + '/' + file - end - end - - # Changed from "require file" to fix bug reported by Hans Allis. - load file - - if FontDef.desc.nil? - self.Error("Could not include font definition file #{file}") - end - - i = @fonts.length + 1 - - @fonts[fontkey] = {'i' => i, - 'type' => FontDef.type, - 'name' => FontDef.name, - 'desc' => FontDef.desc, - 'up' => FontDef.up, - 'ut' => FontDef.ut, - 'cw' => FontDef.cw, - 'enc' => FontDef.enc, - 'file' => FontDef.file - } - - if FontDef.diff - # Search existing encodings - unless @diffs.include?(FontDef.diff) - @diffs.push(FontDef.diff) - @fonts[fontkey]['diff'] = @diffs.length - 1 - end - end - - if FontDef.file - if FontDef.type == 'TrueType' - @FontFiles[FontDef.file] = {'length1' => FontDef.originalsize} - else - @FontFiles[FontDef.file] = {'length1' => FontDef.size1, 'length2' => FontDef.size2} - end - end - - return self - end - - def SetFont(family, style='', size=0) - # Select a font; size given in points - family.downcase! - family=@FontFamily if family=='' - if family=='arial' - family='helvetica' - elsif family=='symbol' or family=='zapfdingbats' - style='' - end - style.upcase! - unless style.index('U').nil? - @underline=true - style.gsub!('U','') - else - @underline=false; - end - style='BI' if style=='IB' - size=@FontSizePt if size==0 - # Test if font is already selected - return if @FontFamily==family and - @FontStyle==style and @FontSizePt==size - # Test if used for the first time - fontkey=family+style - unless @fonts.has_key?(fontkey) - if @CoreFonts.has_key?(fontkey) - unless Charwidths.has_key?(fontkey) - raise 'Font unavailable' - end - @fonts[fontkey]={ - 'i'=>@fonts.size, - 'type'=>'core', - 'name'=>@CoreFonts[fontkey], - 'up'=>-100, - 'ut'=>50, - 'cw'=>Charwidths[fontkey]} - else - raise 'Font unavailable' - end - end - - #Select it - @FontFamily=family - @FontStyle=style; - @FontSizePt=size - @FontSize=size/@k; - @CurrentFont=@fonts[fontkey] - if @page>0 - out(sprintf('BT /F%d %.2f Tf ET', @CurrentFont['i'], @FontSizePt)) - end - end - - def SetFontSize(size) - # Set font size in points - return if @FontSizePt==size - @FontSizePt=size - @FontSize=size/@k - if @page>0 - out(sprintf('BT /F%d %.2f Tf ET',@CurrentFont['i'],@FontSizePt)) - end - end - - def AddLink - # Create a new internal link - @links.push([0, 0]) - @links.size - end - - def SetLink(link, y=0, page=-1) - # Set destination of internal link - y=@y if y==-1 - page=@page if page==-1 - @links[link]=[page, y] - end - - def Link(x, y, w, h, link) - # Put a link on the page - @PageLinks[@page]=Array.new unless @PageLinks.has_key?(@Page) - @PageLinks[@page].push([x*@k,@hPt-y*@k,w*@k,h*@k,link]) - end - - def Text(x, y, txt) - # Output a string - txt.gsub!(')', '\\)') - txt.gsub!('(', '\\(') - txt.gsub!('\\', '\\\\') - s=sprintf('BT %.2f %.2f Td (%s) Tj ET',x*@k,(@h-y)*@k,txt); - s=s+' '+dounderline(x,y,txt) if @underline and txt!='' - s='q '+@TextColor+' '+s+' Q' if @ColorFlag - out(s) - end - - def AcceptPageBreak - # Accept automatic page break or not - @AutoPageBreak - end - - def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='') - # Output a cell - if @y+h>@PageBreakTrigger and !@InFooter and self.AcceptPageBreak - # Automatic page break - x=@x - ws=@ws - if ws>0 - @ws=0 - out('0 Tw') - end - self.AddPage(@CurOrientation) - @x=x - if ws>0 - @ws=ws - out(sprintf('%.3f Tw',ws*@k)) - end - end - w=@w-@rMargin-@x if w==0 - s='' - if fill==1 or border==1 - if fill==1 - op=(border==1) ? 'B' : 'f' - else - op='S' - end - s=sprintf('%.2f %.2f %.2f %.2f re %s ',@x*@k,(@h-@y)*@k,w*@k,-h*@k,op) - end - if border.is_a? String - x=@x - y=@y - unless border.index('L').nil? - s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', - x*@k,(@h-y)*@k,x*@k,(@h-(y+h))*@k) - end - unless border.index('T').nil? - s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', - x*@k,(@h-y)*@k,(x+w)*@k,(@h-y)*@k) - end - unless border.index('R').nil? - s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', - (x+w)*@k,(@h-y)*@k,(x+w)*@k,(@h-(y+h))*@k) - end - unless border.index('B').nil? - s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', - x*@k,(@h-(y+h))*@k,(x+w)*@k,(@h-(y+h))*@k) - end - end - if txt!='' - if align=='R' - dx=w-@cMargin-self.GetStringWidth(txt) - elsif align=='C' - dx=(w-self.GetStringWidth(txt))/2 - else - dx=@cMargin - end - txt = txt.gsub(')', '\\)') - txt.gsub!('(', '\\(') - txt.gsub!('\\', '\\\\') - if @ColorFlag - s=s+'q '+@TextColor+' ' - end - s=s+sprintf('BT %.2f %.2f Td (%s) Tj ET', - (@x+dx)*@k,(@h-(@y+0.5*h+0.3*@FontSize))*@k,txt) - s=s+' '+dounderline(@x+dx,@y+0.5*h+0.3*@FontSize,txt) if @underline - s=s+' Q' if @ColorFlag - if link and link != '' - Link(@x+dx,@y+0.5*h-0.5*@FontSize,GetStringWidth(txt),@FontSize,link) - end - end - out(s) if s - @lasth=h - if ln>0 - # Go to next line - @y=@y+h - @x=@lMargin if ln==1 - else - @x=@x+w - end - end - - def MultiCell(w,h,txt,border=0,align='J',fill=0) - # Output text with automatic or explicit line breaks - cw=@CurrentFont['cw'] - w=@w-@rMargin-@x if w==0 - wmax=(w-2*@cMargin)*1000/@FontSize - s=txt.gsub('\r','') - nb=s.length - nb=nb-1 if nb>0 and s[nb-1].chr=='\n' - b=0 - if border!=0 - if border==1 - border='LTRB' - b='LRT' - b2='LR' - else - b2='' - b2='L' unless border.index('L').nil? - b2=b2+'R' unless border.index('R').nil? - b=(not border.index('T').nil?) ? (b2+'T') : b2 - end - end - sep=-1 - i=0 - j=0 - l=0 - ns=0 - nl=1 - while i0 - @ws=0 - out('0 Tw') - end -#Ed Moss -# Don't let i go negative - end_i = i == 0 ? 0 : i - 1 - # Changed from s[j..i] to fix bug reported by Hans Allis. - self.Cell(w,h,s[j..end_i],b,2,align,fill) -# - i=i+1 - sep=-1 - j=i - l=0 - ns=0 - nl=nl+1 - b=b2 if border and nl==2 - else - if c==' ' - sep=i - ls=l - ns=ns+1 - end - l=l+cw[c[0]] - if l>wmax - # Automatic line break - if sep==-1 - i=i+1 if i==j - if @ws>0 - @ws=0 - out('0 Tw') - end - self.Cell(w,h,s[j..i],b,2,align,fill) -#Ed Moss -# Added so that it wouldn't print the last character of the string if it got close -#FIXME 2006-07-18 Level=0 - but it still puts out an extra new line - i += 1 -# - else - if align=='J' - @ws=(ns>1) ? (wmax-ls)/1000.0*@FontSize/(ns-1) : 0 - out(sprintf('%.3f Tw',@ws*@k)) - end - self.Cell(w,h,s[j..sep],b,2,align,fill) - i=sep+1 - end - sep=-1 - j=i - l=0 - ns=0 - nl=nl+1 - b=b2 if border and nl==2 - else - i=i+1 - end - end - end - - # Last chunk - if @ws>0 - @ws=0 - out('0 Tw') - end - b=b+'B' if border!=0 and not border.index('B').nil? - self.Cell(w,h,s[j..i],b,2,align,fill) - @x=@lMargin - end - - def Write(h,txt,link='') - # Output text in flowing mode - cw=@CurrentFont['cw'] - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - s=txt.gsub("\r",'') - nb=s.length - sep=-1 - i=0 - j=0 - l=0 - nl=1 - while iwmax - # Automatic line break - if sep==-1 - if @x>@lMargin - # Move to next line - @x=@lMargin - @y=@y+h - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - i=i+1 - nl=nl+1 - next - end - i=i+1 if i==j - self.Cell(w,h,s[j,i-j],0,2,'',0,link) - else - self.Cell(w,h,s[j,sep-j],0,2,'',0,link) - i=sep+1 - end - sep=-1 - j=i - l=0 - if nl==1 - @x=@lMargin - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - end - nl=nl+1 - else - i=i+1 - end - end - # Last chunk - self.Cell(l/1000.0*@FontSize,h,s[j,i],0,0,'',0,link) if i!=j - end - - def Image(file,x,y,w=0,h=0,type='',link='') - # Put an image on the page - unless @images.has_key?(file) - # First use of image, get info - if type=='' - pos=file.rindex('.') - if pos.nil? - self.Error('Image file has no extension and no type was '+ - 'specified: '+file) - end - type=file[pos+1..-1] - end - type.downcase! - if type=='jpg' or type=='jpeg' - info=parsejpg(file) - elsif type=='png' - info=parsepng(file) - else - self.Error('Unsupported image file type: '+type) - end - info['i']=@images.length+1 - @images[file]=info - else - info=@images[file] - end -#Ed Moss - if(w==0 && h==0) - #Put image at 72 dpi - w=info['w']/@k; - h=info['h']/@k; - end -# - # Automatic width or height calculation - w=h*info['w']/info['h'] if w==0 - h=w*info['h']/info['w'] if h==0 - out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', - w*@k,h*@k,x*@k,(@h-(y+h))*@k,info['i'])) - Link(x,y,w,h,link) if link and link != '' - end - - def Ln(h='') - # Line feed; default value is last cell height - @x=@lMargin - if h.kind_of?(String) - @y=@y+@lasth - else - @y=@y+h - end - end - - def GetX - # Get x position - @x - end - - def SetX(x) - # Set x position - if x>=0 - @x=x - else - @x=@w+x - end - end - - def GetY - # Get y position - @y - end - - def SetY(y) - # Set y position and reset x - @x=@lMargin - if y>=0 - @y=y - else - @y=@h+y - end - end - - def SetXY(x,y) - # Set x and y positions - SetY(y) - SetX(x) - end - - def Output(file=nil) - # Output PDF to file or return as a string - - # Finish document if necessary - self.Close if(@state<3) - - if file.nil? - # Return as a string - return @buffer - else - # Save file locally - open(file,'wb') do |f| - f.write(@buffer) - end - end - end - - private - - def putpages - nb=@page - unless @AliasNbPages.nil? or @AliasNbPages=='' - # Replace number of pages - 1.upto(nb) do |n| - @pages[n].gsub!(@AliasNbPages,nb.to_s) - end - end - if @DefOrientation=='P' - wPt=@fwPt - hPt=@fhPt - else - wPt=@fhPt - hPt=@fwPt - end - filter=(@compress) ? '/Filter /FlateDecode ' : '' - 1.upto(nb) do |n| - # Page - newobj - out('<>>>' - else - l=@links[pl[4]] - h=@OrientationChanges[l[0]].nil? ? hPt : wPt - annots=annots+sprintf( - '/Dest [%d 0 R /XYZ 0 %.2f null]>>', - 1+2*l[0],h-l[1]*@k) - end - end - out(annots+']') - end - out('/Contents '+(@n+1).to_s+' 0 R>>') - out('endobj') - # Page content - p=(@compress) ? Zlib::Deflate.deflate(@pages[n]) : @pages[n] - newobj - out('<<'+filter+'/Length '+p.length.to_s+'>>') - putstream(p) - out('endobj') - end - # Pages root - @offsets[1]=@buffer.length - out('1 0 obj') - out('<>') - out('endobj') - end - - def putfonts - nf=@n - @diffs.each do |diff| - # Encodings - newobj - out('<>') - out('endobj') - end - - @FontFiles.each do |file, info| - # Font file embedding - newobj - @FontFiles[file]['n'] = @n - - if self.class.const_defined? 'FPDF_FONTPATH' then - if FPDF_FONTPATH[-1,1] == '/' then - file = FPDF_FONTPATH + file - else - file = FPDF_FONTPATH + '/' + file - end - end - - size = File.size(file) - unless File.exists?(file) - Error('Font file not found') - end - - out('<>') - open(file, 'rb') do |f| - putstream(f.read()) - end - out('endobj') - end - - file = 0 - @fonts.each do |k, font| - # Font objects - @fonts[k]['n']=@n+1 - type=font['type'] - name=font['name'] - if type=='core' - # Standard font - newobj - out('<>') - out('endobj') - elsif type=='Type1' or type=='TrueType' - # Additional Type1 or TrueType font - newobj - out('<>') - out('endobj') - # Widths - newobj - cw=font['cw'] - s='[' - 32.upto(255) do |i| - s << cw[i].to_s+' ' - end - out(s+']') - out('endobj') - # Descriptor - newobj - s='<>') - out('endobj') - else - # Allow for additional types - mtd='put'+type.downcase - unless self.respond_to?(mtd) - self.Error('Unsupported font type: '+type) - end - self.send(mtd, font) - end - end - end - - def putimages - filter=(@compress) ? '/Filter /FlateDecode ' : '' - @images.each do |file, info| - newobj - @images[file]['n']=@n - out('<>') - putstream(info['data']) - @images[file]['data']=nil - out('endobj') - # Palette - if info['cs']=='Indexed' - newobj - pal=(@compress) ? Zlib::Deflate.deflate(info['pal']) : info['pal'] - out('<<'+filter+'/Length '+pal.length.to_s+'>>') - putstream(pal) - out('endobj') - end - end - end - - def putxobjectdict - @images.each_value do |image| - out('/I'+image['i'].to_s+' '+image['n'].to_s+' 0 R') - end - end - - def putresourcedict - out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]') - out('/Font <<') - @fonts.each_value do |font| - out('/F'+font['i'].to_s+' '+font['n'].to_s+' 0 R') - end - out('>>') - out('/XObject <<') - putxobjectdict - out('>>') - end - - def putresources - putfonts - putimages - # Resource dictionary - @offsets[2]=@buffer.length - out('2 0 obj') - out('<<') - putresourcedict - out('>>') - out('endobj') - end - - def putinfo - out('/Producer '+textstring('Ruby FPDF '+FPDF_VERSION)); - unless @title.nil? - out('/Title '+textstring(@title)) - end - unless @subject.nil? - out('/Subject '+textstring(@subject)) - end - unless @author.nil? - out('/Author '+textstring(@author)) - end - unless @keywords.nil? - out('/Keywords '+textstring(@keywords)) - end - unless @creator.nil? - out('/Creator '+textstring(@creator)) - end - out('/CreationDate '+textstring('D: '+DateTime.now.to_s)) - end - - def putcatalog - out('/Type /Catalog') - out('/Pages 1 0 R') - if @ZoomMode=='fullpage' - out('/OpenAction [3 0 R /Fit]') - elsif @ZoomMode=='fullwidth' - out('/OpenAction [3 0 R /FitH null]') - elsif @ZoomMode=='real' - out('/OpenAction [3 0 R /XYZ null null 1]') - elsif not @ZoomMode.kind_of?(String) - out('/OpenAction [3 0 R /XYZ null null '+(@ZoomMode/100)+']') - end - - if @LayoutMode=='single' - out('/PageLayout /SinglePage') - elsif @LayoutMode=='continuous' - out('/PageLayout /OneColumn') - elsif @LayoutMode=='two' - out('/PageLayout /TwoColumnLeft') - end - end - - def putheader - out('%PDF-'+@PDFVersion) - end - - def puttrailer - out('/Size '+(@n+1).to_s) - out('/Root '+@n.to_s+' 0 R') - out('/Info '+(@n-1).to_s+' 0 R') - end - - def enddoc - putheader - putpages - putresources - # Info - newobj - out('<<') - putinfo - out('>>') - out('endobj') - # Catalog - newobj - out('<<') - putcatalog - out('>>') - out('endobj') - # Cross-ref - o=@buffer.length - out('xref') - out('0 '+(@n+1).to_s) - out('0000000000 65535 f ') - 1.upto(@n) do |i| - out(sprintf('%010d 00000 n ',@offsets[i])) - end - # Trailer - out('trailer') - out('<<') - puttrailer - out('>>') - out('startxref') - out(o) - out('%%EOF') - state=3 - end - - def beginpage(orientation) - @page=@page+1 - @pages[@page]='' - @state=2 - @x=@lMargin - @y=@tMargin - @lasth=0 - @FontFamily='' - # Page orientation - if orientation=='' - orientation=@DefOrientation - else - orientation=orientation[0].chr.upcase - if orientation!=@DefOrientation - @OrientationChanges[@page]=true - end - end - if orientation!=@CurOrientation - # Change orientation - if orientation=='P' - @wPt=@fwPt - @hPt=@fhPt - @w=@fw - @h=@fh - else - @wPt=@fhPt - @hPt=@fwPt - @w=@fh - @h=@fw - end - @PageBreakTrigger=@h-@bMargin - @CurOrientation=orientation - end - end - - def endpage - # End of page contents - @state=1 - end - - def newobj - # Begin a new object - @n=@n+1 - @offsets[@n]=@buffer.length - out(@n.to_s+' 0 obj') - end - - def dounderline(x,y,txt) - # Underline text - up=@CurrentFont['up'] - ut=@CurrentFont['ut'] - w=GetStringWidth(txt)+@ws*txt.count(' ') - sprintf('%.2f %.2f %.2f %.2f re f', - x*@k,(@h-(y-up/1000.0*@FontSize))*@k,w*@k,-ut/1000.0*@FontSizePt) - end - - def parsejpg(file) - # Extract info from a JPEG file - a=extractjpginfo(file) - raise "Missing or incorrect JPEG file: #{file}" if a.nil? - - if a['channels'].nil? || a['channels']==3 then - colspace='DeviceRGB' - elsif a['channels']==4 then - colspace='DeviceCMYK' - else - colspace='DeviceGray' - end - bpc= a['bits'] ? a['bits'].to_i : 8 - - # Read whole file - data = nil - open(file, 'rb') do |f| - data = f.read - end - return {'w'=>a['width'],'h'=>a['height'],'cs'=>colspace,'bpc'=>bpc,'f'=>'DCTDecode','data'=>data} - end - - def parsepng(file) - # Extract info from a PNG file - f=open(file,'rb') - # Check signature - unless f.read(8)==137.chr+'PNG'+13.chr+10.chr+26.chr+10.chr - self.Error('Not a PNG file: '+file) - end - # Read header chunk - f.read(4) - if f.read(4)!='IHDR' - self.Error('Incorrect PNG file: '+file) - end - w=freadint(f) - h=freadint(f) - bpc=f.read(1)[0] - if bpc>8 - self.Error('16-bit depth not supported: '+file) - end - ct=f.read(1)[0] - if ct==0 - colspace='DeviceGray' - elsif ct==2 - colspace='DeviceRGB' - elsif ct==3 - colspace='Indexed' - else - self.Error('Alpha channel not supported: '+file) - end - if f.read(1)[0]!=0 - self.Error('Unknown compression method: '+file) - end - if f.read(1)[0]!=0 - self.Error('Unknown filter method: '+file) - end - if f.read(1)[0]!=0 - self.Error('Interlacing not supported: '+file) - end - f.read(4) - parms='/DecodeParms <>' - # Scan chunks looking for palette, transparency and image data - pal='' - trns='' - data='' - begin - n=freadint(f) - type=f.read(4) - if type=='PLTE' - # Read palette - pal=f.read(n) - f.read(4) - elsif type=='tRNS' - # Read transparency info - t=f.read(n) - if ct==0 - trns=[t[1]] - elsif ct==2 - trns=[t[1],t[3],t[5]] - else - pos=t.index(0) - trns=[pos] unless pos.nil? - end - f.read(4) - elsif type=='IDAT' - # Read image data block - data << f.read(n) - f.read(4) - elsif type=='IEND' - break - else - f.read(n+4) - end - end while n - if colspace=='Indexed' and pal=='' - self.Error('Missing palette in '+file) - end - f.close - {'w'=>w,'h'=>h,'cs'=>colspace,'bpc'=>bpc,'f'=>'FlateDecode', - 'parms'=>parms,'pal'=>pal,'trns'=>trns,'data'=>data} - end - - def freadint(f) - # Read a 4-byte integer from file - a = f.read(4).unpack('N') - return a[0] - end - - def freadshort(f) - a = f.read(2).unpack('n') - return a[0] - end - - def freadbyte(f) - a = f.read(1).unpack('C') - return a[0] - end - - def textstring(s) - # Format a text string - '('+escape(s)+')' - end - - def escape(s) - # Add \ before \, ( and ) - s.gsub('\\','\\\\').gsub('(','\\(').gsub(')','\\)') - end - - def putstream(s) - out('stream') - out(s) - out('endstream') - end - - def out(s) - # Add a line to the document - if @state==2 - @pages[@page]=@pages[@page]+s+"\n" - else - @buffer=@buffer+s.to_s+"\n" - end - end - - # jpeg marker codes - - M_SOF0 = 0xc0 - M_SOF1 = 0xc1 - M_SOF2 = 0xc2 - M_SOF3 = 0xc3 - - M_SOF5 = 0xc5 - M_SOF6 = 0xc6 - M_SOF7 = 0xc7 - - M_SOF9 = 0xc9 - M_SOF10 = 0xca - M_SOF11 = 0xcb - - M_SOF13 = 0xcd - M_SOF14 = 0xce - M_SOF15 = 0xcf - - M_SOI = 0xd8 - M_EOI = 0xd9 - M_SOS = 0xda - - def extractjpginfo(file) - result = nil - - open(file, "rb") do |f| - marker = jpegnextmarker(f) - - if marker != M_SOI - return nil - end - - while true - marker = jpegnextmarker(f) - - case marker - when M_SOF0, M_SOF1, M_SOF2, M_SOF3, - M_SOF5, M_SOF6, M_SOF7, M_SOF9, - M_SOF10, M_SOF11, M_SOF13, M_SOF14, - M_SOF15 then - - length = freadshort(f) - - if result.nil? - result = {} - - result['bits'] = freadbyte(f) - result['height'] = freadshort(f) - result['width'] = freadshort(f) - result['channels'] = freadbyte(f) - - f.seek(length - 8, IO::SEEK_CUR) - else - f.seek(length - 2, IO::SEEK_CUR) - end - when M_SOS, M_EOI then - return result - else - length = freadshort(f) - f.seek(length - 2, IO::SEEK_CUR) - end - end - end - end - - def jpegnextmarker(f) - while true - # look for 0xff - while (c = freadbyte(f)) != 0xff - end - - c = freadbyte(f) - - if c != 0 - return c - end - end - end -end diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb deleted file mode 100644 index c6a224310..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb +++ /dev/null @@ -1,139 +0,0 @@ -# Information -# -# PDF_EPS class from Valentin Schmidt ported to ruby by Thiago Jackiw (tjackiw@gmail.com) -# working for Mingle LLC (www.mingle.com) -# Release Date: July 13th, 2006 -# -# Description -# -# This script allows to embed vector-based Adobe Illustrator (AI) or AI-compatible EPS files. -# Only vector drawing is supported, not text or bitmap. Although the script was successfully -# tested with various AI format versions, best results are probably achieved with files that -# were exported in the AI3 format (tested with Illustrator CS2, Freehand MX and Photoshop CS2). -# -# ImageEps(string file, float x, float y [, float w [, float h [, string link [, boolean useBoundingBox]]]]) -# -# Same parameters as for regular FPDF::Image() method, with an additional one: -# -# useBoundingBox: specifies whether to position the bounding box (true) or the complete canvas (false) -# at location (x,y). Default value is true. -# -# First added to the Ruby FPDF distribution in 1.53c -# -# Usage is as follows: -# -# require 'fpdf' -# require 'fpdf_eps' -# pdf = FPDF.new -# pdf.extend(PDF_EPS) -# pdf.ImageEps(...) -# -# This allows it to be combined with other extensions, such as the bookmark -# module. - -module PDF_EPS - def ImageEps(file, x, y, w=0, h=0, link='', use_bounding_box=true) - data = nil - if File.exists?(file) - File.open(file, 'rb') do |f| - data = f.read() - end - else - Error('EPS file not found: '+file) - end - - # Find BoundingBox param - regs = data.scan(/%%BoundingBox: [^\r\n]*/m) - regs << regs[0].gsub(/%%BoundingBox: /, '') - if regs.size > 1 - tmp = regs[1].to_s.split(' ') - @x1 = tmp[0].to_i - @y1 = tmp[1].to_i - @x2 = tmp[2].to_i - @y2 = tmp[3].to_i - else - Error('No BoundingBox found in EPS file: '+file) - end - f_start = data.index('%%EndSetup') - f_start = data.index('%%EndProlog') if f_start === false - f_start = data.index('%%BoundingBox') if f_start === false - - data = data.slice(f_start, data.length) - - f_end = data.index('%%PageTrailer') - f_end = data.index('showpage') if f_end === false - data = data.slice(0, f_end) if f_end - - # save the current graphic state - out('q') - - k = @k - - # Translate - if use_bounding_box - dx = x*k-@x1 - dy = @hPt-@y2-y*k - else - dx = x*k - dy = -y*k - end - tm = [1,0,0,1,dx,dy] - out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', - tm[0], tm[1], tm[2], tm[3], tm[4], tm[5])) - - if w > 0 - scale_x = w/((@x2-@x1)/k) - if h > 0 - scale_y = h/((@y2-@y1)/k) - else - scale_y = scale_x - h = (@y2-@y1)/k * scale_y - end - else - if h > 0 - scale_y = $h/((@y2-@y1)/$k) - scale_x = scale_y - w = (@x2-@x1)/k * scale_x - else - w = (@x2-@x1)/k - h = (@y2-@y1)/k - end - end - - if !scale_x.nil? - # Scale - tm = [scale_x,0,0,scale_y,0,@hPt*(1-scale_y)] - out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', - tm[0], tm[1], tm[2], tm[3], tm[4], tm[5])) - end - - data.split(/\r\n|[\r\n]/).each do |line| - next if line == '' || line[0,1] == '%' - len = line.length - # next if (len > 2 && line[len-2,len] != ' ') - cmd = line[len-2,len].strip - case cmd - when 'm', 'l', 'v', 'y', 'c', 'k', 'K', 'g', 'G', 's', 'S', 'J', 'j', 'w', 'M', 'd': - out(line) - - when 'L': - line[len-1,len]='l' - out(line) - - when 'C': - line[len-1,len]='c' - out(line) - - when 'f', 'F': - out('f*') - - when 'b', 'B': - out(cmd + '*') - end - end - - # restore previous graphic state - out('Q') - Link(x,y,w,h,link) if link - end -end diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/japanese.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/japanese.rb deleted file mode 100644 index 7340936bb..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/japanese.rb +++ /dev/null @@ -1,468 +0,0 @@ -# Copyright (c) 2006 4ssoM LLC -# 1.12 contributed by Ed Moss. -# -# The MIT License -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# This is direct port of japanese.php -# -# Japanese PDF support. -# -# Usage is as follows: -# -# require 'fpdf' -# require 'chinese' -# pdf = FPDF.new -# pdf.extend(PDF_Japanese) -# -# This allows it to be combined with other extensions, such as the bookmark -# module. - -module PDF_Japanese - - SJIS_widths={' ' => 278, '!' => 299, '"' => 353, '#' => 614, '$' => 614, '%' => 721, '&' => 735, '\'' => 216, - '(' => 323, ')' => 323, '*' => 449, '+' => 529, ',' => 219, '-' => 306, '.' => 219, '/' => 453, '0' => 614, '1' => 614, - '2' => 614, '3' => 614, '4' => 614, '5' => 614, '6' => 614, '7' => 614, '8' => 614, '9' => 614, ':' => 219, ';' => 219, - '<' => 529, '=' => 529, '>' => 529, '?' => 486, '@' => 744, 'A' => 646, 'B' => 604, 'C' => 617, 'D' => 681, 'E' => 567, - 'F' => 537, 'G' => 647, 'H' => 738, 'I' => 320, 'J' => 433, 'K' => 637, 'L' => 566, 'M' => 904, 'N' => 710, 'O' => 716, - 'P' => 605, 'Q' => 716, 'R' => 623, 'S' => 517, 'T' => 601, 'U' => 690, 'V' => 668, 'W' => 990, 'X' => 681, 'Y' => 634, - 'Z' => 578, '[' => 316, '\\' => 614, ']' => 316, '^' => 529, '_' => 500, '`' => 387, 'a' => 509, 'b' => 566, 'c' => 478, - 'd' => 565, 'e' => 503, 'f' => 337, 'g' => 549, 'h' => 580, 'i' => 275, 'j' => 266, 'k' => 544, 'l' => 276, 'm' => 854, - 'n' => 579, 'o' => 550, 'p' => 578, 'q' => 566, 'r' => 410, 's' => 444, 't' => 340, 'u' => 575, 'v' => 512, 'w' => 760, - 'x' => 503, 'y' => 529, 'z' => 453, '{' => 326, '|' => 380, '}' => 326, '~' => 387} - - def AddCIDFont(family,style,name,cw,cMap,registry) - fontkey=family.downcase+style.upcase - unless @fonts[fontkey].nil? - Error("CID font already added: family style") - end - i=@fonts.length+1 - @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-120,'ut'=>40,'cw'=>cw, - 'CMap'=>cMap,'registry'=>registry} - end - - def AddCIDFonts(family,name,cw,cMap,registry) - AddCIDFont(family,'',name,cw,cMap,registry) - AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) - AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) - AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) - end - - def AddSJISFont(family='SJIS') - #Add SJIS font with proportional Latin - name='KozMinPro-Regular-Acro' - cw=SJIS_widths - cMap='90msp-RKSJ-H' - registry={'ordering'=>'Japan1','supplement'=>2} - AddCIDFonts(family,name,cw,cMap,registry) - end - - def AddSJIShwFont(family='SJIS-hw') - #Add SJIS font with half-width Latin - name='KozMinPro-Regular-Acro' - 32.upto(126) do |i| - cw[i.chr]=500 - end - cMap='90ms-RKSJ-H' - registry={'ordering'=>'Japan1','supplement'=>2} - AddCIDFonts(family,name,cw,cMap,registry) - end - - def GetStringWidth(s) - if(@CurrentFont['type']=='Type0') - return GetSJISStringWidth(s) - else - return super(s) - end - end - - def GetSJISStringWidth(s) - #SJIS version of GetStringWidth() - l=0 - cw=@CurrentFont['cw'] - nb=s.length - i=0 - while(i=161 and o<=223) - #Half-width katakana - l+=500 - i+=1 - else - #Full-width character - l+=1000 - i+=2 - end - end - return l*@FontSize/1000 - end - - def MultiCell(w,h,txt,border=0,align='L',fill=0) - if(@CurrentFont['type']=='Type0') - SJISMultiCell(w,h,txt,border,align,fill) - else - super(w,h,txt,border,align,fill) - end - end - - def SJISMultiCell(w,h,txt,border=0,align='L',fill=0) - #Output text with automatic or explicit line breaks - cw=@CurrentFont['cw'] - if(w==0) - w=@w-@rMargin-@x - end - wmax=(w-2*@cMargin)*1000/@FontSize - s=txt.gsub("\r",'') - nb=s.length - if(nb>0 and s[nb-1]=="\n") - nb-=1 - end - b=0 - if(border) - if(border==1) - border='LTRB' - b='LRT' - b2='LR' - else - b2='' - if(border.index('L').nil?) - b2+='L' - end - if(border.index('R').nil?) - b2+='R' - end - b=border.index('T').nil? ? b2+'T' : b2 - end - end - sep=-1 - i=0 - j=0 - l=0 - nl=1 - while(i=161 and o<=223) - #Half-width katakana - l+=500 - n=1 - sep=i - else - #Full-width character - l+=1000 - n=2 - sep=i - end - if(l>wmax) - #Automatic line break - if(sep==-1 or i==j) - if(i==j) - i+=n - end - Cell(w,h,s[j,i-j],b,2,align,fill) - else - Cell(w,h,s[j,sep-j],b,2,align,fill) - i=(s[sep]==' ') ? sep+1 : sep - end - sep=-1 - j=i - l=0 - nl+=1 - if(border and nl==2) - b=b2 - end - else - i+=n - if(o>=128) - sep=i - end - end - end - #Last chunk - if(border and not border.index('B').nil?) - b+='B' - end - Cell(w,h,s[j,i-j],b,2,align,fill) - @x=@lMargin - end - - def Write(h,txt,link='') - if(@CurrentFont['type']=='Type0') - SJISWrite(h,txt,link) - else - super(h,txt,link) - end - end - - def SJISWrite(h,txt,link) - #SJIS version of Write() - cw=@CurrentFont['cw'] - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - s=txt.gsub("\r",'') - nb=s.length - sep=-1 - i=0 - j=0 - l=0 - nl=1 - while(i=161 and o<=223) - #Half-width katakana - l+=500 - n=1 - sep=i - else - #Full-width character - l+=1000 - n=2 - sep=i - end - if(l>wmax) - #Automatic line break - if(sep==-1 or i==j) - if(@x>@lMargin) - #Move to next line - @x=@lMargin - @y+=h - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - i+=n - nl+=1 - next - end - if(i==j) - i+=n - end - Cell(w,h,s[j,i-j],0,2,'',0,link) - else - Cell(w,h,s[j,sep-j],0,2,'',0,link) - i=(s[sep]==' ') ? sep+1 : sep - end - sep=-1 - j=i - l=0 - if(nl==1) - @x=@lMargin - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - end - nl+=1 - else - i+=n - if(o>=128) - sep=i - end - end - end - #Last chunk - if(i!=j) - Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link) - end - end - -private - - def putfonts() - nf=@n - @diffs.each do |diff| - #Encodings - newobj() - out('<>') - out('endobj') - end - # mqr=get_magic_quotes_runtime() - # set_magic_quotes_runtime(0) - @FontFiles.each_pair do |file, info| - #Font file embedding - newobj() - @FontFiles[file]['n']=@n - if(defined('FPDF_FONTPATH')) - file=FPDF_FONTPATH+file - end - size=filesize(file) - if(!size) - Error('Font file not found') - end - out('<>') - f=fopen(file,'rb') - putstream(fread(f,size)) - fclose(f) - out('endobj') - end - # set_magic_quotes_runtime(mqr) - @fonts.each_pair do |k, font| - #Font objects - newobj() - @fonts[k]['n']=@n - out('<>') - out('endobj') - if(font['type']!='core') - #Widths - newobj() - cw=font['cw'] - s='[' - 32.upto(255) do |i| - s+=cw[i.chr]+' ' - end - out(s+']') - out('endobj') - #Descriptor - newobj() - s='<>') - out('endobj') - end - end - end - end - - def putType0(font) - #Type0 - out('/Subtype /Type0') - out('/BaseFont /'+font['name']+'-'+font['CMap']) - out('/Encoding /'+font['CMap']) - out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') - out('>>') - out('endobj') - #CIDFont - newobj() - out('<>') - out('/FontDescriptor '+(@n+1).to_s+' 0 R') - w='/W [1 [' - font['cw'].keys.sort.each {|key| - w+=font['cw'][key].to_s + " " -# ActionController::Base::logger.debug key.to_s -# ActionController::Base::logger.debug font['cw'][key].to_s - } - out(w+'] 231 325 500 631 [500] 326 389 500]') - out('>>') - out('endobj') - #Font descriptor - newobj() - out('<>') - out('endobj') - end -end diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/korean.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/korean.rb deleted file mode 100644 index 64131405e..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/korean.rb +++ /dev/null @@ -1,436 +0,0 @@ -# Copyright (c) 2006 4ssoM LLC -# 1.12 contributed by Ed Moss. -# -# The MIT License -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# This is direct port of korean.php -# -# Korean PDF support. -# -# Usage is as follows: -# -# require 'fpdf' -# require 'chinese' -# pdf = FPDF.new -# pdf.extend(PDF_Korean) -# -# This allows it to be combined with other extensions, such as the bookmark -# module. - -module PDF_Korean - -UHC_widths={' ' => 333, '!' => 416, '"' => 416, '#' => 833, '$' => 625, '%' => 916, '&' => 833, '\'' => 250, - '(' => 500, ')' => 500, '*' => 500, '+' => 833, ',' => 291, '-' => 833, '.' => 291, '/' => 375, '0' => 625, '1' => 625, - '2' => 625, '3' => 625, '4' => 625, '5' => 625, '6' => 625, '7' => 625, '8' => 625, '9' => 625, ':' => 333, ';' => 333, - '<' => 833, '=' => 833, '>' => 916, '?' => 500, '@' => 1000, 'A' => 791, 'B' => 708, 'C' => 708, 'D' => 750, 'E' => 708, - 'F' => 666, 'G' => 750, 'H' => 791, 'I' => 375, 'J' => 500, 'K' => 791, 'L' => 666, 'M' => 916, 'N' => 791, 'O' => 750, - 'P' => 666, 'Q' => 750, 'R' => 708, 'S' => 666, 'T' => 791, 'U' => 791, 'V' => 750, 'W' => 1000, 'X' => 708, 'Y' => 708, - 'Z' => 666, '[' => 500, '\\' => 375, ']' => 500, '^' => 500, '_' => 500, '`' => 333, 'a' => 541, 'b' => 583, 'c' => 541, - 'd' => 583, 'e' => 583, 'f' => 375, 'g' => 583, 'h' => 583, 'i' => 291, 'j' => 333, 'k' => 583, 'l' => 291, 'm' => 875, - 'n' => 583, 'o' => 583, 'p' => 583, 'q' => 583, 'r' => 458, 's' => 541, 't' => 375, 'u' => 583, 'v' => 583, 'w' => 833, - 'x' => 625, 'y' => 625, 'z' => 500, '{' => 583, '|' => 583, '}' => 583, '~' => 750} - - def AddCIDFont(family,style,name,cw,cMap,registry) - fontkey=family.downcase+style.upcase - unless @fonts[fontkey].nil? - Error("Font already added: family style") - end - i=@fonts.length+1 - name=name.gsub(' ','') - @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw, - 'CMap'=>cMap,'registry'=>registry} - end - - def AddCIDFonts(family,name,cw,cMap,registry) - AddCIDFont(family,'',name,cw,cMap,registry) - AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) - AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) - AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) - end - - def AddUHCFont(family='UHC',name='HYSMyeongJoStd-Medium-Acro') - #Add UHC font with proportional Latin - cw=UHC_widths - cMap='KSCms-UHC-H' - registry={'ordering'=>'Korea1','supplement'=>1} - AddCIDFonts(family,name,cw,cMap,registry) - end - - def AddUHChwFont(family='UHC-hw',name='HYSMyeongJoStd-Medium-Acro') - #Add UHC font with half-witdh Latin - 32.upto(126) do |i| - cw[i.chr]=500 - end - cMap='KSCms-UHC-HW-H' - registry={'ordering'=>'Korea1','supplement'=>1} - AddCIDFonts(family,name,cw,cMap,registry) - end - - def GetStringWidth(s) - if(@CurrentFont['type']=='Type0') - return GetMBStringWidth(s) - else - return super(s) - end - end - - def GetMBStringWidth(s) - #Multi-byte version of GetStringWidth() - l=0 - cw=@CurrentFont['cw'] - nb=s.length - i=0 - while(i0 and s[nb-1]=="\n") - nb-=1 - end - b=0 - if(border) - if(border==1) - border='LTRB' - b='LRT' - b2='LR' - else - b2='' - if(border.index('L').nil?) - b2+='L' - end - if(border.index('R').nil?) - b2+='R' - end - b=border.index('T').nil? ? b2+'T' : b2 - end - end - sep=-1 - i=0 - j=0 - l=0 - nl=1 - while(iwmax) - #Automatic line break - if(sep==-1 or i==j) - if(i==j) - i+=ascii ? 1 : 2 - end - Cell(w,h,s[j,i-j],b,2,align,fill) - else - Cell(w,h,s[j,sep-j],b,2,align,fill) - i=(s[sep]==' ') ? sep+1 : sep - end - sep=-1 - j=i - l=0 - nl+=1 - if(border and nl==2) - b=b2 - end - else - i+=ascii ? 1 : 2 - end - end - #Last chunk - if(border and not border.index('B').nil?) - b+='B' - end - Cell(w,h,s[j,i-j],b,2,align,fill) - @x=@lMargin - end - - def Write(h,txt,link='') - if(@CurrentFont['type']=='Type0') - MBWrite(h,txt,link) - else - super(h,txt,link) - end - end - - def MBWrite(h,txt,link) - #Multi-byte version of Write() - cw=@CurrentFont['cw'] - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - s=txt.gsub("\r",'') - nb=s.length - sep=-1 - i=0 - j=0 - l=0 - nl=1 - while(iwmax) - #Automatic line break - if(sep==-1 or i==j) - if(@x>@lMargin) - #Move to next line - @x=@lMargin - @y+=h - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - i+=1 - nl+=1 - next - end - if(i==j) - i+=ascii ? 1 : 2 - end - Cell(w,h,s[j,i-j],0,2,'',0,link) - else - Cell(w,h,s[j,sep-j],0,2,'',0,link) - i=(s[sep]==' ') ? sep+1 : sep - end - sep=-1 - j=i - l=0 - if(nl==1) - @x=@lMargin - w=@w-@rMargin-@x - wmax=(w-2*@cMargin)*1000/@FontSize - end - nl+=1 - else - i+=ascii ? 1 : 2 - end - end - #Last chunk - if(i!=j) - Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link) - end - end - -private - - def putfonts() - nf=@n - @diffs.each do |diff| - #Encodings - newobj() - out('<>') - out('endobj') - end - # mqr=get_magic_quotes_runtime() - # set_magic_quotes_runtime(0) - @FontFiles.each_pair do |file, info| - #Font file embedding - newobj() - @FontFiles[file]['n']=@n - if(defined('FPDF_FONTPATH')) - file=FPDF_FONTPATH+file - end - size=filesize(file) - if(!size) - Error('Font file not found') - end - out('<>') - f=fopen(file,'rb') - putstream(fread(f,size)) - fclose(f) - out('endobj') - end - # set_magic_quotes_runtime(mqr) - @fonts.each_pair do |k, font| - #Font objects - newobj() - @fonts[k]['n']=@n - out('<>') - out('endobj') - if(font['type']!='core') - #Widths - newobj() - cw=font['cw'] - s='[' - 32.upto(255) do |i| - s+=cw[i.chr]+' ' - end - out(s+']') - out('endobj') - #Descriptor - newobj() - s='<>') - out('endobj') - end - end - end - end - - def putType0(font) - #Type0 - out('/Subtype /Type0') - out('/BaseFont /'+font['name']+'-'+font['CMap']) - out('/Encoding /'+font['CMap']) - out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') - out('>>') - out('endobj') - #CIDFont - newobj() - out('<>') - out('/FontDescriptor '+(@n+1).to_s+' 0 R') - if(font['CMap']=='KSCms-UHC-HW-H') - w='8094 8190 500' - else - w='1 [' - font['cw'].keys.sort.each {|key| - w+=font['cw'][key].to_s + " " - # ActionController::Base::logger.debug key.to_s - # ActionController::Base::logger.debug font['cw'][key].to_s - } - w +=']' - end - out('/W ['+w+']>>') - out('endobj') - #Font descriptor - newobj() - out('<>') - out('endobj') - end -end diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/makefont.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/makefont.rb deleted file mode 100644 index ffc98b48f..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/makefont.rb +++ /dev/null @@ -1,1787 +0,0 @@ -#!/usr/bin/env ruby -# -# Utility to generate font definition files -# Version: 1.1 -# Date: 2006-07-19 -# -# Changelog: -# Version 1.1 - Brian Ollenberger -# - Fixed a very small bug in MakeFont for generating FontDef.diff. - -Charencodings = { -# Central Europe - 'cp1250' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'Euro', '.notdef', 'quotesinglbase', '.notdef', - 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', - '.notdef', 'perthousand', 'Scaron', 'guilsinglleft', - 'Sacute', 'Tcaron', 'Zcaron', 'Zacute', - '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - '.notdef', 'trademark', 'scaron', 'guilsinglright', - 'sacute', 'tcaron', 'zcaron', 'zacute', - 'space', 'caron', 'breve', 'Lslash', - 'currency', 'Aogonek', 'brokenbar', 'section', - 'dieresis', 'copyright', 'Scedilla', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'Zdotaccent', - 'degree', 'plusminus', 'ogonek', 'lslash', - 'acute', 'mu', 'paragraph', 'periodcentered', - 'cedilla', 'aogonek', 'scedilla', 'guillemotright', - 'Lcaron', 'hungarumlaut', 'lcaron', 'zdotaccent', - 'Racute', 'Aacute', 'Acircumflex', 'Abreve', - 'Adieresis', 'Lacute', 'Cacute', 'Ccedilla', - 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', - 'Ecaron', 'Iacute', 'Icircumflex', 'Dcaron', - 'Dcroat', 'Nacute', 'Ncaron', 'Oacute', - 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'multiply', - 'Rcaron', 'Uring', 'Uacute', 'Uhungarumlaut', - 'Udieresis', 'Yacute', 'Tcommaaccent', 'germandbls', - 'racute', 'aacute', 'acircumflex', 'abreve', - 'adieresis', 'lacute', 'cacute', 'ccedilla', - 'ccaron', 'eacute', 'eogonek', 'edieresis', - 'ecaron', 'iacute', 'icircumflex', 'dcaron', - 'dcroat', 'nacute', 'ncaron', 'oacute', - 'ocircumflex', 'ohungarumlaut', 'odieresis', 'divide', - 'rcaron', 'uring', 'uacute', 'uhungarumlaut', - 'udieresis', 'yacute', 'tcommaaccent', 'dotaccent' - ], -# Cyrillic - 'cp1251' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'afii10051', 'afii10052', 'quotesinglbase', 'afii10100', - 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', - 'Euro', 'perthousand', 'afii10058', 'guilsinglleft', - 'afii10059', 'afii10061', 'afii10060', 'afii10145', - 'afii10099', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - '.notdef', 'trademark', 'afii10106', 'guilsinglright', - 'afii10107', 'afii10109', 'afii10108', 'afii10193', - 'space', 'afii10062', 'afii10110', 'afii10057', - 'currency', 'afii10050', 'brokenbar', 'section', - 'afii10023', 'copyright', 'afii10053', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'afii10056', - 'degree', 'plusminus', 'afii10055', 'afii10103', - 'afii10098', 'mu', 'paragraph', 'periodcentered', - 'afii10071', 'afii61352', 'afii10101', 'guillemotright', - 'afii10105', 'afii10054', 'afii10102', 'afii10104', - 'afii10017', 'afii10018', 'afii10019', 'afii10020', - 'afii10021', 'afii10022', 'afii10024', 'afii10025', - 'afii10026', 'afii10027', 'afii10028', 'afii10029', - 'afii10030', 'afii10031', 'afii10032', 'afii10033', - 'afii10034', 'afii10035', 'afii10036', 'afii10037', - 'afii10038', 'afii10039', 'afii10040', 'afii10041', - 'afii10042', 'afii10043', 'afii10044', 'afii10045', - 'afii10046', 'afii10047', 'afii10048', 'afii10049', - 'afii10065', 'afii10066', 'afii10067', 'afii10068', - 'afii10069', 'afii10070', 'afii10072', 'afii10073', - 'afii10074', 'afii10075', 'afii10076', 'afii10077', - 'afii10078', 'afii10079', 'afii10080', 'afii10081', - 'afii10082', 'afii10083', 'afii10084', 'afii10085', - 'afii10086', 'afii10087', 'afii10088', 'afii10089', - 'afii10090', 'afii10091', 'afii10092', 'afii10093', - 'afii10094', 'afii10095', 'afii10096', 'afii10097' - ], -# Western Europe - 'cp1252' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'Euro', '.notdef', 'quotesinglbase', 'florin', - 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', - 'circumflex', 'perthousand', 'Scaron', 'guilsinglleft', - 'OE', '.notdef', 'Zcaron', '.notdef', - '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - 'tilde', 'trademark', 'scaron', 'guilsinglright', - 'oe', '.notdef', 'zcaron', 'Ydieresis', - 'space', 'exclamdown', 'cent', 'sterling', - 'currency', 'yen', 'brokenbar', 'section', - 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'macron', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'acute', 'mu', 'paragraph', 'periodcentered', - 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', - 'onequarter', 'onehalf', 'threequarters', 'questiondown', - 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', - 'Adieresis', 'Aring', 'AE', 'Ccedilla', - 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', - 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', - 'Eth', 'Ntilde', 'Ograve', 'Oacute', - 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', - 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', - 'Udieresis', 'Yacute', 'Thorn', 'germandbls', - 'agrave', 'aacute', 'acircumflex', 'atilde', - 'adieresis', 'aring', 'ae', 'ccedilla', - 'egrave', 'eacute', 'ecircumflex', 'edieresis', - 'igrave', 'iacute', 'icircumflex', 'idieresis', - 'eth', 'ntilde', 'ograve', 'oacute', - 'ocircumflex', 'otilde', 'odieresis', 'divide', - 'oslash', 'ugrave', 'uacute', 'ucircumflex', - 'udieresis', 'yacute', 'thorn', 'ydieresis' - ], -# Greek - 'cp1253' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'Euro', '.notdef', 'quotesinglbase', 'florin', - 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', - '.notdef', 'perthousand', '.notdef', 'guilsinglleft', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - '.notdef', 'trademark', '.notdef', 'guilsinglright', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'dieresistonos', 'Alphatonos', 'sterling', - 'currency', 'yen', 'brokenbar', 'section', - 'dieresis', 'copyright', '.notdef', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'afii00208', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'tonos', 'mu', 'paragraph', 'periodcentered', - 'Epsilontonos', 'Etatonos', 'Iotatonos', 'guillemotright', - 'Omicrontonos', 'onehalf', 'Upsilontonos', 'Omegatonos', - 'iotadieresistonos','Alpha', 'Beta', 'Gamma', - 'Delta', 'Epsilon', 'Zeta', 'Eta', - 'Theta', 'Iota', 'Kappa', 'Lambda', - 'Mu', 'Nu', 'Xi', 'Omicron', - 'Pi', 'Rho', '.notdef', 'Sigma', - 'Tau', 'Upsilon', 'Phi', 'Chi', - 'Psi', 'Omega', 'Iotadieresis', 'Upsilondieresis', - 'alphatonos', 'epsilontonos', 'etatonos', 'iotatonos', - 'upsilondieresistonos','alpha', 'beta', 'gamma', - 'delta', 'epsilon', 'zeta', 'eta', - 'theta', 'iota', 'kappa', 'lambda', - 'mu', 'nu', 'xi', 'omicron', - 'pi', 'rho', 'sigma1', 'sigma', - 'tau', 'upsilon', 'phi', 'chi', - 'psi', 'omega', 'iotadieresis', 'upsilondieresis', - 'omicrontonos', 'upsilontonos', 'omegatonos', '.notdef' - ], -# Turkish - 'cp1254' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'Euro', '.notdef', 'quotesinglbase', 'florin', - 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', - 'circumflex', 'perthousand', 'Scaron', 'guilsinglleft', - 'OE', '.notdef', '.notdef', '.notdef', - '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - 'tilde', 'trademark', 'scaron', 'guilsinglright', - 'oe', '.notdef', '.notdef', 'Ydieresis', - 'space', 'exclamdown', 'cent', 'sterling', - 'currency', 'yen', 'brokenbar', 'section', - 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'macron', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'acute', 'mu', 'paragraph', 'periodcentered', - 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', - 'onequarter', 'onehalf', 'threequarters', 'questiondown', - 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', - 'Adieresis', 'Aring', 'AE', 'Ccedilla', - 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', - 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', - 'Gbreve', 'Ntilde', 'Ograve', 'Oacute', - 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', - 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', - 'Udieresis', 'Idotaccent', 'Scedilla', 'germandbls', - 'agrave', 'aacute', 'acircumflex', 'atilde', - 'adieresis', 'aring', 'ae', 'ccedilla', - 'egrave', 'eacute', 'ecircumflex', 'edieresis', - 'igrave', 'iacute', 'icircumflex', 'idieresis', - 'gbreve', 'ntilde', 'ograve', 'oacute', - 'ocircumflex', 'otilde', 'odieresis', 'divide', - 'oslash', 'ugrave', 'uacute', 'ucircumflex', - 'udieresis', 'dotlessi', 'scedilla', 'ydieresis' - ], -# Hebrew - 'cp1255' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'Euro', '.notdef', 'quotesinglbase', 'florin', - 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', - 'circumflex', 'perthousand', '.notdef', 'guilsinglleft', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - 'tilde', 'trademark', '.notdef', 'guilsinglright', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclamdown', 'cent', 'sterling', - 'afii57636', 'yen', 'brokenbar', 'section', - 'dieresis', 'copyright', 'multiply', 'guillemotleft', - 'logicalnot', 'sfthyphen', 'registered', 'macron', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'acute', 'mu', 'paragraph', 'middot', - 'cedilla', 'onesuperior', 'divide', 'guillemotright', - 'onequarter', 'onehalf', 'threequarters', 'questiondown', - 'afii57799', 'afii57801', 'afii57800', 'afii57802', - 'afii57793', 'afii57794', 'afii57795', 'afii57798', - 'afii57797', 'afii57806', '.notdef', 'afii57796', - 'afii57807', 'afii57839', 'afii57645', 'afii57841', - 'afii57842', 'afii57804', 'afii57803', 'afii57658', - 'afii57716', 'afii57717', 'afii57718', 'gereshhebrew', - 'gershayimhebrew','.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'afii57664', 'afii57665', 'afii57666', 'afii57667', - 'afii57668', 'afii57669', 'afii57670', 'afii57671', - 'afii57672', 'afii57673', 'afii57674', 'afii57675', - 'afii57676', 'afii57677', 'afii57678', 'afii57679', - 'afii57680', 'afii57681', 'afii57682', 'afii57683', - 'afii57684', 'afii57685', 'afii57686', 'afii57687', - 'afii57688', 'afii57689', 'afii57690', '.notdef', - '.notdef', 'afii299', 'afii300', '.notdef' - ], -# Baltic - 'cp1257' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'Euro', '.notdef', 'quotesinglbase', '.notdef', - 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', - '.notdef', 'perthousand', '.notdef', 'guilsinglleft', - '.notdef', 'dieresis', 'caron', 'cedilla', - '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - '.notdef', 'trademark', '.notdef', 'guilsinglright', - '.notdef', 'macron', 'ogonek', '.notdef', - 'space', '.notdef', 'cent', 'sterling', - 'currency', '.notdef', 'brokenbar', 'section', - 'Oslash', 'copyright', 'Rcommaaccent', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'AE', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'acute', 'mu', 'paragraph', 'periodcentered', - 'oslash', 'onesuperior', 'rcommaaccent', 'guillemotright', - 'onequarter', 'onehalf', 'threequarters', 'ae', - 'Aogonek', 'Iogonek', 'Amacron', 'Cacute', - 'Adieresis', 'Aring', 'Eogonek', 'Emacron', - 'Ccaron', 'Eacute', 'Zacute', 'Edotaccent', - 'Gcommaaccent', 'Kcommaaccent', 'Imacron', 'Lcommaaccent', - 'Scaron', 'Nacute', 'Ncommaaccent', 'Oacute', - 'Omacron', 'Otilde', 'Odieresis', 'multiply', - 'Uogonek', 'Lslash', 'Sacute', 'Umacron', - 'Udieresis', 'Zdotaccent', 'Zcaron', 'germandbls', - 'aogonek', 'iogonek', 'amacron', 'cacute', - 'adieresis', 'aring', 'eogonek', 'emacron', - 'ccaron', 'eacute', 'zacute', 'edotaccent', - 'gcommaaccent', 'kcommaaccent', 'imacron', 'lcommaaccent', - 'scaron', 'nacute', 'ncommaaccent', 'oacute', - 'omacron', 'otilde', 'odieresis', 'divide', - 'uogonek', 'lslash', 'sacute', 'umacron', - 'udieresis', 'zdotaccent', 'zcaron', 'dotaccent' - ], -# Vietnamese - 'cp1258' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'Euro', '.notdef', 'quotesinglbase', 'florin', - 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', - 'circumflex', 'perthousand', '.notdef', 'guilsinglleft', - 'OE', '.notdef', '.notdef', '.notdef', - '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - 'tilde', 'trademark', '.notdef', 'guilsinglright', - 'oe', '.notdef', '.notdef', 'Ydieresis', - 'space', 'exclamdown', 'cent', 'sterling', - 'currency', 'yen', 'brokenbar', 'section', - 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'macron', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'acute', 'mu', 'paragraph', 'periodcentered', - 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', - 'onequarter', 'onehalf', 'threequarters', 'questiondown', - 'Agrave', 'Aacute', 'Acircumflex', 'Abreve', - 'Adieresis', 'Aring', 'AE', 'Ccedilla', - 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', - 'gravecomb', 'Iacute', 'Icircumflex', 'Idieresis', - 'Dcroat', 'Ntilde', 'hookabovecomb', 'Oacute', - 'Ocircumflex', 'Ohorn', 'Odieresis', 'multiply', - 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', - 'Udieresis', 'Uhorn', 'tildecomb', 'germandbls', - 'agrave', 'aacute', 'acircumflex', 'abreve', - 'adieresis', 'aring', 'ae', 'ccedilla', - 'egrave', 'eacute', 'ecircumflex', 'edieresis', - 'acutecomb', 'iacute', 'icircumflex', 'idieresis', - 'dcroat', 'ntilde', 'dotbelowcomb', 'oacute', - 'ocircumflex', 'ohorn', 'odieresis', 'divide', - 'oslash', 'ugrave', 'uacute', 'ucircumflex', - 'udieresis', 'uhorn', 'dong', 'ydieresis' - ], -# Thai - 'cp874' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'Euro', '.notdef', '.notdef', '.notdef', - '.notdef', 'ellipsis', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', - 'quotedblright', 'bullet', 'endash', 'emdash', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'kokaithai', 'khokhaithai', 'khokhuatthai', - 'khokhwaithai', 'khokhonthai', 'khorakhangthai', 'ngonguthai', - 'chochanthai', 'chochingthai', 'chochangthai', 'sosothai', - 'chochoethai', 'yoyingthai', 'dochadathai', 'topatakthai', - 'thothanthai', 'thonangmonthothai', 'thophuthaothai', 'nonenthai', - 'dodekthai', 'totaothai', 'thothungthai', 'thothahanthai', - 'thothongthai', 'nonuthai', 'bobaimaithai', 'poplathai', - 'phophungthai', 'fofathai', 'phophanthai', 'fofanthai', - 'phosamphaothai', 'momathai', 'yoyakthai', 'roruathai', - 'ruthai', 'lolingthai', 'luthai', 'wowaenthai', - 'sosalathai', 'sorusithai', 'sosuathai', 'hohipthai', - 'lochulathai', 'oangthai', 'honokhukthai', 'paiyannoithai', - 'saraathai', 'maihanakatthai', 'saraaathai', 'saraamthai', - 'saraithai', 'saraiithai', 'sarauethai', 'saraueethai', - 'sarauthai', 'sarauuthai', 'phinthuthai', '.notdef', - '.notdef', '.notdef', '.notdef', 'bahtthai', - 'saraethai', 'saraaethai', 'saraothai', 'saraaimaimuanthai', - 'saraaimaimalaithai', 'lakkhangyaothai', 'maiyamokthai', 'maitaikhuthai', - 'maiekthai', 'maithothai', 'maitrithai', 'maichattawathai', - 'thanthakhatthai', 'nikhahitthai', 'yamakkanthai', 'fongmanthai', - 'zerothai', 'onethai', 'twothai', 'threethai', - 'fourthai', 'fivethai', 'sixthai', 'seventhai', - 'eightthai', 'ninethai', 'angkhankhuthai', 'khomutthai', - '.notdef', '.notdef', '.notdef', '.notdef' - ], -# Western Europe - 'ISO-8859-1' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclamdown', 'cent', 'sterling', - 'currency', 'yen', 'brokenbar', 'section', - 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'macron', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'acute', 'mu', 'paragraph', 'periodcentered', - 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', - 'onequarter', 'onehalf', 'threequarters', 'questiondown', - 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', - 'Adieresis', 'Aring', 'AE', 'Ccedilla', - 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', - 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', - 'Eth', 'Ntilde', 'Ograve', 'Oacute', - 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', - 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', - 'Udieresis', 'Yacute', 'Thorn', 'germandbls', - 'agrave', 'aacute', 'acircumflex', 'atilde', - 'adieresis', 'aring', 'ae', 'ccedilla', - 'egrave', 'eacute', 'ecircumflex', 'edieresis', - 'igrave', 'iacute', 'icircumflex', 'idieresis', - 'eth', 'ntilde', 'ograve', 'oacute', - 'ocircumflex', 'otilde', 'odieresis', 'divide', - 'oslash', 'ugrave', 'uacute', 'ucircumflex', - 'udieresis', 'yacute', 'thorn', 'ydieresis' - ], -# Central Europe - 'ISO-8859-2' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'Aogonek', 'breve', 'Lslash', - 'currency', 'Lcaron', 'Sacute', 'section', - 'dieresis', 'Scaron', 'Scedilla', 'Tcaron', - 'Zacute', 'hyphen', 'Zcaron', 'Zdotaccent', - 'degree', 'aogonek', 'ogonek', 'lslash', - 'acute', 'lcaron', 'sacute', 'caron', - 'cedilla', 'scaron', 'scedilla', 'tcaron', - 'zacute', 'hungarumlaut', 'zcaron', 'zdotaccent', - 'Racute', 'Aacute', 'Acircumflex', 'Abreve', - 'Adieresis', 'Lacute', 'Cacute', 'Ccedilla', - 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', - 'Ecaron', 'Iacute', 'Icircumflex', 'Dcaron', - 'Dcroat', 'Nacute', 'Ncaron', 'Oacute', - 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'multiply', - 'Rcaron', 'Uring', 'Uacute', 'Uhungarumlaut', - 'Udieresis', 'Yacute', 'Tcommaaccent', 'germandbls', - 'racute', 'aacute', 'acircumflex', 'abreve', - 'adieresis', 'lacute', 'cacute', 'ccedilla', - 'ccaron', 'eacute', 'eogonek', 'edieresis', - 'ecaron', 'iacute', 'icircumflex', 'dcaron', - 'dcroat', 'nacute', 'ncaron', 'oacute', - 'ocircumflex', 'ohungarumlaut', 'odieresis', 'divide', - 'rcaron', 'uring', 'uacute', 'uhungarumlaut', - 'udieresis', 'yacute', 'tcommaaccent', 'dotaccent' - ], -# Baltic - 'ISO-8859-4' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'Aogonek', 'kgreenlandic', 'Rcommaaccent', - 'currency', 'Itilde', 'Lcommaaccent', 'section', - 'dieresis', 'Scaron', 'Emacron', 'Gcommaaccent', - 'Tbar', 'hyphen', 'Zcaron', 'macron', - 'degree', 'aogonek', 'ogonek', 'rcommaaccent', - 'acute', 'itilde', 'lcommaaccent', 'caron', - 'cedilla', 'scaron', 'emacron', 'gcommaaccent', - 'tbar', 'Eng', 'zcaron', 'eng', - 'Amacron', 'Aacute', 'Acircumflex', 'Atilde', - 'Adieresis', 'Aring', 'AE', 'Iogonek', - 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', - 'Edotaccent', 'Iacute', 'Icircumflex', 'Imacron', - 'Dcroat', 'Ncommaaccent', 'Omacron', 'Kcommaaccent', - 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', - 'Oslash', 'Uogonek', 'Uacute', 'Ucircumflex', - 'Udieresis', 'Utilde', 'Umacron', 'germandbls', - 'amacron', 'aacute', 'acircumflex', 'atilde', - 'adieresis', 'aring', 'ae', 'iogonek', - 'ccaron', 'eacute', 'eogonek', 'edieresis', - 'edotaccent', 'iacute', 'icircumflex', 'imacron', - 'dcroat', 'ncommaaccent', 'omacron', 'kcommaaccent', - 'ocircumflex', 'otilde', 'odieresis', 'divide', - 'oslash', 'uogonek', 'uacute', 'ucircumflex', - 'udieresis', 'utilde', 'umacron', 'dotaccent' - ], -# Cyrillic - 'ISO-8859-5' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'afii10023', 'afii10051', 'afii10052', - 'afii10053', 'afii10054', 'afii10055', 'afii10056', - 'afii10057', 'afii10058', 'afii10059', 'afii10060', - 'afii10061', 'hyphen', 'afii10062', 'afii10145', - 'afii10017', 'afii10018', 'afii10019', 'afii10020', - 'afii10021', 'afii10022', 'afii10024', 'afii10025', - 'afii10026', 'afii10027', 'afii10028', 'afii10029', - 'afii10030', 'afii10031', 'afii10032', 'afii10033', - 'afii10034', 'afii10035', 'afii10036', 'afii10037', - 'afii10038', 'afii10039', 'afii10040', 'afii10041', - 'afii10042', 'afii10043', 'afii10044', 'afii10045', - 'afii10046', 'afii10047', 'afii10048', 'afii10049', - 'afii10065', 'afii10066', 'afii10067', 'afii10068', - 'afii10069', 'afii10070', 'afii10072', 'afii10073', - 'afii10074', 'afii10075', 'afii10076', 'afii10077', - 'afii10078', 'afii10079', 'afii10080', 'afii10081', - 'afii10082', 'afii10083', 'afii10084', 'afii10085', - 'afii10086', 'afii10087', 'afii10088', 'afii10089', - 'afii10090', 'afii10091', 'afii10092', 'afii10093', - 'afii10094', 'afii10095', 'afii10096', 'afii10097', - 'afii61352', 'afii10071', 'afii10099', 'afii10100', - 'afii10101', 'afii10102', 'afii10103', 'afii10104', - 'afii10105', 'afii10106', 'afii10107', 'afii10108', - 'afii10109', 'section', 'afii10110', 'afii10193' - ], -# Greek - 'ISO-8859-7' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'quoteleft', 'quoteright', 'sterling', - '.notdef', '.notdef', 'brokenbar', 'section', - 'dieresis', 'copyright', '.notdef', 'guillemotleft', - 'logicalnot', 'hyphen', '.notdef', 'afii00208', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'tonos', 'dieresistonos', 'Alphatonos', 'periodcentered', - 'Epsilontonos', 'Etatonos', 'Iotatonos', 'guillemotright', - 'Omicrontonos', 'onehalf', 'Upsilontonos', 'Omegatonos', - 'iotadieresistonos','Alpha', 'Beta', 'Gamma', - 'Delta', 'Epsilon', 'Zeta', 'Eta', - 'Theta', 'Iota', 'Kappa', 'Lambda', - 'Mu', 'Nu', 'Xi', 'Omicron', - 'Pi', 'Rho', '.notdef', 'Sigma', - 'Tau', 'Upsilon', 'Phi', 'Chi', - 'Psi', 'Omega', 'Iotadieresis', 'Upsilondieresis', - 'alphatonos', 'epsilontonos', 'etatonos', 'iotatonos', - 'upsilondieresistonos','alpha', 'beta', 'gamma', - 'delta', 'epsilon', 'zeta', 'eta', - 'theta', 'iota', 'kappa', 'lambda', - 'mu', 'nu', 'xi', 'omicron', - 'pi', 'rho', 'sigma1', 'sigma', - 'tau', 'upsilon', 'phi', 'chi', - 'psi', 'omega', 'iotadieresis', 'upsilondieresis', - 'omicrontonos', 'upsilontonos', 'omegatonos', '.notdef' - ], -# Turkish - 'ISO-8859-9' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclamdown', 'cent', 'sterling', - 'currency', 'yen', 'brokenbar', 'section', - 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'macron', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'acute', 'mu', 'paragraph', 'periodcentered', - 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', - 'onequarter', 'onehalf', 'threequarters', 'questiondown', - 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', - 'Adieresis', 'Aring', 'AE', 'Ccedilla', - 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', - 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', - 'Gbreve', 'Ntilde', 'Ograve', 'Oacute', - 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', - 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', - 'Udieresis', 'Idotaccent', 'Scedilla', 'germandbls', - 'agrave', 'aacute', 'acircumflex', 'atilde', - 'adieresis', 'aring', 'ae', 'ccedilla', - 'egrave', 'eacute', 'ecircumflex', 'edieresis', - 'igrave', 'iacute', 'icircumflex', 'idieresis', - 'gbreve', 'ntilde', 'ograve', 'oacute', - 'ocircumflex', 'otilde', 'odieresis', 'divide', - 'oslash', 'ugrave', 'uacute', 'ucircumflex', - 'udieresis', 'dotlessi', 'scedilla', 'ydieresis' - ], -# Thai - 'ISO-8859-11' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'kokaithai', 'khokhaithai', 'khokhuatthai', - 'khokhwaithai', 'khokhonthai', 'khorakhangthai', 'ngonguthai', - 'chochanthai', 'chochingthai', 'chochangthai', 'sosothai', - 'chochoethai', 'yoyingthai', 'dochadathai', 'topatakthai', - 'thothanthai', 'thonangmonthothai','thophuthaothai', 'nonenthai', - 'dodekthai', 'totaothai', 'thothungthai', 'thothahanthai', - 'thothongthai', 'nonuthai', 'bobaimaithai', 'poplathai', - 'phophungthai', 'fofathai', 'phophanthai', 'fofanthai', - 'phosamphaothai', 'momathai', 'yoyakthai', 'roruathai', - 'ruthai', 'lolingthai', 'luthai', 'wowaenthai', - 'sosalathai', 'sorusithai', 'sosuathai', 'hohipthai', - 'lochulathai', 'oangthai', 'honokhukthai', 'paiyannoithai', - 'saraathai', 'maihanakatthai', 'saraaathai', 'saraamthai', - 'saraithai', 'saraiithai', 'sarauethai', 'saraueethai', - 'sarauthai', 'sarauuthai', 'phinthuthai', '.notdef', - '.notdef', '.notdef', '.notdef', 'bahtthai', - 'saraethai', 'saraaethai', 'saraothai', 'saraaimaimuanthai', - 'saraaimaimalaithai','lakkhangyaothai','maiyamokthai', 'maitaikhuthai', - 'maiekthai', 'maithothai', 'maitrithai', 'maichattawathai', - 'thanthakhatthai','nikhahitthai', 'yamakkanthai', 'fongmanthai', - 'zerothai', 'onethai', 'twothai', 'threethai', - 'fourthai', 'fivethai', 'sixthai', 'seventhai', - 'eightthai', 'ninethai', 'angkhankhuthai', 'khomutthai', - '.notdef', '.notdef', '.notdef', '.notdef' - ], -# Western Europe - 'ISO-8859-15' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclamdown', 'cent', 'sterling', - 'Euro', 'yen', 'Scaron', 'section', - 'scaron', 'copyright', 'ordfeminine', 'guillemotleft', - 'logicalnot', 'hyphen', 'registered', 'macron', - 'degree', 'plusminus', 'twosuperior', 'threesuperior', - 'Zcaron', 'mu', 'paragraph', 'periodcentered', - 'zcaron', 'onesuperior', 'ordmasculine', 'guillemotright', - 'OE', 'oe', 'Ydieresis', 'questiondown', - 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', - 'Adieresis', 'Aring', 'AE', 'Ccedilla', - 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', - 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', - 'Eth', 'Ntilde', 'Ograve', 'Oacute', - 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', - 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', - 'Udieresis', 'Yacute', 'Thorn', 'germandbls', - 'agrave', 'aacute', 'acircumflex', 'atilde', - 'adieresis', 'aring', 'ae', 'ccedilla', - 'egrave', 'eacute', 'ecircumflex', 'edieresis', - 'igrave', 'iacute', 'icircumflex', 'idieresis', - 'eth', 'ntilde', 'ograve', 'oacute', - 'ocircumflex', 'otilde', 'odieresis', 'divide', - 'oslash', 'ugrave', 'uacute', 'ucircumflex', - 'udieresis', 'yacute', 'thorn', 'ydieresis' - ], -# Central Europe - 'ISO-8859-16' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'Aogonek', 'aogonek', 'Lslash', - 'Euro', 'quotedblbase', 'Scaron', 'section', - 'scaron', 'copyright', 'Scommaaccent', 'guillemotleft', - 'Zacute', 'hyphen', 'zacute', 'Zdotaccent', - 'degree', 'plusminus', 'Ccaron', 'lslash', - 'Zcaron', 'quotedblright', 'paragraph', 'periodcentered', - 'zcaron', 'ccaron', 'scommaaccent', 'guillemotright', - 'OE', 'oe', 'Ydieresis', 'zdotaccent', - 'Agrave', 'Aacute', 'Acircumflex', 'Abreve', - 'Adieresis', 'Cacute', 'AE', 'Ccedilla', - 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', - 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', - 'Dcroat', 'Nacute', 'Ograve', 'Oacute', - 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'Sacute', - 'Uhungarumlaut', 'Ugrave', 'Uacute', 'Ucircumflex', - 'Udieresis', 'Eogonek', 'Tcommaaccent', 'germandbls', - 'agrave', 'aacute', 'acircumflex', 'abreve', - 'adieresis', 'cacute', 'ae', 'ccedilla', - 'egrave', 'eacute', 'ecircumflex', 'edieresis', - 'igrave', 'iacute', 'icircumflex', 'idieresis', - 'dcroat', 'nacute', 'ograve', 'oacute', - 'ocircumflex', 'ohungarumlaut', 'odieresis', 'sacute', - 'uhungarumlaut', 'ugrave', 'uacute', 'ucircumflex', - 'udieresis', 'eogonek', 'tcommaaccent', 'ydieresis' - ], -# Russian - 'KOI8-R' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'SF100000', 'SF110000', 'SF010000', 'SF030000', - 'SF020000', 'SF040000', 'SF080000', 'SF090000', - 'SF060000', 'SF070000', 'SF050000', 'upblock', - 'dnblock', 'block', 'lfblock', 'rtblock', - 'ltshade', 'shade', 'dkshade', 'integraltp', - 'filledbox', 'periodcentered', 'radical', 'approxequal', - 'lessequal', 'greaterequal', 'space', 'integralbt', - 'degree', 'twosuperior', 'periodcentered', 'divide', - 'SF430000', 'SF240000', 'SF510000', 'afii10071', - 'SF520000', 'SF390000', 'SF220000', 'SF210000', - 'SF250000', 'SF500000', 'SF490000', 'SF380000', - 'SF280000', 'SF270000', 'SF260000', 'SF360000', - 'SF370000', 'SF420000', 'SF190000', 'afii10023', - 'SF200000', 'SF230000', 'SF470000', 'SF480000', - 'SF410000', 'SF450000', 'SF460000', 'SF400000', - 'SF540000', 'SF530000', 'SF440000', 'copyright', - 'afii10096', 'afii10065', 'afii10066', 'afii10088', - 'afii10069', 'afii10070', 'afii10086', 'afii10068', - 'afii10087', 'afii10074', 'afii10075', 'afii10076', - 'afii10077', 'afii10078', 'afii10079', 'afii10080', - 'afii10081', 'afii10097', 'afii10082', 'afii10083', - 'afii10084', 'afii10085', 'afii10072', 'afii10067', - 'afii10094', 'afii10093', 'afii10073', 'afii10090', - 'afii10095', 'afii10091', 'afii10089', 'afii10092', - 'afii10048', 'afii10017', 'afii10018', 'afii10040', - 'afii10021', 'afii10022', 'afii10038', 'afii10020', - 'afii10039', 'afii10026', 'afii10027', 'afii10028', - 'afii10029', 'afii10030', 'afii10031', 'afii10032', - 'afii10033', 'afii10049', 'afii10034', 'afii10035', - 'afii10036', 'afii10037', 'afii10024', 'afii10019', - 'afii10046', 'afii10045', 'afii10025', 'afii10042', - 'afii10047', 'afii10043', 'afii10041', 'afii10044' - ], -# Ukrainian - 'KOI8-U' => [ - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - '.notdef', '.notdef', '.notdef', '.notdef', - 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quotesingle', - 'parenleft', 'parenright', 'asterisk', 'plus', - 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', - 'eight', 'nine', 'colon', 'semicolon', - 'less', 'equal', 'greater', 'question', - 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'braceleft', - 'bar', 'braceright', 'asciitilde', '.notdef', - 'SF100000', 'SF110000', 'SF010000', 'SF030000', - 'SF020000', 'SF040000', 'SF080000', 'SF090000', - 'SF060000', 'SF070000', 'SF050000', 'upblock', - 'dnblock', 'block', 'lfblock', 'rtblock', - 'ltshade', 'shade', 'dkshade', 'integraltp', - 'filledbox', 'bullet', 'radical', 'approxequal', - 'lessequal', 'greaterequal', 'space', 'integralbt', - 'degree', 'twosuperior', 'periodcentered', 'divide', - 'SF430000', 'SF240000', 'SF510000', 'afii10071', - 'afii10101', 'SF390000', 'afii10103', 'afii10104', - 'SF250000', 'SF500000', 'SF490000', 'SF380000', - 'SF280000', 'afii10098', 'SF260000', 'SF360000', - 'SF370000', 'SF420000', 'SF190000', 'afii10023', - 'afii10053', 'SF230000', 'afii10055', 'afii10056', - 'SF410000', 'SF450000', 'SF460000', 'SF400000', - 'SF540000', 'afii10050', 'SF440000', 'copyright', - 'afii10096', 'afii10065', 'afii10066', 'afii10088', - 'afii10069', 'afii10070', 'afii10086', 'afii10068', - 'afii10087', 'afii10074', 'afii10075', 'afii10076', - 'afii10077', 'afii10078', 'afii10079', 'afii10080', - 'afii10081', 'afii10097', 'afii10082', 'afii10083', - 'afii10084', 'afii10085', 'afii10072', 'afii10067', - 'afii10094', 'afii10093', 'afii10073', 'afii10090', - 'afii10095', 'afii10091', 'afii10089', 'afii10092', - 'afii10048', 'afii10017', 'afii10018', 'afii10040', - 'afii10021', 'afii10022', 'afii10038', 'afii10020', - 'afii10039', 'afii10026', 'afii10027', 'afii10028', - 'afii10029', 'afii10030', 'afii10031', 'afii10032', - 'afii10033', 'afii10049', 'afii10034', 'afii10035', - 'afii10036', 'afii10037', 'afii10024', 'afii10019', - 'afii10046', 'afii10045', 'afii10025', 'afii10042', - 'afii10047', 'afii10043', 'afii10041', 'afii10044' - ] -} - -def ReadAFM(file, map) - - # Read a font metric file - a = IO.readlines(file) - - raise "File no found: #{file}" if a.size == 0 - - widths = {} - fm = {} - fix = { 'Edot' => 'Edotaccent', 'edot' => 'edotaccent', - 'Idot' => 'Idotaccent', - 'Zdot' => 'Zdotaccent', 'zdot' => 'zdotaccent', - 'Odblacute' => 'Ohungarumlaut', 'odblacute' => 'ohungarumlaut', - 'Udblacute' => 'Uhungarumlaut', 'udblacute' => 'uhungarumlaut', - 'Gcedilla' => 'Gcommaaccent', 'gcedilla' => 'gcommaaccent', - 'Kcedilla' => 'Kcommaaccent', 'kcedilla' => 'kcommaaccent', - 'Lcedilla' => 'Lcommaaccent', 'lcedilla' => 'lcommaaccent', - 'Ncedilla' => 'Ncommaaccent', 'ncedilla' => 'ncommaaccent', - 'Rcedilla' => 'Rcommaaccent', 'rcedilla' => 'rcommaaccent', - 'Scedilla' => 'Scommaaccent',' scedilla' => 'scommaaccent', - 'Tcedilla' => 'Tcommaaccent',' tcedilla' => 'tcommaaccent', - 'Dslash' => 'Dcroat', 'dslash' => 'dcroat', - 'Dmacron' => 'Dcroat', 'dmacron' => 'dcroat', - 'combininggraveaccent' => 'gravecomb', - 'combininghookabove' => 'hookabovecomb', - 'combiningtildeaccent' => 'tildecomb', - 'combiningacuteaccent' => 'acutecomb', - 'combiningdotbelow' => 'dotbelowcomb', - 'dongsign' => 'dong' - } - - a.each do |line| - - e = line.rstrip.split(' ') - next if e.size < 2 - - code = e[0] - param = e[1] - - if code == 'C' then - - # Character metrics - cc = e[1].to_i - w = e[4] - gn = e[7] - - gn = 'Euro' if gn[-4, 4] == '20AC' - - if fix[gn] then - - # Fix incorrect glyph name - 0.upto(map.size - 1) do |i| - if map[i] == fix[gn] then - map[i] = gn - end - end - end - - if map.size == 0 then - # Symbolic font: use built-in encoding - widths[cc] = w - else - widths[gn] = w - fm['CapXHeight'] = e[13].to_i if gn == 'X' - end - - fm['MissingWidth'] = w if gn == '.notdef' - - elsif code == 'FontName' then - fm['FontName'] = param - elsif code == 'Weight' then - fm['Weight'] = param - elsif code == 'ItalicAngle' then - fm['ItalicAngle'] = param.to_f - elsif code == 'Ascender' then - fm['Ascender'] = param.to_i - elsif code == 'Descender' then - fm['Descender'] = param.to_i - elsif code == 'UnderlineThickness' then - fm['UnderlineThickness'] = param.to_i - elsif code == 'UnderlinePosition' then - fm['UnderlinePosition'] = param.to_i - elsif code == 'IsFixedPitch' then - fm['IsFixedPitch'] = (param == 'true') - elsif code == 'FontBBox' then - fm['FontBBox'] = "[#{e[1]},#{e[2]},#{e[3]},#{e[4]}]" - elsif code == 'CapHeight' then - fm['CapHeight'] = param.to_i - elsif code == 'StdVW' then - fm['StdVW'] = param.to_i - end - end - - raise 'FontName not found' unless fm['FontName'] - - if map.size > 0 then - widths['.notdef'] = 600 unless widths['.notdef'] - - if (widths['Delta'] == nil) && widths['increment'] then - widths['Delta'] = widths['increment'] - end - - # Order widths according to map - 0.upto(255) do |i| - if widths[map[i]] == nil - puts "Warning: character #{map[i]} is missing" - widths[i] = widths['.notdef'] - else - widths[i] = widths[map[i]] - end - end - end - - fm['Widths'] = widths - - return fm -end - -def MakeFontDescriptor(fm, symbolic) - - # Ascent - asc = fm['Ascender'] ? fm['Ascender'] : 1000 - fd = "{\n 'Ascent' => '#{asc}'" - - # Descent - desc = fm['Descender'] ? fm['Descender'] : -200 - fd += ", 'Descent' => '#{desc}'" - - # CapHeight - if fm['CapHeight'] then - ch = fm['CapHeight'] - elsif fm['CapXHeight'] - ch = fm['CapXHeight'] - else - ch = asc - end - fd += ", 'CapHeight' => '#{ch}'" - - # Flags - flags = 0 - - if fm['IsFixedPitch'] then - flags += 1 << 0 - end - - if symbolic then - flags += 1 << 2 - else - flags += 1 << 5 - end - - if fm['ItalicAngle'] && (fm['ItalicAngle'] != 0) then - flags += 1 << 6 - end - - fd += ",\n 'Flags' => '#{flags}'" - - # FontBBox - if fm['FontBBox'] then - fbb = fm['FontBBox'].gsub(/,/, ' ') - else - fbb = "[0 #{desc - 100} 1000 #{asc + 100}]" - end - - fd += ", 'FontBBox' => '#{fbb}'" - - # ItalicAngle - ia = fm['ItalicAngle'] ? fm['ItalicAngle'] : 0 - fd += ",\n 'ItalicAngle' => '#{ia}'" - - # StemV - if fm['StdVW'] then - stemv = fm['StdVW'] - elsif fm['Weight'] && (/bold|black/i =~ fm['Weight']) - stemv = 120 - else - stemv = 70 - end - - fd += ", 'StemV' => '#{stemv}'" - - # MissingWidth - if fm['MissingWidth'] then - fd += ", 'MissingWidth' => '#{fm['MissingWidth']}'" - end - - fd += "\n }" - return fd -end - -def MakeWidthArray(fm) - - # Make character width array - s = " [\n " - - cw = fm['Widths'] - - 0.upto(255) do |i| - s += "%5d" % cw[i] - s += "," if i != 255 - s += "\n " if (i % 8) == 7 - end - - s += ']' - - return s -end - -def MakeFontEncoding(map) - - # Build differences from reference encoding - ref = Charencodings['cp1252'] - s = '' - last = 0 - 32.upto(255) do |i| - if map[i] != ref[i] then - if i != last + 1 then - s += i.to_s + ' ' - end - last = i - s += '/' + map[i] + ' ' - end - end - return s.rstrip -end - -def ReadShort(f) - a = f.read(2).unpack('n') - return a[0] -end - -def ReadLong(f) - a = f.read(4).unpack('N') - return a[0] -end - -def CheckTTF(file) - - rl = false - pp = false - e = false - - # Check if font license allows embedding - File.open(file, 'rb') do |f| - - # Extract number of tables - f.seek(4, IO::SEEK_CUR) - nb = ReadShort(f) - f.seek(6, IO::SEEK_CUR) - - # Seek OS/2 table - found = false - 0.upto(nb - 1) do |i| - if f.read(4) == 'OS/2' then - found = true - break - end - - f.seek(12, IO::SEEK_CUR) - end - - if ! found then - return - end - - f.seek(4, IO::SEEK_CUR) - offset = ReadLong(f) - f.seek(offset, IO::SEEK_SET) - - # Extract fsType flags - f.seek(8, IO::SEEK_CUR) - fsType = ReadShort(f) - - rl = (fsType & 0x02) != 0 - pp = (fsType & 0x04) != 0 - e = (fsType & 0x08) != 0 - end - - if rl && ( ! pp) && ( ! e) then - puts 'Warning: font license does not allow embedding' - end -end - -# -# fontfile: path to TTF file (or empty string if not to be embedded) -# afmfile: path to AFM file -# enc: font encoding (or empty string for symbolic fonts) -# patch: optional patch for encoding -# type : font type if $fontfile is empty -# -def MakeFont(fontfile, afmfile, enc = 'cp1252', patch = {}, type = 'TrueType') - # Generate a font definition file - if (enc != nil) && (enc != '') then - map = Charencodings[enc] - patch.each { |cc, gn| map[cc] = gn } - else - map = [] - end - - raise "Error: AFM file not found: #{afmfile}" unless File.exists?(afmfile) - - fm = ReadAFM(afmfile, map) - - if (enc != nil) && (enc != '') then - diff = MakeFontEncoding(map) - else - diff = '' - end - - fd = MakeFontDescriptor(fm, (map.size == 0)) - - # Find font type - if fontfile then - ext = File.extname(fontfile).downcase.sub(/^\./, '') - - if ext == 'ttf' then - type = 'TrueType' - elsif ext == 'pfb' - type = 'Type1' - else - raise "Error: unrecognized font file extension: #{ext}" - end - else - raise "Error: incorrect font type: #{type}" if (type != 'TrueType') && (type != 'Type1') - end - printf "type = #{type}\n" - # Start generation - s = "# #{fm['FontName']} font definition\n\n" - s += "module FontDef\n" - s += " def FontDef.type\n '#{type}'\n end\n" - s += " def FontDef.name\n '#{fm['FontName']}'\n end\n" - s += " def FontDef.desc\n #{fd}\n end\n" - - if fm['UnderlinePosition'] == nil then - fm['UnderlinePosition'] = -100 - end - - if fm['UnderlineThickness'] == nil then - fm['UnderlineThickness'] = 50 - end - - s += " def FontDef.up\n #{fm['UnderlinePosition']}\n end\n" - s += " def FontDef.ut\n #{fm['UnderlineThickness']}\n end\n" - - w = MakeWidthArray(fm) - s += " def FontDef.cw\n#{w}\n end\n" - - s += " def FontDef.enc\n '#{enc}'\n end\n" - s += " def FontDef.diff\n #{(diff == nil) || (diff == '') ? 'nil' : '\'' + diff '\''}\n end\n" - - basename = File.basename(afmfile, '.*') - - if fontfile then - # Embedded font - if ! File.exist?(fontfile) then - raise "Error: font file not found: #{fontfile}" - end - - if type == 'TrueType' then - CheckTTF(fontfile) - end - - file = '' - File.open(fontfile, 'rb') do |f| - file = f.read() - end - - if type == 'Type1' then - # Find first two sections and discard third one - header = file[0] == 128 - file = file[6, file.length - 6] if header - - pos = file.index('eexec') - raise 'Error: font file does not seem to be valid Type1' if pos == nil - - size1 = pos + 6 - - file = file[0, size1] + file[size1 + 6, file.length - (size1 + 6)] if header && file[size1] == 128 - - pos = file.index('00000000') - raise 'Error: font file does not seem to be valid Type1' if pos == nil - - size2 = pos - size1 - file = file[0, size1 + size2] - end - - if require 'zlib' then - File.open(basename + '.z', 'wb') { |f| f.write(Zlib::Deflate.deflate(file)) } - s += " def FontDef.file\n '#{basename}.z'\n end\n" - puts "Font file compressed ('#{basename}.z')" - else - s += " def FontDef.file\n '#{File.basename(fontfile)}'\n end\n" - puts 'Notice: font file could not be compressed (zlib not available)' - end - - if type == 'Type1' then - s += " def FontDef.size1\n '#{size1}'\n end\n" - s += " def FontDef.size2\n '#{size2}'\n end\n" - else - s += " def FontDef.originalsize\n '#{File.size(fontfile)}'\n end\n" - end - - else - # Not embedded font - s += " def FontDef.file\n ''\n end\n" - end - - s += "end\n" - File.open(basename + '.rb', 'w') { |file| file.write(s)} - puts "Font definition file generated (#{basename}.rb)" -end - - -if $0 == __FILE__ then - if ARGV.length >= 3 then - enc = ARGV[2] - else - enc = 'cp1252' - end - - if ARGV.length >= 4 then - patch = ARGV[3] - else - patch = {} - end - - if ARGV.length >= 5 then - type = ARGV[4] - else - type = 'TrueType' - end - - MakeFont(ARGV[0], ARGV[1], enc, patch, type) -end diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb deleted file mode 100644 index 5ad882903..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb +++ /dev/null @@ -1,346 +0,0 @@ -module RFPDF - COLOR_PALETTE = { - :black => [0x00, 0x00, 0x00], - :white => [0xff, 0xff, 0xff], - }.freeze - - # Draw a line from (x1, y1) to (x2, y2). - # - # Options are: - # * :line_color - Default value is COLOR_PALETTE[:black]. - # * :line_width - Default value is 0.5. - # - # Example: - # - # draw_line(x1, y1, x1, y1+h, :line_color => ReportHelper::COLOR_PALETTE[:dark_blue], :line_width => 1) - # - def draw_line(x1, y1, x2, y2, options = {}) - options[:line_color] ||= COLOR_PALETTE[:black] - options[:line_width] ||= 0.5 - set_draw_color(options[:line_color]) - SetLineWidth(options[:line_width]) - Line(x1, y1, x2, y2) - end - - # Draw a string of text at (x, y). - # - # Options are: - # * :font_color - Default value is COLOR_PALETTE[:black]. - # * :font_size - Default value is 10. - # * :font_style - Default value is nothing or ''. - # - # Example: - # - # draw_text(x, y, header_left, :font_size => 10) - # - def draw_text(x, y, text, options = {}) - options[:font_color] ||= COLOR_PALETTE[:black] - options[:font_size] ||= 10 - options[:font_style] ||= '' - set_text_color(options[:font_color]) - SetFont('Arial', options[:font_style], options[:font_size]) - SetXY(x, y) - Write(options[:font_size] + 4, text) - end - - # Draw a block of text at (x, y) bounded by left_margin and right_margin. Both - # margins are measured from their corresponding edge. - # - # Options are: - # * :font_color - Default value is COLOR_PALETTE[:black]. - # * :font_size - Default value is 10. - # * :font_style - Default value is nothing or ''. - # - # Example: - # - # draw_text_block(left_margin, 85, "question", left_margin, 280, - # :font_color => ReportHelper::COLOR_PALETTE[:dark_blue], - # :font_size => 12, - # :font_style => 'I') - # - def draw_text_block(x, y, text, left_margin, right_margin, options = {}) - options[:font_color] ||= COLOR_PALETTE[:black] - options[:font_size] ||= 10 - options[:font_style] ||= '' - set_text_color(options[:font_color]) - SetFont('Arial', options[:font_style], options[:font_size]) - SetXY(x, y) - SetLeftMargin(left_margin) - SetRightMargin(right_margin) - Write(options[:font_size] + 4, text) - SetMargins(0,0,0) - end - - # Draw a box at (x, y), w wide and h high. - # - # Options are: - # * :border - Draw a border, 0 = no, 1 = yes? Default value is 1. - # * :border_color - Default value is COLOR_PALETTE[:black]. - # * :border_width - Default value is 0.5. - # * :fill - Fill the box, 0 = no, 1 = yes? Default value is 1. - # * :fill_color - Default value is nothing or COLOR_PALETTE[:white]. - # - # Example: - # - # draw_box(x, y - 1, 38, 22) - # - def draw_box(x, y, w, h, options = {}) - options[:border] ||= 1 - options[:border_color] ||= COLOR_PALETTE[:black] - options[:border_width] ||= 0.5 - options[:fill] ||= 1 - options[:fill_color] ||= COLOR_PALETTE[:white] - SetLineWidth(options[:border_width]) - set_draw_color(options[:border_color]) - set_fill_color(options[:fill_color]) - fd = "" - fd = "D" if options[:border] == 1 - fd += "F" if options[:fill] == 1 - Rect(x, y, w, h, fd) - end - - # Draw a string of text at (x, y) in a box w wide and h high. - # - # Options are: - # * :align - Vertical alignment 'C' = center, 'L' = left, 'R' = right. Default value is 'C'. - # * :border - Draw a border, 0 = no, 1 = yes? Default value is 0. - # * :border_color - Default value is COLOR_PALETTE[:black]. - # * :border_width - Default value is 0.5. - # * :fill - Fill the box, 0 = no, 1 = yes? Default value is 1. - # * :fill_color - Default value is nothing or COLOR_PALETTE[:white]. - # * :font_color - Default value is COLOR_PALETTE[:black]. - # * :font_size - Default value is nothing or 8. - # * :font_style - 'B' = bold, 'I' = italic, 'U' = underline. Default value is nothing ''. - # * :padding - Default value is nothing or 2. - # * :valign - 'M' = middle, 'T' = top, 'B' = bottom. Default value is nothing or 'M'. - # - # Example: - # - # draw_text_box(x, y - 1, 38, 22, - # "your_score_title", - # :fill => 0, - # :font_color => ReportHelper::COLOR_PALETTE[:blue], - # :font_line_spacing => 0, - # :font_style => "B", - # :valign => "M") - # - def draw_text_box(x, y, w, h, text, options = {}) - options[:align] ||= 'C' - options[:border] ||= 0 - options[:border_color] ||= COLOR_PALETTE[:black] - options[:border_width] ||= 0.5 - options[:fill] ||= 1 - options[:fill_color] ||= COLOR_PALETTE[:white] - options[:font_color] ||= COLOR_PALETTE[:black] - options[:font_size] ||= 8 - options[:font_line_spacing] ||= options[:font_size] * 0.3 - options[:font_style] ||= '' - options[:padding] ||= 2 - options[:valign] ||= "M" - if options[:fill] == 1 or options[:border] == 1 - draw_box(x, y, w, h, options) - end - SetMargins(0,0,0) - set_text_color(options[:font_color]) - font_size = options[:font_size] - SetFont('Arial', options[:font_style], font_size) - font_size += options[:font_line_spacing] - case options[:valign] - when "B" - y -= options[:padding] - text = "\n" + text if text["\n"].nil? - when "T" - y += options[:padding] - end - SetXY(x, y) - if GetStringWidth(text) > w or not text["\n"].nil? or options[:valign] == "T" - font_size += options[:font_size] * 0.1 - #TODO 2006-07-21 Level=1 - this is assuming a 2 line text - SetXY(x, y + ((h - (font_size * 2)) / 2)) if options[:valign] == "M" - MultiCell(w, font_size, text, 0, options[:align]) - else - Cell(w, h, text, 0, 0, options[:align]) - end - end - - # Draw a string of text at (x, y) as a title. - # - # Options are: - # * :font_color - Default value is COLOR_PALETTE[:black]. - # * :font_size - Default value is 18. - # * :font_style - Default value is nothing or ''. - # - # Example: - # - # draw_title(left_margin, 60, - # "title:", - # :font_color => ReportHelper::COLOR_PALETTE[:dark_blue]) - # - def draw_title(x, y, title, options = {}) - options[:font_color] ||= COLOR_PALETTE[:black] - options[:font_size] ||= 18 - options[:font_style] ||= '' - set_text_color(options[:font_color]) - SetFont('Arial', options[:font_style], options[:font_size]) - SetXY(x, y) - Write(options[:font_size] + 2, title) - end - - # Set the draw color. Default value is COLOR_PALETTE[:black]. - # - # Example: - # - # set_draw_color(ReportHelper::COLOR_PALETTE[:dark_blue]) - # - def set_draw_color(color = COLOR_PALETTE[:black]) - SetDrawColor(color[0], color[1], color[2]) - end - - # Set the fill color. Default value is COLOR_PALETTE[:white]. - # - # Example: - # - # set_fill_color(ReportHelper::COLOR_PALETTE[:dark_blue]) - # - def set_fill_color(color = COLOR_PALETTE[:white]) - SetFillColor(color[0], color[1], color[2]) - end - - # Set the text color. Default value is COLOR_PALETTE[:white]. - # - # Example: - # - # set_text_color(ReportHelper::COLOR_PALETTE[:dark_blue]) - # - def set_text_color(color = COLOR_PALETTE[:black]) - SetTextColor(color[0], color[1], color[2]) - end - - # Write a string containing html characters. Default value is COLOR_PALETTE[:white]. - # - # Options are: - # * :height - Line height. Default value is 20. - # - # Example: - # - # write_html(html, :height => 12) - # - def write_html(html, options = {}) - options[:height] ||= 20 - #HTML parser - @href = nil - @style = {} - html.gsub!("\n",' ') - re = %r{ ( | - < (?: - [^<>"] + - | - " (?: \\. | [^\\"]+ ) * " - ) * - > - ) }xm - - html.split(re).each do |value| - if "<" == value[0,1] - #Tag - if (value[1, 1] == '/') - close_tag(value[2..-2], options) - else - tag = value[1..-2] - open_tag(tag, options) - end - else - #Text - if @href - put_link(@href,value) - else - Write(options[:height], value) - end - end - end - end - - def open_tag(tag, options = {}) #:nodoc: - #Opening tag - tag = tag.to_s.upcase - set_style(tag, true) if tag == 'B' or tag == 'I' or tag == 'U' - @href = options['HREF'] if tag == 'A' - Ln(options[:height]) if tag == 'BR' - end - - def close_tag(tag, options = {}) #:nodoc: - #Closing tag - tag = tag.to_s.upcase - set_style(tag, false) if tag == 'B' or tag == 'I' or tag == 'U' - @href = '' if $tag == 'A' - end - - def set_style(tag, enable = true) #:nodoc: - #Modify style and select corresponding font - style = "" - @style[tag] = enable - ['B','I','U'].each do |s| - style += s if not @style[s].nil? and @style[s] - end - SetFont('', style) - end - - def put_link(url, txt) #:nodoc: - #Put a hyperlink - SetTextColor(0,0,255) - set_style('U',true) - Write(5, txt, url) - set_style('U',false) - SetTextColor(0) - end -end - -# class FPDF -# alias_method :set_margins , :SetMargins -# alias_method :set_left_margin , :SetLeftMargin -# alias_method :set_top_margin , :SetTopMargin -# alias_method :set_right_margin , :SetRightMargin -# alias_method :set_auto_pagebreak , :SetAutoPageBreak -# alias_method :set_display_mode , :SetDisplayMode -# alias_method :set_compression , :SetCompression -# alias_method :set_title , :SetTitle -# alias_method :set_subject , :SetSubject -# alias_method :set_author , :SetAuthor -# alias_method :set_keywords , :SetKeywords -# alias_method :set_creator , :SetCreator -# alias_method :set_draw_color , :SetDrawColor -# alias_method :set_fill_color , :SetFillColor -# alias_method :set_text_color , :SetTextColor -# alias_method :set_line_width , :SetLineWidth -# alias_method :set_font , :SetFont -# alias_method :set_font_size , :SetFontSize -# alias_method :set_link , :SetLink -# alias_method :set_y , :SetY -# alias_method :set_xy , :SetXY -# alias_method :get_string_width , :GetStringWidth -# alias_method :get_x , :GetX -# alias_method :set_x , :SetX -# alias_method :get_y , :GetY -# alias_method :accept_pagev_break , :AcceptPageBreak -# alias_method :add_font , :AddFont -# alias_method :add_link , :AddLink -# alias_method :add_page , :AddPage -# alias_method :alias_nb_pages , :AliasNbPages -# alias_method :cell , :Cell -# alias_method :close , :Close -# alias_method :error , :Error -# alias_method :footer , :Footer -# alias_method :header , :Header -# alias_method :image , :Image -# alias_method :line , :Line -# alias_method :link , :Link -# alias_method :ln , :Ln -# alias_method :multi_cell , :MultiCell -# alias_method :open , :Open -# alias_method :Open , :open -# alias_method :output , :Output -# alias_method :page_no , :PageNo -# alias_method :rect , :Rect -# alias_method :text , :Text -# alias_method :write , :Write -# end diff --git a/redmine/vendor/plugins/rfpdf/lib/rfpdf/view.rb b/redmine/vendor/plugins/rfpdf/lib/rfpdf/view.rb deleted file mode 100644 index 185811202..000000000 --- a/redmine/vendor/plugins/rfpdf/lib/rfpdf/view.rb +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (c) 2006 4ssoM LLC -# -# The MIT License -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# Thanks go out to Bruce Williams of codefluency who created RTex. This -# template handler is modification of his work. -# -# Example Registration -# -# ActionView::Base::register_template_handler 'rfpdf', RFpdfView - -module RFPDF - - class View - - def initialize(action_view) - @action_view = action_view - # Override with @options_for_rfpdf Hash in your controller - @options = { - # Run through latex first? (for table of contents, etc) - :pre_process => false, - # Debugging mode; raises exception - :debug => false, - # Filename of pdf to generate - :file_name => "#{@action_view.controller.action_name}.pdf", - # Temporary Directory - :temp_dir => "#{File.expand_path(RAILS_ROOT)}/tmp" - }.merge(@action_view.controller.instance_eval{ @options_for_rfpdf } || {}).with_indifferent_access - end - - def render(template, local_assigns = {}) - @pdf_name = "Default.pdf" if @pdf_name.nil? - unless @action_view.controller.headers["Content-Type"] == 'application/pdf' - @generate = true - @action_view.controller.headers["Content-Type"] = 'application/pdf' - @action_view.controller.headers["Content-disposition:"] = "inline; filename=\"#{@options[:file_name]}\"" - end - assigns = @action_view.assigns.dup - - if content_for_layout = @action_view.instance_variable_get("@content_for_layout") - assigns['content_for_layout'] = content_for_layout - end - - result = @action_view.instance_eval do - assigns.each do |key,val| - instance_variable_set "@#{key}", val - end - local_assigns.each do |key,val| - class << self; self; end.send(:define_method,key){ val } - end - ERB.new(template).result(binding) - end - end - - end - -end \ No newline at end of file diff --git a/redmine/vendor/plugins/rfpdf/test/test_helper.rb b/redmine/vendor/plugins/rfpdf/test/test_helper.rb deleted file mode 100644 index 2e2ea3bc5..000000000 --- a/redmine/vendor/plugins/rfpdf/test/test_helper.rb +++ /dev/null @@ -1 +0,0 @@ -#!/usr/bin/env ruby \ No newline at end of file diff --git a/script/about b/script/about new file mode 100644 index 000000000..7b07d46a3 --- /dev/null +++ b/script/about @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/about' \ No newline at end of file diff --git a/script/breakpointer b/script/breakpointer new file mode 100644 index 000000000..64af76edd --- /dev/null +++ b/script/breakpointer @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/breakpointer' \ No newline at end of file diff --git a/script/console b/script/console new file mode 100644 index 000000000..42f28f7d6 --- /dev/null +++ b/script/console @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/console' \ No newline at end of file diff --git a/script/destroy b/script/destroy new file mode 100644 index 000000000..fa0e6fcd0 --- /dev/null +++ b/script/destroy @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/destroy' \ No newline at end of file diff --git a/script/generate b/script/generate new file mode 100644 index 000000000..ef976e09f --- /dev/null +++ b/script/generate @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/generate' \ No newline at end of file diff --git a/script/performance/benchmarker b/script/performance/benchmarker new file mode 100644 index 000000000..c842d35d3 --- /dev/null +++ b/script/performance/benchmarker @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/performance/benchmarker' diff --git a/script/performance/profiler b/script/performance/profiler new file mode 100644 index 000000000..d855ac8b1 --- /dev/null +++ b/script/performance/profiler @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/performance/profiler' diff --git a/script/plugin b/script/plugin new file mode 100644 index 000000000..26ca64c06 --- /dev/null +++ b/script/plugin @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/plugin' \ No newline at end of file diff --git a/script/process/reaper b/script/process/reaper new file mode 100644 index 000000000..c77f04535 --- /dev/null +++ b/script/process/reaper @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/process/reaper' diff --git a/script/process/spawner b/script/process/spawner new file mode 100644 index 000000000..7118f3983 --- /dev/null +++ b/script/process/spawner @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/process/spawner' diff --git a/script/process/spinner b/script/process/spinner new file mode 100644 index 000000000..6816b32ef --- /dev/null +++ b/script/process/spinner @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/process/spinner' diff --git a/script/runner b/script/runner new file mode 100644 index 000000000..ccc30f9d2 --- /dev/null +++ b/script/runner @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/runner' \ No newline at end of file diff --git a/script/server b/script/server new file mode 100644 index 000000000..dfabcb881 --- /dev/null +++ b/script/server @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/server' \ No newline at end of file diff --git a/test/fixtures/attachments.yml b/test/fixtures/attachments.yml new file mode 100644 index 000000000..6c352e1e3 --- /dev/null +++ b/test/fixtures/attachments.yml @@ -0,0 +1,13 @@ +--- +attachments_001: + created_on: 2006-07-19 21:07:27 +02:00 + downloads: 0 + content_type: text/plain + disk_filename: 060719210727_error281.txt + container_id: 3 + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 1 + container_type: Issue + filesize: 28 + filename: error281.txt + author_id: 2 diff --git a/test/fixtures/auth_sources.yml b/test/fixtures/auth_sources.yml new file mode 100644 index 000000000..086c00f62 --- /dev/null +++ b/test/fixtures/auth_sources.yml @@ -0,0 +1,2 @@ +--- {} + diff --git a/test/fixtures/custom_fields.yml b/test/fixtures/custom_fields.yml new file mode 100644 index 000000000..fcf52c17a --- /dev/null +++ b/test/fixtures/custom_fields.yml @@ -0,0 +1,45 @@ +--- +custom_fields_001: + name: Database + min_length: 0 + regexp: "" + is_for_all: false + type: IssueCustomField + max_length: 0 + possible_values: MySQL|PostgreSQL|Oracle + id: 1 + is_required: false + field_format: list +custom_fields_002: + name: Build + min_length: 1 + regexp: "" + is_for_all: true + type: IssueCustomField + max_length: 10 + possible_values: "" + id: 2 + is_required: false + field_format: string +custom_fields_003: + name: Development status + min_length: 0 + regexp: "" + is_for_all: false + type: ProjectCustomField + max_length: 0 + possible_values: Stable|Beta|Alpha|Planning + id: 3 + is_required: true + field_format: list +custom_fields_004: + name: Phone number + min_length: 0 + regexp: "" + is_for_all: false + type: UserCustomField + max_length: 0 + possible_values: "" + id: 4 + is_required: false + field_format: string diff --git a/test/fixtures/custom_fields_projects.yml b/test/fixtures/custom_fields_projects.yml new file mode 100644 index 000000000..086c00f62 --- /dev/null +++ b/test/fixtures/custom_fields_projects.yml @@ -0,0 +1,2 @@ +--- {} + diff --git a/test/fixtures/custom_fields_trackers.yml b/test/fixtures/custom_fields_trackers.yml new file mode 100644 index 000000000..cb06d2fcf --- /dev/null +++ b/test/fixtures/custom_fields_trackers.yml @@ -0,0 +1,10 @@ +--- +custom_fields_trackers_001: + custom_field_id: 1 + tracker_id: 1 +custom_fields_trackers_002: + custom_field_id: 2 + tracker_id: 1 +custom_fields_trackers_003: + custom_field_id: 2 + tracker_id: 3 diff --git a/test/fixtures/custom_values.yml b/test/fixtures/custom_values.yml new file mode 100644 index 000000000..4a65619c4 --- /dev/null +++ b/test/fixtures/custom_values.yml @@ -0,0 +1,43 @@ +--- +custom_values_006: + customized_type: Issue + custom_field_id: 2 + customized_id: 3 + id: 9 + value: "125" +custom_values_007: + customized_type: Project + custom_field_id: 3 + customized_id: 1 + id: 10 + value: Stable +custom_values_001: + customized_type: User + custom_field_id: 4 + customized_id: 3 + id: 2 + value: "" +custom_values_002: + customized_type: User + custom_field_id: 4 + customized_id: 4 + id: 3 + value: 01 23 45 67 89 +custom_values_003: + customized_type: User + custom_field_id: 4 + customized_id: 2 + id: 4 + value: "" +custom_values_004: + customized_type: Issue + custom_field_id: 2 + customized_id: 1 + id: 7 + value: "101" +custom_values_005: + customized_type: Issue + custom_field_id: 2 + customized_id: 2 + id: 8 + value: "" diff --git a/test/fixtures/documents.yml b/test/fixtures/documents.yml new file mode 100644 index 000000000..086c00f62 --- /dev/null +++ b/test/fixtures/documents.yml @@ -0,0 +1,2 @@ +--- {} + diff --git a/test/fixtures/enumerations.yml b/test/fixtures/enumerations.yml new file mode 100644 index 000000000..eeef99b5b --- /dev/null +++ b/test/fixtures/enumerations.yml @@ -0,0 +1,33 @@ +--- +enumerations_001: + name: Uncategorized + id: 1 + opt: DCAT +enumerations_002: + name: User documentation + id: 2 + opt: DCAT +enumerations_003: + name: Technical documentation + id: 3 + opt: DCAT +enumerations_004: + name: Low + id: 4 + opt: IPRI +enumerations_005: + name: Normal + id: 5 + opt: IPRI +enumerations_006: + name: High + id: 6 + opt: IPRI +enumerations_007: + name: Urgent + id: 7 + opt: IPRI +enumerations_008: + name: Immediate + id: 8 + opt: IPRI diff --git a/test/fixtures/issue_categories.yml b/test/fixtures/issue_categories.yml new file mode 100644 index 000000000..a994560d4 --- /dev/null +++ b/test/fixtures/issue_categories.yml @@ -0,0 +1,9 @@ +--- +issue_categories_001: + name: Printing + project_id: 1 + id: 1 +issue_categories_002: + name: Recipes + project_id: 1 + id: 2 diff --git a/test/fixtures/issue_statuses.yml b/test/fixtures/issue_statuses.yml new file mode 100644 index 000000000..b5a509f39 --- /dev/null +++ b/test/fixtures/issue_statuses.yml @@ -0,0 +1,37 @@ +--- +issue_statuses_006: + name: Rejected + is_default: false + html_color: F5C28B + is_closed: true + id: 6 +issue_statuses_001: + name: New + is_default: true + html_color: F98787 + is_closed: false + id: 1 +issue_statuses_002: + name: Assigned + is_default: false + html_color: C0C0FF + is_closed: false + id: 2 +issue_statuses_003: + name: Resolved + is_default: false + html_color: 88E0B3 + is_closed: false + id: 3 +issue_statuses_004: + name: Feedback + is_default: false + html_color: F3A4F4 + is_closed: false + id: 4 +issue_statuses_005: + name: Closed + is_default: false + html_color: DBDBDB + is_closed: true + id: 5 diff --git a/test/fixtures/issues.yml b/test/fixtures/issues.yml new file mode 100644 index 000000000..5719a9bc9 --- /dev/null +++ b/test/fixtures/issues.yml @@ -0,0 +1,43 @@ +--- +issues_001: + created_on: 2006-07-19 21:02:17 +02:00 + project_id: 1 + updated_on: 2006-07-19 21:04:30 +02:00 + priority_id: 4 + subject: Can't print recipes + id: 1 + fixed_version_id: + category_id: 1 + description: Unable to print recipes + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 +issues_002: + created_on: 2006-07-19 21:04:21 +02:00 + project_id: 1 + updated_on: 2006-07-19 21:09:50 +02:00 + priority_id: 5 + subject: Add ingredients categories + id: 2 + fixed_version_id: + category_id: + description: Ingredients should be classified by categories + tracker_id: 2 + assigned_to_id: 3 + author_id: 2 + status_id: 2 +issues_003: + created_on: 2006-07-19 21:07:27 +02:00 + project_id: 1 + updated_on: 2006-07-19 21:07:27 +02:00 + priority_id: 4 + subject: Error 281 when updating a recipe + id: 3 + fixed_version_id: + category_id: + description: Error 281 is encountered when saving a recipe + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 diff --git a/test/fixtures/members.yml b/test/fixtures/members.yml new file mode 100644 index 000000000..0626bdb18 --- /dev/null +++ b/test/fixtures/members.yml @@ -0,0 +1,13 @@ +--- +members_001: + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 1 + role_id: 1 + id: 1 + user_id: 2 +members_002: + created_on: 2006-07-19 19:35:36 +02:00 + project_id: 1 + role_id: 2 + id: 2 + user_id: 3 diff --git a/test/fixtures/news.yml b/test/fixtures/news.yml new file mode 100644 index 000000000..1bef9184e --- /dev/null +++ b/test/fixtures/news.yml @@ -0,0 +1,20 @@ +--- +news_001: + created_on: 2006-07-19 22:40:26 +02:00 + project_id: 1 + title: eCookbook first release ! + id: 1 + description: |- + eCookbook 1.0 has been released. + + Visit http://ecookbook.somenet.foo/ + summary: First version was released... + author_id: 2 +news_002: + created_on: 2006-07-19 22:42:58 +02:00 + project_id: 1 + title: 100,000 downloads for eCookbook + id: 2 + description: eCookbook 1.0 have downloaded 100,000 times + summary: eCookbook 1.0 have downloaded 100,000 times + author_id: 2 diff --git a/test/fixtures/permissions.yml b/test/fixtures/permissions.yml new file mode 100644 index 000000000..81350e1af --- /dev/null +++ b/test/fixtures/permissions.yml @@ -0,0 +1,379 @@ +--- +permissions_041: + action: add_file + id: 41 + description: button_add + controller: projects + mail_enabled: false + mail_option: false + sort: 1320 + is_public: false +permissions_030: + action: destroy + id: 30 + description: button_delete + controller: news + mail_enabled: false + mail_option: false + sort: 1122 + is_public: false +permissions_019: + action: download + id: 19 + description: button_download + controller: issues + mail_enabled: false + mail_option: false + sort: 1010 + is_public: true +permissions_008: + action: edit + id: 8 + description: button_edit + controller: members + mail_enabled: false + mail_option: false + sort: 221 + is_public: false +permissions_042: + action: destroy_file + id: 42 + description: button_delete + controller: versions + mail_enabled: false + mail_option: false + sort: 1322 + is_public: false +permissions_031: + action: list_documents + id: 31 + description: button_list + controller: projects + mail_enabled: false + mail_option: false + sort: 1200 + is_public: true +permissions_020: + action: add_issue + id: 20 + description: button_add + controller: projects + mail_enabled: true + mail_option: true + sort: 1050 + is_public: false +permissions_009: + action: destroy + id: 9 + description: button_delete + controller: members + mail_enabled: false + mail_option: false + sort: 222 + is_public: false +permissions_032: + action: show + id: 32 + description: button_view + controller: documents + mail_enabled: false + mail_option: false + sort: 1201 + is_public: true +permissions_021: + action: edit + id: 21 + description: button_edit + controller: issues + mail_enabled: false + mail_option: false + sort: 1055 + is_public: false +permissions_010: + action: add_version + id: 10 + description: button_add + controller: projects + mail_enabled: false + mail_option: false + sort: 320 + is_public: false +permissions_033: + action: download + id: 33 + description: button_download + controller: documents + mail_enabled: false + mail_option: false + sort: 1202 + is_public: true +permissions_022: + action: change_status + id: 22 + description: label_change_status + controller: issues + mail_enabled: true + mail_option: true + sort: 1060 + is_public: false +permissions_011: + action: edit + id: 11 + description: button_edit + controller: versions + mail_enabled: false + mail_option: false + sort: 321 + is_public: false +permissions_034: + action: add_document + id: 34 + description: button_add + controller: projects + mail_enabled: false + mail_option: false + sort: 1220 + is_public: false +permissions_023: + action: destroy + id: 23 + description: button_delete + controller: issues + mail_enabled: false + mail_option: false + sort: 1065 + is_public: false +permissions_012: + action: destroy + id: 12 + description: button_delete + controller: versions + mail_enabled: false + mail_option: false + sort: 322 + is_public: false +permissions_001: + action: show + id: 1 + description: label_overview + controller: projects + mail_enabled: false + mail_option: false + sort: 100 + is_public: true +permissions_035: + action: edit + id: 35 + description: button_edit + controller: documents + mail_enabled: false + mail_option: false + sort: 1221 + is_public: false +permissions_024: + action: add_attachment + id: 24 + description: label_attachment_new + controller: issues + mail_enabled: false + mail_option: false + sort: 1070 + is_public: false +permissions_013: + action: add_issue_category + id: 13 + description: button_add + controller: projects + mail_enabled: false + mail_option: false + sort: 420 + is_public: false +permissions_002: + action: changelog + id: 2 + description: label_change_log + controller: projects + mail_enabled: false + mail_option: false + sort: 105 + is_public: true +permissions_036: + action: destroy + id: 36 + description: button_delete + controller: documents + mail_enabled: false + mail_option: false + sort: 1222 + is_public: false +permissions_025: + action: destroy_attachment + id: 25 + description: label_attachment_delete + controller: issues + mail_enabled: false + mail_option: false + sort: 1075 + is_public: false +permissions_014: + action: edit + id: 14 + description: button_edit + controller: issue_categories + mail_enabled: false + mail_option: false + sort: 421 + is_public: false +permissions_003: + action: issue_report + id: 3 + description: label_report_plural + controller: reports + mail_enabled: false + mail_option: false + sort: 110 + is_public: true +permissions_037: + action: add_attachment + id: 37 + description: label_attachment_new + controller: documents + mail_enabled: false + mail_option: false + sort: 1223 + is_public: false +permissions_026: + action: list_news + id: 26 + description: button_list + controller: projects + mail_enabled: false + mail_option: false + sort: 1100 + is_public: true +permissions_015: + action: destroy + id: 15 + description: button_delete + controller: issue_categories + mail_enabled: false + mail_option: false + sort: 422 + is_public: false +permissions_004: + action: settings + id: 4 + description: label_settings + controller: projects + mail_enabled: false + mail_option: false + sort: 150 + is_public: false +permissions_038: + action: destroy_attachment + id: 38 + description: label_attachment_delete + controller: documents + mail_enabled: false + mail_option: false + sort: 1224 + is_public: false +permissions_027: + action: show + id: 27 + description: button_view + controller: news + mail_enabled: false + mail_option: false + sort: 1101 + is_public: true +permissions_016: + action: list_issues + id: 16 + description: button_list + controller: projects + mail_enabled: false + mail_option: false + sort: 1000 + is_public: true +permissions_005: + action: edit + id: 5 + description: button_edit + controller: projects + mail_enabled: false + mail_option: false + sort: 151 + is_public: false +permissions_039: + action: list_files + id: 39 + description: button_list + controller: projects + mail_enabled: false + mail_option: false + sort: 1300 + is_public: true +permissions_028: + action: add_news + id: 28 + description: button_add + controller: projects + mail_enabled: false + mail_option: false + sort: 1120 + is_public: false +permissions_017: + action: export_issues_csv + id: 17 + description: label_export_csv + controller: projects + mail_enabled: false + mail_option: false + sort: 1001 + is_public: true +permissions_006: + action: list_members + id: 6 + description: button_list + controller: projects + mail_enabled: false + mail_option: false + sort: 200 + is_public: true +permissions_040: + action: download + id: 40 + description: button_download + controller: versions + mail_enabled: false + mail_option: false + sort: 1301 + is_public: true +permissions_029: + action: edit + id: 29 + description: button_edit + controller: news + mail_enabled: false + mail_option: false + sort: 1121 + is_public: false +permissions_018: + action: show + id: 18 + description: button_view + controller: issues + mail_enabled: false + mail_option: false + sort: 1005 + is_public: true +permissions_007: + action: add_member + id: 7 + description: button_add + controller: projects + mail_enabled: false + mail_option: false + sort: 220 + is_public: false diff --git a/test/fixtures/permissions_roles.yml b/test/fixtures/permissions_roles.yml new file mode 100644 index 000000000..d4a054ecc --- /dev/null +++ b/test/fixtures/permissions_roles.yml @@ -0,0 +1,379 @@ +--- +permissions_roles_075: + role_id: 3 + permission_id: 34 +permissions_roles_047: + role_id: 1 + permission_id: 15 +permissions_roles_102: + role_id: 2 + permission_id: 4 +permissions_roles_019: + role_id: 3 + permission_id: 30 +permissions_roles_048: + role_id: 2 + permission_id: 24 +permissions_roles_103: + role_id: 2 + permission_id: 27 +permissions_roles_076: + role_id: 2 + permission_id: 41 +permissions_roles_049: + role_id: 1 + permission_id: 3 +permissions_roles_104: + role_id: 2 + permission_id: 36 +permissions_roles_077: + role_id: 2 + permission_id: 7 +permissions_roles_105: + role_id: 2 + permission_id: 32 +permissions_roles_078: + role_id: 3 + permission_id: 38 +permissions_roles_106: + role_id: 2 + permission_id: 14 +permissions_roles_020: + role_id: 2 + permission_id: 9 +permissions_roles_079: + role_id: 2 + permission_id: 18 +permissions_roles_107: + role_id: 3 + permission_id: 40 +permissions_roles_021: + role_id: 1 + permission_id: 13 +permissions_roles_108: + role_id: 1 + permission_id: 29 +permissions_roles_050: + role_id: 2 + permission_id: 29 +permissions_roles_022: + role_id: 3 + permission_id: 4 +permissions_roles_109: + role_id: 3 + permission_id: 22 +permissions_roles_051: + role_id: 3 + permission_id: 37 +permissions_roles_023: + role_id: 1 + permission_id: 23 +permissions_roles_052: + role_id: 2 + permission_id: 33 +permissions_roles_024: + role_id: 1 + permission_id: 1 +permissions_roles_080: + role_id: 2 + permission_id: 13 +permissions_roles_053: + role_id: 2 + permission_id: 1 +permissions_roles_025: + role_id: 2 + permission_id: 10 +permissions_roles_081: + role_id: 3 + permission_id: 20 +permissions_roles_054: + role_id: 2 + permission_id: 12 +permissions_roles_026: + role_id: 1 + permission_id: 36 +permissions_roles_082: + role_id: 1 + permission_id: 39 +permissions_roles_110: + role_id: 3 + permission_id: 6 +permissions_roles_027: + role_id: 3 + permission_id: 31 +permissions_roles_083: + role_id: 1 + permission_id: 33 +permissions_roles_055: + role_id: 1 + permission_id: 38 +permissions_roles_111: + role_id: 3 + permission_id: 1 +permissions_roles_028: + role_id: 1 + permission_id: 24 +permissions_roles_084: + role_id: 3 + permission_id: 16 +permissions_roles_056: + role_id: 2 + permission_id: 5 +permissions_roles_029: + role_id: 1 + permission_id: 9 +permissions_roles_085: + role_id: 3 + permission_id: 27 +permissions_roles_057: + role_id: 1 + permission_id: 16 +permissions_roles_112: + role_id: 1 + permission_id: 20 +permissions_roles_086: + role_id: 3 + permission_id: 12 +permissions_roles_058: + role_id: 1 + permission_id: 26 +permissions_roles_113: + role_id: 2 + permission_id: 37 +permissions_roles_087: + role_id: 1 + permission_id: 5 +permissions_roles_059: + role_id: 3 + permission_id: 18 +permissions_roles_114: + role_id: 2 + permission_id: 20 +permissions_roles_115: + role_id: 2 + permission_id: 15 +permissions_roles_088: + role_id: 2 + permission_id: 3 +permissions_roles_001: + role_id: 2 + permission_id: 21 +permissions_roles_116: + role_id: 3 + permission_id: 23 +permissions_roles_030: + role_id: 1 + permission_id: 30 +permissions_roles_089: + role_id: 1 + permission_id: 28 +permissions_roles_002: + role_id: 3 + permission_id: 29 +permissions_roles_117: + role_id: 3 + permission_id: 28 +permissions_roles_031: + role_id: 2 + permission_id: 38 +permissions_roles_003: + role_id: 3 + permission_id: 41 +permissions_roles_118: + role_id: 1 + permission_id: 34 +permissions_roles_032: + role_id: 3 + permission_id: 9 +permissions_roles_004: + role_id: 2 + permission_id: 8 +permissions_roles_060: + role_id: 2 + permission_id: 2 +permissions_roles_119: + role_id: 1 + permission_id: 21 +permissions_roles_033: + role_id: 2 + permission_id: 28 +permissions_roles_005: + role_id: 3 + permission_id: 3 +permissions_roles_061: + role_id: 2 + permission_id: 40 +permissions_roles_006: + role_id: 3 + permission_id: 14 +permissions_roles_090: + role_id: 2 + permission_id: 26 +permissions_roles_062: + role_id: 1 + permission_id: 19 +permissions_roles_034: + role_id: 2 + permission_id: 11 +permissions_roles_007: + role_id: 1 + permission_id: 35 +permissions_roles_091: + role_id: 3 + permission_id: 35 +permissions_roles_063: + role_id: 2 + permission_id: 30 +permissions_roles_035: + role_id: 2 + permission_id: 23 +permissions_roles_008: + role_id: 2 + permission_id: 17 +permissions_roles_092: + role_id: 2 + permission_id: 31 +permissions_roles_064: + role_id: 3 + permission_id: 33 +permissions_roles_036: + role_id: 3 + permission_id: 5 +permissions_roles_120: + role_id: 3 + permission_id: 13 +permissions_roles_009: + role_id: 1 + permission_id: 12 +permissions_roles_093: + role_id: 2 + permission_id: 42 +permissions_roles_065: + role_id: 3 + permission_id: 26 +permissions_roles_037: + role_id: 1 + permission_id: 42 +permissions_roles_121: + role_id: 3 + permission_id: 2 +permissions_roles_094: + role_id: 3 + permission_id: 39 +permissions_roles_066: + role_id: 2 + permission_id: 6 +permissions_roles_038: + role_id: 1 + permission_id: 25 +permissions_roles_122: + role_id: 1 + permission_id: 7 +permissions_roles_095: + role_id: 2 + permission_id: 19 +permissions_roles_067: + role_id: 1 + permission_id: 17 +permissions_roles_039: + role_id: 3 + permission_id: 36 +permissions_roles_123: + role_id: 3 + permission_id: 24 +permissions_roles_096: + role_id: 1 + permission_id: 18 +permissions_roles_068: + role_id: 1 + permission_id: 32 +permissions_roles_124: + role_id: 1 + permission_id: 11 +permissions_roles_010: + role_id: 1 + permission_id: 8 +permissions_roles_069: + role_id: 3 + permission_id: 19 +permissions_roles_097: + role_id: 2 + permission_id: 35 +permissions_roles_125: + role_id: 2 + permission_id: 16 +permissions_roles_011: + role_id: 3 + permission_id: 42 +permissions_roles_098: + role_id: 1 + permission_id: 6 +permissions_roles_126: + role_id: 3 + permission_id: 7 +permissions_roles_012: + role_id: 3 + permission_id: 8 +permissions_roles_040: + role_id: 1 + permission_id: 2 +permissions_roles_099: + role_id: 3 + permission_id: 17 +permissions_roles_041: + role_id: 2 + permission_id: 39 +permissions_roles_013: + role_id: 1 + permission_id: 40 +permissions_roles_070: + role_id: 3 + permission_id: 11 +permissions_roles_042: + role_id: 1 + permission_id: 37 +permissions_roles_014: + role_id: 1 + permission_id: 22 +permissions_roles_071: + role_id: 1 + permission_id: 4 +permissions_roles_043: + role_id: 3 + permission_id: 32 +permissions_roles_015: + role_id: 2 + permission_id: 22 +permissions_roles_072: + role_id: 1 + permission_id: 27 +permissions_roles_044: + role_id: 1 + permission_id: 14 +permissions_roles_016: + role_id: 3 + permission_id: 15 +permissions_roles_073: + role_id: 2 + permission_id: 34 +permissions_roles_045: + role_id: 3 + permission_id: 10 +permissions_roles_100: + role_id: 1 + permission_id: 10 +permissions_roles_017: + role_id: 3 + permission_id: 25 +permissions_roles_074: + role_id: 2 + permission_id: 25 +permissions_roles_046: + role_id: 1 + permission_id: 31 +permissions_roles_101: + role_id: 3 + permission_id: 21 +permissions_roles_018: + role_id: 1 + permission_id: 41 diff --git a/test/fixtures/projects.yml b/test/fixtures/projects.yml new file mode 100644 index 000000000..9aa2f9abe --- /dev/null +++ b/test/fixtures/projects.yml @@ -0,0 +1,41 @@ +--- +projects_001: + created_on: 2006-07-19 19:13:59 +02:00 + name: eCookbook + updated_on: 2006-07-19 22:53:01 +02:00 + projects_count: 2 + id: 1 + description: Recipes management application + homepage: http://ecookbook.somenet.foo/ + is_public: true + parent_id: +projects_002: + created_on: 2006-07-19 19:14:19 +02:00 + name: OnlineStore + updated_on: 2006-07-19 19:14:19 +02:00 + projects_count: 0 + id: 2 + description: E-commerce web site + homepage: "" + is_public: false + parent_id: +projects_003: + created_on: 2006-07-19 19:15:21 +02:00 + name: eCookbook Subproject 1 + updated_on: 2006-07-19 19:18:12 +02:00 + projects_count: 0 + id: 3 + description: eCookBook Subproject 1 + homepage: "" + is_public: true + parent_id: 1 +projects_004: + created_on: 2006-07-19 19:15:51 +02:00 + name: eCookbook Subproject 2 + updated_on: 2006-07-19 19:17:07 +02:00 + projects_count: 0 + id: 4 + description: eCookbook Subproject 2 + homepage: "" + is_public: true + parent_id: 1 diff --git a/test/fixtures/roles.yml b/test/fixtures/roles.yml new file mode 100644 index 000000000..4fc9881b4 --- /dev/null +++ b/test/fixtures/roles.yml @@ -0,0 +1,10 @@ +--- +roles_001: + name: Manager + id: 1 +roles_002: + name: Developer + id: 2 +roles_003: + name: Reporter + id: 3 diff --git a/test/fixtures/tokens.yml b/test/fixtures/tokens.yml new file mode 100644 index 000000000..977bafe6e --- /dev/null +++ b/test/fixtures/tokens.yml @@ -0,0 +1 @@ +--- diff --git a/test/fixtures/trackers.yml b/test/fixtures/trackers.yml new file mode 100644 index 000000000..d4ea34ac8 --- /dev/null +++ b/test/fixtures/trackers.yml @@ -0,0 +1,13 @@ +--- +trackers_001: + name: Bug + id: 1 + is_in_chlog: true +trackers_002: + name: Feature request + id: 2 + is_in_chlog: true +trackers_003: + name: Support request + id: 3 + is_in_chlog: false diff --git a/test/fixtures/user_preferences.yml b/test/fixtures/user_preferences.yml new file mode 100644 index 000000000..8794d28ae --- /dev/null +++ b/test/fixtures/user_preferences.yml @@ -0,0 +1,5 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html +first: + id: 1 +another: + id: 2 diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 000000000..ffa2fe42e --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,61 @@ +--- +users_004: + created_on: 2006-07-19 19:34:07 +02:00 + status: 1 + last_login_on: + language: en + hashed_password: 4e4aeb7baaf0706bd670263fef42dad15763b608 + updated_on: 2006-07-19 19:34:07 +02:00 + admin: false + mail: rhill@somenet.foo + lastname: Hill + firstname: Robert + id: 4 + auth_source_id: + mail_notification: true + login: rhill +users_001: + created_on: 2006-07-19 19:12:21 +02:00 + status: 1 + last_login_on: 2006-07-19 22:57:52 +02:00 + language: en + hashed_password: d033e22ae348aeb5660fc2140aec35850c4da997 + updated_on: 2006-07-19 22:57:52 +02:00 + admin: true + mail: admin@somenet.foo + lastname: Admin + firstname: redMine + id: 1 + auth_source_id: + mail_notification: true + login: admin +users_002: + created_on: 2006-07-19 19:32:09 +02:00 + status: 1 + last_login_on: 2006-07-19 22:42:15 +02:00 + language: en + hashed_password: a9a653d4151fa2c081ba1ffc2c2726f3b80b7d7d + updated_on: 2006-07-19 22:42:15 +02:00 + admin: false + mail: jsmith@somenet.foo + lastname: Smith + firstname: John + id: 2 + auth_source_id: + mail_notification: true + login: jsmith +users_003: + created_on: 2006-07-19 19:33:19 +02:00 + status: 1 + last_login_on: + language: en + hashed_password: 7feb7657aa7a7bf5aef3414a5084875f27192415 + updated_on: 2006-07-19 19:33:19 +02:00 + admin: false + mail: dlopper@somenet.foo + lastname: Lopper + firstname: Dave + id: 3 + auth_source_id: + mail_notification: true + login: dlopper diff --git a/test/fixtures/versions.yml b/test/fixtures/versions.yml new file mode 100644 index 000000000..89a738abd --- /dev/null +++ b/test/fixtures/versions.yml @@ -0,0 +1,17 @@ +--- +versions_001: + created_on: 2006-07-19 21:00:07 +02:00 + name: "0.1" + project_id: 1 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 1 + description: Beta + effective_date: 2006-07-01 +versions_002: + created_on: 2006-07-19 21:00:33 +02:00 + name: "1.0" + project_id: 1 + updated_on: 2006-07-19 21:00:33 +02:00 + id: 2 + description: Stable release + effective_date: 2006-07-19 diff --git a/test/fixtures/workflows.yml b/test/fixtures/workflows.yml new file mode 100644 index 000000000..47e95e6e3 --- /dev/null +++ b/test/fixtures/workflows.yml @@ -0,0 +1,1621 @@ +--- +workflows_189: + new_status_id: 5 + role_id: 1 + old_status_id: 2 + id: 189 + tracker_id: 3 +workflows_001: + new_status_id: 2 + role_id: 1 + old_status_id: 1 + id: 1 + tracker_id: 1 +workflows_002: + new_status_id: 3 + role_id: 1 + old_status_id: 1 + id: 2 + tracker_id: 1 +workflows_003: + new_status_id: 4 + role_id: 1 + old_status_id: 1 + id: 3 + tracker_id: 1 +workflows_110: + new_status_id: 6 + role_id: 1 + old_status_id: 4 + id: 110 + tracker_id: 2 +workflows_004: + new_status_id: 5 + role_id: 1 + old_status_id: 1 + id: 4 + tracker_id: 1 +workflows_030: + new_status_id: 5 + role_id: 1 + old_status_id: 6 + id: 30 + tracker_id: 1 +workflows_111: + new_status_id: 1 + role_id: 1 + old_status_id: 5 + id: 111 + tracker_id: 2 +workflows_005: + new_status_id: 6 + role_id: 1 + old_status_id: 1 + id: 5 + tracker_id: 1 +workflows_031: + new_status_id: 2 + role_id: 2 + old_status_id: 1 + id: 31 + tracker_id: 1 +workflows_112: + new_status_id: 2 + role_id: 1 + old_status_id: 5 + id: 112 + tracker_id: 2 +workflows_006: + new_status_id: 1 + role_id: 1 + old_status_id: 2 + id: 6 + tracker_id: 1 +workflows_032: + new_status_id: 3 + role_id: 2 + old_status_id: 1 + id: 32 + tracker_id: 1 +workflows_113: + new_status_id: 3 + role_id: 1 + old_status_id: 5 + id: 113 + tracker_id: 2 +workflows_220: + new_status_id: 6 + role_id: 2 + old_status_id: 2 + id: 220 + tracker_id: 3 +workflows_007: + new_status_id: 3 + role_id: 1 + old_status_id: 2 + id: 7 + tracker_id: 1 +workflows_033: + new_status_id: 4 + role_id: 2 + old_status_id: 1 + id: 33 + tracker_id: 1 +workflows_060: + new_status_id: 5 + role_id: 2 + old_status_id: 6 + id: 60 + tracker_id: 1 +workflows_114: + new_status_id: 4 + role_id: 1 + old_status_id: 5 + id: 114 + tracker_id: 2 +workflows_140: + new_status_id: 6 + role_id: 2 + old_status_id: 4 + id: 140 + tracker_id: 2 +workflows_221: + new_status_id: 1 + role_id: 2 + old_status_id: 3 + id: 221 + tracker_id: 3 +workflows_008: + new_status_id: 4 + role_id: 1 + old_status_id: 2 + id: 8 + tracker_id: 1 +workflows_034: + new_status_id: 5 + role_id: 2 + old_status_id: 1 + id: 34 + tracker_id: 1 +workflows_115: + new_status_id: 6 + role_id: 1 + old_status_id: 5 + id: 115 + tracker_id: 2 +workflows_141: + new_status_id: 1 + role_id: 2 + old_status_id: 5 + id: 141 + tracker_id: 2 +workflows_222: + new_status_id: 2 + role_id: 2 + old_status_id: 3 + id: 222 + tracker_id: 3 +workflows_223: + new_status_id: 4 + role_id: 2 + old_status_id: 3 + id: 223 + tracker_id: 3 +workflows_009: + new_status_id: 5 + role_id: 1 + old_status_id: 2 + id: 9 + tracker_id: 1 +workflows_035: + new_status_id: 6 + role_id: 2 + old_status_id: 1 + id: 35 + tracker_id: 1 +workflows_061: + new_status_id: 2 + role_id: 3 + old_status_id: 1 + id: 61 + tracker_id: 1 +workflows_116: + new_status_id: 1 + role_id: 1 + old_status_id: 6 + id: 116 + tracker_id: 2 +workflows_142: + new_status_id: 2 + role_id: 2 + old_status_id: 5 + id: 142 + tracker_id: 2 +workflows_250: + new_status_id: 6 + role_id: 3 + old_status_id: 2 + id: 250 + tracker_id: 3 +workflows_224: + new_status_id: 5 + role_id: 2 + old_status_id: 3 + id: 224 + tracker_id: 3 +workflows_036: + new_status_id: 1 + role_id: 2 + old_status_id: 2 + id: 36 + tracker_id: 1 +workflows_062: + new_status_id: 3 + role_id: 3 + old_status_id: 1 + id: 62 + tracker_id: 1 +workflows_117: + new_status_id: 2 + role_id: 1 + old_status_id: 6 + id: 117 + tracker_id: 2 +workflows_143: + new_status_id: 3 + role_id: 2 + old_status_id: 5 + id: 143 + tracker_id: 2 +workflows_170: + new_status_id: 6 + role_id: 3 + old_status_id: 4 + id: 170 + tracker_id: 2 +workflows_251: + new_status_id: 1 + role_id: 3 + old_status_id: 3 + id: 251 + tracker_id: 3 +workflows_225: + new_status_id: 6 + role_id: 2 + old_status_id: 3 + id: 225 + tracker_id: 3 +workflows_037: + new_status_id: 3 + role_id: 2 + old_status_id: 2 + id: 37 + tracker_id: 1 +workflows_063: + new_status_id: 4 + role_id: 3 + old_status_id: 1 + id: 63 + tracker_id: 1 +workflows_090: + new_status_id: 5 + role_id: 3 + old_status_id: 6 + id: 90 + tracker_id: 1 +workflows_118: + new_status_id: 3 + role_id: 1 + old_status_id: 6 + id: 118 + tracker_id: 2 +workflows_144: + new_status_id: 4 + role_id: 2 + old_status_id: 5 + id: 144 + tracker_id: 2 +workflows_252: + new_status_id: 2 + role_id: 3 + old_status_id: 3 + id: 252 + tracker_id: 3 +workflows_226: + new_status_id: 1 + role_id: 2 + old_status_id: 4 + id: 226 + tracker_id: 3 +workflows_038: + new_status_id: 4 + role_id: 2 + old_status_id: 2 + id: 38 + tracker_id: 1 +workflows_064: + new_status_id: 5 + role_id: 3 + old_status_id: 1 + id: 64 + tracker_id: 1 +workflows_091: + new_status_id: 2 + role_id: 1 + old_status_id: 1 + id: 91 + tracker_id: 2 +workflows_119: + new_status_id: 4 + role_id: 1 + old_status_id: 6 + id: 119 + tracker_id: 2 +workflows_145: + new_status_id: 6 + role_id: 2 + old_status_id: 5 + id: 145 + tracker_id: 2 +workflows_171: + new_status_id: 1 + role_id: 3 + old_status_id: 5 + id: 171 + tracker_id: 2 +workflows_253: + new_status_id: 4 + role_id: 3 + old_status_id: 3 + id: 253 + tracker_id: 3 +workflows_227: + new_status_id: 2 + role_id: 2 + old_status_id: 4 + id: 227 + tracker_id: 3 +workflows_039: + new_status_id: 5 + role_id: 2 + old_status_id: 2 + id: 39 + tracker_id: 1 +workflows_065: + new_status_id: 6 + role_id: 3 + old_status_id: 1 + id: 65 + tracker_id: 1 +workflows_092: + new_status_id: 3 + role_id: 1 + old_status_id: 1 + id: 92 + tracker_id: 2 +workflows_146: + new_status_id: 1 + role_id: 2 + old_status_id: 6 + id: 146 + tracker_id: 2 +workflows_172: + new_status_id: 2 + role_id: 3 + old_status_id: 5 + id: 172 + tracker_id: 2 +workflows_254: + new_status_id: 5 + role_id: 3 + old_status_id: 3 + id: 254 + tracker_id: 3 +workflows_228: + new_status_id: 3 + role_id: 2 + old_status_id: 4 + id: 228 + tracker_id: 3 +workflows_066: + new_status_id: 1 + role_id: 3 + old_status_id: 2 + id: 66 + tracker_id: 1 +workflows_093: + new_status_id: 4 + role_id: 1 + old_status_id: 1 + id: 93 + tracker_id: 2 +workflows_147: + new_status_id: 2 + role_id: 2 + old_status_id: 6 + id: 147 + tracker_id: 2 +workflows_173: + new_status_id: 3 + role_id: 3 + old_status_id: 5 + id: 173 + tracker_id: 2 +workflows_255: + new_status_id: 6 + role_id: 3 + old_status_id: 3 + id: 255 + tracker_id: 3 +workflows_229: + new_status_id: 5 + role_id: 2 + old_status_id: 4 + id: 229 + tracker_id: 3 +workflows_067: + new_status_id: 3 + role_id: 3 + old_status_id: 2 + id: 67 + tracker_id: 1 +workflows_148: + new_status_id: 3 + role_id: 2 + old_status_id: 6 + id: 148 + tracker_id: 2 +workflows_174: + new_status_id: 4 + role_id: 3 + old_status_id: 5 + id: 174 + tracker_id: 2 +workflows_256: + new_status_id: 1 + role_id: 3 + old_status_id: 4 + id: 256 + tracker_id: 3 +workflows_068: + new_status_id: 4 + role_id: 3 + old_status_id: 2 + id: 68 + tracker_id: 1 +workflows_094: + new_status_id: 5 + role_id: 1 + old_status_id: 1 + id: 94 + tracker_id: 2 +workflows_149: + new_status_id: 4 + role_id: 2 + old_status_id: 6 + id: 149 + tracker_id: 2 +workflows_175: + new_status_id: 6 + role_id: 3 + old_status_id: 5 + id: 175 + tracker_id: 2 +workflows_257: + new_status_id: 2 + role_id: 3 + old_status_id: 4 + id: 257 + tracker_id: 3 +workflows_069: + new_status_id: 5 + role_id: 3 + old_status_id: 2 + id: 69 + tracker_id: 1 +workflows_095: + new_status_id: 6 + role_id: 1 + old_status_id: 1 + id: 95 + tracker_id: 2 +workflows_176: + new_status_id: 1 + role_id: 3 + old_status_id: 6 + id: 176 + tracker_id: 2 +workflows_258: + new_status_id: 3 + role_id: 3 + old_status_id: 4 + id: 258 + tracker_id: 3 +workflows_096: + new_status_id: 1 + role_id: 1 + old_status_id: 2 + id: 96 + tracker_id: 2 +workflows_177: + new_status_id: 2 + role_id: 3 + old_status_id: 6 + id: 177 + tracker_id: 2 +workflows_259: + new_status_id: 5 + role_id: 3 + old_status_id: 4 + id: 259 + tracker_id: 3 +workflows_097: + new_status_id: 3 + role_id: 1 + old_status_id: 2 + id: 97 + tracker_id: 2 +workflows_178: + new_status_id: 3 + role_id: 3 + old_status_id: 6 + id: 178 + tracker_id: 2 +workflows_098: + new_status_id: 4 + role_id: 1 + old_status_id: 2 + id: 98 + tracker_id: 2 +workflows_179: + new_status_id: 4 + role_id: 3 + old_status_id: 6 + id: 179 + tracker_id: 2 +workflows_099: + new_status_id: 5 + role_id: 1 + old_status_id: 2 + id: 99 + tracker_id: 2 +workflows_100: + new_status_id: 6 + role_id: 1 + old_status_id: 2 + id: 100 + tracker_id: 2 +workflows_020: + new_status_id: 6 + role_id: 1 + old_status_id: 4 + id: 20 + tracker_id: 1 +workflows_101: + new_status_id: 1 + role_id: 1 + old_status_id: 3 + id: 101 + tracker_id: 2 +workflows_021: + new_status_id: 1 + role_id: 1 + old_status_id: 5 + id: 21 + tracker_id: 1 +workflows_102: + new_status_id: 2 + role_id: 1 + old_status_id: 3 + id: 102 + tracker_id: 2 +workflows_210: + new_status_id: 5 + role_id: 1 + old_status_id: 6 + id: 210 + tracker_id: 3 +workflows_022: + new_status_id: 2 + role_id: 1 + old_status_id: 5 + id: 22 + tracker_id: 1 +workflows_103: + new_status_id: 4 + role_id: 1 + old_status_id: 3 + id: 103 + tracker_id: 2 +workflows_023: + new_status_id: 3 + role_id: 1 + old_status_id: 5 + id: 23 + tracker_id: 1 +workflows_104: + new_status_id: 5 + role_id: 1 + old_status_id: 3 + id: 104 + tracker_id: 2 +workflows_130: + new_status_id: 6 + role_id: 2 + old_status_id: 2 + id: 130 + tracker_id: 2 +workflows_211: + new_status_id: 2 + role_id: 2 + old_status_id: 1 + id: 211 + tracker_id: 3 +workflows_024: + new_status_id: 4 + role_id: 1 + old_status_id: 5 + id: 24 + tracker_id: 1 +workflows_050: + new_status_id: 6 + role_id: 2 + old_status_id: 4 + id: 50 + tracker_id: 1 +workflows_105: + new_status_id: 6 + role_id: 1 + old_status_id: 3 + id: 105 + tracker_id: 2 +workflows_131: + new_status_id: 1 + role_id: 2 + old_status_id: 3 + id: 131 + tracker_id: 2 +workflows_212: + new_status_id: 3 + role_id: 2 + old_status_id: 1 + id: 212 + tracker_id: 3 +workflows_025: + new_status_id: 6 + role_id: 1 + old_status_id: 5 + id: 25 + tracker_id: 1 +workflows_051: + new_status_id: 1 + role_id: 2 + old_status_id: 5 + id: 51 + tracker_id: 1 +workflows_106: + new_status_id: 1 + role_id: 1 + old_status_id: 4 + id: 106 + tracker_id: 2 +workflows_132: + new_status_id: 2 + role_id: 2 + old_status_id: 3 + id: 132 + tracker_id: 2 +workflows_213: + new_status_id: 4 + role_id: 2 + old_status_id: 1 + id: 213 + tracker_id: 3 +workflows_240: + new_status_id: 5 + role_id: 2 + old_status_id: 6 + id: 240 + tracker_id: 3 +workflows_026: + new_status_id: 1 + role_id: 1 + old_status_id: 6 + id: 26 + tracker_id: 1 +workflows_052: + new_status_id: 2 + role_id: 2 + old_status_id: 5 + id: 52 + tracker_id: 1 +workflows_107: + new_status_id: 2 + role_id: 1 + old_status_id: 4 + id: 107 + tracker_id: 2 +workflows_133: + new_status_id: 4 + role_id: 2 + old_status_id: 3 + id: 133 + tracker_id: 2 +workflows_214: + new_status_id: 5 + role_id: 2 + old_status_id: 1 + id: 214 + tracker_id: 3 +workflows_241: + new_status_id: 2 + role_id: 3 + old_status_id: 1 + id: 241 + tracker_id: 3 +workflows_027: + new_status_id: 2 + role_id: 1 + old_status_id: 6 + id: 27 + tracker_id: 1 +workflows_053: + new_status_id: 3 + role_id: 2 + old_status_id: 5 + id: 53 + tracker_id: 1 +workflows_080: + new_status_id: 6 + role_id: 3 + old_status_id: 4 + id: 80 + tracker_id: 1 +workflows_108: + new_status_id: 3 + role_id: 1 + old_status_id: 4 + id: 108 + tracker_id: 2 +workflows_134: + new_status_id: 5 + role_id: 2 + old_status_id: 3 + id: 134 + tracker_id: 2 +workflows_160: + new_status_id: 6 + role_id: 3 + old_status_id: 2 + id: 160 + tracker_id: 2 +workflows_215: + new_status_id: 6 + role_id: 2 + old_status_id: 1 + id: 215 + tracker_id: 3 +workflows_242: + new_status_id: 3 + role_id: 3 + old_status_id: 1 + id: 242 + tracker_id: 3 +workflows_028: + new_status_id: 3 + role_id: 1 + old_status_id: 6 + id: 28 + tracker_id: 1 +workflows_054: + new_status_id: 4 + role_id: 2 + old_status_id: 5 + id: 54 + tracker_id: 1 +workflows_081: + new_status_id: 1 + role_id: 3 + old_status_id: 5 + id: 81 + tracker_id: 1 +workflows_109: + new_status_id: 5 + role_id: 1 + old_status_id: 4 + id: 109 + tracker_id: 2 +workflows_135: + new_status_id: 6 + role_id: 2 + old_status_id: 3 + id: 135 + tracker_id: 2 +workflows_161: + new_status_id: 1 + role_id: 3 + old_status_id: 3 + id: 161 + tracker_id: 2 +workflows_216: + new_status_id: 1 + role_id: 2 + old_status_id: 2 + id: 216 + tracker_id: 3 +workflows_243: + new_status_id: 4 + role_id: 3 + old_status_id: 1 + id: 243 + tracker_id: 3 +workflows_029: + new_status_id: 4 + role_id: 1 + old_status_id: 6 + id: 29 + tracker_id: 1 +workflows_055: + new_status_id: 6 + role_id: 2 + old_status_id: 5 + id: 55 + tracker_id: 1 +workflows_082: + new_status_id: 2 + role_id: 3 + old_status_id: 5 + id: 82 + tracker_id: 1 +workflows_136: + new_status_id: 1 + role_id: 2 + old_status_id: 4 + id: 136 + tracker_id: 2 +workflows_162: + new_status_id: 2 + role_id: 3 + old_status_id: 3 + id: 162 + tracker_id: 2 +workflows_217: + new_status_id: 3 + role_id: 2 + old_status_id: 2 + id: 217 + tracker_id: 3 +workflows_270: + new_status_id: 5 + role_id: 3 + old_status_id: 6 + id: 270 + tracker_id: 3 +workflows_244: + new_status_id: 5 + role_id: 3 + old_status_id: 1 + id: 244 + tracker_id: 3 +workflows_056: + new_status_id: 1 + role_id: 2 + old_status_id: 6 + id: 56 + tracker_id: 1 +workflows_137: + new_status_id: 2 + role_id: 2 + old_status_id: 4 + id: 137 + tracker_id: 2 +workflows_163: + new_status_id: 4 + role_id: 3 + old_status_id: 3 + id: 163 + tracker_id: 2 +workflows_190: + new_status_id: 6 + role_id: 1 + old_status_id: 2 + id: 190 + tracker_id: 3 +workflows_218: + new_status_id: 4 + role_id: 2 + old_status_id: 2 + id: 218 + tracker_id: 3 +workflows_245: + new_status_id: 6 + role_id: 3 + old_status_id: 1 + id: 245 + tracker_id: 3 +workflows_057: + new_status_id: 2 + role_id: 2 + old_status_id: 6 + id: 57 + tracker_id: 1 +workflows_083: + new_status_id: 3 + role_id: 3 + old_status_id: 5 + id: 83 + tracker_id: 1 +workflows_138: + new_status_id: 3 + role_id: 2 + old_status_id: 4 + id: 138 + tracker_id: 2 +workflows_164: + new_status_id: 5 + role_id: 3 + old_status_id: 3 + id: 164 + tracker_id: 2 +workflows_191: + new_status_id: 1 + role_id: 1 + old_status_id: 3 + id: 191 + tracker_id: 3 +workflows_219: + new_status_id: 5 + role_id: 2 + old_status_id: 2 + id: 219 + tracker_id: 3 +workflows_246: + new_status_id: 1 + role_id: 3 + old_status_id: 2 + id: 246 + tracker_id: 3 +workflows_058: + new_status_id: 3 + role_id: 2 + old_status_id: 6 + id: 58 + tracker_id: 1 +workflows_084: + new_status_id: 4 + role_id: 3 + old_status_id: 5 + id: 84 + tracker_id: 1 +workflows_139: + new_status_id: 5 + role_id: 2 + old_status_id: 4 + id: 139 + tracker_id: 2 +workflows_165: + new_status_id: 6 + role_id: 3 + old_status_id: 3 + id: 165 + tracker_id: 2 +workflows_192: + new_status_id: 2 + role_id: 1 + old_status_id: 3 + id: 192 + tracker_id: 3 +workflows_247: + new_status_id: 3 + role_id: 3 + old_status_id: 2 + id: 247 + tracker_id: 3 +workflows_059: + new_status_id: 4 + role_id: 2 + old_status_id: 6 + id: 59 + tracker_id: 1 +workflows_085: + new_status_id: 6 + role_id: 3 + old_status_id: 5 + id: 85 + tracker_id: 1 +workflows_166: + new_status_id: 1 + role_id: 3 + old_status_id: 4 + id: 166 + tracker_id: 2 +workflows_248: + new_status_id: 4 + role_id: 3 + old_status_id: 2 + id: 248 + tracker_id: 3 +workflows_086: + new_status_id: 1 + role_id: 3 + old_status_id: 6 + id: 86 + tracker_id: 1 +workflows_167: + new_status_id: 2 + role_id: 3 + old_status_id: 4 + id: 167 + tracker_id: 2 +workflows_193: + new_status_id: 4 + role_id: 1 + old_status_id: 3 + id: 193 + tracker_id: 3 +workflows_249: + new_status_id: 5 + role_id: 3 + old_status_id: 2 + id: 249 + tracker_id: 3 +workflows_087: + new_status_id: 2 + role_id: 3 + old_status_id: 6 + id: 87 + tracker_id: 1 +workflows_168: + new_status_id: 3 + role_id: 3 + old_status_id: 4 + id: 168 + tracker_id: 2 +workflows_194: + new_status_id: 5 + role_id: 1 + old_status_id: 3 + id: 194 + tracker_id: 3 +workflows_088: + new_status_id: 3 + role_id: 3 + old_status_id: 6 + id: 88 + tracker_id: 1 +workflows_169: + new_status_id: 5 + role_id: 3 + old_status_id: 4 + id: 169 + tracker_id: 2 +workflows_195: + new_status_id: 6 + role_id: 1 + old_status_id: 3 + id: 195 + tracker_id: 3 +workflows_089: + new_status_id: 4 + role_id: 3 + old_status_id: 6 + id: 89 + tracker_id: 1 +workflows_196: + new_status_id: 1 + role_id: 1 + old_status_id: 4 + id: 196 + tracker_id: 3 +workflows_197: + new_status_id: 2 + role_id: 1 + old_status_id: 4 + id: 197 + tracker_id: 3 +workflows_198: + new_status_id: 3 + role_id: 1 + old_status_id: 4 + id: 198 + tracker_id: 3 +workflows_199: + new_status_id: 5 + role_id: 1 + old_status_id: 4 + id: 199 + tracker_id: 3 +workflows_010: + new_status_id: 6 + role_id: 1 + old_status_id: 2 + id: 10 + tracker_id: 1 +workflows_011: + new_status_id: 1 + role_id: 1 + old_status_id: 3 + id: 11 + tracker_id: 1 +workflows_012: + new_status_id: 2 + role_id: 1 + old_status_id: 3 + id: 12 + tracker_id: 1 +workflows_200: + new_status_id: 6 + role_id: 1 + old_status_id: 4 + id: 200 + tracker_id: 3 +workflows_013: + new_status_id: 4 + role_id: 1 + old_status_id: 3 + id: 13 + tracker_id: 1 +workflows_120: + new_status_id: 5 + role_id: 1 + old_status_id: 6 + id: 120 + tracker_id: 2 +workflows_201: + new_status_id: 1 + role_id: 1 + old_status_id: 5 + id: 201 + tracker_id: 3 +workflows_040: + new_status_id: 6 + role_id: 2 + old_status_id: 2 + id: 40 + tracker_id: 1 +workflows_121: + new_status_id: 2 + role_id: 2 + old_status_id: 1 + id: 121 + tracker_id: 2 +workflows_202: + new_status_id: 2 + role_id: 1 + old_status_id: 5 + id: 202 + tracker_id: 3 +workflows_014: + new_status_id: 5 + role_id: 1 + old_status_id: 3 + id: 14 + tracker_id: 1 +workflows_041: + new_status_id: 1 + role_id: 2 + old_status_id: 3 + id: 41 + tracker_id: 1 +workflows_122: + new_status_id: 3 + role_id: 2 + old_status_id: 1 + id: 122 + tracker_id: 2 +workflows_203: + new_status_id: 3 + role_id: 1 + old_status_id: 5 + id: 203 + tracker_id: 3 +workflows_015: + new_status_id: 6 + role_id: 1 + old_status_id: 3 + id: 15 + tracker_id: 1 +workflows_230: + new_status_id: 6 + role_id: 2 + old_status_id: 4 + id: 230 + tracker_id: 3 +workflows_123: + new_status_id: 4 + role_id: 2 + old_status_id: 1 + id: 123 + tracker_id: 2 +workflows_204: + new_status_id: 4 + role_id: 1 + old_status_id: 5 + id: 204 + tracker_id: 3 +workflows_016: + new_status_id: 1 + role_id: 1 + old_status_id: 4 + id: 16 + tracker_id: 1 +workflows_042: + new_status_id: 2 + role_id: 2 + old_status_id: 3 + id: 42 + tracker_id: 1 +workflows_231: + new_status_id: 1 + role_id: 2 + old_status_id: 5 + id: 231 + tracker_id: 3 +workflows_070: + new_status_id: 6 + role_id: 3 + old_status_id: 2 + id: 70 + tracker_id: 1 +workflows_124: + new_status_id: 5 + role_id: 2 + old_status_id: 1 + id: 124 + tracker_id: 2 +workflows_150: + new_status_id: 5 + role_id: 2 + old_status_id: 6 + id: 150 + tracker_id: 2 +workflows_205: + new_status_id: 6 + role_id: 1 + old_status_id: 5 + id: 205 + tracker_id: 3 +workflows_017: + new_status_id: 2 + role_id: 1 + old_status_id: 4 + id: 17 + tracker_id: 1 +workflows_043: + new_status_id: 4 + role_id: 2 + old_status_id: 3 + id: 43 + tracker_id: 1 +workflows_232: + new_status_id: 2 + role_id: 2 + old_status_id: 5 + id: 232 + tracker_id: 3 +workflows_125: + new_status_id: 6 + role_id: 2 + old_status_id: 1 + id: 125 + tracker_id: 2 +workflows_151: + new_status_id: 2 + role_id: 3 + old_status_id: 1 + id: 151 + tracker_id: 2 +workflows_206: + new_status_id: 1 + role_id: 1 + old_status_id: 6 + id: 206 + tracker_id: 3 +workflows_018: + new_status_id: 3 + role_id: 1 + old_status_id: 4 + id: 18 + tracker_id: 1 +workflows_044: + new_status_id: 5 + role_id: 2 + old_status_id: 3 + id: 44 + tracker_id: 1 +workflows_071: + new_status_id: 1 + role_id: 3 + old_status_id: 3 + id: 71 + tracker_id: 1 +workflows_233: + new_status_id: 3 + role_id: 2 + old_status_id: 5 + id: 233 + tracker_id: 3 +workflows_126: + new_status_id: 1 + role_id: 2 + old_status_id: 2 + id: 126 + tracker_id: 2 +workflows_152: + new_status_id: 3 + role_id: 3 + old_status_id: 1 + id: 152 + tracker_id: 2 +workflows_207: + new_status_id: 2 + role_id: 1 + old_status_id: 6 + id: 207 + tracker_id: 3 +workflows_019: + new_status_id: 5 + role_id: 1 + old_status_id: 4 + id: 19 + tracker_id: 1 +workflows_045: + new_status_id: 6 + role_id: 2 + old_status_id: 3 + id: 45 + tracker_id: 1 +workflows_260: + new_status_id: 6 + role_id: 3 + old_status_id: 4 + id: 260 + tracker_id: 3 +workflows_234: + new_status_id: 4 + role_id: 2 + old_status_id: 5 + id: 234 + tracker_id: 3 +workflows_127: + new_status_id: 3 + role_id: 2 + old_status_id: 2 + id: 127 + tracker_id: 2 +workflows_153: + new_status_id: 4 + role_id: 3 + old_status_id: 1 + id: 153 + tracker_id: 2 +workflows_180: + new_status_id: 5 + role_id: 3 + old_status_id: 6 + id: 180 + tracker_id: 2 +workflows_208: + new_status_id: 3 + role_id: 1 + old_status_id: 6 + id: 208 + tracker_id: 3 +workflows_046: + new_status_id: 1 + role_id: 2 + old_status_id: 4 + id: 46 + tracker_id: 1 +workflows_072: + new_status_id: 2 + role_id: 3 + old_status_id: 3 + id: 72 + tracker_id: 1 +workflows_261: + new_status_id: 1 + role_id: 3 + old_status_id: 5 + id: 261 + tracker_id: 3 +workflows_235: + new_status_id: 6 + role_id: 2 + old_status_id: 5 + id: 235 + tracker_id: 3 +workflows_154: + new_status_id: 5 + role_id: 3 + old_status_id: 1 + id: 154 + tracker_id: 2 +workflows_181: + new_status_id: 2 + role_id: 1 + old_status_id: 1 + id: 181 + tracker_id: 3 +workflows_209: + new_status_id: 4 + role_id: 1 + old_status_id: 6 + id: 209 + tracker_id: 3 +workflows_047: + new_status_id: 2 + role_id: 2 + old_status_id: 4 + id: 47 + tracker_id: 1 +workflows_073: + new_status_id: 4 + role_id: 3 + old_status_id: 3 + id: 73 + tracker_id: 1 +workflows_128: + new_status_id: 4 + role_id: 2 + old_status_id: 2 + id: 128 + tracker_id: 2 +workflows_262: + new_status_id: 2 + role_id: 3 + old_status_id: 5 + id: 262 + tracker_id: 3 +workflows_236: + new_status_id: 1 + role_id: 2 + old_status_id: 6 + id: 236 + tracker_id: 3 +workflows_155: + new_status_id: 6 + role_id: 3 + old_status_id: 1 + id: 155 + tracker_id: 2 +workflows_048: + new_status_id: 3 + role_id: 2 + old_status_id: 4 + id: 48 + tracker_id: 1 +workflows_074: + new_status_id: 5 + role_id: 3 + old_status_id: 3 + id: 74 + tracker_id: 1 +workflows_129: + new_status_id: 5 + role_id: 2 + old_status_id: 2 + id: 129 + tracker_id: 2 +workflows_263: + new_status_id: 3 + role_id: 3 + old_status_id: 5 + id: 263 + tracker_id: 3 +workflows_237: + new_status_id: 2 + role_id: 2 + old_status_id: 6 + id: 237 + tracker_id: 3 +workflows_182: + new_status_id: 3 + role_id: 1 + old_status_id: 1 + id: 182 + tracker_id: 3 +workflows_049: + new_status_id: 5 + role_id: 2 + old_status_id: 4 + id: 49 + tracker_id: 1 +workflows_075: + new_status_id: 6 + role_id: 3 + old_status_id: 3 + id: 75 + tracker_id: 1 +workflows_156: + new_status_id: 1 + role_id: 3 + old_status_id: 2 + id: 156 + tracker_id: 2 +workflows_264: + new_status_id: 4 + role_id: 3 + old_status_id: 5 + id: 264 + tracker_id: 3 +workflows_238: + new_status_id: 3 + role_id: 2 + old_status_id: 6 + id: 238 + tracker_id: 3 +workflows_183: + new_status_id: 4 + role_id: 1 + old_status_id: 1 + id: 183 + tracker_id: 3 +workflows_076: + new_status_id: 1 + role_id: 3 + old_status_id: 4 + id: 76 + tracker_id: 1 +workflows_157: + new_status_id: 3 + role_id: 3 + old_status_id: 2 + id: 157 + tracker_id: 2 +workflows_265: + new_status_id: 6 + role_id: 3 + old_status_id: 5 + id: 265 + tracker_id: 3 +workflows_239: + new_status_id: 4 + role_id: 2 + old_status_id: 6 + id: 239 + tracker_id: 3 +workflows_077: + new_status_id: 2 + role_id: 3 + old_status_id: 4 + id: 77 + tracker_id: 1 +workflows_158: + new_status_id: 4 + role_id: 3 + old_status_id: 2 + id: 158 + tracker_id: 2 +workflows_184: + new_status_id: 5 + role_id: 1 + old_status_id: 1 + id: 184 + tracker_id: 3 +workflows_266: + new_status_id: 1 + role_id: 3 + old_status_id: 6 + id: 266 + tracker_id: 3 +workflows_078: + new_status_id: 3 + role_id: 3 + old_status_id: 4 + id: 78 + tracker_id: 1 +workflows_159: + new_status_id: 5 + role_id: 3 + old_status_id: 2 + id: 159 + tracker_id: 2 +workflows_185: + new_status_id: 6 + role_id: 1 + old_status_id: 1 + id: 185 + tracker_id: 3 +workflows_267: + new_status_id: 2 + role_id: 3 + old_status_id: 6 + id: 267 + tracker_id: 3 +workflows_079: + new_status_id: 5 + role_id: 3 + old_status_id: 4 + id: 79 + tracker_id: 1 +workflows_186: + new_status_id: 1 + role_id: 1 + old_status_id: 2 + id: 186 + tracker_id: 3 +workflows_268: + new_status_id: 3 + role_id: 3 + old_status_id: 6 + id: 268 + tracker_id: 3 +workflows_187: + new_status_id: 3 + role_id: 1 + old_status_id: 2 + id: 187 + tracker_id: 3 +workflows_269: + new_status_id: 4 + role_id: 3 + old_status_id: 6 + id: 269 + tracker_id: 3 +workflows_188: + new_status_id: 4 + role_id: 1 + old_status_id: 2 + id: 188 + tracker_id: 3 diff --git a/test/functional/my_controller_test.rb b/test/functional/my_controller_test.rb new file mode 100644 index 000000000..525c71b45 --- /dev/null +++ b/test/functional/my_controller_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'my_controller' + +# Re-raise errors caught by the controller. +class MyController; def rescue_action(e) raise e end; end + +class MyControllerTest < Test::Unit::TestCase + def setup + @controller = MyController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb new file mode 100644 index 000000000..f20f8ad0f --- /dev/null +++ b/test/functional/projects_controller_test.rb @@ -0,0 +1,114 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' +require 'projects_controller' + +# Re-raise errors caught by the controller. +class ProjectsController; def rescue_action(e) raise e end; end + +class ProjectsControllerTest < Test::Unit::TestCase + fixtures :projects, :permissions + + def setup + @controller = ProjectsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_index + get :index + assert_response :success + assert_template 'list' + end + + def test_list + get :list + assert_response :success + assert_template 'list' + assert_not_nil assigns(:projects) + end + + def test_show + get :show, :id => 1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:project) + end + + def test_list_members + get :list_members, :id => 1 + assert_response :success + assert_template 'list_members' + assert_not_nil assigns(:members) + end + + def test_list_documents + get :list_documents, :id => 1 + assert_response :success + assert_template 'list_documents' + assert_not_nil assigns(:documents) + end + + def test_list_issues + get :list_issues, :id => 1 + assert_response :success + assert_template 'list_issues' + assert_not_nil assigns(:issues) + end + + def test_list_issues_with_filter + get :list_issues, :id => 1, :set_filter => 1 + assert_response :success + assert_template 'list_issues' + assert_not_nil assigns(:issues) + end + + def test_list_issues_reset_filter + post :list_issues, :id => 1 + assert_response :success + assert_template 'list_issues' + assert_not_nil assigns(:issues) + end + + def test_export_issues_csv + get :export_issues_csv, :id => 1 + assert_response :success + assert_not_nil assigns(:issues) + end + + def test_list_news + get :list_news, :id => 1 + assert_response :success + assert_template 'list_news' + assert_not_nil assigns(:news) + end + + def test_list_files + get :list_files, :id => 1 + assert_response :success + assert_template 'list_files' + assert_not_nil assigns(:versions) + end + + def test_changelog + get :changelog, :id => 1 + assert_response :success + assert_template 'changelog' + assert_not_nil assigns(:fixed_issues) + end +end diff --git a/test/integration/account_test.rb b/test/integration/account_test.rb new file mode 100644 index 000000000..0d6f75d70 --- /dev/null +++ b/test/integration/account_test.rb @@ -0,0 +1,100 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "#{File.dirname(__FILE__)}/../test_helper" + +class AccountTest < ActionController::IntegrationTest + fixtures :users + + # Replace this with your real tests. + def test_login + get "my/page" + assert_redirected_to "account/login" + log_user('jsmith', 'jsmith') + + get "my/account" + assert_response :success + assert_template "my/account" + end + + def test_change_password + log_user('jsmith', 'jsmith') + get "my/account" + assert_response :success + assert_template "my/account" + + post "my/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello2" + assert_response :success + assert_template "my/account" + assert_tag :tag => "div", :attributes => { :class => "errorExplanation" } + + post "my/change_password", :password => 'jsmithZZ', :new_password => "hello", :new_password_confirmation => "hello" + assert_redirected_to "my/account" + assert_equal 'Wrong password', flash[:notice] + + post "my/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello" + assert_redirected_to "my/account" + log_user('jsmith', 'hello') + end + + def test_my_account + log_user('jsmith', 'jsmith') + get "my/account" + assert_response :success + assert_template "my/account" + + post "my/account", :user => {:firstname => "Joe", :login => "root", :admin => 1} + assert_response :success + assert_template "my/account" + user = User.find(2) + assert_equal "Joe", user.firstname + assert_equal "jsmith", user.login + assert_equal false, user.admin? + end + + def test_my_page + log_user('jsmith', 'jsmith') + get "my/page" + assert_response :success + assert_template "my/page" + end + + def test_lost_password + get "account/lost_password" + assert_response :success + assert_template "account/lost_password" + + post "account/lost_password", :mail => 'jsmith@somenet.foo' + assert_redirected_to "account/login" + + token = Token.find(:first) + assert_equal 'recovery', token.action + assert_equal 'jsmith@somenet.foo', token.user.mail + assert !token.expired? + + get "account/lost_password", :token => token.value + assert_response :success + assert_template "account/password_recovery" + + post "account/lost_password", :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'newpass' + assert_redirected_to "account/login" + assert_equal 'Password was successfully updated.', flash[:notice] + + log_user('jsmith', 'newpass') + assert_equal 0, Token.count + end +end diff --git a/test/integration/admin_test.rb b/test/integration/admin_test.rb new file mode 100644 index 000000000..0241ae8da --- /dev/null +++ b/test/integration/admin_test.rb @@ -0,0 +1,61 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "#{File.dirname(__FILE__)}/../test_helper" + +class AdminTest < ActionController::IntegrationTest + fixtures :users + + def test_add_user + log_user("admin", "admin") + get "/users/add" + assert_response :success + assert_template "users/add" + post "/users/add", :user => { :login => "psmith", :firstname => "Paul", :lastname => "Smith", :mail => "psmith@somenet.foo", :language => "en" }, :password => "psmith09", :password_confirmation => "psmith09" + assert_redirected_to "users/list" + + user = User.find_by_login("psmith") + assert_kind_of User, user + logged_user = User.try_to_login("psmith", "psmith09") + assert_kind_of User, logged_user + assert_equal "Paul", logged_user.firstname + + post "users/edit", :id => user.id, :user => { :status => User::STATUS_LOCKED } + assert_redirected_to "users/list" + locked_user = User.try_to_login("psmith", "psmith09") + assert_equal nil, locked_user + end + + def test_add_project + log_user("admin", "admin") + get "projects/add" + assert_response :success + assert_template "projects/add" + post "projects/add", :project => { :name => "blog", :description => "weblog", :is_public => 1} + assert_redirected_to "admin/projects" + assert_equal 'Successful creation.', flash[:notice] + + project = Project.find_by_name("blog") + assert_kind_of Project, project + assert_equal "weblog", project.description + assert_equal true, project.is_public? + + get "admin/projects" + assert_response :success + assert_template "admin/projects" + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 000000000..2e4f7dcd0 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,55 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +ENV["RAILS_ENV"] ||= "test" +require File.expand_path(File.dirname(__FILE__) + "/../config/environment") +require 'test_help' + +class Test::Unit::TestCase + # Transactional fixtures accelerate your tests by wrapping each test method + # in a transaction that's rolled back on completion. This ensures that the + # test database remains unchanged so your fixtures don't have to be reloaded + # between every test method. Fewer database queries means faster tests. + # + # Read Mike Clark's excellent walkthrough at + # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting + # + # Every Active Record database supports transactions except MyISAM tables + # in MySQL. Turn off transactional fixtures in this case; however, if you + # don't care one way or the other, switching from MyISAM to InnoDB tables + # is recommended. + self.use_transactional_fixtures = true + + # Instantiated fixtures are slow, but give you @david where otherwise you + # would need people(:david). If you don't want to migrate your existing + # test cases which use the @david style and don't mind the speed hit (each + # instantiated fixtures translates to a database query per test method), + # then set this back to true. + self.use_instantiated_fixtures = false + + # Add more helper methods to be used by all tests here... + + def log_user(login, password) + get "/account/login" + assert_equal nil, session[:user_id] + assert_response :success + assert_template "account/login" + post "/account/login", :login => login, :password => password + assert_redirected_to "my/page" + assert_equal login, User.find(session[:user_id]).login + end +end diff --git a/test/unit/member_test.rb b/test/unit/member_test.rb new file mode 100644 index 000000000..079782306 --- /dev/null +++ b/test/unit/member_test.rb @@ -0,0 +1,51 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' + +class MemberTest < Test::Unit::TestCase + fixtures :users, :projects, :roles, :members + + def setup + @jsmith = Member.find(1) + end + + def test_create + member = Member.new(:project_id => 1, :user_id => 4, :role_id => 1) + assert member.save + end + + def test_update + assert_equal "eCookbook", @jsmith.project.name + assert_equal "Manager", @jsmith.role.name + assert_equal "jsmith", @jsmith.user.login + + @jsmith.role = Role.find(2) + assert @jsmith.save + end + + def test_validate + member = Member.new(:project_id => 1, :user_id => 2, :role_id =>2) + # same use can't have more than one role for a project + assert !member.save + end + + def test_destroy + @jsmith.destroy + assert_raise(ActiveRecord::RecordNotFound) { Member.find(@jsmith.id) } + end +end diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb new file mode 100644 index 000000000..9c8f0c97e --- /dev/null +++ b/test/unit/project_test.rb @@ -0,0 +1,79 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' + +class ProjectTest < Test::Unit::TestCase + fixtures :projects + + def setup + @ecookbook = Project.find(1) + @ecookbook_sub1 = Project.find(3) + end + + def test_truth + assert_kind_of Project, @ecookbook + assert_equal "eCookbook", @ecookbook.name + end + + def test_update + assert_equal "eCookbook", @ecookbook.name + @ecookbook.name = "eCook" + assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ") + @ecookbook.reload + assert_equal "eCook", @ecookbook.name + end + + def test_validate + @ecookbook.name = "" + assert !@ecookbook.save + assert_equal 1, @ecookbook.errors.count + assert_equal l(:activerecord_error_blank), @ecookbook.errors.on(:name) + end + + def test_public_projects + public_projects = Project.find(:all, :conditions => ["is_public=?", true]) + assert_equal 3, public_projects.length + assert_equal true, public_projects[0].is_public? + end + + def test_destroy + @ecookbook.destroy + assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) } + end + + def test_subproject_ok + sub = Project.find(2) + sub.parent = @ecookbook + assert sub.save + assert_equal @ecookbook.id, sub.parent.id + @ecookbook.reload + assert_equal 3, @ecookbook.projects_count + end + + def test_subproject_invalid + sub = Project.find(2) + sub.parent = @ecookbook_sub1 + assert !sub.save + end + + def test_subproject_invalid_2 + sub = @ecookbook + sub.parent = Project.find(2) + assert !sub.save + end +end diff --git a/test/unit/token_test.rb b/test/unit/token_test.rb new file mode 100644 index 000000000..1c3820e99 --- /dev/null +++ b/test/unit/token_test.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class TokenTest < Test::Unit::TestCase + fixtures :tokens + + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/test/unit/user_preference_test.rb b/test/unit/user_preference_test.rb new file mode 100644 index 000000000..4675a2652 --- /dev/null +++ b/test/unit/user_preference_test.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class UserPreferenceTest < Test::Unit::TestCase + fixtures :user_preferences + + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb new file mode 100644 index 000000000..211e6554c --- /dev/null +++ b/test/unit/user_test.rb @@ -0,0 +1,88 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' + +class UserTest < Test::Unit::TestCase + fixtures :users + + def setup + @admin = User.find(1) + @jsmith = User.find(2) + end + + def test_truth + assert_kind_of User, @jsmith + end + + def test_create + user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo") + + user.login = "jsmith" + user.password, user.password_confirmation = "password", "password" + # login uniqueness + assert !user.save + assert_equal 1, user.errors.count + + user.login = "newuser" + user.password, user.password_confirmation = "passwd", "password" + # password confirmation + assert !user.save + assert_equal 1, user.errors.count + + user.password, user.password_confirmation = "password", "password" + assert user.save + end + + def test_update + assert_equal "admin", @admin.login + @admin.login = "john" + assert @admin.save, @admin.errors.full_messages.join("; ") + @admin.reload + assert_equal "john", @admin.login + end + + def test_validate + @admin.login = "" + assert !@admin.save + assert_equal 2, @admin.errors.count + end + + def test_password + user = User.try_to_login("admin", "admin") + assert_kind_of User, user + assert_equal "admin", user.login + user.password = "hello" + assert user.save + + user = User.try_to_login("admin", "hello") + assert_kind_of User, user + assert_equal "admin", user.login + assert_equal User.hash_password("hello"), user.hashed_password + end + + def test_lock + user = User.try_to_login("jsmith", "jsmith") + assert_equal @jsmith, user + + @jsmith.status = User::STATUS_LOCKED + assert @jsmith.save + + user = User.try_to_login("jsmith", "jsmith") + assert_equal nil, user + end +end diff --git a/vendor/plugins/gloc-1.1.0/CHANGELOG b/vendor/plugins/gloc-1.1.0/CHANGELOG new file mode 100644 index 000000000..6392d7cbe --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/CHANGELOG @@ -0,0 +1,19 @@ +== Version 1.1 (28 May 2006) + +* The charset for each and/or all languages can now be easily configured. +* Added a ActionController filter that auto-detects the client language. +* The rake task "sort" now merges lines that match 100%, and warns if duplicate keys are found. +* Rule support. Create flexible rules to handle issues such as pluralization. +* Massive speed and stability improvements to development mode. +* Added Russian strings. (Thanks to Evgeny Lineytsev) +* Complete RDoc documentation. +* Improved helpers. +* GLoc now configurable via get_config and set_config +* Added an option to tell GLoc to output various verbose information. +* More useful functions such as set_language_if_valid, similar_language +* GLoc's entire internal state can now be backed up and restored. + + +== Version 1.0 (17 April 2006) + +* Initial public release. diff --git a/vendor/plugins/gloc-1.1.0/MIT-LICENSE b/vendor/plugins/gloc-1.1.0/MIT-LICENSE new file mode 100644 index 000000000..081774a65 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/MIT-LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2005-2006 David Barri + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/README b/vendor/plugins/gloc-1.1.0/README new file mode 100644 index 000000000..66f8e5e9f --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/README @@ -0,0 +1,208 @@ += About + +=== Preface +I originally started designing this on weekends and after work in 2005. We started to become very interested in Rails at work and I wanted to get some experience with ruby with before we started using it full-time. I didn't have very many ideas for anything interesting to create so, because we write a lot of multilingual webapps at my company, I decided to write a localization library. That way if my little hobby project developed into something decent, I could at least put it to good use. +And here we are in 2006, my little hobby project has come a long way and become quite a useful piece of software. Not only do I use it in production sites I write at work, but I also prefer it to other existing alternatives. Therefore I have decided to make it publicly available, and I hope that other developers will find it useful too. + +=== About +GLoc is a localization library. It doesn't aim to do everything l10n-related that you can imagine, but what it does, it does very well. It was originally designed as a Rails plugin, but can also be used for plain ruby projects. Here are a list of its main features: +* Lightweight and efficient. +* Uses file-based string bundles. Strings can also be set directly. +* Intelligent, cascading language configuration. +* Create flexible rules to handle issues such as pluralization. +* Includes a ActionController filter that auto-detects the client language. +* Works perfectly with Rails Engines and allows strings to be overridden just as easily as controllers, models, etc. +* Automatically localizes Rails functions such as distance_in_minutes, select_month etc +* Supports different charsets. You can even specify the encoding to use for each language seperately. +* Special Rails mods/helpers. + +=== What does GLoc mean? +If you're wondering about the name "GLoc", I'm sure you're not alone. +This project was originally just called "Localization" which was a bit too common, so when I decided to release it I decided to call it "Golly's Localization Library" instead (Golly is my nickname), and that was long and boring so I then abbreviated that to "GLoc". What a fun story!! + +=== Localization helpers +This also includes a few helpers for common situations such as displaying localized date, time, "yes" or "no", etc. + +=== Rails Localization +At the moment, unless you manually remove the require 'gloc-rails-text' line from init.rb, this plugin overrides certain Rails functions to provide multilingual versions. This automatically localizes functions such as select_date(), distance_of_time_in_words() and more... +The strings can be found in lang/*.yml. +NOTE: This is not complete. Timezones and countries are not currently localized. + + + + += Usage + +=== Quickstart + +Windows users will need to first install iconv. http://wiki.rubyonrails.com/rails/pages/iconv + +* Create a dir "#{RAILS_ROOT}/lang" +* Create a file "#{RAILS_ROOT}/lang/en.yml" and write your strings. The format is "key: string". Save it as UTF-8. If you save it in a different encoding, add a key called file_charset (eg. "file_charset: iso-2022-jp") +* Put the following in config/environment.rb and change the values as you see fit. The following example is for an app that uses English and Japanese, with Japanese being the default. + GLoc.set_config :default_language => :ja + GLoc.clear_strings_except :en, :ja + GLoc.set_kcode + GLoc.load_localized_strings +* Add 'include GLoc' to all classes that will use localization. This is added to most Rails classes automatically. +* Optionally, you can set the language for models and controllers by simply inserting set_language :en in classes and/or methods. +* To use localized strings, replace text such as "Welcome" with l(:welcome_string_key), and "Hello #{name}." with l(:hello_string_key, name). (Of course the strings will need to exist in your string bundle.) + +There is more functionality provided by this plugin, that is not demonstrated above. Please read the API summary for details. + +=== API summary + +The following methods are added as both class methods and instance methods to modules/classes that include GLoc. They are also available as class methods of GLoc. + current_language # Returns the current language + l(symbol, *arguments) # Returns a localized string + ll(lang, symbol, *arguments) # Returns a localized string in a specific language + ltry(possible_key) # Returns a localized string if passed a Symbol, else returns the same argument passed + lwr(symbol, *arguments) # Uses the default rule to return a localized string. + lwr_(rule, symbol, *arguments) # Uses a specified rule to return a localized string. + l_has_string?(symbol) # Checks if a localized string exists + set_language(language) # Sets the language for the current class or class instance + set_language_if_valid(lang) # Sets the current language if the language passed is a valid language + +The GLoc module also defines the following class methods: + add_localized_strings(lang, symbol_hash, override=true) # Adds a hash of localized strings + backup_state(clear=false) # Creates a backup of GLoc's internal state and optionally clears everything too + clear_strings(*languages) # Removes localized strings from memory + clear_strings_except(*languages) # Removes localized strings from memory except for those of certain specified languages + get_charset(lang) # Returns the charset used to store localized strings in memory + get_config(key) # Returns a GLoc configuration value (see below) + load_localized_strings(dir=nil, override=true) # Loads localized strings from all YML files in a given directory + restore_state(state) # Restores a backup of GLoc's internal state + set_charset(new_charset, *langs) # Sets the charset used to internally store localized strings + set_config(hash) # Sets GLoc configuration values (see below) + set_kcode(charset=nil) # Sets the $KCODE global variable + similar_language(language) # Tries to find a valid language that is similar to the argument passed + valid_languages # Returns an array of (currently) valid languages (ie. languages for which localized data exists) + valid_language?(language) # Checks whether any localized strings are in memory for a given language + +GLoc uses the following configuration items. They can be accessed via get_config and set_config. + :default_cookie_name + :default_language + :default_param_name + :raise_string_not_found_errors + :verbose + +The GLoc module is automatically included in the following classes: + ActionController::Base + ActionMailer::Base + ActionView::Base + ActionView::Helpers::InstanceTag + ActiveRecord::Base + ActiveRecord::Errors + ApplicationHelper + Test::Unit::TestCase + +The GLoc module also defines the following controller filters: + autodetect_language_filter + +GLoc also makes the following change to Rails: +* Views for ActionMailer are now #{view_name}_#{language}.rb rather than just #{view_name}.rb +* All ActiveRecord validation class methods now accept a localized string key (symbol) as a :message value. +* ActiveRecord::Errors.add now accepts symbols as valid message values. At runtime these symbols are converted to localized strings using the current_language of the base record. +* ActiveRecord::Errors.add now accepts arrays as arguments so that printf-style strings can be generated at runtime. This also applies to the validates_* class methods. + Eg. validates_xxxxxx_of :name, :message => ['Your name must be at least %d characters.', MIN_LEN] + Eg. validates_xxxxxx_of :name, :message => [:user_error_validation_name_too_short, MIN_LEN] +* Instances of ActiveView inherit their current_language from the controller (or mailer) creating them. + +This plugin also adds the following rake tasks: + * gloc:sort - Sorts the keys in the lang ymls (also accepts a DIR argument) + +=== Cascading language configuration + +The language can be set at three levels: + 1. The default # GLoc.get_config :default_language + 2. Class level # class A; set_language :de; end + 3. Instance level # b= B.new; b.set_language :zh + +Instance level has the highest priority and the default has the lowest. + +Because GLoc is included at class level too, it becomes easy to associate languages with contexts. +For example: + class Student + set_language :en + def say_hello + puts "We say #{l :hello} but our teachers say #{Teacher.l :hello}" + end + end + +=== Rules + +There are often situations when depending on the value of one or more variables, the surrounding text +changes. The most common case of this is pluralization. Rather than hardcode these rules, they are +completely definable by the user so that the user can eaasily accomodate for more complicated grammatical +rules such as those found in Russian and Polish (or so I hear). To define a rule, simply include a string +in the string bundle whose key begins with "_gloc_rule_" and then write ruby code as the value. The ruby +code will be converted to a Proc when the string bundle is first read, and should return a prefix that will +be appended to the string key at runtime to point to a new string. Make sense? Probably not... Please look +at the following example and I am sure it will all make sense. + +Simple example (string bundle / en.yml) + _gloc_rule_default: ' |n| n==1 ? "_single" : "_plural" ' + man_count_plural: There are %d men. + man_count_single: There is 1 man. + +Simple example (code) + lwr(:man_count, 1) # => There is 1 man. + lwr(:man_count, 8) # => There are 8 men. + +To use rules other than the default simply call lwr_ instead of lwr, and specify the rule. + +Example #2 (string bundle / en.yml) + _gloc_rule_default: ' |n| n==1 ? "_single" : "_plural" ' + _gloc_rule_custom: ' |n| return "_none" if n==0; return "_heaps" if n>100; n==1 ? "_single" : "_plural" ' + man_count_none: There are no men. + man_count_heaps: There are heaps of men!! + man_count_plural: There are %d men. + man_count_single: There is 1 man. + +Example #2 (code) + lwr_(:custom, :man_count, 0) # => There are no men. + lwr_(:custom, :man_count, 1) # => There is 1 man. + lwr_(:custom, :man_count, 8) # => There are 8 men. + lwr_(:custom, :man_count, 150) # => There are heaps of men!! + + +=== Helpers + +GLoc includes the following helpers: + l_age(age) # Returns a localized version of an age. eg "3 years old" + l_date(date) # Returns a date in a localized format + l_datetime(date) # Returns a date+time in a localized format + l_datetime_short(date) # Returns a date+time in a localized short format. + l_lang_name(l,dl=nil) # Returns the name of a language (you must supply your own strings) + l_strftime(date,fmt) # Formats a date/time in a localized format. + l_time(date) # Returns a time in a localized format + l_YesNo(value) # Returns localized string of "Yes" or "No" depending on the arg + l_yesno(value) # Returns localized string of "yes" or "no" depending on the arg + +=== Rails localization + +Not all of Rails is covered but the following functions are: + distance_of_time_in_words + select_day + select_month + select_year + add_options + + + + += FAQ + +==== How do I use it in engines? +Simply put this in your init_engine.rb + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') +That way your engines strings will be loaded when the engine is started. Just simply make sure that you load your application strings after you start your engines to safely override any engine strings. + +==== Why am I getting an Iconv::IllegalSequence error when calling GLoc.set_charset? +By default GLoc loads all of its default strings at startup. For example, calling set_charset 'iso-2022-jp' will cause this error because Russian strings are loaded by default, and the Russian strings use characters that cannot be expressed in the ISO-2022-JP charset. +Before calling set_charset you should call clear_strings_except to remove strings from any languages that you will not be using. +Alternatively, you can simply specify the language(s) as follows, set_charset 'iso-2022-jp', :ja. + +==== How do I make GLoc ignore StringNotFoundErrors? +Disable it as follows: + GLoc.set_config :raise_string_not_found_errors => false diff --git a/vendor/plugins/gloc-1.1.0/Rakefile b/vendor/plugins/gloc-1.1.0/Rakefile new file mode 100644 index 000000000..a5b8fe762 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/Rakefile @@ -0,0 +1,15 @@ +Dir.glob("#{File.dirname(__FILE__)}/tasks/*.rake").each {|f| load f} + +task :default => 'gloc:sort' + +# RDoc task +require 'rake/rdoctask' +Rake::RDocTask.new() { |rdoc| + rdoc.rdoc_dir = 'doc' + rdoc.title = "GLoc Localization Library Documentation" + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README', 'CHANGELOG') + rdoc.rdoc_files.include('lib/**/*.rb') + rdoc.rdoc_files.exclude('lib/gloc-dev.rb') + rdoc.rdoc_files.exclude('lib/gloc-config.rb') +} diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/ActionController/Filters/ClassMethods.html b/vendor/plugins/gloc-1.1.0/doc/classes/ActionController/Filters/ClassMethods.html new file mode 100644 index 000000000..fba33b5b5 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/ActionController/Filters/ClassMethods.html @@ -0,0 +1,230 @@ + + + + + + Module: ActionController::Filters::ClassMethods + + + + + + + + + + +
    + + + + + + + + + + +
    ModuleActionController::Filters::ClassMethods
    In: + + lib/gloc-rails.rb + +
    +
    +
    + + +
    + + + +
    + + + +
    + +
    +

    Methods

    + + +
    + +
    + + + + +
    + + + + + + + + + +
    +

    Public Instance methods

    + +
    + + + + +
    +

    +This filter attempts to auto-detect the clients desired language. It first +checks the params, then a cookie and then the HTTP_ACCEPT_LANGUAGE request +header. If a language is found to match or be similar to a currently valid +language, then it sets the current_language of the controller. +

    +
    +  class ExampleController < ApplicationController
    +    set_language :en
    +    autodetect_language_filter :except => 'monkey', :on_no_lang => :lang_not_autodetected_callback
    +    autodetect_language_filter :only => 'monkey', :check_cookie => 'monkey_lang', :check_accept_header => false
    +    ...
    +    def lang_not_autodetected_callback
    +      redirect_to somewhere
    +    end
    +  end
    +
    +

    +The args for this filter are exactly the same the arguments of +before_filter with the following exceptions: +

    +
      +
    • :check_params — If false, then params will not be checked +for a language. If a String, then this will value will be used as the name +of the param. + +
    • +
    • :check_cookie — If false, then the cookie will not be +checked for a language. If a String, then this will value will be used as +the name of the cookie. + +
    • +
    • :check_accept_header — If false, then HTTP_ACCEPT_LANGUAGE +will not be checked for a language. + +
    • +
    • :on_set_lang — You can specify the name of a callback +function to be called when the language is successfully detected and set. +The param must be a Symbol or a String which is the name of the function. +The callback function must accept one argument (the language) and must be +instance level. + +
    • +
    • :on_no_lang — You can specify the name of a callback +function to be called when the language couldn’t be detected +automatically. The param must be a Symbol or a String which is the name of +the function. The callback function must be instance level. + +
    • +
    +

    +You override the default names of the param or cookie by calling GLoc.set_config :default_param_name +=> ‘new_param_name‘ and GLoc.set_config :default_cookie_name +=> ‘new_cookie_name‘. +

    +

    [Source]

    +
    +
    +    # File lib/gloc-rails.rb, line 43
    +43:       def autodetect_language_filter(*args)
    +44:         options= args.last.is_a?(Hash) ? args.last : {}
    +45:         x= 'Proc.new { |c| l= nil;'
    +46:         # :check_params
    +47:         unless (v= options.delete(:check_params)) == false
    +48:           name= v ? ":#{v}" : 'GLoc.get_config(:default_param_name)'
    +49:           x << "l ||= GLoc.similar_language(c.params[#{name}]);"
    +50:         end
    +51:         # :check_cookie
    +52:         unless (v= options.delete(:check_cookie)) == false
    +53:           name= v ? ":#{v}" : 'GLoc.get_config(:default_cookie_name)'
    +54:           x << "l ||= GLoc.similar_language(c.send(:cookies)[#{name}]);"
    +55:         end
    +56:         # :check_accept_header
    +57:         unless options.delete(:check_accept_header) == false
    +58:           x << %<
    +59:               unless l
    +60:                 a= c.request.env['HTTP_ACCEPT_LANGUAGE'].split(/,|;/) rescue nil
    +61:                 a.each {|x| l ||= GLoc.similar_language(x)} if a
    +62:               end; >
    +63:         end
    +64:         # Set language
    +65:         x << 'ret= true;'
    +66:         x << 'if l; c.set_language(l); c.headers[\'Content-Language\']= l.to_s; '
    +67:         if options.has_key?(:on_set_lang)
    +68:           x << "ret= c.#{options.delete(:on_set_lang)}(l);"
    +69:         end
    +70:         if options.has_key?(:on_no_lang)
    +71:           x << "else; ret= c.#{options.delete(:on_no_lang)};"
    +72:         end
    +73:         x << 'end; ret }'
    +74:         
    +75:         # Create filter
    +76:         block= eval x
    +77:         before_filter(*args, &block)
    +78:       end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/ActionMailer/Base.html b/vendor/plugins/gloc-1.1.0/doc/classes/ActionMailer/Base.html new file mode 100644 index 000000000..056b23d85 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/ActionMailer/Base.html @@ -0,0 +1,140 @@ + + + + + + Class: ActionMailer::Base + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    ClassActionMailer::Base
    In: + + lib/gloc-rails.rb + +
    +
    Parent: + Object +
    +
    + + +
    + + + +
    + +
    +

    +In addition to including GLoc, +render_message is also overridden so that mail templates contain +the current language at the end of the file. Eg. deliver_hello +will render hello_en.rhtml. +

    + +
    + + +
    + + +
    + + + +
    +

    Included Modules

    + +
    + GLoc +
    +
    + +
    + + + +
    +

    External Aliases

    + +
    + + + + + + +
    render_message->render_message_without_gloc
    +
    +
    + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Base.html b/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Base.html new file mode 100644 index 000000000..00767055d --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Base.html @@ -0,0 +1,174 @@ + + + + + + Class: ActionView::Base + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    ClassActionView::Base
    In: + + lib/gloc-rails.rb + +
    +
    Parent: + Object +
    +
    + + +
    + + + +
    + +
    +

    +initialize is overridden so that new instances of this class +inherit the current language of the controller. +

    + +
    + + +
    + +
    +

    Methods

    + +
    + new   +
    +
    + +
    + + + +
    +

    Included Modules

    + +
    + GLoc +
    +
    + +
    + + + +
    +

    External Aliases

    + +
    + + + + + + +
    initialize->initialize_without_gloc
    +
    +
    + + + + + + +
    +

    Public Class methods

    + +
    + + + + +
    +

    [Source]

    +
    +
    +     # File lib/gloc-rails.rb, line 109
    +109:     def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)
    +110:       initialize_without_gloc(base_path, assigns_for_first_render, controller)
    +111:       set_language controller.current_language unless controller.nil?
    +112:     end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/DateHelper.html b/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/DateHelper.html new file mode 100644 index 000000000..84ca8fae3 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/DateHelper.html @@ -0,0 +1,348 @@ + + + + + + Module: ActionView::Helpers::DateHelper + + + + + + + + + + +
    + + + + + + + + + + +
    ModuleActionView::Helpers::DateHelper
    In: + + lib/gloc-rails-text.rb + +
    +
    +
    + + +
    + + + +
    + + + +
    + +
    +

    Methods

    + + +
    + +
    + + + + +
    + + +
    +

    Constants

    + +
    + + + + + + + + + + + + + + + + +
    LOCALIZED_HELPERS=true
    LOCALIZED_MONTHNAMES={}
    LOCALIZED_ABBR_MONTHNAMES={}
    +
    +
    + + + + + + + +
    +

    Public Instance methods

    + +
    + + + + +
    +

    +This method uses current_language to return a localized string. +

    +

    [Source]

    +
    +
    +    # File lib/gloc-rails-text.rb, line 16
    +16:       def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
    +17:         from_time = from_time.to_time if from_time.respond_to?(:to_time)
    +18:         to_time = to_time.to_time if to_time.respond_to?(:to_time)
    +19:         distance_in_minutes = (((to_time - from_time).abs)/60).round
    +20:         distance_in_seconds = ((to_time - from_time).abs).round
    +21: 
    +22:         case distance_in_minutes
    +23:           when 0..1
    +24:             return (distance_in_minutes==0) ? l(:actionview_datehelper_time_in_words_minute_less_than) : l(:actionview_datehelper_time_in_words_minute_single) unless include_seconds
    +25:             case distance_in_seconds
    +26:               when 0..5   then lwr(:actionview_datehelper_time_in_words_second_less_than, 5)
    +27:               when 6..10  then lwr(:actionview_datehelper_time_in_words_second_less_than, 10)
    +28:               when 11..20 then lwr(:actionview_datehelper_time_in_words_second_less_than, 20)
    +29:               when 21..40 then l(:actionview_datehelper_time_in_words_minute_half)
    +30:               when 41..59 then l(:actionview_datehelper_time_in_words_minute_less_than)
    +31:               else             l(:actionview_datehelper_time_in_words_minute)
    +32:             end
    +33:                                 
    +34:           when 2..45      then lwr(:actionview_datehelper_time_in_words_minute, distance_in_minutes)
    +35:           when 46..90     then l(:actionview_datehelper_time_in_words_hour_about_single)
    +36:           when 90..1440   then lwr(:actionview_datehelper_time_in_words_hour_about, (distance_in_minutes.to_f / 60.0).round)
    +37:           when 1441..2880 then lwr(:actionview_datehelper_time_in_words_day, 1)
    +38:           else                 lwr(:actionview_datehelper_time_in_words_day, (distance_in_minutes / 1440).round)
    +39:         end
    +40:       end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +This method has been modified so that a localized string can be appended to +the day numbers. +

    +

    [Source]

    +
    +
    +    # File lib/gloc-rails-text.rb, line 43
    +43:       def select_day(date, options = {})
    +44:         day_options = []
    +45:         prefix = l :actionview_datehelper_select_day_prefix
    +46: 
    +47:         1.upto(31) do |day|
    +48:           day_options << ((date && (date.kind_of?(Fixnum) ? date : date.day) == day) ?
    +49:             %(<option value="#{day}" selected="selected">#{day}#{prefix}</option>\n) :
    +50:             %(<option value="#{day}">#{day}#{prefix}</option>\n)
    +51:           )
    +52:         end
    +53: 
    +54:         select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
    +55:       end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +This method has been modified so that +

    +
      +
    • the month names are localized. + +
    • +
    • it uses options: :min_date, :max_date, +:start_month, :end_month + +
    • +
    • a localized string can be appended to the month numbers when the +:use_month_numbers option is specified. + +
    • +
    +

    [Source]

    +
    +
    +    # File lib/gloc-rails-text.rb, line 61
    +61:       def select_month(date, options = {})
    +62:         unless LOCALIZED_MONTHNAMES.has_key?(current_language)
    +63:           LOCALIZED_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names).split(',')
    +64:           LOCALIZED_ABBR_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names_abbr).split(',')
    +65:         end
    +66:         
    +67:         month_options = []
    +68:         month_names = options[:use_short_month] ? LOCALIZED_ABBR_MONTHNAMES[current_language] : LOCALIZED_MONTHNAMES[current_language]
    +69:         
    +70:         if options.has_key?(:min_date) && options.has_key?(:max_date)
    +71:           if options[:min_date].year == options[:max_date].year
    +72:             start_month, end_month = options[:min_date].month, options[:max_date].month
    +73:           end
    +74:         end
    +75:         start_month = (options[:start_month] || 1) unless start_month
    +76:         end_month = (options[:end_month] || 12) unless end_month
    +77:         prefix = l :actionview_datehelper_select_month_prefix
    +78: 
    +79:         start_month.upto(end_month) do |month_number|
    +80:           month_name = if options[:use_month_numbers]
    +81:             "#{month_number}#{prefix}"
    +82:           elsif options[:add_month_numbers]
    +83:             month_number.to_s + ' - ' + month_names[month_number]
    +84:           else
    +85:             month_names[month_number]
    +86:           end
    +87: 
    +88:           month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ?
    +89:             %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
    +90:             %(<option value="#{month_number}">#{month_name}</option>\n)
    +91:           )
    +92:         end
    +93: 
    +94:         select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
    +95:       end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +This method has been modified so that +

    +
      +
    • it uses options: :min_date, :max_date + +
    • +
    • a localized string can be appended to the years numbers. + +
    • +
    +

    [Source]

    +
    +
    +     # File lib/gloc-rails-text.rb, line 100
    +100:       def select_year(date, options = {})
    +101:         year_options = []
    +102:         y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year
    +103: 
    +104:         start_year = options.has_key?(:min_date) ? options[:min_date].year : (options[:start_year] || y-5)
    +105:         end_year = options.has_key?(:max_date) ? options[:max_date].year : (options[:end_year] || y+5)
    +106:         step_val = start_year < end_year ? 1 : -1
    +107:         prefix = l :actionview_datehelper_select_year_prefix
    +108: 
    +109:         start_year.step(end_year, step_val) do |year|
    +110:           year_options << ((date && (date.kind_of?(Fixnum) ? date : date.year) == year) ?
    +111:             %(<option value="#{year}" selected="selected">#{year}#{prefix}</option>\n) :
    +112:             %(<option value="#{year}">#{year}#{prefix}</option>\n)
    +113:           )
    +114:         end
    +115: 
    +116:         select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
    +117:       end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/InstanceTag.html b/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/InstanceTag.html new file mode 100644 index 000000000..a236e0e5d --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/ActionView/Helpers/InstanceTag.html @@ -0,0 +1,167 @@ + + + + + + Class: ActionView::Helpers::InstanceTag + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    ClassActionView::Helpers::InstanceTag
    In: + + lib/gloc-rails-text.rb + +
    + + lib/gloc-rails.rb + +
    +
    Parent: + Object +
    +
    + + +
    + + + +
    + +
    +

    +The private method add_options is overridden so that "Please +select" is localized. +

    + +
    + + +
    + +
    +

    Methods

    + + +
    + +
    + + + +
    +

    Included Modules

    + +
    + GLoc +
    +
    + +
    + + + + + + + + + +
    +

    Public Instance methods

    + +
    + + + + +
    +

    +Inherits the current language from the template object. +

    +

    [Source]

    +
    +
    +     # File lib/gloc-rails.rb, line 119
    +119:       def current_language
    +120:         @template_object.current_language
    +121:       end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Errors.html b/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Errors.html new file mode 100644 index 000000000..9a16f608b --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Errors.html @@ -0,0 +1,215 @@ + + + + + + Class: ActiveRecord::Errors + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    ClassActiveRecord::Errors
    In: + + lib/gloc-rails.rb + +
    +
    Parent: + Object +
    +
    + + +
    + + + +
    + + + +
    + +
    +

    Methods

    + +
    + add   + current_language   +
    +
    + +
    + + + +
    +

    Included Modules

    + +
    + GLoc +
    +
    + +
    + + + +
    +

    External Aliases

    + +
    + + + + + + +
    add->add_without_gloc
    +
    +
    + + + + + + +
    +

    Public Instance methods

    + +
    + + + + +
    +

    +The GLoc version of this method provides two +extra features +

    +
      +
    • If msg is a string, it will be considered a GLoc string key. + +
    • +
    • If msg is an array, the first element will be considered the +string and the remaining elements will be considered arguments for the +string. Eg. [‘Hi %s.’,’John’] + +
    • +
    +

    [Source]

    +
    +
    +     # File lib/gloc-rails.rb, line 141
    +141:     def add(attribute, msg= @@default_error_messages[:invalid])
    +142:       if msg.is_a?(Array)
    +143:         args= msg.clone
    +144:         msg= args.shift
    +145:         args= nil if args.empty?
    +146:       end
    +147:       msg= ltry(msg)
    +148:       msg= msg % args unless args.nil?
    +149:       add_without_gloc(attribute, msg)
    +150:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Inherits the current language from the base record. +

    +

    [Source]

    +
    +
    +     # File lib/gloc-rails.rb, line 152
    +152:     def current_language
    +153:       @base.current_language
    +154:     end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Validations/ClassMethods.html b/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Validations/ClassMethods.html new file mode 100644 index 000000000..145a74c2b --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/ActiveRecord/Validations/ClassMethods.html @@ -0,0 +1,217 @@ + + + + + + Module: ActiveRecord::Validations::ClassMethods + + + + + + + + + + +
    + + + + + + + + + + +
    ModuleActiveRecord::Validations::ClassMethods
    In: + + lib/gloc-rails.rb + +
    +
    +
    + + +
    + + + +
    + + + +
    + +
    +

    Methods

    + + +
    + +
    + + + + +
    + + + + + + + + + +
    +

    Public Instance methods

    + +
    + + + + +
    +

    +The default Rails version of this function creates an error message and +then passes it to ActiveRecord.Errors. The GLoc version of this method, sends an array to +ActiveRecord.Errors that will be turned into a +string by ActiveRecord.Errors which in turn +allows for the message of this validation function to be a GLoc string key. +

    +

    [Source]

    +
    +
    +     # File lib/gloc-rails.rb, line 164
    +164:       def validates_length_of(*attrs)
    +165:         # Merge given options with defaults.
    +166:         options = {
    +167:           :too_long     => ActiveRecord::Errors.default_error_messages[:too_long],
    +168:           :too_short    => ActiveRecord::Errors.default_error_messages[:too_short],
    +169:           :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]
    +170:         }.merge(DEFAULT_VALIDATION_OPTIONS)
    +171:         options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash)
    +172: 
    +173:         # Ensure that one and only one range option is specified.
    +174:         range_options = ALL_RANGE_OPTIONS & options.keys
    +175:         case range_options.size
    +176:           when 0
    +177:             raise ArgumentError, 'Range unspecified.  Specify the :within, :maximum, :minimum, or :is option.'
    +178:           when 1
    +179:             # Valid number of options; do nothing.
    +180:           else
    +181:             raise ArgumentError, 'Too many range options specified.  Choose only one.'
    +182:         end
    +183: 
    +184:         # Get range option and value.
    +185:         option = range_options.first
    +186:         option_value = options[range_options.first]
    +187: 
    +188:         case option
    +189:         when :within, :in
    +190:           raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range)
    +191: 
    +192:           too_short = [options[:too_short] , option_value.begin]
    +193:           too_long  = [options[:too_long]  , option_value.end  ]
    +194: 
    +195:           validates_each(attrs, options) do |record, attr, value|
    +196:             if value.nil? or value.split(//).size < option_value.begin
    +197:               record.errors.add(attr, too_short)
    +198:             elsif value.split(//).size > option_value.end
    +199:               record.errors.add(attr, too_long)
    +200:             end
    +201:           end
    +202:         when :is, :minimum, :maximum
    +203:           raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0
    +204: 
    +205:           # Declare different validations per option.
    +206:           validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
    +207:           message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
    +208: 
    +209:           message = [(options[:message] || options[message_options[option]]) , option_value]
    +210: 
    +211:           validates_each(attrs, options) do |record, attr, value|
    +212:             if value.kind_of?(String)
    +213:               record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value]
    +214:             else
    +215:               record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]
    +216:             end
    +217:           end
    +218:         end
    +219:       end
    +
    +
    +
    +
    + +
    + + +
    + validates_size_of(*attrs) +
    + +
    +

    +Alias for validates_length_of +

    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html b/vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html new file mode 100644 index 000000000..8a25c7de8 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/GLoc.html @@ -0,0 +1,774 @@ + + + + + + Module: GLoc + + + + + + + + + + + + + +
    + + + +
    + +
    +

    +Copyright © 2005-2006 David Barri +

    + +
    + + +
    + + + +
    + + + +
    +

    Included Modules

    + + +
    + +
    + +
    +

    Classes and Modules

    + + Module GLoc::ClassMethods
    +Module GLoc::Helpers
    +Module GLoc::InstanceMethods
    + +
    + +
    +

    Constants

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    LOCALIZED_STRINGS={}
    RULES={}
    LOWERCASE_LANGUAGES={}
    UTF_8='utf-8'
    SHIFT_JIS='sjis'
    EUC_JP='euc-jp'
    +
    +
    + +
    +

    External Aliases

    + +
    + + + + + + +
    clear_strings->_clear_strings
    +
    +
    + + + + + + +
    +

    Public Class methods

    + +
    + + + + +
    +

    +Adds a collection of localized strings to the in-memory string store. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 113
    +113:     def add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil)
    +114:       _verbose_msg {"Adding #{symbol_hash.size} #{lang} strings."}
    +115:       _add_localized_strings(lang, symbol_hash, override, strings_charset)
    +116:       _verbose_msg :stats
    +117:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Creates a backup of the internal state of GLoc (ie. +strings, langs, rules, config) and optionally clears everything. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 121
    +121:     def backup_state(clear=false)
    +122:       s= _get_internal_state_vars.map{|o| o.clone}
    +123:       _get_internal_state_vars.each{|o| o.clear} if clear
    +124:       s
    +125:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Removes all localized strings from memory, either of a certain language (or +languages), or entirely. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 129
    +129:     def clear_strings(*languages)
    +130:       if languages.empty?
    +131:         _verbose_msg {"Clearing all strings"}
    +132:         LOCALIZED_STRINGS.clear
    +133:         LOWERCASE_LANGUAGES.clear
    +134:       else
    +135:         languages.each {|l|
    +136:           _verbose_msg {"Clearing :#{l} strings"}
    +137:           l= l.to_sym
    +138:           LOCALIZED_STRINGS.delete l
    +139:           LOWERCASE_LANGUAGES.each_pair {|k,v| LOWERCASE_LANGUAGES.delete k if v == l}
    +140:         }
    +141:       end
    +142:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Removes all localized strings from memory, except for those of certain +specified languages. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 146
    +146:     def clear_strings_except(*languages)
    +147:       clear= (LOCALIZED_STRINGS.keys - languages)
    +148:       _clear_strings(*clear) unless clear.empty?
    +149:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Returns the default language +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 108
    +108:     def current_language
    +109:       GLoc::CONFIG[:default_language]
    +110:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Returns the charset used to store localized strings in memory. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 152
    +152:     def get_charset(lang)
    +153:       CONFIG[:internal_charset_per_lang][lang] || CONFIG[:internal_charset]
    +154:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Returns a GLoc configuration value. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 157
    +157:     def get_config(key)
    +158:       CONFIG[key]
    +159:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Loads the localized strings that are included in the GLoc library. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 162
    +162:     def load_gloc_default_localized_strings(override=false)
    +163:       GLoc.load_localized_strings "#{File.dirname(__FILE__)}/../lang", override
    +164:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Loads localized strings from all yml files in the specifed directory. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 167
    +167:     def load_localized_strings(dir=nil, override=true)
    +168:       _charset_required
    +169:       _get_lang_file_list(dir).each {|filename|
    +170:         
    +171:         # Load file
    +172:         raw_hash = YAML::load(File.read(filename))
    +173:         raw_hash={} unless raw_hash.kind_of?(Hash)
    +174:         filename =~ /([^\/\\]+)\.ya?ml$/
    +175:         lang = $1.to_sym
    +176:         file_charset = raw_hash['file_charset'] || UTF_8
    +177:   
    +178:         # Convert string keys to symbols
    +179:         dest_charset= get_charset(lang)
    +180:         _verbose_msg {"Reading file #{filename} [charset: #{file_charset} --> #{dest_charset}]"}
    +181:         symbol_hash = {}
    +182:         Iconv.open(dest_charset, file_charset) do |i|
    +183:           raw_hash.each {|key, value|
    +184:             symbol_hash[key.to_sym] = i.iconv(value)
    +185:           }
    +186:         end
    +187:   
    +188:         # Add strings to repos
    +189:         _add_localized_strings(lang, symbol_hash, override)
    +190:       }
    +191:       _verbose_msg :stats
    +192:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Restores a backup of GLoc’s internal state +that was made with backup_state. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 195
    +195:     def restore_state(state)
    +196:       _get_internal_state_vars.each do |o|
    +197:         o.clear
    +198:         o.send o.respond_to?(:merge!) ? :merge! : :concat, state.shift
    +199:       end
    +200:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Sets the charset used to internally store localized strings. You can set +the charset to use for a specific language or languages, or if none are +specified the charset for ALL localized strings will be set. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 205
    +205:     def set_charset(new_charset, *langs)
    +206:       CONFIG[:internal_charset_per_lang] ||= {}
    +207:       
    +208:       # Convert symbol shortcuts
    +209:       if new_charset.is_a?(Symbol)
    +210:         new_charset= case new_charset
    +211:           when :utf8, :utf_8 then UTF_8
    +212:           when :sjis, :shift_jis, :shiftjis then SHIFT_JIS
    +213:           when :eucjp, :euc_jp then EUC_JP
    +214:           else new_charset.to_s
    +215:           end
    +216:       end
    +217:       
    +218:       # Convert existing strings
    +219:       (langs.empty? ? LOCALIZED_STRINGS.keys : langs).each do |lang|
    +220:         cur_charset= get_charset(lang)
    +221:         if cur_charset && new_charset != cur_charset
    +222:           _verbose_msg {"Converting :#{lang} strings from #{cur_charset} to #{new_charset}"}
    +223:           Iconv.open(new_charset, cur_charset) do |i|
    +224:             bundle= LOCALIZED_STRINGS[lang]
    +225:             bundle.each_pair {|k,v| bundle[k]= i.iconv(v)}
    +226:           end
    +227:         end
    +228:       end
    +229:       
    +230:       # Set new charset value
    +231:       if langs.empty?
    +232:         _verbose_msg {"Setting GLoc charset for all languages to #{new_charset}"}
    +233:         CONFIG[:internal_charset]= new_charset
    +234:         CONFIG[:internal_charset_per_lang].clear
    +235:       else
    +236:         langs.each do |lang|
    +237:           _verbose_msg {"Setting GLoc charset for :#{lang} strings to #{new_charset}"}
    +238:           CONFIG[:internal_charset_per_lang][lang]= new_charset
    +239:         end
    +240:       end
    +241:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Sets GLoc configuration values. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 244
    +244:     def set_config(hash)
    +245:       CONFIG.merge! hash
    +246:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Sets the $KCODE global variable according to a specified charset, or else +the current default charset for the default language. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 250
    +250:     def set_kcode(charset=nil)
    +251:       _charset_required
    +252:       charset ||= get_charset(current_language)
    +253:       $KCODE= case charset
    +254:         when UTF_8 then 'u'
    +255:         when SHIFT_JIS then 's'
    +256:         when EUC_JP then 'e'
    +257:         else 'n'
    +258:         end
    +259:       _verbose_msg {"$KCODE set to #{$KCODE}"}
    +260:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Tries to find a valid language that is similar to the argument passed. Eg. +:en, :en_au, :EN_US are all similar languages. Returns nil if no +similar languages are found. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 265
    +265:     def similar_language(lang)
    +266:       return nil if lang.nil?
    +267:       return lang.to_sym if valid_language?(lang)
    +268:       # Check lowercase without dashes
    +269:       lang= lang.to_s.downcase.gsub('-','_')
    +270:       return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang)
    +271:       # Check without dialect
    +272:       if lang.to_s =~ /^([a-z]+?)[^a-z].*/
    +273:         lang= $1
    +274:         return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang)
    +275:       end
    +276:       # Check other dialects
    +277:       lang= "#{lang}_"
    +278:       LOWERCASE_LANGUAGES.keys.each {|k| return LOWERCASE_LANGUAGES[k] if k.starts_with?(lang)}
    +279:       # Nothing found
    +280:       nil
    +281:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Returns true if there are any localized strings for a specified +language. Note that although set_langauge nil is perfectly valid, +nil is not a valid language. +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 290
    +290:     def valid_language?(language)
    +291:       LOCALIZED_STRINGS.has_key? language.to_sym rescue false
    +292:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Returns an array of (currently) valid languages (ie. languages for which +localized data exists). +

    +

    [Source]

    +
    +
    +     # File lib/gloc.rb, line 284
    +284:     def valid_languages
    +285:       LOCALIZED_STRINGS.keys
    +286:     end
    +
    +
    +
    +
    + +

    Public Instance methods

    + +
    + + + + +
    +

    +Returns the instance-level current language, or if not set, returns the +class-level current language. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 77
    +77:   def current_language
    +78:     @gloc_language || self.class.current_language
    +79:   end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/ClassMethods.html b/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/ClassMethods.html new file mode 100644 index 000000000..ba1a28ad0 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/ClassMethods.html @@ -0,0 +1,160 @@ + + + + + + Module: GLoc::ClassMethods + + + + + + + + + + +
    + + + + + + + + + + +
    ModuleGLoc::ClassMethods
    In: + + lib/gloc.rb + +
    +
    +
    + + +
    + + + +
    + +
    +

    +All classes/modules that include GLoc will also +gain these class methods. Notice that the GLoc::InstanceMethods module is also +included. +

    + +
    + + +
    + +
    +

    Methods

    + + +
    + +
    + + + +
    +

    Included Modules

    + + +
    + +
    + + + + + + + + + +
    +

    Public Instance methods

    + +
    + + + + +
    +

    +Returns the current language, or if not set, returns the GLoc current language. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 89
    +89:     def current_language
    +90:       @gloc_language || GLoc.current_language
    +91:     end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/Helpers.html b/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/Helpers.html new file mode 100644 index 000000000..f3fdf63e1 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/Helpers.html @@ -0,0 +1,323 @@ + + + + + + Module: GLoc::Helpers + + + + + + + + + + +
    + + + + + + + + + + +
    ModuleGLoc::Helpers
    In: + + lib/gloc-helpers.rb + +
    +
    +
    + + +
    + + + +
    + +
    +

    +These helper methods will be included in the InstanceMethods module. +

    + +
    + + +
    + +
    +

    Methods

    + +
    + l_YesNo   + l_age   + l_date   + l_datetime   + l_datetime_short   + l_lang_name   + l_strftime   + l_time   + l_yesno   +
    +
    + +
    + + + + +
    + + + + + + + + + +
    +

    Public Instance methods

    + +
    + + + + +
    +

    [Source]

    +
    +
    +    # File lib/gloc-helpers.rb, line 12
    +12:     def l_YesNo(value)         l(value ? :general_text_Yes : :general_text_No) end
    +
    +
    +
    +
    + +
    + + + + +
    +

    [Source]

    +
    +
    +   # File lib/gloc-helpers.rb, line 6
    +6:     def l_age(age)             lwr :general_fmt_age, age end
    +
    +
    +
    +
    + +
    + + + + +
    +

    [Source]

    +
    +
    +   # File lib/gloc-helpers.rb, line 7
    +7:     def l_date(date)           l_strftime date, :general_fmt_date end
    +
    +
    +
    +
    + +
    + + + + +
    +

    [Source]

    +
    +
    +   # File lib/gloc-helpers.rb, line 8
    +8:     def l_datetime(date)       l_strftime date, :general_fmt_datetime end
    +
    +
    +
    +
    + +
    + + + + +
    +

    [Source]

    +
    +
    +   # File lib/gloc-helpers.rb, line 9
    +9:     def l_datetime_short(date) l_strftime date, :general_fmt_datetime_short end
    +
    +
    +
    +
    + +
    + + + + +
    +

    [Source]

    +
    +
    +    # File lib/gloc-helpers.rb, line 15
    +15:     def l_lang_name(lang, display_lang=nil)
    +16:       ll display_lang || current_language, "general_lang_#{lang}"
    +17:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    [Source]

    +
    +
    +    # File lib/gloc-helpers.rb, line 10
    +10:     def l_strftime(date,fmt)   date.strftime l(fmt) end
    +
    +
    +
    +
    + +
    + + + + +
    +

    [Source]

    +
    +
    +    # File lib/gloc-helpers.rb, line 11
    +11:     def l_time(time)           l_strftime time, :general_fmt_time end
    +
    +
    +
    +
    + +
    + + + + +
    +

    [Source]

    +
    +
    +    # File lib/gloc-helpers.rb, line 13
    +13:     def l_yesno(value)         l(value ? :general_text_yes : :general_text_no) end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/InstanceMethods.html b/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/InstanceMethods.html new file mode 100644 index 000000000..4e15c9383 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/classes/GLoc/InstanceMethods.html @@ -0,0 +1,364 @@ + + + + + + Module: GLoc::InstanceMethods + + + + + + + + + + +
    + + + + + + + + + + +
    ModuleGLoc::InstanceMethods
    In: + + lib/gloc.rb + +
    +
    +
    + + +
    + + + +
    + +
    +

    +This module will be included in both instances and classes of GLoc includees. It is also included as class +methods in the GLoc module itself. +

    + +
    + + +
    + +
    +

    Methods

    + +
    + l   + l_has_string?   + ll   + ltry   + lwr   + lwr_   + set_language   + set_language_if_valid   +
    +
    + +
    + + + +
    +

    Included Modules

    + +
    + Helpers +
    +
    + +
    + + + + + + + + + +
    +

    Public Instance methods

    + +
    + + + + +
    +

    +Returns a localized string. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 18
    +18:     def l(symbol, *arguments)
    +19:       return GLoc._l(symbol,current_language,*arguments)
    +20:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Returns true if a localized string with the specified key exists. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 48
    +48:     def l_has_string?(symbol)
    +49:       return GLoc._l_has_string?(symbol,current_language)
    +50:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Returns a localized string in a specified language. This does not effect +current_language. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 24
    +24:     def ll(lang, symbol, *arguments)
    +25:       return GLoc._l(symbol,lang.to_sym,*arguments)
    +26:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Returns a localized string if the argument is a Symbol, else just returns +the argument. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 29
    +29:     def ltry(possible_key)
    +30:       possible_key.is_a?(Symbol) ? l(possible_key) : possible_key
    +31:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Uses the default GLoc rule to return a localized +string. See lwr_() for more info. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 35
    +35:     def lwr(symbol, *arguments)
    +36:       lwr_(:default, symbol, *arguments)
    +37:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Uses a rule to return a localized string. A rule is a function +that uses specified arguments to return a localization key prefix. The +prefix is appended to the localization key originally specified, to create +a new key which is then used to lookup a localized string. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 43
    +43:     def lwr_(rule, symbol, *arguments)
    +44:       GLoc._l("#{symbol}#{GLoc::_l_rule(rule,current_language).call(*arguments)}",current_language,*arguments)
    +45:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Sets the current language for this instance/class. Setting the language of +a class effects all instances unless the instance has its own language +defined. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 54
    +54:     def set_language(language)
    +55:       @gloc_language= language.nil? ? nil : language.to_sym
    +56:     end
    +
    +
    +
    +
    + +
    + + + + +
    +

    +Sets the current language if the language passed is a valid language. If +the language was valid, this method returns true else it will +return false. Note that nil is not a valid language. See +set_language(language) for more +info. +

    +

    [Source]

    +
    +
    +    # File lib/gloc.rb, line 62
    +62:     def set_language_if_valid(language)
    +63:       if GLoc.valid_language?(language)
    +64:         set_language(language)
    +65:         true
    +66:       else
    +67:         false
    +68:       end
    +69:     end
    +
    +
    +
    +
    + + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/created.rid b/vendor/plugins/gloc-1.1.0/doc/created.rid new file mode 100644 index 000000000..eba9efa29 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/created.rid @@ -0,0 +1 @@ +Sun May 28 15:21:13 E. Australia Standard Time 2006 diff --git a/vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html b/vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html new file mode 100644 index 000000000..aec36c5bf --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/CHANGELOG.html @@ -0,0 +1,153 @@ + + + + + + File: CHANGELOG + + + + + + + + + + +
    +

    CHANGELOG

    + + + + + + + + + +
    Path:CHANGELOG +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + +
    +

    Version 1.1 (28 May 2006)

    +
      +
    • The charset for each and/or all languages can now be easily configured. + +
    • +
    • Added a ActionController filter that auto-detects the client language. + +
    • +
    • The rake task "sort" now merges lines that match 100%, and warns +if duplicate keys are found. + +
    • +
    • Rule support. Create flexible rules to handle issues such as pluralization. + +
    • +
    • Massive speed and stability improvements to development mode. + +
    • +
    • Added Russian strings. (Thanks to Evgeny Lineytsev) + +
    • +
    • Complete RDoc documentation. + +
    • +
    • Improved helpers. + +
    • +
    • GLoc now configurable via get_config and +set_config + +
    • +
    • Added an option to tell GLoc to output +various verbose information. + +
    • +
    • More useful functions such as set_language_if_valid, similar_language + +
    • +
    • GLoc’s entire internal state can +now be backed up and restored. + +
    • +
    +

    Version 1.0 (17 April 2006)

    +
      +
    • Initial public release. + +
    • +
    + +
    + + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/files/README.html b/vendor/plugins/gloc-1.1.0/doc/files/README.html new file mode 100644 index 000000000..d078659d2 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/README.html @@ -0,0 +1,480 @@ + + + + + + File: README + + + + + + + + + + +
    +

    README

    + + + + + + + + + +
    Path:README +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + +
    +

    About

    +

    Preface

    +

    +I originally started designing this on weekends and after work in 2005. We +started to become very interested in Rails at work and I wanted to get some +experience with ruby with before we started using it full-time. I +didn’t have very many ideas for anything interesting to create so, +because we write a lot of multilingual webapps at my company, I decided to +write a localization library. That way if my little hobby project developed +into something decent, I could at least put it to good use. And here we are +in 2006, my little hobby project has come a long way and become quite a +useful piece of software. Not only do I use it in production sites I write +at work, but I also prefer it to other existing alternatives. Therefore I +have decided to make it publicly available, and I hope that other +developers will find it useful too. +

    +

    About

    +

    +GLoc is a localization library. It +doesn’t aim to do everything l10n-related that you can imagine, but +what it does, it does very well. It was originally designed as a Rails +plugin, but can also be used for plain ruby projects. Here are a list of +its main features: +

    +
      +
    • Lightweight and efficient. + +
    • +
    • Uses file-based string bundles. Strings can also be set directly. + +
    • +
    • Intelligent, cascading language configuration. + +
    • +
    • Create flexible rules to handle issues such as pluralization. + +
    • +
    • Includes a ActionController filter that auto-detects the client language. + +
    • +
    • Works perfectly with Rails Engines and allows strings to be overridden just +as easily as controllers, models, etc. + +
    • +
    • Automatically localizes Rails functions such as distance_in_minutes, +select_month etc + +
    • +
    • Supports different charsets. You can even specify the encoding to use for +each language seperately. + +
    • +
    • Special Rails mods/helpers. + +
    • +
    +

    What does GLoc mean?

    +

    +If you’re wondering about the name "GLoc", I’m sure you’re not +alone. This project was originally just called "Localization" +which was a bit too common, so when I decided to release it I decided to +call it "Golly’s Localization Library" instead (Golly is my +nickname), and that was long and boring so I then abbreviated that to +"GLoc". What a fun story!! +

    +

    Localization helpers

    +

    +This also includes a few helpers for common situations such as displaying +localized date, time, "yes" or "no", etc. +

    +

    Rails Localization

    +

    +At the moment, unless you manually remove the require +‘gloc-rails-text’ line from init.rb, this plugin overrides +certain Rails functions to provide multilingual versions. This +automatically localizes functions such as select_date(), +distance_of_time_in_words() and more… The strings can be found in +lang/*.yml. NOTE: This is not complete. Timezones and countries are not +currently localized. +

    +

    Usage

    +

    Quickstart

    +

    +Windows users will need to first install iconv. wiki.rubyonrails.com/rails/pages/iconv +

    +
      +
    • Create a dir "#{RAILS_ROOT}/lang" + +
    • +
    • Create a file "#{RAILS_ROOT}/lang/en.yml" and write your strings. +The format is "key: string". Save it as UTF-8. If you save it in +a different encoding, add a key called file_charset (eg. +"file_charset: iso-2022-jp") + +
    • +
    • Put the following in config/environment.rb and change the values as you see +fit. The following example is for an app that uses English and Japanese, +with Japanese being the default. + +
      +  GLoc.set_config :default_language => :ja
      +  GLoc.clear_strings_except :en, :ja
      +  GLoc.set_kcode
      +  GLoc.load_localized_strings
      +
      +
    • +
    • Add ‘include GLoc’ to all +classes that will use localization. This is added to most Rails classes +automatically. + +
    • +
    • Optionally, you can set the language for models and controllers by simply +inserting set_language :en in classes and/or methods. + +
    • +
    • To use localized strings, replace text such as "Welcome" +with l(:welcome_string_key), and "Hello +#{name}." with l(:hello_string_key, name). (Of course +the strings will need to exist in your string bundle.) + +
    • +
    +

    +There is more functionality provided by this plugin, that is not +demonstrated above. Please read the API summary for details. +

    +

    API summary

    +

    +The following methods are added as both class methods and instance methods +to modules/classes that include GLoc. +They are also available as class methods of GLoc. +

    +
    +  current_language               # Returns the current language
    +  l(symbol, *arguments)          # Returns a localized string
    +  ll(lang, symbol, *arguments)   # Returns a localized string in a specific language
    +  ltry(possible_key)             # Returns a localized string if passed a Symbol, else returns the same argument passed
    +  lwr(symbol, *arguments)        # Uses the default rule to return a localized string.
    +  lwr_(rule, symbol, *arguments) # Uses a specified rule to return a localized string.
    +  l_has_string?(symbol)          # Checks if a localized string exists
    +  set_language(language)         # Sets the language for the current class or class instance
    +  set_language_if_valid(lang)    # Sets the current language if the language passed is a valid language
    +
    +

    +The GLoc module also defines the +following class methods: +

    +
    +  add_localized_strings(lang, symbol_hash, override=true) # Adds a hash of localized strings
    +  backup_state(clear=false)                               # Creates a backup of GLoc's internal state and optionally clears everything too
    +  clear_strings(*languages)                               # Removes localized strings from memory
    +  clear_strings_except(*languages)                        # Removes localized strings from memory except for those of certain specified languages
    +  get_charset(lang)                                       # Returns the charset used to store localized strings in memory
    +  get_config(key)                                         # Returns a GLoc configuration value (see below)
    +  load_localized_strings(dir=nil, override=true)          # Loads localized strings from all YML files in a given directory
    +  restore_state(state)                                    # Restores a backup of GLoc's internal state
    +  set_charset(new_charset, *langs)                        # Sets the charset used to internally store localized strings
    +  set_config(hash)                                        # Sets GLoc configuration values (see below)
    +  set_kcode(charset=nil)                                  # Sets the $KCODE global variable
    +  similar_language(language)                              # Tries to find a valid language that is similar to the argument passed
    +  valid_languages                                         # Returns an array of (currently) valid languages (ie. languages for which localized data exists)
    +  valid_language?(language)                               # Checks whether any localized strings are in memory for a given language
    +
    +

    +GLoc uses the following configuration +items. They can be accessed via get_config and +set_config. +

    +
    +  :default_cookie_name
    +  :default_language
    +  :default_param_name
    +  :raise_string_not_found_errors
    +  :verbose
    +
    +

    +The GLoc module is automatically +included in the following classes: +

    +
    +  ActionController::Base
    +  ActionMailer::Base
    +  ActionView::Base
    +  ActionView::Helpers::InstanceTag
    +  ActiveRecord::Base
    +  ActiveRecord::Errors
    +  ApplicationHelper
    +  Test::Unit::TestCase
    +
    +

    +The GLoc module also defines the +following controller filters: +

    +
    +  autodetect_language_filter
    +
    +

    +GLoc also makes the following change to +Rails: +

    +
      +
    • Views for ActionMailer are now #{view_name}_#{language}.rb rather than just +#{view_name}.rb + +
    • +
    • All ActiveRecord validation class methods now accept a localized string key +(symbol) as a :message value. + +
    • +
    • ActiveRecord::Errors.add +now accepts symbols as valid message values. At runtime these symbols are +converted to localized strings using the current_language of the base +record. + +
    • +
    • ActiveRecord::Errors.add +now accepts arrays as arguments so that printf-style strings can be +generated at runtime. This also applies to the validates_* class methods. + +
      +  Eg. validates_xxxxxx_of :name, :message => ['Your name must be at least %d characters.', MIN_LEN]
      +  Eg. validates_xxxxxx_of :name, :message => [:user_error_validation_name_too_short, MIN_LEN]
      +
      +
    • +
    • Instances of ActiveView inherit their current_language from the controller +(or mailer) creating them. + +
    • +
    +

    +This plugin also adds the following rake tasks: +

    +
    +  * gloc:sort - Sorts the keys in the lang ymls (also accepts a DIR argument)
    +
    +

    Cascading language configuration

    +

    +The language can be set at three levels: +

    +
    +  1. The default     # GLoc.get_config :default_language
    +  2. Class level     # class A; set_language :de; end
    +  3. Instance level  # b= B.new; b.set_language :zh
    +
    +

    +Instance level has the highest priority and the default has the lowest. +

    +

    +Because GLoc is included at class level +too, it becomes easy to associate languages with contexts. For example: +

    +
    +  class Student
    +    set_language :en
    +    def say_hello
    +      puts "We say #{l :hello} but our teachers say #{Teacher.l :hello}"
    +    end
    +  end
    +
    +

    Rules

    +

    +There are often situations when depending on the value of one or more +variables, the surrounding text changes. The most common case of this is +pluralization. Rather than hardcode these rules, they are completely +definable by the user so that the user can eaasily accomodate for more +complicated grammatical rules such as those found in Russian and Polish (or +so I hear). To define a rule, simply include a string in the string bundle +whose key begins with "gloc_rule" and then write ruby +code as the value. The ruby code will be converted to a Proc when the +string bundle is first read, and should return a prefix that will be +appended to the string key at runtime to point to a new string. Make sense? +Probably not… Please look at the following example and I am sure it +will all make sense. +

    +

    +Simple example (string bundle / en.yml) +

    +
    +  _gloc_rule_default: ' |n| n==1 ? "_single" : "_plural" '
    +  man_count_plural: There are %d men.
    +  man_count_single: There is 1 man.
    +
    +

    +Simple example (code) +

    +
    +  lwr(:man_count, 1)  # => There is 1 man.
    +  lwr(:man_count, 8)  # => There are 8 men.
    +
    +

    +To use rules other than the default simply call lwr_ instead of lwr, and +specify the rule. +

    +

    +Example 2 (string bundle / en.yml) +

    +
    +  _gloc_rule_default: ' |n| n==1 ? "_single" : "_plural" '
    +  _gloc_rule_custom: ' |n| return "_none" if n==0; return "_heaps" if n>100; n==1 ? "_single" : "_plural" '
    +  man_count_none: There are no men.
    +  man_count_heaps: There are heaps of men!!
    +  man_count_plural: There are %d men.
    +  man_count_single: There is 1 man.
    +
    +

    +Example 2 (code) +

    +
    +  lwr_(:custom, :man_count, 0)    # => There are no men.
    +  lwr_(:custom, :man_count, 1)    # => There is 1 man.
    +  lwr_(:custom, :man_count, 8)    # => There are 8 men.
    +  lwr_(:custom, :man_count, 150)  # => There are heaps of men!!
    +
    +

    Helpers

    +

    +GLoc includes the following helpers: +

    +
    +  l_age(age)             # Returns a localized version of an age. eg "3 years old"
    +  l_date(date)           # Returns a date in a localized format
    +  l_datetime(date)       # Returns a date+time in a localized format
    +  l_datetime_short(date) # Returns a date+time in a localized short format.
    +  l_lang_name(l,dl=nil)  # Returns the name of a language (you must supply your own strings)
    +  l_strftime(date,fmt)   # Formats a date/time in a localized format.
    +  l_time(date)           # Returns a time in a localized format
    +  l_YesNo(value)         # Returns localized string of "Yes" or "No" depending on the arg
    +  l_yesno(value)         # Returns localized string of "yes" or "no" depending on the arg
    +
    +

    Rails localization

    +

    +Not all of Rails is covered but the following functions are: +

    +
    +  distance_of_time_in_words
    +  select_day
    +  select_month
    +  select_year
    +  add_options
    +
    +

    FAQ

    +

    How do I use it in engines?

    +

    +Simply put this in your init_engine.rb +

    +
    +  GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang')
    +
    +

    +That way your engines strings will be loaded when the engine is started. +Just simply make sure that you load your application strings after you +start your engines to safely override any engine strings. +

    +

    Why am I getting an Iconv::IllegalSequence error when calling GLoc.set_charset?

    +

    +By default GLoc loads all of its default +strings at startup. For example, calling set_charset +‘iso-2022-jp’ will cause this error because Russian +strings are loaded by default, and the Russian strings use characters that +cannot be expressed in the ISO-2022-JP charset. Before calling +set_charset you should call clear_strings_except to +remove strings from any languages that you will not be using. +Alternatively, you can simply specify the language(s) as follows, +set_charset ‘iso-2022-jp’, :ja. +

    +

    How do I make GLoc ignore StringNotFoundErrors?

    +

    +Disable it as follows: +

    +
    +  GLoc.set_config :raise_string_not_found_errors => false
    +
    + +
    + + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html new file mode 100644 index 000000000..394b79d70 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-helpers_rb.html @@ -0,0 +1,107 @@ + + + + + + File: gloc-helpers.rb + + + + + + + + + + +
    +

    gloc-helpers.rb

    + + + + + + + + + +
    Path:lib/gloc-helpers.rb +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + +
    +

    +Copyright © 2005-2006 David Barri +

    + +
    + + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-internal_rb.html b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-internal_rb.html new file mode 100644 index 000000000..6d09fec7b --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-internal_rb.html @@ -0,0 +1,115 @@ + + + + + + File: gloc-internal.rb + + + + + + + + + + +
    +

    gloc-internal.rb

    + + + + + + + + + +
    Path:lib/gloc-internal.rb +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + +
    +

    +Copyright © 2005-2006 David Barri +

    + +
    + +
    +

    Required files

    + +
    + iconv   + gloc-version   +
    +
    + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails-text_rb.html b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails-text_rb.html new file mode 100644 index 000000000..52a387218 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails-text_rb.html @@ -0,0 +1,114 @@ + + + + + + File: gloc-rails-text.rb + + + + + + + + + + +
    +

    gloc-rails-text.rb

    + + + + + + + + + +
    Path:lib/gloc-rails-text.rb +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + +
    +

    +Copyright © 2005-2006 David Barri +

    + +
    + +
    +

    Required files

    + +
    + date   +
    +
    + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails_rb.html b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails_rb.html new file mode 100644 index 000000000..3ae73b87b --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-rails_rb.html @@ -0,0 +1,114 @@ + + + + + + File: gloc-rails.rb + + + + + + + + + + +
    +

    gloc-rails.rb

    + + + + + + + + + +
    Path:lib/gloc-rails.rb +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + +
    +

    +Copyright © 2005-2006 David Barri +

    + +
    + +
    +

    Required files

    + +
    + gloc   +
    +
    + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html new file mode 100644 index 000000000..4b29e9d94 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-ruby_rb.html @@ -0,0 +1,107 @@ + + + + + + File: gloc-ruby.rb + + + + + + + + + + +
    +

    gloc-ruby.rb

    + + + + + + + + + +
    Path:lib/gloc-ruby.rb +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + +
    +

    +Copyright © 2005-2006 David Barri +

    + +
    + + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-version_rb.html b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-version_rb.html new file mode 100644 index 000000000..17f93aa43 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc-version_rb.html @@ -0,0 +1,101 @@ + + + + + + File: gloc-version.rb + + + + + + + + + + +
    +

    gloc-version.rb

    + + + + + + + + + +
    Path:lib/gloc-version.rb +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + + + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html new file mode 100644 index 000000000..9e68a89cd --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/files/lib/gloc_rb.html @@ -0,0 +1,116 @@ + + + + + + File: gloc.rb + + + + + + + + + + +
    +

    gloc.rb

    + + + + + + + + + +
    Path:lib/gloc.rb +
    Last Update:Sun May 28 15:19:38 E. Australia Standard Time 2006
    +
    + + +
    + + + +
    + +
    +

    +Copyright © 2005-2006 David Barri +

    + +
    + +
    +

    Required files

    + +
    + yaml   + gloc-internal   + gloc-helpers   +
    +
    + +
    + + +
    + + + + +
    + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/fr_class_index.html b/vendor/plugins/gloc-1.1.0/doc/fr_class_index.html new file mode 100644 index 000000000..08e0418f3 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/fr_class_index.html @@ -0,0 +1,37 @@ + + + + + + + + Classes + + + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/fr_file_index.html b/vendor/plugins/gloc-1.1.0/doc/fr_file_index.html new file mode 100644 index 000000000..839e378d3 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/fr_file_index.html @@ -0,0 +1,35 @@ + + + + + + + + Files + + + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/fr_method_index.html b/vendor/plugins/gloc-1.1.0/doc/fr_method_index.html new file mode 100644 index 000000000..325ed3589 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/fr_method_index.html @@ -0,0 +1,72 @@ + + + + + + + + Methods + + + + + +
    +

    Methods

    +
    + add (ActiveRecord::Errors)
    + add_localized_strings (GLoc)
    + autodetect_language_filter (ActionController::Filters::ClassMethods)
    + backup_state (GLoc)
    + clear_strings (GLoc)
    + clear_strings_except (GLoc)
    + current_language (GLoc::ClassMethods)
    + current_language (GLoc)
    + current_language (GLoc)
    + current_language (ActionView::Helpers::InstanceTag)
    + current_language (ActiveRecord::Errors)
    + distance_of_time_in_words (ActionView::Helpers::DateHelper)
    + get_charset (GLoc)
    + get_config (GLoc)
    + l (GLoc::InstanceMethods)
    + l_YesNo (GLoc::Helpers)
    + l_age (GLoc::Helpers)
    + l_date (GLoc::Helpers)
    + l_datetime (GLoc::Helpers)
    + l_datetime_short (GLoc::Helpers)
    + l_has_string? (GLoc::InstanceMethods)
    + l_lang_name (GLoc::Helpers)
    + l_strftime (GLoc::Helpers)
    + l_time (GLoc::Helpers)
    + l_yesno (GLoc::Helpers)
    + ll (GLoc::InstanceMethods)
    + load_gloc_default_localized_strings (GLoc)
    + load_localized_strings (GLoc)
    + ltry (GLoc::InstanceMethods)
    + lwr (GLoc::InstanceMethods)
    + lwr_ (GLoc::InstanceMethods)
    + new (ActionView::Base)
    + restore_state (GLoc)
    + select_day (ActionView::Helpers::DateHelper)
    + select_month (ActionView::Helpers::DateHelper)
    + select_year (ActionView::Helpers::DateHelper)
    + set_charset (GLoc)
    + set_config (GLoc)
    + set_kcode (GLoc)
    + set_language (GLoc::InstanceMethods)
    + set_language_if_valid (GLoc::InstanceMethods)
    + similar_language (GLoc)
    + valid_language? (GLoc)
    + valid_languages (GLoc)
    + validates_length_of (ActiveRecord::Validations::ClassMethods)
    + validates_size_of (ActiveRecord::Validations::ClassMethods)
    +
    +
    + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/index.html b/vendor/plugins/gloc-1.1.0/doc/index.html new file mode 100644 index 000000000..f29103142 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/index.html @@ -0,0 +1,24 @@ + + + + + + + GLoc Localization Library Documentation + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/doc/rdoc-style.css b/vendor/plugins/gloc-1.1.0/doc/rdoc-style.css new file mode 100644 index 000000000..fbf7326af --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/doc/rdoc-style.css @@ -0,0 +1,208 @@ + +body { + font-family: Verdana,Arial,Helvetica,sans-serif; + font-size: 90%; + margin: 0; + margin-left: 40px; + padding: 0; + background: white; +} + +h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; } +h1 { font-size: 150%; } +h2,h3,h4 { margin-top: 1em; } + +a { background: #eef; color: #039; text-decoration: none; } +a:hover { background: #039; color: #eef; } + +/* Override the base stylesheet's Anchor inside a table cell */ +td > a { + background: transparent; + color: #039; + text-decoration: none; +} + +/* and inside a section title */ +.section-title > a { + background: transparent; + color: #eee; + text-decoration: none; +} + +/* === Structural elements =================================== */ + +div#index { + margin: 0; + margin-left: -40px; + padding: 0; + font-size: 90%; +} + + +div#index a { + margin-left: 0.7em; +} + +div#index .section-bar { + margin-left: 0px; + padding-left: 0.7em; + background: #ccc; + font-size: small; +} + + +div#classHeader, div#fileHeader { + width: auto; + color: white; + padding: 0.5em 1.5em 0.5em 1.5em; + margin: 0; + margin-left: -40px; + border-bottom: 3px solid #006; +} + +div#classHeader a, div#fileHeader a { + background: inherit; + color: white; +} + +div#classHeader td, div#fileHeader td { + background: inherit; + color: white; +} + + +div#fileHeader { + background: #057; +} + +div#classHeader { + background: #048; +} + + +.class-name-in-header { + font-size: 180%; + font-weight: bold; +} + + +div#bodyContent { + padding: 0 1.5em 0 1.5em; +} + +div#description { + padding: 0.5em 1.5em; + background: #efefef; + border: 1px dotted #999; +} + +div#description h1,h2,h3,h4,h5,h6 { + color: #125;; + background: transparent; +} + +div#validator-badges { + text-align: center; +} +div#validator-badges img { border: 0; } + +div#copyright { + color: #333; + background: #efefef; + font: 0.75em sans-serif; + margin-top: 5em; + margin-bottom: 0; + padding: 0.5em 2em; +} + + +/* === Classes =================================== */ + +table.header-table { + color: white; + font-size: small; +} + +.type-note { + font-size: small; + color: #DEDEDE; +} + +.xxsection-bar { + background: #eee; + color: #333; + padding: 3px; +} + +.section-bar { + color: #333; + border-bottom: 1px solid #999; + margin-left: -20px; +} + + +.section-title { + background: #79a; + color: #eee; + padding: 3px; + margin-top: 2em; + margin-left: -30px; + border: 1px solid #999; +} + +.top-aligned-row { vertical-align: top } +.bottom-aligned-row { vertical-align: bottom } + +/* --- Context section classes ----------------------- */ + +.context-row { } +.context-item-name { font-family: monospace; font-weight: bold; color: black; } +.context-item-value { font-size: small; color: #448; } +.context-item-desc { color: #333; padding-left: 2em; } + +/* --- Method classes -------------------------- */ +.method-detail { + background: #efefef; + padding: 0; + margin-top: 0.5em; + margin-bottom: 1em; + border: 1px dotted #ccc; +} +.method-heading { + color: black; + background: #ccc; + border-bottom: 1px solid #666; + padding: 0.2em 0.5em 0 0.5em; +} +.method-signature { color: black; background: inherit; } +.method-name { font-weight: bold; } +.method-args { font-style: italic; } +.method-description { padding: 0 0.5em 0 0.5em; } + +/* --- Source code sections -------------------- */ + +a.source-toggle { font-size: 90%; } +div.method-source-code { + background: #262626; + color: #ffdead; + margin: 1em; + padding: 0.5em; + border: 1px dashed #999; + overflow: hidden; +} + +div.method-source-code pre { color: #ffdead; overflow: hidden; } + +/* --- Ruby keyword styles --------------------- */ + +.standalone-code { background: #221111; color: #ffdead; overflow: hidden; } + +.ruby-constant { color: #7fffd4; background: transparent; } +.ruby-keyword { color: #00ffff; background: transparent; } +.ruby-ivar { color: #eedd82; background: transparent; } +.ruby-operator { color: #00ffee; background: transparent; } +.ruby-identifier { color: #ffdead; background: transparent; } +.ruby-node { color: #ffa07a; background: transparent; } +.ruby-comment { color: #b22222; font-weight: bold; background: transparent; } +.ruby-regexp { color: #ffa07a; background: transparent; } +.ruby-value { color: #7fffd4; background: transparent; } \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/init.rb b/vendor/plugins/gloc-1.1.0/init.rb new file mode 100644 index 000000000..9d99acd61 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/init.rb @@ -0,0 +1,11 @@ +# Copyright (c) 2005-2006 David Barri + +require 'gloc' +require 'gloc-ruby' +require 'gloc-rails' +require 'gloc-rails-text' +require 'gloc-config' + +require 'gloc-dev' if ENV['RAILS_ENV'] == 'development' + +GLoc.load_gloc_default_localized_strings diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc-config.rb b/vendor/plugins/gloc-1.1.0/lib/gloc-config.rb new file mode 100644 index 000000000..e85b041f5 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc-config.rb @@ -0,0 +1,16 @@ +# Copyright (c) 2005-2006 David Barri + +module GLoc + + private + + CONFIG= {} unless const_defined?(:CONFIG) + unless CONFIG.frozen? + CONFIG[:default_language] ||= :en + CONFIG[:default_param_name] ||= 'lang' + CONFIG[:default_cookie_name] ||= 'lang' + CONFIG[:raise_string_not_found_errors]= true unless CONFIG.has_key?(:raise_string_not_found_errors) + CONFIG[:verbose] ||= false + end + +end diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb b/vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb new file mode 100644 index 000000000..cb12b4cb3 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc-dev.rb @@ -0,0 +1,97 @@ +# Copyright (c) 2005-2006 David Barri + +puts "GLoc v#{GLoc::VERSION} running in development mode. Strings can be modified at runtime." + +module GLoc + class << self + + alias :actual_add_localized_strings :add_localized_strings + def add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) + _verbose_msg {"dev::add_localized_strings #{lang}, [#{symbol_hash.size}], #{override}, #{strings_charset ? strings_charset : 'nil'}"} + STATE.push [:hash, lang, {}.merge(symbol_hash), override, strings_charset] + _force_refresh + end + + alias :actual_load_localized_strings :load_localized_strings + def load_localized_strings(dir=nil, override=true) + _verbose_msg {"dev::load_localized_strings #{dir ? dir : 'nil'}, #{override}"} + STATE.push [:dir, dir, override] + _get_lang_file_list(dir).each {|filename| FILES[filename]= nil} + end + + alias :actual_clear_strings :clear_strings + def clear_strings(*languages) + _verbose_msg {"dev::clear_strings #{languages.map{|l|l.to_s}.join(', ')}"} + STATE.push [:clear, languages.clone] + _force_refresh + end + + alias :actual_clear_strings_except :clear_strings_except + def clear_strings_except(*languages) + _verbose_msg {"dev::clear_strings_except #{languages.map{|l|l.to_s}.join(', ')}"} + STATE.push [:clear_except, languages.clone] + _force_refresh + end + + # Replace methods + [:_l, :_l_rule, :_l_has_string?, :similar_language, :valid_languages, :valid_language?].each do |m| + class_eval <<-EOB + alias :actual_#{m} :#{m} + def #{m}(*args) + _assert_gloc_strings_up_to_date + actual_#{m}(*args) + end + EOB + end + + #------------------------------------------------------------------------- + private + + STATE= [] + FILES= {} + + def _assert_gloc_strings_up_to_date + changed= @@force_refresh + + # Check if any lang files have changed + unless changed + FILES.each_pair {|f,mtime| + changed ||= (File.stat(f).mtime != mtime) + } + end + + return unless changed + puts "GLoc reloading strings..." + @@force_refresh= false + + # Update file timestamps + FILES.each_key {|f| + FILES[f]= File.stat(f).mtime + } + + # Reload strings + actual_clear_strings + STATE.each {|s| + case s[0] + when :dir then actual_load_localized_strings s[1], s[2] + when :hash then actual_add_localized_strings s[1], s[2], s[3], s[4] + when :clear then actual_clear_strings(*s[1]) + when :clear_except then actual_clear_strings_except(*s[1]) + else raise "Invalid state id: '#{s[0]}'" + end + } + _verbose_msg :stats + end + + @@force_refresh= false + def _force_refresh + @@force_refresh= true + end + + alias :super_get_internal_state_vars :_get_internal_state_vars + def _get_internal_state_vars + super_get_internal_state_vars + [ STATE, FILES ] + end + + end +end diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb b/vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb new file mode 100644 index 000000000..f2ceb8e3d --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc-helpers.rb @@ -0,0 +1,20 @@ +# Copyright (c) 2005-2006 David Barri + +module GLoc + # These helper methods will be included in the InstanceMethods module. + module Helpers + def l_age(age) lwr :general_fmt_age, age end + def l_date(date) l_strftime date, :general_fmt_date end + def l_datetime(date) l_strftime date, :general_fmt_datetime end + def l_datetime_short(date) l_strftime date, :general_fmt_datetime_short end + def l_strftime(date,fmt) date.strftime l(fmt) end + def l_time(time) l_strftime time, :general_fmt_time end + def l_YesNo(value) l(value ? :general_text_Yes : :general_text_No) end + def l_yesno(value) l(value ? :general_text_yes : :general_text_no) end + + def l_lang_name(lang, display_lang=nil) + ll display_lang || current_language, "general_lang_#{lang}" + end + + end +end diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb b/vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb new file mode 100644 index 000000000..f16e90555 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc-internal.rb @@ -0,0 +1,134 @@ +# Copyright (c) 2005-2006 David Barri + +require 'iconv' +require 'gloc-version' + +module GLoc + class GLocError < StandardError #:nodoc: + end + class InvalidArgumentsError < GLocError #:nodoc: + end + class InvalidKeyError < GLocError #:nodoc: + end + class RuleNotFoundError < GLocError #:nodoc: + end + class StringNotFoundError < GLocError #:nodoc: + end + + class << self + private + + def _add_localized_data(lang, symbol_hash, override, target) #:nodoc: + lang= lang.to_sym + if override + target[lang] ||= {} + target[lang].merge!(symbol_hash) + else + symbol_hash.merge!(target[lang]) if target[lang] + target[lang]= symbol_hash + end + end + + def _add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) #:nodoc: + _charset_required + + # Convert all incoming strings to the gloc charset + if strings_charset + Iconv.open(get_charset(lang), strings_charset) do |i| + symbol_hash.each_pair {|k,v| symbol_hash[k]= i.iconv(v)} + end + end + + # Convert rules + rules= {} + old_kcode= $KCODE + begin + $KCODE= 'u' + Iconv.open(UTF_8, get_charset(lang)) do |i| + symbol_hash.each {|k,v| + if /^_gloc_rule_(.+)$/ =~ k.to_s + v= i.iconv(v) if v + v= '""' if v.nil? + rules[$1.to_sym]= eval "Proc.new do #{v} end" + end + } + end + ensure + $KCODE= old_kcode + end + rules.keys.each {|k| symbol_hash.delete "_gloc_rule_#{k}".to_sym} + + # Add new localized data + LOWERCASE_LANGUAGES[lang.to_s.downcase]= lang + _add_localized_data(lang, symbol_hash, override, LOCALIZED_STRINGS) + _add_localized_data(lang, rules, override, RULES) + end + + def _charset_required #:nodoc: + set_charset UTF_8 unless CONFIG[:internal_charset] + end + + def _get_internal_state_vars + [ CONFIG, LOCALIZED_STRINGS, RULES, LOWERCASE_LANGUAGES ] + end + + def _get_lang_file_list(dir) #:nodoc: + dir= File.join(RAILS_ROOT,'lang') if dir.nil? + Dir[File.join(dir,'*.{yaml,yml}')] + end + + def _l(symbol, language, *arguments) #:nodoc: + symbol= symbol.to_sym if symbol.is_a?(String) + raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol) + + translation= LOCALIZED_STRINGS[language][symbol] rescue nil + if translation.nil? + raise StringNotFoundError.new("There is no key called '#{symbol}' in the #{language} strings.") if CONFIG[:raise_string_not_found_errors] + translation= symbol.to_s + end + + begin + return translation % arguments + rescue => e + raise InvalidArgumentsError.new("Translation value #{translation.inspect} with arguments #{arguments.inspect} caused error '#{e.message}'") + end + end + + def _l_has_string?(symbol,lang) #:nodoc: + symbol= symbol.to_sym if symbol.is_a?(String) + LOCALIZED_STRINGS[lang].has_key?(symbol.to_sym) rescue false + end + + def _l_rule(symbol,lang) #:nodoc: + symbol= symbol.to_sym if symbol.is_a?(String) + raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol) + + r= RULES[lang][symbol] rescue nil + raise RuleNotFoundError.new("There is no rule called '#{symbol}' in the #{lang} rules.") if r.nil? + r + end + + def _verbose_msg(type=nil) + return unless CONFIG[:verbose] + x= case type + when :stats + x= valid_languages.map{|l| ":#{l}(#{LOCALIZED_STRINGS[l].size}/#{RULES[l].size})"}.sort.join(', ') + "Current stats -- #{x}" + else + yield + end + puts "[GLoc] #{x}" + end + + public :_l, :_l_has_string?, :_l_rule + end + + private + + unless const_defined?(:LOCALIZED_STRINGS) + LOCALIZED_STRINGS= {} + RULES= {} + LOWERCASE_LANGUAGES= {} + end + +end diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb b/vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb new file mode 100644 index 000000000..abbb7a190 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc-rails-text.rb @@ -0,0 +1,137 @@ +# Copyright (c) 2005-2006 David Barri + +require 'date' + +module ActionView #:nodoc: + module Helpers #:nodoc: + module DateHelper + + unless const_defined?(:LOCALIZED_HELPERS) + LOCALIZED_HELPERS= true + LOCALIZED_MONTHNAMES = {} + LOCALIZED_ABBR_MONTHNAMES = {} + end + + # This method uses current_language to return a localized string. + def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false) + from_time = from_time.to_time if from_time.respond_to?(:to_time) + to_time = to_time.to_time if to_time.respond_to?(:to_time) + distance_in_minutes = (((to_time - from_time).abs)/60).round + distance_in_seconds = ((to_time - from_time).abs).round + + case distance_in_minutes + when 0..1 + return (distance_in_minutes==0) ? l(:actionview_datehelper_time_in_words_minute_less_than) : l(:actionview_datehelper_time_in_words_minute_single) unless include_seconds + case distance_in_seconds + when 0..5 then lwr(:actionview_datehelper_time_in_words_second_less_than, 5) + when 6..10 then lwr(:actionview_datehelper_time_in_words_second_less_than, 10) + when 11..20 then lwr(:actionview_datehelper_time_in_words_second_less_than, 20) + when 21..40 then l(:actionview_datehelper_time_in_words_minute_half) + when 41..59 then l(:actionview_datehelper_time_in_words_minute_less_than) + else l(:actionview_datehelper_time_in_words_minute) + end + + when 2..45 then lwr(:actionview_datehelper_time_in_words_minute, distance_in_minutes) + when 46..90 then l(:actionview_datehelper_time_in_words_hour_about_single) + when 90..1440 then lwr(:actionview_datehelper_time_in_words_hour_about, (distance_in_minutes.to_f / 60.0).round) + when 1441..2880 then lwr(:actionview_datehelper_time_in_words_day, 1) + else lwr(:actionview_datehelper_time_in_words_day, (distance_in_minutes / 1440).round) + end + end + + # This method has been modified so that a localized string can be appended to the day numbers. + def select_day(date, options = {}) + day_options = [] + prefix = l :actionview_datehelper_select_day_prefix + + 1.upto(31) do |day| + day_options << ((date && (date.kind_of?(Fixnum) ? date : date.day) == day) ? + %(\n) : + %(\n) + ) + end + + select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled]) + end + + # This method has been modified so that + # * the month names are localized. + # * it uses options: :min_date, :max_date, :start_month, :end_month + # * a localized string can be appended to the month numbers when the :use_month_numbers option is specified. + def select_month(date, options = {}) + unless LOCALIZED_MONTHNAMES.has_key?(current_language) + LOCALIZED_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names).split(',') + LOCALIZED_ABBR_MONTHNAMES[current_language] = [''] + l(:actionview_datehelper_select_month_names_abbr).split(',') + end + + month_options = [] + month_names = options[:use_short_month] ? LOCALIZED_ABBR_MONTHNAMES[current_language] : LOCALIZED_MONTHNAMES[current_language] + + if options.has_key?(:min_date) && options.has_key?(:max_date) + if options[:min_date].year == options[:max_date].year + start_month, end_month = options[:min_date].month, options[:max_date].month + end + end + start_month = (options[:start_month] || 1) unless start_month + end_month = (options[:end_month] || 12) unless end_month + prefix = l :actionview_datehelper_select_month_prefix + + start_month.upto(end_month) do |month_number| + month_name = if options[:use_month_numbers] + "#{month_number}#{prefix}" + elsif options[:add_month_numbers] + month_number.to_s + ' - ' + month_names[month_number] + else + month_names[month_number] + end + + month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ? + %(\n) : + %(\n) + ) + end + + select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled]) + end + + # This method has been modified so that + # * it uses options: :min_date, :max_date + # * a localized string can be appended to the years numbers. + def select_year(date, options = {}) + year_options = [] + y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year + + start_year = options.has_key?(:min_date) ? options[:min_date].year : (options[:start_year] || y-5) + end_year = options.has_key?(:max_date) ? options[:max_date].year : (options[:end_year] || y+5) + step_val = start_year < end_year ? 1 : -1 + prefix = l :actionview_datehelper_select_year_prefix + + start_year.step(end_year, step_val) do |year| + year_options << ((date && (date.kind_of?(Fixnum) ? date : date.year) == year) ? + %(\n) : + %(\n) + ) + end + + select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled]) + end + + end + + # The private method add_options is overridden so that "Please select" is localized. + class InstanceTag + private + + def add_options(option_tags, options, value = nil) + option_tags = "\n" + option_tags if options[:include_blank] + + if value.blank? && options[:prompt] + ("\n") + option_tags + else + option_tags + end + end + + end + end +end diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb b/vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb new file mode 100644 index 000000000..0a35b90ab --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc-rails.rb @@ -0,0 +1,230 @@ +# Copyright (c) 2005-2006 David Barri + +require 'gloc' + +module ActionController #:nodoc: + class Base #:nodoc: + include GLoc + end + module Filters #:nodoc: + module ClassMethods + + # This filter attempts to auto-detect the clients desired language. + # It first checks the params, then a cookie and then the HTTP_ACCEPT_LANGUAGE + # request header. If a language is found to match or be similar to a currently + # valid language, then it sets the current_language of the controller. + # + # class ExampleController < ApplicationController + # set_language :en + # autodetect_language_filter :except => 'monkey', :on_no_lang => :lang_not_autodetected_callback + # autodetect_language_filter :only => 'monkey', :check_cookie => 'monkey_lang', :check_accept_header => false + # ... + # def lang_not_autodetected_callback + # redirect_to somewhere + # end + # end + # + # The args for this filter are exactly the same the arguments of + # before_filter with the following exceptions: + # * :check_params -- If false, then params will not be checked for a language. + # If a String, then this will value will be used as the name of the param. + # * :check_cookie -- If false, then the cookie will not be checked for a language. + # If a String, then this will value will be used as the name of the cookie. + # * :check_accept_header -- If false, then HTTP_ACCEPT_LANGUAGE will not be checked for a language. + # * :on_set_lang -- You can specify the name of a callback function to be called when the language + # is successfully detected and set. The param must be a Symbol or a String which is the name of the function. + # The callback function must accept one argument (the language) and must be instance level. + # * :on_no_lang -- You can specify the name of a callback function to be called when the language + # couldn't be detected automatically. The param must be a Symbol or a String which is the name of the function. + # The callback function must be instance level. + # + # You override the default names of the param or cookie by calling GLoc.set_config :default_param_name => 'new_param_name' + # and GLoc.set_config :default_cookie_name => 'new_cookie_name'. + def autodetect_language_filter(*args) + options= args.last.is_a?(Hash) ? args.last : {} + x= 'Proc.new { |c| l= nil;' + # :check_params + unless (v= options.delete(:check_params)) == false + name= v ? ":#{v}" : 'GLoc.get_config(:default_param_name)' + x << "l ||= GLoc.similar_language(c.params[#{name}]);" + end + # :check_cookie + unless (v= options.delete(:check_cookie)) == false + name= v ? ":#{v}" : 'GLoc.get_config(:default_cookie_name)' + x << "l ||= GLoc.similar_language(c.send(:cookies)[#{name}]);" + end + # :check_accept_header + unless options.delete(:check_accept_header) == false + x << %< + unless l + a= c.request.env['HTTP_ACCEPT_LANGUAGE'].split(/,|;/) rescue nil + a.each {|x| l ||= GLoc.similar_language(x)} if a + end; > + end + # Set language + x << 'ret= true;' + x << 'if l; c.set_language(l); c.headers[\'Content-Language\']= l.to_s; ' + if options.has_key?(:on_set_lang) + x << "ret= c.#{options.delete(:on_set_lang)}(l);" + end + if options.has_key?(:on_no_lang) + x << "else; ret= c.#{options.delete(:on_no_lang)};" + end + x << 'end; ret }' + + # Create filter + block= eval x + before_filter(*args, &block) + end + + end + end +end + +# ============================================================================== + +module ActionMailer #:nodoc: + # In addition to including GLoc, render_message is also overridden so + # that mail templates contain the current language at the end of the file. + # Eg. deliver_hello will render hello_en.rhtml. + class Base + include GLoc + private + alias :render_message_without_gloc :render_message + def render_message(method_name, body) + render_message_without_gloc("#{method_name}_#{current_language}", body) + end + end +end + +# ============================================================================== + +module ActionView #:nodoc: + # initialize is overridden so that new instances of this class inherit + # the current language of the controller. + class Base + include GLoc + + alias :initialize_without_gloc :initialize + def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil) + initialize_without_gloc(base_path, assigns_for_first_render, controller) + set_language controller.current_language unless controller.nil? + end + end + + module Helpers #:nodoc: + class InstanceTag + include GLoc + # Inherits the current language from the template object. + def current_language + @template_object.current_language + end + end + end +end + +# ============================================================================== + +module ActiveRecord #:nodoc: + class Base #:nodoc: + include GLoc + end + + class Errors + include GLoc + alias :add_without_gloc :add + # The GLoc version of this method provides two extra features + # * If msg is a string, it will be considered a GLoc string key. + # * If msg is an array, the first element will be considered + # the string and the remaining elements will be considered arguments for the + # string. Eg. ['Hi %s.','John'] + def add(attribute, msg= @@default_error_messages[:invalid]) + if msg.is_a?(Array) + args= msg.clone + msg= args.shift + args= nil if args.empty? + end + msg= ltry(msg) + msg= msg % args unless args.nil? + add_without_gloc(attribute, msg) + end + # Inherits the current language from the base record. + def current_language + @base.current_language + end + end + + module Validations #:nodoc: + module ClassMethods + # The default Rails version of this function creates an error message and then + # passes it to ActiveRecord.Errors. + # The GLoc version of this method, sends an array to ActiveRecord.Errors that will + # be turned into a string by ActiveRecord.Errors which in turn allows for the message + # of this validation function to be a GLoc string key. + def validates_length_of(*attrs) + # Merge given options with defaults. + options = { + :too_long => ActiveRecord::Errors.default_error_messages[:too_long], + :too_short => ActiveRecord::Errors.default_error_messages[:too_short], + :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length] + }.merge(DEFAULT_VALIDATION_OPTIONS) + options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash) + + # Ensure that one and only one range option is specified. + range_options = ALL_RANGE_OPTIONS & options.keys + case range_options.size + when 0 + raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.' + when 1 + # Valid number of options; do nothing. + else + raise ArgumentError, 'Too many range options specified. Choose only one.' + end + + # Get range option and value. + option = range_options.first + option_value = options[range_options.first] + + case option + when :within, :in + raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) + + too_short = [options[:too_short] , option_value.begin] + too_long = [options[:too_long] , option_value.end ] + + validates_each(attrs, options) do |record, attr, value| + if value.nil? or value.split(//).size < option_value.begin + record.errors.add(attr, too_short) + elsif value.split(//).size > option_value.end + record.errors.add(attr, too_long) + end + end + when :is, :minimum, :maximum + raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0 + + # Declare different validations per option. + validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } + message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } + + message = [(options[:message] || options[message_options[option]]) , option_value] + + validates_each(attrs, options) do |record, attr, value| + if value.kind_of?(String) + record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value] + else + record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] + end + end + end + end + + alias_method :validates_size_of, :validates_length_of + end + end +end + +# ============================================================================== + +module ApplicationHelper #:nodoc: + include GLoc +end diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb b/vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb new file mode 100644 index 000000000..f96ab6cf9 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc-ruby.rb @@ -0,0 +1,7 @@ +# Copyright (c) 2005-2006 David Barri + +module Test # :nodoc: + module Unit # :nodoc: + class TestCase # :nodoc: + include GLoc +end; end; end diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc-version.rb b/vendor/plugins/gloc-1.1.0/lib/gloc-version.rb new file mode 100644 index 000000000..91afcf482 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc-version.rb @@ -0,0 +1,12 @@ +module GLoc + module VERSION #:nodoc: + MAJOR = 1 + MINOR = 1 + TINY = nil + + STRING= [MAJOR, MINOR, TINY].delete_if{|x|x.nil?}.join('.') + def self.to_s; STRING end + end +end + +puts "NOTICE: You are using a dev version of GLoc." if GLoc::VERSION::TINY == 'DEV' \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc.rb b/vendor/plugins/gloc-1.1.0/lib/gloc.rb new file mode 100644 index 000000000..bcad0ed9b --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/lib/gloc.rb @@ -0,0 +1,294 @@ +# Copyright (c) 2005-2006 David Barri + +require 'yaml' +require 'gloc-internal' +require 'gloc-helpers' + +module GLoc + UTF_8= 'utf-8' + SHIFT_JIS= 'sjis' + EUC_JP= 'euc-jp' + + # This module will be included in both instances and classes of GLoc includees. + # It is also included as class methods in the GLoc module itself. + module InstanceMethods + include Helpers + + # Returns a localized string. + def l(symbol, *arguments) + return GLoc._l(symbol,current_language,*arguments) + end + + # Returns a localized string in a specified language. + # This does not effect current_language. + def ll(lang, symbol, *arguments) + return GLoc._l(symbol,lang.to_sym,*arguments) + end + + # Returns a localized string if the argument is a Symbol, else just returns the argument. + def ltry(possible_key) + possible_key.is_a?(Symbol) ? l(possible_key) : possible_key + end + + # Uses the default GLoc rule to return a localized string. + # See lwr_() for more info. + def lwr(symbol, *arguments) + lwr_(:default, symbol, *arguments) + end + + # Uses a rule to return a localized string. + # A rule is a function that uses specified arguments to return a localization key prefix. + # The prefix is appended to the localization key originally specified, to create a new key which + # is then used to lookup a localized string. + def lwr_(rule, symbol, *arguments) + GLoc._l("#{symbol}#{GLoc::_l_rule(rule,current_language).call(*arguments)}",current_language,*arguments) + end + + # Returns true if a localized string with the specified key exists. + def l_has_string?(symbol) + return GLoc._l_has_string?(symbol,current_language) + end + + # Sets the current language for this instance/class. + # Setting the language of a class effects all instances unless the instance has its own language defined. + def set_language(language) + @gloc_language= language.nil? ? nil : language.to_sym + end + + # Sets the current language if the language passed is a valid language. + # If the language was valid, this method returns true else it will return false. + # Note that nil is not a valid language. + # See set_language(language) for more info. + def set_language_if_valid(language) + if GLoc.valid_language?(language) + set_language(language) + true + else + false + end + end + end + + #--------------------------------------------------------------------------- + # Instance + + include ::GLoc::InstanceMethods + # Returns the instance-level current language, or if not set, returns the class-level current language. + def current_language + @gloc_language || self.class.current_language + end + + #--------------------------------------------------------------------------- + # Class + + # All classes/modules that include GLoc will also gain these class methods. + # Notice that the GLoc::InstanceMethods module is also included. + module ClassMethods + include ::GLoc::InstanceMethods + # Returns the current language, or if not set, returns the GLoc current language. + def current_language + @gloc_language || GLoc.current_language + end + end + + def self.included(target) #:nodoc: + super + class << target + include ::GLoc::ClassMethods + end + end + + #--------------------------------------------------------------------------- + # GLoc module + + class << self + include ::GLoc::InstanceMethods + + # Returns the default language + def current_language + GLoc::CONFIG[:default_language] + end + + # Adds a collection of localized strings to the in-memory string store. + def add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) + _verbose_msg {"Adding #{symbol_hash.size} #{lang} strings."} + _add_localized_strings(lang, symbol_hash, override, strings_charset) + _verbose_msg :stats + end + + # Creates a backup of the internal state of GLoc (ie. strings, langs, rules, config) + # and optionally clears everything. + def backup_state(clear=false) + s= _get_internal_state_vars.map{|o| o.clone} + _get_internal_state_vars.each{|o| o.clear} if clear + s + end + + # Removes all localized strings from memory, either of a certain language (or languages), + # or entirely. + def clear_strings(*languages) + if languages.empty? + _verbose_msg {"Clearing all strings"} + LOCALIZED_STRINGS.clear + LOWERCASE_LANGUAGES.clear + else + languages.each {|l| + _verbose_msg {"Clearing :#{l} strings"} + l= l.to_sym + LOCALIZED_STRINGS.delete l + LOWERCASE_LANGUAGES.each_pair {|k,v| LOWERCASE_LANGUAGES.delete k if v == l} + } + end + end + alias :_clear_strings :clear_strings + + # Removes all localized strings from memory, except for those of certain specified languages. + def clear_strings_except(*languages) + clear= (LOCALIZED_STRINGS.keys - languages) + _clear_strings(*clear) unless clear.empty? + end + + # Returns the charset used to store localized strings in memory. + def get_charset(lang) + CONFIG[:internal_charset_per_lang][lang] || CONFIG[:internal_charset] + end + + # Returns a GLoc configuration value. + def get_config(key) + CONFIG[key] + end + + # Loads the localized strings that are included in the GLoc library. + def load_gloc_default_localized_strings(override=false) + GLoc.load_localized_strings "#{File.dirname(__FILE__)}/../lang", override + end + + # Loads localized strings from all yml files in the specifed directory. + def load_localized_strings(dir=nil, override=true) + _charset_required + _get_lang_file_list(dir).each {|filename| + + # Load file + raw_hash = YAML::load(File.read(filename)) + raw_hash={} unless raw_hash.kind_of?(Hash) + filename =~ /([^\/\\]+)\.ya?ml$/ + lang = $1.to_sym + file_charset = raw_hash['file_charset'] || UTF_8 + + # Convert string keys to symbols + dest_charset= get_charset(lang) + _verbose_msg {"Reading file #{filename} [charset: #{file_charset} --> #{dest_charset}]"} + symbol_hash = {} + Iconv.open(dest_charset, file_charset) do |i| + raw_hash.each {|key, value| + symbol_hash[key.to_sym] = i.iconv(value) + } + end + + # Add strings to repos + _add_localized_strings(lang, symbol_hash, override) + } + _verbose_msg :stats + end + + # Restores a backup of GLoc's internal state that was made with backup_state. + def restore_state(state) + _get_internal_state_vars.each do |o| + o.clear + o.send o.respond_to?(:merge!) ? :merge! : :concat, state.shift + end + end + + # Sets the charset used to internally store localized strings. + # You can set the charset to use for a specific language or languages, + # or if none are specified the charset for ALL localized strings will be set. + def set_charset(new_charset, *langs) + CONFIG[:internal_charset_per_lang] ||= {} + + # Convert symbol shortcuts + if new_charset.is_a?(Symbol) + new_charset= case new_charset + when :utf8, :utf_8 then UTF_8 + when :sjis, :shift_jis, :shiftjis then SHIFT_JIS + when :eucjp, :euc_jp then EUC_JP + else new_charset.to_s + end + end + + # Convert existing strings + (langs.empty? ? LOCALIZED_STRINGS.keys : langs).each do |lang| + cur_charset= get_charset(lang) + if cur_charset && new_charset != cur_charset + _verbose_msg {"Converting :#{lang} strings from #{cur_charset} to #{new_charset}"} + Iconv.open(new_charset, cur_charset) do |i| + bundle= LOCALIZED_STRINGS[lang] + bundle.each_pair {|k,v| bundle[k]= i.iconv(v)} + end + end + end + + # Set new charset value + if langs.empty? + _verbose_msg {"Setting GLoc charset for all languages to #{new_charset}"} + CONFIG[:internal_charset]= new_charset + CONFIG[:internal_charset_per_lang].clear + else + langs.each do |lang| + _verbose_msg {"Setting GLoc charset for :#{lang} strings to #{new_charset}"} + CONFIG[:internal_charset_per_lang][lang]= new_charset + end + end + end + + # Sets GLoc configuration values. + def set_config(hash) + CONFIG.merge! hash + end + + # Sets the $KCODE global variable according to a specified charset, or else the + # current default charset for the default language. + def set_kcode(charset=nil) + _charset_required + charset ||= get_charset(current_language) + $KCODE= case charset + when UTF_8 then 'u' + when SHIFT_JIS then 's' + when EUC_JP then 'e' + else 'n' + end + _verbose_msg {"$KCODE set to #{$KCODE}"} + end + + # Tries to find a valid language that is similar to the argument passed. + # Eg. :en, :en_au, :EN_US are all similar languages. + # Returns nil if no similar languages are found. + def similar_language(lang) + return nil if lang.nil? + return lang.to_sym if valid_language?(lang) + # Check lowercase without dashes + lang= lang.to_s.downcase.gsub('-','_') + return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang) + # Check without dialect + if lang.to_s =~ /^([a-z]+?)[^a-z].*/ + lang= $1 + return LOWERCASE_LANGUAGES[lang] if LOWERCASE_LANGUAGES.has_key?(lang) + end + # Check other dialects + lang= "#{lang}_" + LOWERCASE_LANGUAGES.keys.each {|k| return LOWERCASE_LANGUAGES[k] if k.starts_with?(lang)} + # Nothing found + nil + end + + # Returns an array of (currently) valid languages (ie. languages for which localized data exists). + def valid_languages + LOCALIZED_STRINGS.keys + end + + # Returns true if there are any localized strings for a specified language. + # Note that although set_langauge nil is perfectly valid, nil is not a valid language. + def valid_language?(language) + LOCALIZED_STRINGS.has_key? language.to_sym rescue false + end + end +end diff --git a/vendor/plugins/gloc-1.1.0/tasks/gloc.rake b/vendor/plugins/gloc-1.1.0/tasks/gloc.rake new file mode 100644 index 000000000..8da73779e --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/tasks/gloc.rake @@ -0,0 +1,30 @@ +namespace :gloc do + desc 'Sorts the keys in the lang ymls' + task :sort do + dir = ENV['DIR'] || '{.,vendor/plugins/*}/lang' + puts "Processing directory #{dir}" + files = Dir.glob(File.join(dir,'*.{yaml,yml}')) + puts 'No files found.' if files.empty? + files.each {|file| + puts "Sorting file: #{file}" + header = [] + content = IO.readlines(file) + content.each {|line| line.gsub!(/[\s\r\n\t]+$/,'')} + content.delete_if {|line| line==''} + tmp= [] + content.each {|x| tmp << x unless tmp.include?(x)} + content= tmp + header << content.shift if !content.empty? && content[0] =~ /^file_charset:/ + content.sort! + filebak = "#{file}.bak" + File.rename file, filebak + File.open(file, 'w') {|fout| fout << header.join("\n") << content.join("\n") << "\n"} + File.delete filebak + # Report duplicates + count= {} + content.map {|x| x.gsub(/:.+$/, '') }.each {|x| count[x] ||= 0; count[x] += 1} + count.delete_if {|k,v|v==1} + puts count.keys.sort.map{|x|" WARNING: Duplicate key '#{x}' (#{count[x]} occurances)"}.join("\n") unless count.empty? + } + end +end \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb b/vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb new file mode 100644 index 000000000..4cb232904 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/gloc_rails_test.rb @@ -0,0 +1,118 @@ +# Copyright (c) 2005-2006 David Barri + +$LOAD_PATH.push File.join(File.dirname(__FILE__),'..','lib') +require "#{File.dirname(__FILE__)}/../../../../test/test_helper" +require "#{File.dirname(__FILE__)}/../init" + +class GLocRailsTestController < ActionController::Base + autodetect_language_filter :only => :auto, :on_set_lang => :called_when_set, :on_no_lang => :called_when_bad + autodetect_language_filter :only => :auto2, :check_accept_header => false, :check_params => 'xx' + autodetect_language_filter :only => :auto3, :check_cookie => false + autodetect_language_filter :only => :auto4, :check_cookie => 'qwe', :check_params => false + def rescue_action(e) raise e end + def auto; render :text => 'auto'; end + def auto2; render :text => 'auto'; end + def auto3; render :text => 'auto'; end + def auto4; render :text => 'auto'; end + attr_accessor :callback_set, :callback_bad + def called_when_set(l) @callback_set ||= 0; @callback_set += 1 end + def called_when_bad; @callback_bad ||= 0; @callback_bad += 1 end +end + +class GLocRailsTest < Test::Unit::TestCase + + def setup + @lstrings = GLoc::LOCALIZED_STRINGS.clone + @old_config= GLoc::CONFIG.clone + begin_new_request + end + + def teardown + GLoc.clear_strings + GLoc::LOCALIZED_STRINGS.merge! @lstrings + GLoc::CONFIG.merge! @old_config + end + + def begin_new_request + @controller = GLocRailsTestController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_autodetect_language + GLoc::CONFIG[:default_language]= :def + GLoc::CONFIG[:default_param_name] = 'plang' + GLoc::CONFIG[:default_cookie_name] = 'clang' + GLoc.clear_strings + GLoc.add_localized_strings :en, :a => 'a' + GLoc.add_localized_strings :en_au, :a => 'a' + GLoc.add_localized_strings :en_US, :a => 'a' + GLoc.add_localized_strings :Ja, :a => 'a' + GLoc.add_localized_strings :ZH_HK, :a => 'a' + + # default + subtest_autodetect_language :def, nil, nil, nil + subtest_autodetect_language :def, 'its', 'all', 'bullshit,man;q=zxc' + # simple + subtest_autodetect_language :en_au, 'en_au', nil, nil + subtest_autodetect_language :en_US, nil, 'en_us', nil + subtest_autodetect_language :Ja, nil, nil, 'ja' + # priority + subtest_autodetect_language :Ja, 'ja', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5' + subtest_autodetect_language :en_US, 'why', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5' + subtest_autodetect_language :Ja, nil, nil, 'qwe_en,JA,zh,monkey_en;q=0.5' + # dashes to underscores in accept string + subtest_autodetect_language :en_au, 'monkey', nil, 'de,EN-Au' + # remove dialect + subtest_autodetect_language :en, nil, 'en-bullshit', nil + subtest_autodetect_language :en, 'monkey', nil, 'de,EN-NZ,ja' + # different dialect + subtest_autodetect_language :ZH_HK, 'zh', nil, 'de,EN-NZ,ja' + subtest_autodetect_language :ZH_HK, 'monkey', 'zh', 'de,EN-NZ,ja' + + # Check param/cookie names use defaults + GLoc::CONFIG[:default_param_name] = 'p_lang' + GLoc::CONFIG[:default_cookie_name] = 'c_lang' + # :check_params + subtest_autodetect_language :def, 'en_au', nil, nil + subtest_autodetect_language :en_au, {:p_lang => 'en_au'}, nil, nil + # :check_cookie + subtest_autodetect_language :def, nil, 'en_us', nil + subtest_autodetect_language :en_US, nil, {:c_lang => 'en_us'}, nil + GLoc::CONFIG[:default_param_name] = 'plang' + GLoc::CONFIG[:default_cookie_name] = 'clang' + + # autodetect_language_filter :only => :auto2, :check_accept_header => false, :check_params => 'xx' + subtest_autodetect_language :def, 'ja', nil, 'en_US', :auto2 + subtest_autodetect_language :Ja, {:xx => 'ja'}, nil, 'en_US', :auto2 + subtest_autodetect_language :en_au, 'ja', 'en_au', 'en_US', :auto2 + + # autodetect_language_filter :only => :auto3, :check_cookie => false + subtest_autodetect_language :Ja, 'ja', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5', :auto3 + subtest_autodetect_language :ZH_HK, 'hehe', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5', :auto3 + + # autodetect_language_filter :only => :auto4, :check_cookie => 'qwe', :check_params => false + subtest_autodetect_language :def, 'ja', 'en_us', nil, :auto4 + subtest_autodetect_language :ZH_HK, 'ja', 'en_us', 'qwe_ja,zh,monkey_en;q=0.5', :auto4 + subtest_autodetect_language :en_US, 'ja', {:qwe => 'en_us'}, 'ja', :auto4 + end + + def subtest_autodetect_language(expected,params,cookie,accept, action=:auto) + begin_new_request + params= {'plang' => params} if params.is_a?(String) + params ||= {} + if cookie + cookie={'clang' => cookie} unless cookie.is_a?(Hash) + cookie.each_pair {|k,v| @request.cookies[k.to_s]= CGI::Cookie.new(k.to_s,v)} + end + @request.env['HTTP_ACCEPT_LANGUAGE']= accept + get action, params + assert_equal expected, @controller.current_language + if action == :auto + s,b = expected != :def ? [1,nil] : [nil,1] + assert_equal s, @controller.callback_set + assert_equal b, @controller.callback_bad + end + end + +end \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/gloc_test.rb b/vendor/plugins/gloc-1.1.0/test/gloc_test.rb new file mode 100644 index 000000000..a39d5c41c --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/gloc_test.rb @@ -0,0 +1,433 @@ +# Copyright (c) 2005-2006 David Barri + +$LOAD_PATH.push File.join(File.dirname(__FILE__),'..','lib') +require 'gloc' +require 'gloc-ruby' +require 'gloc-config' +require 'gloc-rails-text' +require File.join(File.dirname(__FILE__),'lib','rails-time_ext') unless 3.respond_to?(:days) +require File.join(File.dirname(__FILE__),'lib','rails-string_ext') unless ''.respond_to?(:starts_with?) +#require 'gloc-dev' + +class LClass; include GLoc; end +class LClass2 < LClass; end +class LClass_en < LClass2; set_language :en; end +class LClass_ja < LClass2; set_language :ja; end +# class LClass_forced_au < LClass; set_language :en; force_language :en_AU; set_language :ja; end + +class GLocTest < Test::Unit::TestCase + include GLoc + include ActionView::Helpers::DateHelper + + def setup + @l1 = LClass.new + @l2 = LClass.new + @l3 = LClass.new + @l1.set_language :ja + @l2.set_language :en + @l3.set_language 'en_AU' + @gloc_state= GLoc.backup_state true + GLoc::CONFIG.merge!({ + :default_param_name => 'lang', + :default_cookie_name => 'lang', + :default_language => :ja, + :raise_string_not_found_errors => true, + :verbose => false, + }) + end + + def teardown + GLoc.restore_state @gloc_state + end + + #--------------------------------------------------------------------------- + + def test_basic + assert_localized_value [nil, @l1, @l2, @l3], nil, :in_both_langs + + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') + + assert_localized_value [nil, @l1], 'enにもjaにもある', :in_both_langs + assert_localized_value [nil, @l1], '日本語のみ', :ja_only + assert_localized_value [nil, @l1], nil, :en_only + + assert_localized_value @l2, 'This is in en+ja', :in_both_langs + assert_localized_value @l2, nil, :ja_only + assert_localized_value @l2, 'English only', :en_only + + assert_localized_value @l3, "Thiz in en 'n' ja", :in_both_langs + assert_localized_value @l3, nil, :ja_only + assert_localized_value @l3, 'Aussie English only bro', :en_only + + @l3.set_language :en + assert_localized_value @l3, 'This is in en+ja', :in_both_langs + assert_localized_value @l3, nil, :ja_only + assert_localized_value @l3, 'English only', :en_only + + assert_localized_value nil, 'enにもjaにもある', :in_both_langs + assert_localized_value nil, '日本語のみ', :ja_only + assert_localized_value nil, nil, :en_only + end + + def test_load_twice_with_override + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang2') + + assert_localized_value [nil, @l1], '更新された', :in_both_langs + assert_localized_value [nil, @l1], '日本語のみ', :ja_only + assert_localized_value [nil, @l1], nil, :en_only + assert_localized_value [nil, @l1], nil, :new_en + assert_localized_value [nil, @l1], '新たな日本語ストリング', :new_ja + + assert_localized_value @l2, 'This is in en+ja', :in_both_langs + assert_localized_value @l2, nil, :ja_only + assert_localized_value @l2, 'overriden dude', :en_only + assert_localized_value @l2, 'This is a new English string', :new_en + assert_localized_value @l2, nil, :new_ja + + assert_localized_value @l3, "Thiz in en 'n' ja", :in_both_langs + assert_localized_value @l3, nil, :ja_only + assert_localized_value @l3, 'Aussie English only bro', :en_only + end + + def test_load_twice_without_override + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang2'), false + + assert_localized_value [nil, @l1], 'enにもjaにもある', :in_both_langs + assert_localized_value [nil, @l1], '日本語のみ', :ja_only + assert_localized_value [nil, @l1], nil, :en_only + assert_localized_value [nil, @l1], nil, :new_en + assert_localized_value [nil, @l1], '新たな日本語ストリング', :new_ja + + assert_localized_value @l2, 'This is in en+ja', :in_both_langs + assert_localized_value @l2, nil, :ja_only + assert_localized_value @l2, 'English only', :en_only + assert_localized_value @l2, 'This is a new English string', :new_en + assert_localized_value @l2, nil, :new_ja + + assert_localized_value @l3, "Thiz in en 'n' ja", :in_both_langs + assert_localized_value @l3, nil, :ja_only + assert_localized_value @l3, 'Aussie English only bro', :en_only + end + + def test_add_localized_strings + assert_localized_value nil, nil, :add + assert_localized_value nil, nil, :ja_only + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') + assert_localized_value nil, nil, :add + assert_localized_value nil, '日本語のみ', :ja_only + GLoc.add_localized_strings 'en', {:ja_only => 'bullshit'}, true + GLoc.add_localized_strings 'en', {:ja_only => 'bullshit'}, false + assert_localized_value nil, nil, :add + assert_localized_value nil, '日本語のみ', :ja_only + GLoc.add_localized_strings 'ja', {:ja_only => 'bullshit', :add => '123'}, false + assert_localized_value nil, '123', :add + assert_localized_value nil, '日本語のみ', :ja_only + GLoc.add_localized_strings 'ja', {:ja_only => 'bullshit', :add => '234'} + assert_localized_value nil, '234', :add + assert_localized_value nil, 'bullshit', :ja_only + end + + def test_class_set_language + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') + + @l1 = LClass_ja.new + @l2 = LClass_en.new + @l3 = LClass_en.new + + assert_localized_value @l1, 'enにもjaにもある', :in_both_langs + assert_localized_value @l2, 'This is in en+ja', :in_both_langs + assert_localized_value @l3, 'This is in en+ja', :in_both_langs + + @l3.set_language 'en_AU' + + assert_localized_value @l1, 'enにもjaにもある', :in_both_langs + assert_localized_value @l2, 'This is in en+ja', :in_both_langs + assert_localized_value @l3, "Thiz in en 'n' ja", :in_both_langs + end + + def test_ll + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') + + assert_equal 'enにもjaにもある', ll('ja',:in_both_langs) + assert_equal 'enにもjaにもある', GLoc::ll('ja',:in_both_langs) + assert_equal 'enにもjaにもある', LClass_en.ll('ja',:in_both_langs) + assert_equal 'enにもjaにもある', LClass_ja.ll('ja',:in_both_langs) + + assert_equal 'This is in en+ja', ll('en',:in_both_langs) + assert_equal 'This is in en+ja', GLoc::ll('en',:in_both_langs) + assert_equal 'This is in en+ja', LClass_en.ll('en',:in_both_langs) + assert_equal 'This is in en+ja', LClass_ja.ll('en',:in_both_langs) + end + + def test_lsym + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'lang') + assert_equal 'enにもjaにもある', LClass_ja.ltry(:in_both_langs) + assert_equal 'hello', LClass_ja.ltry('hello') + assert_equal nil, LClass_ja.ltry(nil) + end + +# def test_forced +# assert_equal :en_AU, LClass_forced_au.current_language +# a= LClass_forced_au.new +# a.set_language :ja +# assert_equal :en_AU, a.current_language +# a.force_language :ja +# assert_equal :ja, a.current_language +# assert_equal :en_AU, LClass_forced_au.current_language +# end + + def test_pluralization + GLoc.add_localized_strings :en, :_gloc_rule_default => %[|n| case n; when 0 then '_none'; when 1 then '_single'; else '_many'; end], :a_single => '%d man', :a_many => '%d men', :a_none => 'No men' + GLoc.add_localized_strings :en, :_gloc_rule_asd => %[|n| n<10 ? '_few' : '_heaps'], :a_few => 'a few men (%d)', :a_heaps=> 'soo many men' + set_language :en + + assert_equal 'No men', lwr(:a, 0) + assert_equal '1 man', lwr(:a, 1) + assert_equal '3 men', lwr(:a, 3) + assert_equal '20 men', lwr(:a, 20) + + assert_equal 'a few men (0)', lwr_(:asd, :a, 0) + assert_equal 'a few men (1)', lwr_(:asd, :a, 1) + assert_equal 'a few men (3)', lwr_(:asd, :a, 3) + assert_equal 'soo many men', lwr_(:asd, :a, 12) + assert_equal 'soo many men', lwr_(:asd, :a, 20) + + end + + def test_distance_in_words + load_default_strings + [ + [20.seconds, 'less than a minute', '1分以内', 'меньше минуты'], + [80.seconds, '1 minute', '1分', '1 минуту'], + [3.seconds, 'less than 5 seconds', '5秒以内', 'менее 5 секунд', true], + [9.seconds, 'less than 10 seconds', '10秒以内', 'менее 10 секунд', true], + [16.seconds, 'less than 20 seconds', '20秒以内', 'менее 20 секунд', true], + [35.seconds, 'half a minute', '約30秒', 'полминуты', true], + [50.seconds, 'less than a minute', '1分以内', 'меньше минуты', true], + [1.1.minutes, '1 minute', '1分', '1 минуту'], + [2.1.minutes, '2 minutes', '2分', '2 минуты'], + [4.1.minutes, '4 minutes', '4分', '4 минуты'], + [5.1.minutes, '5 minutes', '5分', '5 минут'], + [1.1.hours, 'about an hour', '約1時間', 'около часа'], + [3.1.hours, 'about 3 hours', '約3時間', 'около 3 часов'], + [9.1.hours, 'about 9 hours', '約9時間', 'около 9 часов'], + [1.1.days, '1 day', '1日間', '1 день'], + [2.1.days, '2 days', '2日間', '2 дня'], + [4.days, '4 days', '4日間', '4 дня'], + [6.days, '6 days', '6日間', '6 дней'], + [11.days, '11 days', '11日間', '11 дней'], + [12.days, '12 days', '12日間', '12 дней'], + [15.days, '15 days', '15日間', '15 дней'], + [20.days, '20 days', '20日間', '20 дней'], + [21.days, '21 days', '21日間', '21 день'], + [22.days, '22 days', '22日間', '22 дня'], + [25.days, '25 days', '25日間', '25 дней'], + ].each do |a| + t, en, ja, ru = a + inc_sec= (a.size == 5) ? a[-1] : false + set_language :en + assert_equal en, distance_of_time_in_words(t,0,inc_sec) + set_language :ja + assert_equal ja, distance_of_time_in_words(t,0,inc_sec) + set_language :ru + assert_equal ru, distance_of_time_in_words(t,0,inc_sec) + end + end + + def test_age + load_default_strings + [ + [1, '1 yr', '1歳', '1 год'], + [22, '22 yrs', '22歳', '22 года'], + [27, '27 yrs', '27歳', '27 лет'], + ].each do |a, en, ja, ru| + set_language :en + assert_equal en, l_age(a) + set_language :ja + assert_equal ja, l_age(a) + set_language :ru + assert_equal ru, l_age(a) + end + end + + def test_yesno + load_default_strings + set_language :en + assert_equal 'yes', l_yesno(true) + assert_equal 'no', l_yesno(false) + assert_equal 'Yes', l_YesNo(true) + assert_equal 'No', l_YesNo(false) + end + + def test_all_languages_have_values_for_helpers + load_default_strings + t= Time.local(2000, 9, 15, 11, 23, 57) + GLoc.valid_languages.each {|l| + set_language l + 0.upto(120) {|n| l_age(n)} + l_date(t) + l_datetime(t) + l_datetime_short(t) + l_time(t) + [true,false].each{|v| l_YesNo(v); l_yesno(v) } + } + end + + def test_similar_languages + GLoc.add_localized_strings :en, :a => 'a' + GLoc.add_localized_strings :en_AU, :a => 'a' + GLoc.add_localized_strings :ja, :a => 'a' + GLoc.add_localized_strings :zh_tw, :a => 'a' + + assert_equal :en, GLoc.similar_language(:en) + assert_equal :en, GLoc.similar_language('en') + assert_equal :ja, GLoc.similar_language(:ja) + assert_equal :ja, GLoc.similar_language('ja') + # lowercase + dashes to underscores + assert_equal :en, GLoc.similar_language('EN') + assert_equal :en, GLoc.similar_language(:EN) + assert_equal :en_AU, GLoc.similar_language(:EN_Au) + assert_equal :en_AU, GLoc.similar_language('eN-Au') + # remove dialect + assert_equal :ja, GLoc.similar_language(:ja_Au) + assert_equal :ja, GLoc.similar_language('JA-ASDF') + assert_equal :ja, GLoc.similar_language('jA_ASD_ZXC') + # different dialect + assert_equal :zh_tw, GLoc.similar_language('ZH') + assert_equal :zh_tw, GLoc.similar_language('ZH_HK') + assert_equal :zh_tw, GLoc.similar_language('ZH-BUL') + # non matching + assert_equal nil, GLoc.similar_language('WW') + assert_equal nil, GLoc.similar_language('WW_AU') + assert_equal nil, GLoc.similar_language('WW-AU') + assert_equal nil, GLoc.similar_language('eZ_en') + assert_equal nil, GLoc.similar_language('AU-ZH') + end + + def test_clear_strings_and_similar_langs + GLoc.add_localized_strings :en, :a => 'a' + GLoc.add_localized_strings :en_AU, :a => 'a' + GLoc.add_localized_strings :ja, :a => 'a' + GLoc.add_localized_strings :zh_tw, :a => 'a' + GLoc.clear_strings :en, :ja + assert_equal nil, GLoc.similar_language('ja') + assert_equal :en_AU, GLoc.similar_language('en') + assert_equal :zh_tw, GLoc.similar_language('ZH_HK') + GLoc.clear_strings + assert_equal nil, GLoc.similar_language('ZH_HK') + end + + def test_lang_name + GLoc.add_localized_strings :en, :general_lang_en => 'English', :general_lang_ja => 'Japanese' + GLoc.add_localized_strings :ja, :general_lang_en => '英語', :general_lang_ja => '日本語' + set_language :en + assert_equal 'Japanese', l_lang_name(:ja) + assert_equal 'English', l_lang_name('en') + set_language :ja + assert_equal '日本語', l_lang_name('ja') + assert_equal '英語', l_lang_name(:en) + end + + def test_charset_change_all + load_default_strings + GLoc.add_localized_strings :ja2, :a => 'a' + GLoc.valid_languages # Force refresh if in dev mode + GLoc.class_eval 'LOCALIZED_STRINGS[:ja2]= LOCALIZED_STRINGS[:ja].clone' + + [:ja, :ja2].each do |l| + set_language l + assert_equal 'はい', l_yesno(true) + assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase + end + + GLoc.set_charset 'sjis' + assert_equal 'sjis', GLoc.get_charset(:ja) + assert_equal 'sjis', GLoc.get_charset(:ja2) + + [:ja, :ja2].each do |l| + set_language l + assert_equal "82CD82A2", l_yesno(true).unpack('H*')[0].upcase + end + end + + def test_charset_change_single + load_default_strings + GLoc.add_localized_strings :ja2, :a => 'a' + GLoc.add_localized_strings :ja3, :a => 'a' + GLoc.valid_languages # Force refresh if in dev mode + GLoc.class_eval 'LOCALIZED_STRINGS[:ja2]= LOCALIZED_STRINGS[:ja].clone' + GLoc.class_eval 'LOCALIZED_STRINGS[:ja3]= LOCALIZED_STRINGS[:ja].clone' + + [:ja, :ja2, :ja3].each do |l| + set_language l + assert_equal 'はい', l_yesno(true) + assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase + end + + GLoc.set_charset 'sjis', :ja + assert_equal 'sjis', GLoc.get_charset(:ja) + assert_equal 'utf-8', GLoc.get_charset(:ja2) + assert_equal 'utf-8', GLoc.get_charset(:ja3) + + set_language :ja + assert_equal "82CD82A2", l_yesno(true).unpack('H*')[0].upcase + set_language :ja2 + assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase + set_language :ja3 + assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase + + GLoc.set_charset 'euc-jp', :ja, :ja3 + assert_equal 'euc-jp', GLoc.get_charset(:ja) + assert_equal 'utf-8', GLoc.get_charset(:ja2) + assert_equal 'euc-jp', GLoc.get_charset(:ja3) + + set_language :ja + assert_equal "A4CFA4A4", l_yesno(true).unpack('H*')[0].upcase + set_language :ja2 + assert_equal "E381AFE38184", l_yesno(true).unpack('H*')[0].upcase + set_language :ja3 + assert_equal "A4CFA4A4", l_yesno(true).unpack('H*')[0].upcase + end + + def test_set_language_if_valid + GLoc.add_localized_strings :en, :a => 'a' + GLoc.add_localized_strings :zh_tw, :a => 'a' + + assert set_language_if_valid('en') + assert_equal :en, current_language + + assert set_language_if_valid('zh_tw') + assert_equal :zh_tw, current_language + + assert !set_language_if_valid(nil) + assert_equal :zh_tw, current_language + + assert !set_language_if_valid('ja') + assert_equal :zh_tw, current_language + + assert set_language_if_valid(:en) + assert_equal :en, current_language + end + + #=========================================================================== + protected + + def assert_localized_value(objects,expected,key) + objects = [objects] unless objects.kind_of?(Array) + objects.each {|object| + o = object || GLoc + assert_equal !expected.nil?, o.l_has_string?(key) + if expected.nil? + assert_raise(GLoc::StringNotFoundError) {o.l(key)} + else + assert_equal expected, o.l(key) + end + } + end + + def load_default_strings + GLoc.load_localized_strings File.join(File.dirname(__FILE__),'..','lang') + end +end \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/lang/en.yaml b/vendor/plugins/gloc-1.1.0/test/lang/en.yaml new file mode 100644 index 000000000..325dc599e --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/lang/en.yaml @@ -0,0 +1,2 @@ +in_both_langs: This is in en+ja +en_only: English only \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml b/vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml new file mode 100644 index 000000000..307cc7859 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/lang/en_AU.yaml @@ -0,0 +1,2 @@ +in_both_langs: Thiz in en 'n' ja +en_only: Aussie English only bro \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/lang/ja.yml b/vendor/plugins/gloc-1.1.0/test/lang/ja.yml new file mode 100644 index 000000000..64df03376 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/lang/ja.yml @@ -0,0 +1,2 @@ +in_both_langs: enにもjaにもある +ja_only: 日本語のみ \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/lang2/en.yml b/vendor/plugins/gloc-1.1.0/test/lang2/en.yml new file mode 100644 index 000000000..e6467e7a0 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/lang2/en.yml @@ -0,0 +1,2 @@ +en_only: overriden dude +new_en: This is a new English string \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml b/vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml new file mode 100644 index 000000000..864b287d0 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/lang2/ja.yaml @@ -0,0 +1,2 @@ +in_both_langs: 更新された +new_ja: 新たな日本語ストリング \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/lib/rails-string_ext.rb b/vendor/plugins/gloc-1.1.0/test/lib/rails-string_ext.rb new file mode 100644 index 000000000..418d28db2 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/lib/rails-string_ext.rb @@ -0,0 +1,23 @@ +module ActiveSupport #:nodoc: + module CoreExtensions #:nodoc: + module String #:nodoc: + # Additional string tests. + module StartsEndsWith + # Does the string start with the specified +prefix+? + def starts_with?(prefix) + prefix = prefix.to_s + self[0, prefix.length] == prefix + end + + # Does the string end with the specified +suffix+? + def ends_with?(suffix) + suffix = suffix.to_s + self[-suffix.length, suffix.length] == suffix + end + end + end + end +end +class String + include ActiveSupport::CoreExtensions::String::StartsEndsWith +end \ No newline at end of file diff --git a/vendor/plugins/gloc-1.1.0/test/lib/rails-time_ext.rb b/vendor/plugins/gloc-1.1.0/test/lib/rails-time_ext.rb new file mode 100644 index 000000000..d8771e4e6 --- /dev/null +++ b/vendor/plugins/gloc-1.1.0/test/lib/rails-time_ext.rb @@ -0,0 +1,76 @@ +module ActiveSupport #:nodoc: + module CoreExtensions #:nodoc: + module Numeric #:nodoc: + # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years. + # + # If you need precise date calculations that doesn't just treat months as 30 days, then have + # a look at Time#advance. + # + # Some of these methods are approximations, Ruby's core + # Date[http://stdlib.rubyonrails.org/libdoc/date/rdoc/index.html] and + # Time[http://stdlib.rubyonrails.org/libdoc/time/rdoc/index.html] should be used for precision + # date and time arithmetic + module Time + def seconds + self + end + alias :second :seconds + + def minutes + self * 60 + end + alias :minute :minutes + + def hours + self * 60.minutes + end + alias :hour :hours + + def days + self * 24.hours + end + alias :day :days + + def weeks + self * 7.days + end + alias :week :weeks + + def fortnights + self * 2.weeks + end + alias :fortnight :fortnights + + def months + self * 30.days + end + alias :month :months + + def years + (self * 365.25.days).to_i + end + alias :year :years + + # Reads best without arguments: 10.minutes.ago + def ago(time = ::Time.now) + time - self + end + + # Reads best with argument: 10.minutes.until(time) + alias :until :ago + + # Reads best with argument: 10.minutes.since(time) + def since(time = ::Time.now) + time + self + end + + # Reads best without arguments: 10.minutes.from_now + alias :from_now :since + end + end + end +end + +class Numeric #:nodoc: + include ActiveSupport::CoreExtensions::Numeric::Time +end diff --git a/vendor/plugins/rfpdf/CHANGELOG b/vendor/plugins/rfpdf/CHANGELOG new file mode 100644 index 000000000..6822b8364 --- /dev/null +++ b/vendor/plugins/rfpdf/CHANGELOG @@ -0,0 +1,13 @@ +1.00 Added view template functionality +1.10 Added Chinese support +1.11 Added Japanese support +1.12 Added Korean support +1.13 Updated to fpdf.rb 1.53d. + Added makefont and fpdf_eps. + Handle \n at the beginning of a string in MultiCell. + Tried to fix clipping issue in MultiCell - still needs some work. +1.14 2006-09-26 +* Added support for @options_for_rfpdf hash for configuration: + * Added :filename option in this hash +If you're using the same settings for @options_for_rfpdf often, you might want to +put your assignment in a before_filter (perhaps overriding :filename, etc in your actions). diff --git a/vendor/plugins/rfpdf/MIT-LICENSE b/vendor/plugins/rfpdf/MIT-LICENSE new file mode 100644 index 000000000..f39a79dc0 --- /dev/null +++ b/vendor/plugins/rfpdf/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2006 4ssoM LLC + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND +NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/plugins/rfpdf/README b/vendor/plugins/rfpdf/README new file mode 100644 index 000000000..9db19075b --- /dev/null +++ b/vendor/plugins/rfpdf/README @@ -0,0 +1,99 @@ += RFPDF Template Plugin + +A template plugin allowing the inclusion of ERB-enabled RFPDF template files. + +== Example .rb method Usage + +In the controller, something like: + + def mypdf + pdf = FPDF.new() + + # + # Chinese + # + pdf.extend(PDF_Chinese) + pdf.AddPage + pdf.AddBig5Font + pdf.SetFont('Big5','',18) + pdf.Write(5, '²{®É®ð·Å 18 C Àã«× 83 %') + icBig5 = Iconv.new('Big5', 'UTF-8') + pdf.Write(15, icBig5.iconv("宋体 should be working")) + send_data pdf.Output, :filename => "something.pdf", :type => "application/pdf" + end + +== Example .rfdf Usage + +In the controller, something like: + + def mypdf + @options_for_rfpdf ||= {} + @options_for_rfpdf[:file_name] = "nice_looking.pdf" + end + +In the layout (make sure this is the only item in the layout): +<%= @content_for_layout %> + +In the view (mypdf.rfpdf): + +<% + pdf = FPDF.new() + # + # Chinese + # + pdf.extend(PDF_Chinese) + pdf.AddPage + pdf.AddBig5Font + pdf.SetFont('Big5','',18) + pdf.Write(5, '²{®É®ð·Å 18 C Àã«× 83 %') + icBig5 = Iconv.new('Big5', 'UTF-8') + pdf.Write(15, icBig5.iconv("宋体 should be working")) + + # + # Japanese + # + pdf.extend(PDF_Japanese) + pdf.AddSJISFont(); + pdf.AddPage(); + pdf.SetFont('SJIS','',18); + pdf.Write(5,'9ÉñåéÇÃåˆäJÉeÉXÉgÇåoǃPHP 3.0ÇÕ1998îN6åéÇ…åˆéÆÇ…ÉäÉäÅ[ÉXÇ≥ÇÍNjǵÇΩÅB'); + icSJIS = Iconv.new('SJIS', 'UTF-8') + pdf.Write(15, icSJIS.iconv("これはテキストである should be working")) + + # + # Korean + # + pdf.extend(PDF_Korean) + pdf.AddUHCFont(); + pdf.AddPage(); + pdf.SetFont('UHC','',18); + pdf.Write(5,'PHP 3.0Àº 1998³â 6¿ù¿¡ °ø½ÄÀûÀ¸·Î ¸±¸®ÁîµÇ¾ú´Ù. °ø°³ÀûÀÎ Å×½ºÆ® ÀÌÈľà 9°³¿ù¸¸À̾ú´Ù.'); + icUHC = Iconv.new('UHC', 'UTF-8') + pdf.Write(15, icUHC.iconv("이것은 원본 이다")) + + # + # English + # + pdf.AddPage(); + pdf.SetFont('Arial', '', 10) + pdf.Write(5, "should be working") +%> +<%= pdf.Output() %> + + +== Configuring + +You can configure Rfpdf by using an @options_for_rfpdf hash in your controllers. + +Here are a few options: + +:filename (default: action_name.pdf) + Filename of PDF to generate + +Note: If you're using the same settings for @options_for_rfpdf often, you might want to +put your assignment in a before_filter (perhaps overriding :filename, etc in your actions). + +== Problems + +Layouts and partials are currently not supported; just need +to wrap the PDF generation differently. diff --git a/vendor/plugins/rfpdf/init.rb b/vendor/plugins/rfpdf/init.rb new file mode 100644 index 000000000..7e51d9eba --- /dev/null +++ b/vendor/plugins/rfpdf/init.rb @@ -0,0 +1,3 @@ +require 'rfpdf' + +ActionView::Base::register_template_handler 'rfpdf', RFPDF::View \ No newline at end of file diff --git a/vendor/plugins/rfpdf/lib/rfpdf.rb b/vendor/plugins/rfpdf/lib/rfpdf.rb new file mode 100644 index 000000000..9fc0683ef --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf.rb @@ -0,0 +1,31 @@ +# Copyright (c) 2006 4ssoM LLC +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +$LOAD_PATH.unshift(File.dirname(__FILE__)) + +require 'rfpdf/errors' +require 'rfpdf/view' +require 'rfpdf/fpdf' +require 'rfpdf/rfpdf' +require 'rfpdf/chinese' +require 'rfpdf/japanese' +require 'rfpdf/korean' diff --git a/vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb b/vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb new file mode 100644 index 000000000..a04ccd18d --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb @@ -0,0 +1,99 @@ +# Translation of the bookmark class from the PHP FPDF script from Olivier Plathey +# Translated by Sylvain Lafleur and ?? with the help of Brian Ollenberger +# +# First added in 1.53b +# +# Usage is as follows: +# +# require 'fpdf' +# require 'bookmark' +# pdf = FPDF.new +# pdf.extend(PDF_Bookmark) +# +# This allows it to be combined with other extensions, such as the Chinese +# module. + +module PDF_Bookmark + def PDF_Bookmark.extend_object(o) + o.instance_eval('@outlines,@OutlineRoot=[],0') + super(o) + end + + def Bookmark(txt,level=0,y=0) + y=self.GetY() if y==-1 + @outlines.push({'t'=>txt,'l'=>level,'y'=>y,'p'=>self.PageNo()}) + end + + def putbookmarks + @nb=@outlines.size + return if @nb==0 + lru=[] + level=0 + @outlines.each_index do |i| + o=@outlines[i] + if o['l']>0 + parent=lru[o['l']-1] + # Set parent and last pointers + @outlines[i]['parent']=parent + @outlines[parent]['last']=i + if o['l']>level + # Level increasing: set first pointer + @outlines[parent]['first']=i + end + else + @outlines[i]['parent']=@nb + end + if o['l']<=level and i>0 + # Set prev and next pointers + prev=lru[o['l']] + @outlines[prev]['next']=i + @outlines[i]['prev']=prev + end + lru[o['l']]=i + level=o['l'] + end + # Outline items + n=@n+1 + @outlines.each_index do |i| + o=@outlines[i] + newobj + out('<>') + out('endobj') + end + # Outline root + newobj + @OutlineRoot=@n + out('<>') + out('endobj') + end + + def putresources + super + putbookmarks + end + + def putcatalog + super + if not @outlines.empty? + out('/Outlines '+@OutlineRoot.to_s+' 0 R') + out('/PageMode /UseOutlines') + end + end +end diff --git a/vendor/plugins/rfpdf/lib/rfpdf/chinese.rb b/vendor/plugins/rfpdf/lib/rfpdf/chinese.rb new file mode 100644 index 000000000..731d582a2 --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/chinese.rb @@ -0,0 +1,473 @@ +# Copyright (c) 2006 4ssoM LLC +# 1.12 contributed by Ed Moss. +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# This is direct port of chinese.php +# +# Chinese PDF support. +# +# Usage is as follows: +# +# require 'fpdf' +# require 'chinese' +# pdf = FPDF.new +# pdf.extend(PDF_Chinese) +# +# This allows it to be combined with other extensions, such as the bookmark +# module. + +module PDF_Chinese + + Big5_widths={' '=>250,'!'=>250,'"'=>408,'#'=>668,''=>490,'%'=>875,'&'=>698,'\''=>250, + '('=>240,')'=>240,'*'=>417,'+'=>667,','=>250,'-'=>313,'.'=>250,'/'=>520,'0'=>500,'1'=>500, + '2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>250,''=>250, + '<'=>667,'='=>667,'>'=>667,'?'=>396,'@'=>921,'A'=>677,'B'=>615,'C'=>719,'D'=>760,'E'=>625, + 'F'=>552,'G'=>771,'H'=>802,'I'=>354,'J'=>354,'K'=>781,'L'=>604,'M'=>927,'N'=>750,'O'=>823, + 'P'=>563,'Q'=>823,'R'=>729,'S'=>542,'T'=>698,'U'=>771,'V'=>729,'W'=>948,'X'=>771,'Y'=>677, + 'Z'=>635,'['=>344,'\\'=>520,']'=>344,'^'=>469,'_'=>500,'`'=>250,'a'=>469,'b'=>521,'c'=>427, + 'd'=>521,'e'=>438,'f'=>271,'g'=>469,'h'=>531,'i'=>250,'j'=>250,'k'=>458,'l'=>240,'m'=>802, + 'n'=>531,'o'=>500,'p'=>521,'q'=>521,'r'=>365,'s'=>333,'t'=>292,'u'=>521,'v'=>458,'w'=>677, + 'x'=>479,'y'=>458,'z'=>427,'{'=>480,'|'=>496,'end'=>480,'~'=>667} + + GB_widths={' '=>207,'!'=>270,'"'=>342,'#'=>467,''=>462,'%'=>797,'&'=>710,'\''=>239, + '('=>374,')'=>374,'*'=>423,'+'=>605,','=>238,'-'=>375,'.'=>238,'/'=>334,'0'=>462,'1'=>462, + '2'=>462,'3'=>462,'4'=>462,'5'=>462,'6'=>462,'7'=>462,'8'=>462,'9'=>462,':'=>238,''=>238, + '<'=>605,'='=>605,'>'=>605,'?'=>344,'@'=>748,'A'=>684,'B'=>560,'C'=>695,'D'=>739,'E'=>563, + 'F'=>511,'G'=>729,'H'=>793,'I'=>318,'J'=>312,'K'=>666,'L'=>526,'M'=>896,'N'=>758,'O'=>772, + 'P'=>544,'Q'=>772,'R'=>628,'S'=>465,'T'=>607,'U'=>753,'V'=>711,'W'=>972,'X'=>647,'Y'=>620, + 'Z'=>607,'['=>374,'\\'=>333,']'=>374,'^'=>606,'_'=>500,'`'=>239,'a'=>417,'b'=>503,'c'=>427, + 'd'=>529,'e'=>415,'f'=>264,'g'=>444,'h'=>518,'i'=>241,'j'=>230,'k'=>495,'l'=>228,'m'=>793, + 'n'=>527,'o'=>524,'p'=>524,'q'=>504,'r'=>338,'s'=>336,'t'=>277,'u'=>517,'v'=>450,'w'=>652, + 'x'=>466,'y'=>452,'z'=>407,'{'=>370,'|'=>258,'end'=>370,'~'=>605} + + def AddCIDFont(family,style,name,cw,cMap,registry) +#ActionController::Base::logger.debug registry.to_a.join(":").to_s + fontkey=family.downcase+style.upcase + unless @fonts[fontkey].nil? + Error("Font already added: family style") + end + i=@fonts.length+1 + name=name.gsub(' ','') + @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw, 'CMap'=>cMap,'registry'=>registry} + end + + def AddCIDFonts(family,name,cw,cMap,registry) + AddCIDFont(family,'',name,cw,cMap,registry) + AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) + AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) + AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) + end + + def AddBig5Font(family='Big5',name='MSungStd-Light-Acro') + #Add Big5 font with proportional Latin + cw=Big5_widths + cMap='ETenms-B5-H' + registry={'ordering'=>'CNS1','supplement'=>0} +#ActionController::Base::logger.debug registry.to_a.join(":").to_s + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddBig5hwFont(family='Big5-hw',name='MSungStd-Light-Acro') + #Add Big5 font with half-witdh Latin + cw = {} + 32.upto(126) do |i| + cw[i.chr]=500 + end + cMap='ETen-B5-H' + registry={'ordering'=>'CNS1','supplement'=>0} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddGBFont(family='GB',name='STSongStd-Light-Acro') + #Add GB font with proportional Latin + cw=GB_widths + cMap='GBKp-EUC-H' + registry={'ordering'=>'GB1','supplement'=>2} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddGBhwFont(family='GB-hw',name='STSongStd-Light-Acro') + #Add GB font with half-width Latin + 32.upto(126) do |i| + cw[i.chr]=500 + end + cMap='GBK-EUC-H' + registry={'ordering'=>'GB1','supplement'=>2} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def GetStringWidth(s) + if(@CurrentFont['type']=='Type0') + return GetMBStringWidth(s) + else + return super(s) + end + end + + def GetMBStringWidth(s) + #Multi-byte version of GetStringWidth() + l=0 + cw=@CurrentFont['cw'] + nb=s.length + i=0 + while(i0 and s[nb-1]=="\n") + nb-=1 + end + b=0 + if(border) + if(border==1) + border='LTRB' + b='LRT' + b2='LR' + else + b2='' + if(border.index('L').nil?) + b2+='L' + end + if(border.index('R').nil?) + b2+='R' + end + b=border.index('T').nil? ? b2+'T' : b2 + end + end + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(iwmax) + #Automatic line break + if(sep==-1 or i==j) + if(i==j) + i+=ascii ? 1 : 2 + end + Cell(w,h,s[j,i-j],b,2,align,fill) + else + Cell(w,h,s[j,sep-j],b,2,align,fill) + i=(s[sep]==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 +# nl+=1 + if(border and nl==2) + b=b2 + end + else + i+=ascii ? 1 : 2 + end + end + #Last chunk + if(border and not border.index('B').nil?) + b+='B' + end + Cell(w,h,s[j,i-j],b,2,align,fill) + @x=@lMargin + end + + def Write(h,txt,link='') + if(@CurrentFont['type']=='Type0') + MBWrite(h,txt,link) + else + super(h,txt,link) + end + end + + def MBWrite(h,txt,link) + #Multi-byte version of Write() + cw=@CurrentFont['cw'] + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + s=txt.gsub("\r",'') + nb=s.length + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(iwmax) + #Automatic line break + if(sep==-1 or i==j) + if(@x>@lMargin) + #Move to next line + @x=@lMargin + @y+=h + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + i+=1 + nl+=1 + next + end + if(i==j) + i+=ascii ? 1 : 2 + end + Cell(w,h,s[j,i-j],0,2,'',0,link) + else + Cell(w,h,s[j,sep-j],0,2,'',0,link) + i=(s[sep]==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + if(nl==1) + @x=@lMargin + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + end + nl+=1 + else + i+=ascii ? 1 : 2 + end + end + #Last chunk + if(i!=j) + Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link) + end + end + +private + + def putfonts() + nf=@n + @diffs.each do |diff| + #Encodings + newobj() + out('<>') + out('endobj') + end + # mqr=get_magic_quotes_runtime() + # set_magic_quotes_runtime(0) + @FontFiles.each_pair do |file, info| + #Font file embedding + newobj() + @FontFiles[file]['n']=@n + if(defined('FPDF_FONTPATH')) + file=FPDF_FONTPATH+file + end + size=filesize(file) + if(!size) + Error('Font file not found') + end + out('<>') + f=fopen(file,'rb') + putstream(fread(f,size)) + fclose(f) + out('endobj') + end +# + # set_magic_quotes_runtime(mqr) +# + @fonts.each_pair do |k, font| + #Font objects + newobj() + @fonts[k]['n']=@n + out('<>') + out('endobj') + if(font['type']!='core') + #Widths + newobj() + cw=font['cw'] + s='[' + 32.upto(255) do |i| + s+=cw[i.chr]+' ' + end + out(s+']') + out('endobj') + #Descriptor + newobj() + s='<>') + out('endobj') + end + end + end + end + + def putType0(font) + #Type0 + out('/Subtype /Type0') + out('/BaseFont /'+font['name']+'-'+font['CMap']) + out('/Encoding /'+font['CMap']) + out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') + out('>>') + out('endobj') + #CIDFont + newobj() + out('<>') + out('/FontDescriptor '+(@n+1).to_s+' 0 R') + if(font['CMap']=='ETen-B5-H') + w='13648 13742 500' + elsif(font['CMap']=='GBK-EUC-H') + w='814 907 500 7716 [500]' + else + # ActionController::Base::logger.debug font['cw'].keys.sort.join(' ').to_s + # ActionController::Base::logger.debug font['cw'].values.join(' ').to_s + w='1 [' + font['cw'].keys.sort.each {|key| + w+=font['cw'][key].to_s + " " +# ActionController::Base::logger.debug key.to_s +# ActionController::Base::logger.debug font['cw'][key].to_s + } + w +=']' + end + out('/W ['+w+']>>') + out('endobj') + #Font descriptor + newobj() + out('<>') + out('endobj') + end +end diff --git a/vendor/plugins/rfpdf/lib/rfpdf/errors.rb b/vendor/plugins/rfpdf/lib/rfpdf/errors.rb new file mode 100644 index 000000000..2be2dae16 --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/errors.rb @@ -0,0 +1,4 @@ +module RFPDF + class GenerationError < StandardError #:nodoc: + end +end \ No newline at end of file diff --git a/vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb b/vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb new file mode 100644 index 000000000..ad52e9e62 --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb @@ -0,0 +1,1550 @@ +# Ruby FPDF 1.53d +# FPDF 1.53 by Olivier Plathey ported to Ruby by Brian Ollenberger +# Copyright 2005 Brian Ollenberger +# Please retain this entire copyright notice. If you distribute any +# modifications, place an additional comment here that clearly indicates +# that it was modified. You may (but are not send any useful modifications that you make +# back to me at http://zeropluszero.com/software/fpdf/ + +# Bug fixes, examples, external fonts, JPEG support, and upgrade to version +# 1.53 contributed by Kim Shrier. +# +# Bookmark support contributed by Sylvain Lafleur. +# +# EPS support contributed by Thiago Jackiw, ported from the PHP version by Valentin Schmidt. +# +# Bookmarks contributed by Sylvain Lafleur. +# +# 1.53 contributed by Ed Moss +# Handle '\n' at the beginning of a string +# Bookmarks contributed by Sylvain Lafleur. + +require 'date' +require 'zlib' + +class FPDF + FPDF_VERSION = '1.53d' + + Charwidths = { + 'courier'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], + + 'courierB'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], + + 'courierI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], + + 'courierBI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], + + 'helvetica'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500], + + 'helveticaB'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556], + + 'helveticaI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500], + + 'helveticaBI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556], + + 'times'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500, 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 350, 500, 350, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 350, 611, 350, 350, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333, 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500, 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500], + + 'timesB'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500, 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 350, 667, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333, 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500], + + 'timesI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500, 920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722, 611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500, 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500, 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 350, 500, 350, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 350, 556, 350, 350, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 350, 389, 556, 250, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 333, 760, 333, 400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500, 611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500, 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444], + + 'timesBI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722, 611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500, 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500, 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 350, 611, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 389, 611, 250, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 333, 747, 333, 400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500, 667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444], + + 'symbol'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444, 549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722, 768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500, 500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549, 549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 750, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603, 400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658, 823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713, 768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603, 494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494, 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0], + + 'zapfdingbats'=>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933, 911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537, 577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831, 923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826, 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762, 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0, 390, 390, 317, 317, 276, 276, 509, 509, 410, 410, 234, 234, 334, 334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834, 873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874, 0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0] + } + + def initialize(orientation='P', unit='mm', format='A4') + # Initialization of properties + @page=0 + @n=2 + @buffer='' + @pages=[] + @OrientationChanges=[] + @state=0 + @fonts={} + @FontFiles={} + @diffs=[] + @images={} + @links=[] + @PageLinks={} + @InFooter=false + @FontFamily='' + @FontStyle='' + @FontSizePt=12 + @underline= false + @DrawColor='0 G' + @FillColor='0 g' + @TextColor='0 g' + @ColorFlag=false + @ws=0 + @offsets=[] + + # Standard fonts + @CoreFonts={} + @CoreFonts['courier']='Courier' + @CoreFonts['courierB']='Courier-Bold' + @CoreFonts['courierI']='Courier-Oblique' + @CoreFonts['courierBI']='Courier-BoldOblique' + @CoreFonts['helvetica']='Helvetica' + @CoreFonts['helveticaB']='Helvetica-Bold' + @CoreFonts['helveticaI']='Helvetica-Oblique' + @CoreFonts['helveticaBI']='Helvetica-BoldOblique' + @CoreFonts['times']='Times-Roman' + @CoreFonts['timesB']='Times-Bold' + @CoreFonts['timesI']='Times-Italic' + @CoreFonts['timesBI']='Times-BoldItalic' + @CoreFonts['symbol']='Symbol' + @CoreFonts['zapfdingbats']='ZapfDingbats' + + # Scale factor + if unit=='pt' + @k=1 + elsif unit=='mm' + @k=72/25.4 + elsif unit=='cm' + @k=72/2.54; + elsif unit=='in' + @k=72 + else + raise 'Incorrect unit: '+unit + end + + # Page format + if format.is_a? String + format.downcase! + if format=='a3' + format=[841.89,1190.55] + elsif format=='a4' + format=[595.28,841.89] + elsif format=='a5' + format=[420.94,595.28] + elsif format=='letter' + format=[612,792] + elsif format=='legal' + format=[612,1008] + else + raise 'Unknown page format: '+format + end + @fwPt,@fhPt=format + else + @fwPt=format[0]*@k + @fhPt=format[1]*@k + end + @fw=@fwPt/@k; + @fh=@fhPt/@k; + + # Page orientation + orientation.downcase! + if orientation=='p' or orientation=='portrait' + @DefOrientation='P' + @wPt=@fwPt + @hPt=@fhPt + elsif orientation=='l' or orientation=='landscape' + @DefOrientation='L' + @wPt=@fhPt + @hPt=@fwPt + else + raise 'Incorrect orientation: '+orientation + end + @CurOrientation=@DefOrientation + @w=@wPt/@k + @h=@hPt/@k + + # Page margins (1 cm) + margin=28.35/@k + SetMargins(margin,margin) + # Interior cell margin (1 mm) + @cMargin=margin/10 + # Line width (0.2 mm) + @LineWidth=0.567/@k + # Automatic page break + SetAutoPageBreak(true,2*margin) + # Full width display mode + SetDisplayMode('fullwidth') + # Enable compression + SetCompression(true) + # Set default PDF version number + @PDFVersion='1.3' + end + + def SetMargins(left, top, right=-1) + # Set left, top and right margins + @lMargin=left + @tMargin=top + right=left if right==-1 + @rMargin=right + end + + def SetLeftMargin(margin) + # Set left margin + @lMargin=margin + @x=margin if @page>0 and @x0 + # Page footer + @InFooter=true + self.Footer + @InFooter=false + # Close page + endpage + end + # Start new page + beginpage(orientation) + # Set line cap style to square + out('2 J') + # Set line width + @LineWidth=lw + out(sprintf('%.2f w',lw*@k)) + # Set font + SetFont(family,style,size) if family + # Set colors + @DrawColor=dc + out(dc) if dc!='0 G' + @FillColor=fc + out(fc) if fc!='0 g' + @TextColor=tc + @ColorFlag=cf + # Page header + self.Header + # Restore line width + if @LineWidth!=lw + @LineWidth=lw + out(sprintf('%.2f w',lw*@k)) + end + # Restore font + self.SetFont(family,style,size) if family + # Restore colors + if @DrawColor!=dc + @DrawColor=dc + out(dc) + end + if @FillColor!=fc + @FillColor=fc + out(fc) + end + @TextColor=tc + @ColorFlag=cf + end + + def Header + # To be implemented in your inherited class + end + + def Footer + # To be implemented in your inherited class + end + + def PageNo + # Get current page number + @page + end + + def SetDrawColor(r,g=-1,b=-1) + # Set color for all stroking operations + if (r==0 and g==0 and b==0) or g==-1 + @DrawColor=sprintf('%.3f G',r/255.0) + else + @DrawColor=sprintf('%.3f %.3f %.3f RG',r/255.0,g/255.0,b/255.0) + end + out(@DrawColor) if(@page>0) + end + + def SetFillColor(r,g=-1,b=-1) + # Set color for all filling operations + if (r==0 and g==0 and b==0) or g==-1 + @FillColor=sprintf('%.3f g',r/255.0) + else + @FillColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0) + end + @ColorFlag=(@FillColor!=@TextColor) + out(@FillColor) if(@page>0) + end + + def SetTextColor(r,g=-1,b=-1) + # Set color for text + if (r==0 and g==0 and b==0) or g==-1 + @TextColor=sprintf('%.3f g',r/255.0) + else + @TextColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0) + end + @ColorFlag=(@FillColor!=@TextColor) + end + + def GetStringWidth(s) + # Get width of a string in the current font + cw=@CurrentFont['cw'] + w=0 + s.each_byte do |c| + w=w+cw[c] + end + w*@FontSize/1000.0 + end + + def SetLineWidth(width) + # Set line width + @LineWidth=width + out(sprintf('%.2f w',width*@k)) if @page>0 + end + + def Line(x1, y1, x2, y2) + # Draw a line + out(sprintf('%.2f %.2f m %.2f %.2f l S', + x1*@k,(@h-y1)*@k,x2*@k,(@h-y2)*@k)) + end + + def Rect(x, y, w, h, style='') + # Draw a rectangle + if style=='F' + op='f' + elsif style=='FD' or style=='DF' + op='B' + else + op='S' + end + out(sprintf('%.2f %.2f %.2f %.2f re %s', x*@k,(@h-y)*@k,w*@k,-h*@k,op)) + end + + def AddFont(family, style='', file='') + # Add a TrueType or Type1 font + family = family.downcase + family = 'helvetica' if family == 'arial' + + style = style.upcase + style = 'BI' if style == 'IB' + + fontkey = family + style + + if @fonts.has_key?(fontkey) + self.Error("Font already added: #{family} #{style}") + end + + file = family.gsub(' ', '') + style.downcase + '.rb' if file == '' + + if self.class.const_defined? 'FPDF_FONTPATH' + if FPDF_FONTPATH[-1,1] == '/' + file = FPDF_FONTPATH + file + else + file = FPDF_FONTPATH + '/' + file + end + end + + # Changed from "require file" to fix bug reported by Hans Allis. + load file + + if FontDef.desc.nil? + self.Error("Could not include font definition file #{file}") + end + + i = @fonts.length + 1 + + @fonts[fontkey] = {'i' => i, + 'type' => FontDef.type, + 'name' => FontDef.name, + 'desc' => FontDef.desc, + 'up' => FontDef.up, + 'ut' => FontDef.ut, + 'cw' => FontDef.cw, + 'enc' => FontDef.enc, + 'file' => FontDef.file + } + + if FontDef.diff + # Search existing encodings + unless @diffs.include?(FontDef.diff) + @diffs.push(FontDef.diff) + @fonts[fontkey]['diff'] = @diffs.length - 1 + end + end + + if FontDef.file + if FontDef.type == 'TrueType' + @FontFiles[FontDef.file] = {'length1' => FontDef.originalsize} + else + @FontFiles[FontDef.file] = {'length1' => FontDef.size1, 'length2' => FontDef.size2} + end + end + + return self + end + + def SetFont(family, style='', size=0) + # Select a font; size given in points + family.downcase! + family=@FontFamily if family=='' + if family=='arial' + family='helvetica' + elsif family=='symbol' or family=='zapfdingbats' + style='' + end + style.upcase! + unless style.index('U').nil? + @underline=true + style.gsub!('U','') + else + @underline=false; + end + style='BI' if style=='IB' + size=@FontSizePt if size==0 + # Test if font is already selected + return if @FontFamily==family and + @FontStyle==style and @FontSizePt==size + # Test if used for the first time + fontkey=family+style + unless @fonts.has_key?(fontkey) + if @CoreFonts.has_key?(fontkey) + unless Charwidths.has_key?(fontkey) + raise 'Font unavailable' + end + @fonts[fontkey]={ + 'i'=>@fonts.size, + 'type'=>'core', + 'name'=>@CoreFonts[fontkey], + 'up'=>-100, + 'ut'=>50, + 'cw'=>Charwidths[fontkey]} + else + raise 'Font unavailable' + end + end + + #Select it + @FontFamily=family + @FontStyle=style; + @FontSizePt=size + @FontSize=size/@k; + @CurrentFont=@fonts[fontkey] + if @page>0 + out(sprintf('BT /F%d %.2f Tf ET', @CurrentFont['i'], @FontSizePt)) + end + end + + def SetFontSize(size) + # Set font size in points + return if @FontSizePt==size + @FontSizePt=size + @FontSize=size/@k + if @page>0 + out(sprintf('BT /F%d %.2f Tf ET',@CurrentFont['i'],@FontSizePt)) + end + end + + def AddLink + # Create a new internal link + @links.push([0, 0]) + @links.size + end + + def SetLink(link, y=0, page=-1) + # Set destination of internal link + y=@y if y==-1 + page=@page if page==-1 + @links[link]=[page, y] + end + + def Link(x, y, w, h, link) + # Put a link on the page + @PageLinks[@page]=Array.new unless @PageLinks.has_key?(@Page) + @PageLinks[@page].push([x*@k,@hPt-y*@k,w*@k,h*@k,link]) + end + + def Text(x, y, txt) + # Output a string + txt.gsub!(')', '\\)') + txt.gsub!('(', '\\(') + txt.gsub!('\\', '\\\\') + s=sprintf('BT %.2f %.2f Td (%s) Tj ET',x*@k,(@h-y)*@k,txt); + s=s+' '+dounderline(x,y,txt) if @underline and txt!='' + s='q '+@TextColor+' '+s+' Q' if @ColorFlag + out(s) + end + + def AcceptPageBreak + # Accept automatic page break or not + @AutoPageBreak + end + + def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='') + # Output a cell + if @y+h>@PageBreakTrigger and !@InFooter and self.AcceptPageBreak + # Automatic page break + x=@x + ws=@ws + if ws>0 + @ws=0 + out('0 Tw') + end + self.AddPage(@CurOrientation) + @x=x + if ws>0 + @ws=ws + out(sprintf('%.3f Tw',ws*@k)) + end + end + w=@w-@rMargin-@x if w==0 + s='' + if fill==1 or border==1 + if fill==1 + op=(border==1) ? 'B' : 'f' + else + op='S' + end + s=sprintf('%.2f %.2f %.2f %.2f re %s ',@x*@k,(@h-@y)*@k,w*@k,-h*@k,op) + end + if border.is_a? String + x=@x + y=@y + unless border.index('L').nil? + s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', + x*@k,(@h-y)*@k,x*@k,(@h-(y+h))*@k) + end + unless border.index('T').nil? + s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', + x*@k,(@h-y)*@k,(x+w)*@k,(@h-y)*@k) + end + unless border.index('R').nil? + s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', + (x+w)*@k,(@h-y)*@k,(x+w)*@k,(@h-(y+h))*@k) + end + unless border.index('B').nil? + s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', + x*@k,(@h-(y+h))*@k,(x+w)*@k,(@h-(y+h))*@k) + end + end + if txt!='' + if align=='R' + dx=w-@cMargin-self.GetStringWidth(txt) + elsif align=='C' + dx=(w-self.GetStringWidth(txt))/2 + else + dx=@cMargin + end + txt = txt.gsub(')', '\\)') + txt.gsub!('(', '\\(') + txt.gsub!('\\', '\\\\') + if @ColorFlag + s=s+'q '+@TextColor+' ' + end + s=s+sprintf('BT %.2f %.2f Td (%s) Tj ET', + (@x+dx)*@k,(@h-(@y+0.5*h+0.3*@FontSize))*@k,txt) + s=s+' '+dounderline(@x+dx,@y+0.5*h+0.3*@FontSize,txt) if @underline + s=s+' Q' if @ColorFlag + if link and link != '' + Link(@x+dx,@y+0.5*h-0.5*@FontSize,GetStringWidth(txt),@FontSize,link) + end + end + out(s) if s + @lasth=h + if ln>0 + # Go to next line + @y=@y+h + @x=@lMargin if ln==1 + else + @x=@x+w + end + end + + def MultiCell(w,h,txt,border=0,align='J',fill=0) + # Output text with automatic or explicit line breaks + cw=@CurrentFont['cw'] + w=@w-@rMargin-@x if w==0 + wmax=(w-2*@cMargin)*1000/@FontSize + s=txt.gsub('\r','') + nb=s.length + nb=nb-1 if nb>0 and s[nb-1].chr=='\n' + b=0 + if border!=0 + if border==1 + border='LTRB' + b='LRT' + b2='LR' + else + b2='' + b2='L' unless border.index('L').nil? + b2=b2+'R' unless border.index('R').nil? + b=(not border.index('T').nil?) ? (b2+'T') : b2 + end + end + sep=-1 + i=0 + j=0 + l=0 + ns=0 + nl=1 + while i0 + @ws=0 + out('0 Tw') + end +#Ed Moss +# Don't let i go negative + end_i = i == 0 ? 0 : i - 1 + # Changed from s[j..i] to fix bug reported by Hans Allis. + self.Cell(w,h,s[j..end_i],b,2,align,fill) +# + i=i+1 + sep=-1 + j=i + l=0 + ns=0 + nl=nl+1 + b=b2 if border and nl==2 + else + if c==' ' + sep=i + ls=l + ns=ns+1 + end + l=l+cw[c[0]] + if l>wmax + # Automatic line break + if sep==-1 + i=i+1 if i==j + if @ws>0 + @ws=0 + out('0 Tw') + end + self.Cell(w,h,s[j..i],b,2,align,fill) +#Ed Moss +# Added so that it wouldn't print the last character of the string if it got close +#FIXME 2006-07-18 Level=0 - but it still puts out an extra new line + i += 1 +# + else + if align=='J' + @ws=(ns>1) ? (wmax-ls)/1000.0*@FontSize/(ns-1) : 0 + out(sprintf('%.3f Tw',@ws*@k)) + end + self.Cell(w,h,s[j..sep],b,2,align,fill) + i=sep+1 + end + sep=-1 + j=i + l=0 + ns=0 + nl=nl+1 + b=b2 if border and nl==2 + else + i=i+1 + end + end + end + + # Last chunk + if @ws>0 + @ws=0 + out('0 Tw') + end + b=b+'B' if border!=0 and not border.index('B').nil? + self.Cell(w,h,s[j..i],b,2,align,fill) + @x=@lMargin + end + + def Write(h,txt,link='') + # Output text in flowing mode + cw=@CurrentFont['cw'] + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + s=txt.gsub("\r",'') + nb=s.length + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while iwmax + # Automatic line break + if sep==-1 + if @x>@lMargin + # Move to next line + @x=@lMargin + @y=@y+h + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + i=i+1 + nl=nl+1 + next + end + i=i+1 if i==j + self.Cell(w,h,s[j,i-j],0,2,'',0,link) + else + self.Cell(w,h,s[j,sep-j],0,2,'',0,link) + i=sep+1 + end + sep=-1 + j=i + l=0 + if nl==1 + @x=@lMargin + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + end + nl=nl+1 + else + i=i+1 + end + end + # Last chunk + self.Cell(l/1000.0*@FontSize,h,s[j,i],0,0,'',0,link) if i!=j + end + + def Image(file,x,y,w=0,h=0,type='',link='') + # Put an image on the page + unless @images.has_key?(file) + # First use of image, get info + if type=='' + pos=file.rindex('.') + if pos.nil? + self.Error('Image file has no extension and no type was '+ + 'specified: '+file) + end + type=file[pos+1..-1] + end + type.downcase! + if type=='jpg' or type=='jpeg' + info=parsejpg(file) + elsif type=='png' + info=parsepng(file) + else + self.Error('Unsupported image file type: '+type) + end + info['i']=@images.length+1 + @images[file]=info + else + info=@images[file] + end +#Ed Moss + if(w==0 && h==0) + #Put image at 72 dpi + w=info['w']/@k; + h=info['h']/@k; + end +# + # Automatic width or height calculation + w=h*info['w']/info['h'] if w==0 + h=w*info['h']/info['w'] if h==0 + out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', + w*@k,h*@k,x*@k,(@h-(y+h))*@k,info['i'])) + Link(x,y,w,h,link) if link and link != '' + end + + def Ln(h='') + # Line feed; default value is last cell height + @x=@lMargin + if h.kind_of?(String) + @y=@y+@lasth + else + @y=@y+h + end + end + + def GetX + # Get x position + @x + end + + def SetX(x) + # Set x position + if x>=0 + @x=x + else + @x=@w+x + end + end + + def GetY + # Get y position + @y + end + + def SetY(y) + # Set y position and reset x + @x=@lMargin + if y>=0 + @y=y + else + @y=@h+y + end + end + + def SetXY(x,y) + # Set x and y positions + SetY(y) + SetX(x) + end + + def Output(file=nil) + # Output PDF to file or return as a string + + # Finish document if necessary + self.Close if(@state<3) + + if file.nil? + # Return as a string + return @buffer + else + # Save file locally + open(file,'wb') do |f| + f.write(@buffer) + end + end + end + + private + + def putpages + nb=@page + unless @AliasNbPages.nil? or @AliasNbPages=='' + # Replace number of pages + 1.upto(nb) do |n| + @pages[n].gsub!(@AliasNbPages,nb.to_s) + end + end + if @DefOrientation=='P' + wPt=@fwPt + hPt=@fhPt + else + wPt=@fhPt + hPt=@fwPt + end + filter=(@compress) ? '/Filter /FlateDecode ' : '' + 1.upto(nb) do |n| + # Page + newobj + out('<>>>' + else + l=@links[pl[4]] + h=@OrientationChanges[l[0]].nil? ? hPt : wPt + annots=annots+sprintf( + '/Dest [%d 0 R /XYZ 0 %.2f null]>>', + 1+2*l[0],h-l[1]*@k) + end + end + out(annots+']') + end + out('/Contents '+(@n+1).to_s+' 0 R>>') + out('endobj') + # Page content + p=(@compress) ? Zlib::Deflate.deflate(@pages[n]) : @pages[n] + newobj + out('<<'+filter+'/Length '+p.length.to_s+'>>') + putstream(p) + out('endobj') + end + # Pages root + @offsets[1]=@buffer.length + out('1 0 obj') + out('<>') + out('endobj') + end + + def putfonts + nf=@n + @diffs.each do |diff| + # Encodings + newobj + out('<>') + out('endobj') + end + + @FontFiles.each do |file, info| + # Font file embedding + newobj + @FontFiles[file]['n'] = @n + + if self.class.const_defined? 'FPDF_FONTPATH' then + if FPDF_FONTPATH[-1,1] == '/' then + file = FPDF_FONTPATH + file + else + file = FPDF_FONTPATH + '/' + file + end + end + + size = File.size(file) + unless File.exists?(file) + Error('Font file not found') + end + + out('<>') + open(file, 'rb') do |f| + putstream(f.read()) + end + out('endobj') + end + + file = 0 + @fonts.each do |k, font| + # Font objects + @fonts[k]['n']=@n+1 + type=font['type'] + name=font['name'] + if type=='core' + # Standard font + newobj + out('<>') + out('endobj') + elsif type=='Type1' or type=='TrueType' + # Additional Type1 or TrueType font + newobj + out('<>') + out('endobj') + # Widths + newobj + cw=font['cw'] + s='[' + 32.upto(255) do |i| + s << cw[i].to_s+' ' + end + out(s+']') + out('endobj') + # Descriptor + newobj + s='<>') + out('endobj') + else + # Allow for additional types + mtd='put'+type.downcase + unless self.respond_to?(mtd) + self.Error('Unsupported font type: '+type) + end + self.send(mtd, font) + end + end + end + + def putimages + filter=(@compress) ? '/Filter /FlateDecode ' : '' + @images.each do |file, info| + newobj + @images[file]['n']=@n + out('<>') + putstream(info['data']) + @images[file]['data']=nil + out('endobj') + # Palette + if info['cs']=='Indexed' + newobj + pal=(@compress) ? Zlib::Deflate.deflate(info['pal']) : info['pal'] + out('<<'+filter+'/Length '+pal.length.to_s+'>>') + putstream(pal) + out('endobj') + end + end + end + + def putxobjectdict + @images.each_value do |image| + out('/I'+image['i'].to_s+' '+image['n'].to_s+' 0 R') + end + end + + def putresourcedict + out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]') + out('/Font <<') + @fonts.each_value do |font| + out('/F'+font['i'].to_s+' '+font['n'].to_s+' 0 R') + end + out('>>') + out('/XObject <<') + putxobjectdict + out('>>') + end + + def putresources + putfonts + putimages + # Resource dictionary + @offsets[2]=@buffer.length + out('2 0 obj') + out('<<') + putresourcedict + out('>>') + out('endobj') + end + + def putinfo + out('/Producer '+textstring('Ruby FPDF '+FPDF_VERSION)); + unless @title.nil? + out('/Title '+textstring(@title)) + end + unless @subject.nil? + out('/Subject '+textstring(@subject)) + end + unless @author.nil? + out('/Author '+textstring(@author)) + end + unless @keywords.nil? + out('/Keywords '+textstring(@keywords)) + end + unless @creator.nil? + out('/Creator '+textstring(@creator)) + end + out('/CreationDate '+textstring('D: '+DateTime.now.to_s)) + end + + def putcatalog + out('/Type /Catalog') + out('/Pages 1 0 R') + if @ZoomMode=='fullpage' + out('/OpenAction [3 0 R /Fit]') + elsif @ZoomMode=='fullwidth' + out('/OpenAction [3 0 R /FitH null]') + elsif @ZoomMode=='real' + out('/OpenAction [3 0 R /XYZ null null 1]') + elsif not @ZoomMode.kind_of?(String) + out('/OpenAction [3 0 R /XYZ null null '+(@ZoomMode/100)+']') + end + + if @LayoutMode=='single' + out('/PageLayout /SinglePage') + elsif @LayoutMode=='continuous' + out('/PageLayout /OneColumn') + elsif @LayoutMode=='two' + out('/PageLayout /TwoColumnLeft') + end + end + + def putheader + out('%PDF-'+@PDFVersion) + end + + def puttrailer + out('/Size '+(@n+1).to_s) + out('/Root '+@n.to_s+' 0 R') + out('/Info '+(@n-1).to_s+' 0 R') + end + + def enddoc + putheader + putpages + putresources + # Info + newobj + out('<<') + putinfo + out('>>') + out('endobj') + # Catalog + newobj + out('<<') + putcatalog + out('>>') + out('endobj') + # Cross-ref + o=@buffer.length + out('xref') + out('0 '+(@n+1).to_s) + out('0000000000 65535 f ') + 1.upto(@n) do |i| + out(sprintf('%010d 00000 n ',@offsets[i])) + end + # Trailer + out('trailer') + out('<<') + puttrailer + out('>>') + out('startxref') + out(o) + out('%%EOF') + state=3 + end + + def beginpage(orientation) + @page=@page+1 + @pages[@page]='' + @state=2 + @x=@lMargin + @y=@tMargin + @lasth=0 + @FontFamily='' + # Page orientation + if orientation=='' + orientation=@DefOrientation + else + orientation=orientation[0].chr.upcase + if orientation!=@DefOrientation + @OrientationChanges[@page]=true + end + end + if orientation!=@CurOrientation + # Change orientation + if orientation=='P' + @wPt=@fwPt + @hPt=@fhPt + @w=@fw + @h=@fh + else + @wPt=@fhPt + @hPt=@fwPt + @w=@fh + @h=@fw + end + @PageBreakTrigger=@h-@bMargin + @CurOrientation=orientation + end + end + + def endpage + # End of page contents + @state=1 + end + + def newobj + # Begin a new object + @n=@n+1 + @offsets[@n]=@buffer.length + out(@n.to_s+' 0 obj') + end + + def dounderline(x,y,txt) + # Underline text + up=@CurrentFont['up'] + ut=@CurrentFont['ut'] + w=GetStringWidth(txt)+@ws*txt.count(' ') + sprintf('%.2f %.2f %.2f %.2f re f', + x*@k,(@h-(y-up/1000.0*@FontSize))*@k,w*@k,-ut/1000.0*@FontSizePt) + end + + def parsejpg(file) + # Extract info from a JPEG file + a=extractjpginfo(file) + raise "Missing or incorrect JPEG file: #{file}" if a.nil? + + if a['channels'].nil? || a['channels']==3 then + colspace='DeviceRGB' + elsif a['channels']==4 then + colspace='DeviceCMYK' + else + colspace='DeviceGray' + end + bpc= a['bits'] ? a['bits'].to_i : 8 + + # Read whole file + data = nil + open(file, 'rb') do |f| + data = f.read + end + return {'w'=>a['width'],'h'=>a['height'],'cs'=>colspace,'bpc'=>bpc,'f'=>'DCTDecode','data'=>data} + end + + def parsepng(file) + # Extract info from a PNG file + f=open(file,'rb') + # Check signature + unless f.read(8)==137.chr+'PNG'+13.chr+10.chr+26.chr+10.chr + self.Error('Not a PNG file: '+file) + end + # Read header chunk + f.read(4) + if f.read(4)!='IHDR' + self.Error('Incorrect PNG file: '+file) + end + w=freadint(f) + h=freadint(f) + bpc=f.read(1)[0] + if bpc>8 + self.Error('16-bit depth not supported: '+file) + end + ct=f.read(1)[0] + if ct==0 + colspace='DeviceGray' + elsif ct==2 + colspace='DeviceRGB' + elsif ct==3 + colspace='Indexed' + else + self.Error('Alpha channel not supported: '+file) + end + if f.read(1)[0]!=0 + self.Error('Unknown compression method: '+file) + end + if f.read(1)[0]!=0 + self.Error('Unknown filter method: '+file) + end + if f.read(1)[0]!=0 + self.Error('Interlacing not supported: '+file) + end + f.read(4) + parms='/DecodeParms <>' + # Scan chunks looking for palette, transparency and image data + pal='' + trns='' + data='' + begin + n=freadint(f) + type=f.read(4) + if type=='PLTE' + # Read palette + pal=f.read(n) + f.read(4) + elsif type=='tRNS' + # Read transparency info + t=f.read(n) + if ct==0 + trns=[t[1]] + elsif ct==2 + trns=[t[1],t[3],t[5]] + else + pos=t.index(0) + trns=[pos] unless pos.nil? + end + f.read(4) + elsif type=='IDAT' + # Read image data block + data << f.read(n) + f.read(4) + elsif type=='IEND' + break + else + f.read(n+4) + end + end while n + if colspace=='Indexed' and pal=='' + self.Error('Missing palette in '+file) + end + f.close + {'w'=>w,'h'=>h,'cs'=>colspace,'bpc'=>bpc,'f'=>'FlateDecode', + 'parms'=>parms,'pal'=>pal,'trns'=>trns,'data'=>data} + end + + def freadint(f) + # Read a 4-byte integer from file + a = f.read(4).unpack('N') + return a[0] + end + + def freadshort(f) + a = f.read(2).unpack('n') + return a[0] + end + + def freadbyte(f) + a = f.read(1).unpack('C') + return a[0] + end + + def textstring(s) + # Format a text string + '('+escape(s)+')' + end + + def escape(s) + # Add \ before \, ( and ) + s.gsub('\\','\\\\').gsub('(','\\(').gsub(')','\\)') + end + + def putstream(s) + out('stream') + out(s) + out('endstream') + end + + def out(s) + # Add a line to the document + if @state==2 + @pages[@page]=@pages[@page]+s+"\n" + else + @buffer=@buffer+s.to_s+"\n" + end + end + + # jpeg marker codes + + M_SOF0 = 0xc0 + M_SOF1 = 0xc1 + M_SOF2 = 0xc2 + M_SOF3 = 0xc3 + + M_SOF5 = 0xc5 + M_SOF6 = 0xc6 + M_SOF7 = 0xc7 + + M_SOF9 = 0xc9 + M_SOF10 = 0xca + M_SOF11 = 0xcb + + M_SOF13 = 0xcd + M_SOF14 = 0xce + M_SOF15 = 0xcf + + M_SOI = 0xd8 + M_EOI = 0xd9 + M_SOS = 0xda + + def extractjpginfo(file) + result = nil + + open(file, "rb") do |f| + marker = jpegnextmarker(f) + + if marker != M_SOI + return nil + end + + while true + marker = jpegnextmarker(f) + + case marker + when M_SOF0, M_SOF1, M_SOF2, M_SOF3, + M_SOF5, M_SOF6, M_SOF7, M_SOF9, + M_SOF10, M_SOF11, M_SOF13, M_SOF14, + M_SOF15 then + + length = freadshort(f) + + if result.nil? + result = {} + + result['bits'] = freadbyte(f) + result['height'] = freadshort(f) + result['width'] = freadshort(f) + result['channels'] = freadbyte(f) + + f.seek(length - 8, IO::SEEK_CUR) + else + f.seek(length - 2, IO::SEEK_CUR) + end + when M_SOS, M_EOI then + return result + else + length = freadshort(f) + f.seek(length - 2, IO::SEEK_CUR) + end + end + end + end + + def jpegnextmarker(f) + while true + # look for 0xff + while (c = freadbyte(f)) != 0xff + end + + c = freadbyte(f) + + if c != 0 + return c + end + end + end +end diff --git a/vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb b/vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb new file mode 100644 index 000000000..c6a224310 --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb @@ -0,0 +1,139 @@ +# Information +# +# PDF_EPS class from Valentin Schmidt ported to ruby by Thiago Jackiw (tjackiw@gmail.com) +# working for Mingle LLC (www.mingle.com) +# Release Date: July 13th, 2006 +# +# Description +# +# This script allows to embed vector-based Adobe Illustrator (AI) or AI-compatible EPS files. +# Only vector drawing is supported, not text or bitmap. Although the script was successfully +# tested with various AI format versions, best results are probably achieved with files that +# were exported in the AI3 format (tested with Illustrator CS2, Freehand MX and Photoshop CS2). +# +# ImageEps(string file, float x, float y [, float w [, float h [, string link [, boolean useBoundingBox]]]]) +# +# Same parameters as for regular FPDF::Image() method, with an additional one: +# +# useBoundingBox: specifies whether to position the bounding box (true) or the complete canvas (false) +# at location (x,y). Default value is true. +# +# First added to the Ruby FPDF distribution in 1.53c +# +# Usage is as follows: +# +# require 'fpdf' +# require 'fpdf_eps' +# pdf = FPDF.new +# pdf.extend(PDF_EPS) +# pdf.ImageEps(...) +# +# This allows it to be combined with other extensions, such as the bookmark +# module. + +module PDF_EPS + def ImageEps(file, x, y, w=0, h=0, link='', use_bounding_box=true) + data = nil + if File.exists?(file) + File.open(file, 'rb') do |f| + data = f.read() + end + else + Error('EPS file not found: '+file) + end + + # Find BoundingBox param + regs = data.scan(/%%BoundingBox: [^\r\n]*/m) + regs << regs[0].gsub(/%%BoundingBox: /, '') + if regs.size > 1 + tmp = regs[1].to_s.split(' ') + @x1 = tmp[0].to_i + @y1 = tmp[1].to_i + @x2 = tmp[2].to_i + @y2 = tmp[3].to_i + else + Error('No BoundingBox found in EPS file: '+file) + end + f_start = data.index('%%EndSetup') + f_start = data.index('%%EndProlog') if f_start === false + f_start = data.index('%%BoundingBox') if f_start === false + + data = data.slice(f_start, data.length) + + f_end = data.index('%%PageTrailer') + f_end = data.index('showpage') if f_end === false + data = data.slice(0, f_end) if f_end + + # save the current graphic state + out('q') + + k = @k + + # Translate + if use_bounding_box + dx = x*k-@x1 + dy = @hPt-@y2-y*k + else + dx = x*k + dy = -y*k + end + tm = [1,0,0,1,dx,dy] + out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', + tm[0], tm[1], tm[2], tm[3], tm[4], tm[5])) + + if w > 0 + scale_x = w/((@x2-@x1)/k) + if h > 0 + scale_y = h/((@y2-@y1)/k) + else + scale_y = scale_x + h = (@y2-@y1)/k * scale_y + end + else + if h > 0 + scale_y = $h/((@y2-@y1)/$k) + scale_x = scale_y + w = (@x2-@x1)/k * scale_x + else + w = (@x2-@x1)/k + h = (@y2-@y1)/k + end + end + + if !scale_x.nil? + # Scale + tm = [scale_x,0,0,scale_y,0,@hPt*(1-scale_y)] + out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', + tm[0], tm[1], tm[2], tm[3], tm[4], tm[5])) + end + + data.split(/\r\n|[\r\n]/).each do |line| + next if line == '' || line[0,1] == '%' + len = line.length + # next if (len > 2 && line[len-2,len] != ' ') + cmd = line[len-2,len].strip + case cmd + when 'm', 'l', 'v', 'y', 'c', 'k', 'K', 'g', 'G', 's', 'S', 'J', 'j', 'w', 'M', 'd': + out(line) + + when 'L': + line[len-1,len]='l' + out(line) + + when 'C': + line[len-1,len]='c' + out(line) + + when 'f', 'F': + out('f*') + + when 'b', 'B': + out(cmd + '*') + end + end + + # restore previous graphic state + out('Q') + Link(x,y,w,h,link) if link + end +end diff --git a/vendor/plugins/rfpdf/lib/rfpdf/japanese.rb b/vendor/plugins/rfpdf/lib/rfpdf/japanese.rb new file mode 100644 index 000000000..7340936bb --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/japanese.rb @@ -0,0 +1,468 @@ +# Copyright (c) 2006 4ssoM LLC +# 1.12 contributed by Ed Moss. +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# This is direct port of japanese.php +# +# Japanese PDF support. +# +# Usage is as follows: +# +# require 'fpdf' +# require 'chinese' +# pdf = FPDF.new +# pdf.extend(PDF_Japanese) +# +# This allows it to be combined with other extensions, such as the bookmark +# module. + +module PDF_Japanese + + SJIS_widths={' ' => 278, '!' => 299, '"' => 353, '#' => 614, '$' => 614, '%' => 721, '&' => 735, '\'' => 216, + '(' => 323, ')' => 323, '*' => 449, '+' => 529, ',' => 219, '-' => 306, '.' => 219, '/' => 453, '0' => 614, '1' => 614, + '2' => 614, '3' => 614, '4' => 614, '5' => 614, '6' => 614, '7' => 614, '8' => 614, '9' => 614, ':' => 219, ';' => 219, + '<' => 529, '=' => 529, '>' => 529, '?' => 486, '@' => 744, 'A' => 646, 'B' => 604, 'C' => 617, 'D' => 681, 'E' => 567, + 'F' => 537, 'G' => 647, 'H' => 738, 'I' => 320, 'J' => 433, 'K' => 637, 'L' => 566, 'M' => 904, 'N' => 710, 'O' => 716, + 'P' => 605, 'Q' => 716, 'R' => 623, 'S' => 517, 'T' => 601, 'U' => 690, 'V' => 668, 'W' => 990, 'X' => 681, 'Y' => 634, + 'Z' => 578, '[' => 316, '\\' => 614, ']' => 316, '^' => 529, '_' => 500, '`' => 387, 'a' => 509, 'b' => 566, 'c' => 478, + 'd' => 565, 'e' => 503, 'f' => 337, 'g' => 549, 'h' => 580, 'i' => 275, 'j' => 266, 'k' => 544, 'l' => 276, 'm' => 854, + 'n' => 579, 'o' => 550, 'p' => 578, 'q' => 566, 'r' => 410, 's' => 444, 't' => 340, 'u' => 575, 'v' => 512, 'w' => 760, + 'x' => 503, 'y' => 529, 'z' => 453, '{' => 326, '|' => 380, '}' => 326, '~' => 387} + + def AddCIDFont(family,style,name,cw,cMap,registry) + fontkey=family.downcase+style.upcase + unless @fonts[fontkey].nil? + Error("CID font already added: family style") + end + i=@fonts.length+1 + @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-120,'ut'=>40,'cw'=>cw, + 'CMap'=>cMap,'registry'=>registry} + end + + def AddCIDFonts(family,name,cw,cMap,registry) + AddCIDFont(family,'',name,cw,cMap,registry) + AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) + AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) + AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) + end + + def AddSJISFont(family='SJIS') + #Add SJIS font with proportional Latin + name='KozMinPro-Regular-Acro' + cw=SJIS_widths + cMap='90msp-RKSJ-H' + registry={'ordering'=>'Japan1','supplement'=>2} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddSJIShwFont(family='SJIS-hw') + #Add SJIS font with half-width Latin + name='KozMinPro-Regular-Acro' + 32.upto(126) do |i| + cw[i.chr]=500 + end + cMap='90ms-RKSJ-H' + registry={'ordering'=>'Japan1','supplement'=>2} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def GetStringWidth(s) + if(@CurrentFont['type']=='Type0') + return GetSJISStringWidth(s) + else + return super(s) + end + end + + def GetSJISStringWidth(s) + #SJIS version of GetStringWidth() + l=0 + cw=@CurrentFont['cw'] + nb=s.length + i=0 + while(i=161 and o<=223) + #Half-width katakana + l+=500 + i+=1 + else + #Full-width character + l+=1000 + i+=2 + end + end + return l*@FontSize/1000 + end + + def MultiCell(w,h,txt,border=0,align='L',fill=0) + if(@CurrentFont['type']=='Type0') + SJISMultiCell(w,h,txt,border,align,fill) + else + super(w,h,txt,border,align,fill) + end + end + + def SJISMultiCell(w,h,txt,border=0,align='L',fill=0) + #Output text with automatic or explicit line breaks + cw=@CurrentFont['cw'] + if(w==0) + w=@w-@rMargin-@x + end + wmax=(w-2*@cMargin)*1000/@FontSize + s=txt.gsub("\r",'') + nb=s.length + if(nb>0 and s[nb-1]=="\n") + nb-=1 + end + b=0 + if(border) + if(border==1) + border='LTRB' + b='LRT' + b2='LR' + else + b2='' + if(border.index('L').nil?) + b2+='L' + end + if(border.index('R').nil?) + b2+='R' + end + b=border.index('T').nil? ? b2+'T' : b2 + end + end + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(i=161 and o<=223) + #Half-width katakana + l+=500 + n=1 + sep=i + else + #Full-width character + l+=1000 + n=2 + sep=i + end + if(l>wmax) + #Automatic line break + if(sep==-1 or i==j) + if(i==j) + i+=n + end + Cell(w,h,s[j,i-j],b,2,align,fill) + else + Cell(w,h,s[j,sep-j],b,2,align,fill) + i=(s[sep]==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + nl+=1 + if(border and nl==2) + b=b2 + end + else + i+=n + if(o>=128) + sep=i + end + end + end + #Last chunk + if(border and not border.index('B').nil?) + b+='B' + end + Cell(w,h,s[j,i-j],b,2,align,fill) + @x=@lMargin + end + + def Write(h,txt,link='') + if(@CurrentFont['type']=='Type0') + SJISWrite(h,txt,link) + else + super(h,txt,link) + end + end + + def SJISWrite(h,txt,link) + #SJIS version of Write() + cw=@CurrentFont['cw'] + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + s=txt.gsub("\r",'') + nb=s.length + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(i=161 and o<=223) + #Half-width katakana + l+=500 + n=1 + sep=i + else + #Full-width character + l+=1000 + n=2 + sep=i + end + if(l>wmax) + #Automatic line break + if(sep==-1 or i==j) + if(@x>@lMargin) + #Move to next line + @x=@lMargin + @y+=h + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + i+=n + nl+=1 + next + end + if(i==j) + i+=n + end + Cell(w,h,s[j,i-j],0,2,'',0,link) + else + Cell(w,h,s[j,sep-j],0,2,'',0,link) + i=(s[sep]==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + if(nl==1) + @x=@lMargin + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + end + nl+=1 + else + i+=n + if(o>=128) + sep=i + end + end + end + #Last chunk + if(i!=j) + Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link) + end + end + +private + + def putfonts() + nf=@n + @diffs.each do |diff| + #Encodings + newobj() + out('<>') + out('endobj') + end + # mqr=get_magic_quotes_runtime() + # set_magic_quotes_runtime(0) + @FontFiles.each_pair do |file, info| + #Font file embedding + newobj() + @FontFiles[file]['n']=@n + if(defined('FPDF_FONTPATH')) + file=FPDF_FONTPATH+file + end + size=filesize(file) + if(!size) + Error('Font file not found') + end + out('<>') + f=fopen(file,'rb') + putstream(fread(f,size)) + fclose(f) + out('endobj') + end + # set_magic_quotes_runtime(mqr) + @fonts.each_pair do |k, font| + #Font objects + newobj() + @fonts[k]['n']=@n + out('<>') + out('endobj') + if(font['type']!='core') + #Widths + newobj() + cw=font['cw'] + s='[' + 32.upto(255) do |i| + s+=cw[i.chr]+' ' + end + out(s+']') + out('endobj') + #Descriptor + newobj() + s='<>') + out('endobj') + end + end + end + end + + def putType0(font) + #Type0 + out('/Subtype /Type0') + out('/BaseFont /'+font['name']+'-'+font['CMap']) + out('/Encoding /'+font['CMap']) + out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') + out('>>') + out('endobj') + #CIDFont + newobj() + out('<>') + out('/FontDescriptor '+(@n+1).to_s+' 0 R') + w='/W [1 [' + font['cw'].keys.sort.each {|key| + w+=font['cw'][key].to_s + " " +# ActionController::Base::logger.debug key.to_s +# ActionController::Base::logger.debug font['cw'][key].to_s + } + out(w+'] 231 325 500 631 [500] 326 389 500]') + out('>>') + out('endobj') + #Font descriptor + newobj() + out('<>') + out('endobj') + end +end diff --git a/vendor/plugins/rfpdf/lib/rfpdf/korean.rb b/vendor/plugins/rfpdf/lib/rfpdf/korean.rb new file mode 100644 index 000000000..64131405e --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/korean.rb @@ -0,0 +1,436 @@ +# Copyright (c) 2006 4ssoM LLC +# 1.12 contributed by Ed Moss. +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# This is direct port of korean.php +# +# Korean PDF support. +# +# Usage is as follows: +# +# require 'fpdf' +# require 'chinese' +# pdf = FPDF.new +# pdf.extend(PDF_Korean) +# +# This allows it to be combined with other extensions, such as the bookmark +# module. + +module PDF_Korean + +UHC_widths={' ' => 333, '!' => 416, '"' => 416, '#' => 833, '$' => 625, '%' => 916, '&' => 833, '\'' => 250, + '(' => 500, ')' => 500, '*' => 500, '+' => 833, ',' => 291, '-' => 833, '.' => 291, '/' => 375, '0' => 625, '1' => 625, + '2' => 625, '3' => 625, '4' => 625, '5' => 625, '6' => 625, '7' => 625, '8' => 625, '9' => 625, ':' => 333, ';' => 333, + '<' => 833, '=' => 833, '>' => 916, '?' => 500, '@' => 1000, 'A' => 791, 'B' => 708, 'C' => 708, 'D' => 750, 'E' => 708, + 'F' => 666, 'G' => 750, 'H' => 791, 'I' => 375, 'J' => 500, 'K' => 791, 'L' => 666, 'M' => 916, 'N' => 791, 'O' => 750, + 'P' => 666, 'Q' => 750, 'R' => 708, 'S' => 666, 'T' => 791, 'U' => 791, 'V' => 750, 'W' => 1000, 'X' => 708, 'Y' => 708, + 'Z' => 666, '[' => 500, '\\' => 375, ']' => 500, '^' => 500, '_' => 500, '`' => 333, 'a' => 541, 'b' => 583, 'c' => 541, + 'd' => 583, 'e' => 583, 'f' => 375, 'g' => 583, 'h' => 583, 'i' => 291, 'j' => 333, 'k' => 583, 'l' => 291, 'm' => 875, + 'n' => 583, 'o' => 583, 'p' => 583, 'q' => 583, 'r' => 458, 's' => 541, 't' => 375, 'u' => 583, 'v' => 583, 'w' => 833, + 'x' => 625, 'y' => 625, 'z' => 500, '{' => 583, '|' => 583, '}' => 583, '~' => 750} + + def AddCIDFont(family,style,name,cw,cMap,registry) + fontkey=family.downcase+style.upcase + unless @fonts[fontkey].nil? + Error("Font already added: family style") + end + i=@fonts.length+1 + name=name.gsub(' ','') + @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw, + 'CMap'=>cMap,'registry'=>registry} + end + + def AddCIDFonts(family,name,cw,cMap,registry) + AddCIDFont(family,'',name,cw,cMap,registry) + AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) + AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) + AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) + end + + def AddUHCFont(family='UHC',name='HYSMyeongJoStd-Medium-Acro') + #Add UHC font with proportional Latin + cw=UHC_widths + cMap='KSCms-UHC-H' + registry={'ordering'=>'Korea1','supplement'=>1} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddUHChwFont(family='UHC-hw',name='HYSMyeongJoStd-Medium-Acro') + #Add UHC font with half-witdh Latin + 32.upto(126) do |i| + cw[i.chr]=500 + end + cMap='KSCms-UHC-HW-H' + registry={'ordering'=>'Korea1','supplement'=>1} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def GetStringWidth(s) + if(@CurrentFont['type']=='Type0') + return GetMBStringWidth(s) + else + return super(s) + end + end + + def GetMBStringWidth(s) + #Multi-byte version of GetStringWidth() + l=0 + cw=@CurrentFont['cw'] + nb=s.length + i=0 + while(i0 and s[nb-1]=="\n") + nb-=1 + end + b=0 + if(border) + if(border==1) + border='LTRB' + b='LRT' + b2='LR' + else + b2='' + if(border.index('L').nil?) + b2+='L' + end + if(border.index('R').nil?) + b2+='R' + end + b=border.index('T').nil? ? b2+'T' : b2 + end + end + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(iwmax) + #Automatic line break + if(sep==-1 or i==j) + if(i==j) + i+=ascii ? 1 : 2 + end + Cell(w,h,s[j,i-j],b,2,align,fill) + else + Cell(w,h,s[j,sep-j],b,2,align,fill) + i=(s[sep]==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + nl+=1 + if(border and nl==2) + b=b2 + end + else + i+=ascii ? 1 : 2 + end + end + #Last chunk + if(border and not border.index('B').nil?) + b+='B' + end + Cell(w,h,s[j,i-j],b,2,align,fill) + @x=@lMargin + end + + def Write(h,txt,link='') + if(@CurrentFont['type']=='Type0') + MBWrite(h,txt,link) + else + super(h,txt,link) + end + end + + def MBWrite(h,txt,link) + #Multi-byte version of Write() + cw=@CurrentFont['cw'] + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + s=txt.gsub("\r",'') + nb=s.length + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(iwmax) + #Automatic line break + if(sep==-1 or i==j) + if(@x>@lMargin) + #Move to next line + @x=@lMargin + @y+=h + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + i+=1 + nl+=1 + next + end + if(i==j) + i+=ascii ? 1 : 2 + end + Cell(w,h,s[j,i-j],0,2,'',0,link) + else + Cell(w,h,s[j,sep-j],0,2,'',0,link) + i=(s[sep]==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + if(nl==1) + @x=@lMargin + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + end + nl+=1 + else + i+=ascii ? 1 : 2 + end + end + #Last chunk + if(i!=j) + Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link) + end + end + +private + + def putfonts() + nf=@n + @diffs.each do |diff| + #Encodings + newobj() + out('<>') + out('endobj') + end + # mqr=get_magic_quotes_runtime() + # set_magic_quotes_runtime(0) + @FontFiles.each_pair do |file, info| + #Font file embedding + newobj() + @FontFiles[file]['n']=@n + if(defined('FPDF_FONTPATH')) + file=FPDF_FONTPATH+file + end + size=filesize(file) + if(!size) + Error('Font file not found') + end + out('<>') + f=fopen(file,'rb') + putstream(fread(f,size)) + fclose(f) + out('endobj') + end + # set_magic_quotes_runtime(mqr) + @fonts.each_pair do |k, font| + #Font objects + newobj() + @fonts[k]['n']=@n + out('<>') + out('endobj') + if(font['type']!='core') + #Widths + newobj() + cw=font['cw'] + s='[' + 32.upto(255) do |i| + s+=cw[i.chr]+' ' + end + out(s+']') + out('endobj') + #Descriptor + newobj() + s='<>') + out('endobj') + end + end + end + end + + def putType0(font) + #Type0 + out('/Subtype /Type0') + out('/BaseFont /'+font['name']+'-'+font['CMap']) + out('/Encoding /'+font['CMap']) + out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') + out('>>') + out('endobj') + #CIDFont + newobj() + out('<>') + out('/FontDescriptor '+(@n+1).to_s+' 0 R') + if(font['CMap']=='KSCms-UHC-HW-H') + w='8094 8190 500' + else + w='1 [' + font['cw'].keys.sort.each {|key| + w+=font['cw'][key].to_s + " " + # ActionController::Base::logger.debug key.to_s + # ActionController::Base::logger.debug font['cw'][key].to_s + } + w +=']' + end + out('/W ['+w+']>>') + out('endobj') + #Font descriptor + newobj() + out('<>') + out('endobj') + end +end diff --git a/vendor/plugins/rfpdf/lib/rfpdf/makefont.rb b/vendor/plugins/rfpdf/lib/rfpdf/makefont.rb new file mode 100644 index 000000000..ffc98b48f --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/makefont.rb @@ -0,0 +1,1787 @@ +#!/usr/bin/env ruby +# +# Utility to generate font definition files +# Version: 1.1 +# Date: 2006-07-19 +# +# Changelog: +# Version 1.1 - Brian Ollenberger +# - Fixed a very small bug in MakeFont for generating FontDef.diff. + +Charencodings = { +# Central Europe + 'cp1250' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', '.notdef', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + '.notdef', 'perthousand', 'Scaron', 'guilsinglleft', + 'Sacute', 'Tcaron', 'Zcaron', 'Zacute', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', 'trademark', 'scaron', 'guilsinglright', + 'sacute', 'tcaron', 'zcaron', 'zacute', + 'space', 'caron', 'breve', 'Lslash', + 'currency', 'Aogonek', 'brokenbar', 'section', + 'dieresis', 'copyright', 'Scedilla', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'Zdotaccent', + 'degree', 'plusminus', 'ogonek', 'lslash', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'aogonek', 'scedilla', 'guillemotright', + 'Lcaron', 'hungarumlaut', 'lcaron', 'zdotaccent', + 'Racute', 'Aacute', 'Acircumflex', 'Abreve', + 'Adieresis', 'Lacute', 'Cacute', 'Ccedilla', + 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', + 'Ecaron', 'Iacute', 'Icircumflex', 'Dcaron', + 'Dcroat', 'Nacute', 'Ncaron', 'Oacute', + 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'multiply', + 'Rcaron', 'Uring', 'Uacute', 'Uhungarumlaut', + 'Udieresis', 'Yacute', 'Tcommaaccent', 'germandbls', + 'racute', 'aacute', 'acircumflex', 'abreve', + 'adieresis', 'lacute', 'cacute', 'ccedilla', + 'ccaron', 'eacute', 'eogonek', 'edieresis', + 'ecaron', 'iacute', 'icircumflex', 'dcaron', + 'dcroat', 'nacute', 'ncaron', 'oacute', + 'ocircumflex', 'ohungarumlaut', 'odieresis', 'divide', + 'rcaron', 'uring', 'uacute', 'uhungarumlaut', + 'udieresis', 'yacute', 'tcommaaccent', 'dotaccent' + ], +# Cyrillic + 'cp1251' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'afii10051', 'afii10052', 'quotesinglbase', 'afii10100', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'Euro', 'perthousand', 'afii10058', 'guilsinglleft', + 'afii10059', 'afii10061', 'afii10060', 'afii10145', + 'afii10099', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', 'trademark', 'afii10106', 'guilsinglright', + 'afii10107', 'afii10109', 'afii10108', 'afii10193', + 'space', 'afii10062', 'afii10110', 'afii10057', + 'currency', 'afii10050', 'brokenbar', 'section', + 'afii10023', 'copyright', 'afii10053', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'afii10056', + 'degree', 'plusminus', 'afii10055', 'afii10103', + 'afii10098', 'mu', 'paragraph', 'periodcentered', + 'afii10071', 'afii61352', 'afii10101', 'guillemotright', + 'afii10105', 'afii10054', 'afii10102', 'afii10104', + 'afii10017', 'afii10018', 'afii10019', 'afii10020', + 'afii10021', 'afii10022', 'afii10024', 'afii10025', + 'afii10026', 'afii10027', 'afii10028', 'afii10029', + 'afii10030', 'afii10031', 'afii10032', 'afii10033', + 'afii10034', 'afii10035', 'afii10036', 'afii10037', + 'afii10038', 'afii10039', 'afii10040', 'afii10041', + 'afii10042', 'afii10043', 'afii10044', 'afii10045', + 'afii10046', 'afii10047', 'afii10048', 'afii10049', + 'afii10065', 'afii10066', 'afii10067', 'afii10068', + 'afii10069', 'afii10070', 'afii10072', 'afii10073', + 'afii10074', 'afii10075', 'afii10076', 'afii10077', + 'afii10078', 'afii10079', 'afii10080', 'afii10081', + 'afii10082', 'afii10083', 'afii10084', 'afii10085', + 'afii10086', 'afii10087', 'afii10088', 'afii10089', + 'afii10090', 'afii10091', 'afii10092', 'afii10093', + 'afii10094', 'afii10095', 'afii10096', 'afii10097' + ], +# Western Europe + 'cp1252' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'circumflex', 'perthousand', 'Scaron', 'guilsinglleft', + 'OE', '.notdef', 'Zcaron', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + 'tilde', 'trademark', 'scaron', 'guilsinglright', + 'oe', '.notdef', 'zcaron', 'Ydieresis', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Eth', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Yacute', 'Thorn', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'eth', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'yacute', 'thorn', 'ydieresis' + ], +# Greek + 'cp1253' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + '.notdef', 'perthousand', '.notdef', 'guilsinglleft', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', 'trademark', '.notdef', 'guilsinglright', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'dieresistonos', 'Alphatonos', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', '.notdef', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'afii00208', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'tonos', 'mu', 'paragraph', 'periodcentered', + 'Epsilontonos', 'Etatonos', 'Iotatonos', 'guillemotright', + 'Omicrontonos', 'onehalf', 'Upsilontonos', 'Omegatonos', + 'iotadieresistonos','Alpha', 'Beta', 'Gamma', + 'Delta', 'Epsilon', 'Zeta', 'Eta', + 'Theta', 'Iota', 'Kappa', 'Lambda', + 'Mu', 'Nu', 'Xi', 'Omicron', + 'Pi', 'Rho', '.notdef', 'Sigma', + 'Tau', 'Upsilon', 'Phi', 'Chi', + 'Psi', 'Omega', 'Iotadieresis', 'Upsilondieresis', + 'alphatonos', 'epsilontonos', 'etatonos', 'iotatonos', + 'upsilondieresistonos','alpha', 'beta', 'gamma', + 'delta', 'epsilon', 'zeta', 'eta', + 'theta', 'iota', 'kappa', 'lambda', + 'mu', 'nu', 'xi', 'omicron', + 'pi', 'rho', 'sigma1', 'sigma', + 'tau', 'upsilon', 'phi', 'chi', + 'psi', 'omega', 'iotadieresis', 'upsilondieresis', + 'omicrontonos', 'upsilontonos', 'omegatonos', '.notdef' + ], +# Turkish + 'cp1254' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'circumflex', 'perthousand', 'Scaron', 'guilsinglleft', + 'OE', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + 'tilde', 'trademark', 'scaron', 'guilsinglright', + 'oe', '.notdef', '.notdef', 'Ydieresis', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Gbreve', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Idotaccent', 'Scedilla', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'gbreve', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'dotlessi', 'scedilla', 'ydieresis' + ], +# Hebrew + 'cp1255' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'circumflex', 'perthousand', '.notdef', 'guilsinglleft', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + 'tilde', 'trademark', '.notdef', 'guilsinglright', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclamdown', 'cent', 'sterling', + 'afii57636', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'multiply', 'guillemotleft', + 'logicalnot', 'sfthyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'middot', + 'cedilla', 'onesuperior', 'divide', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'afii57799', 'afii57801', 'afii57800', 'afii57802', + 'afii57793', 'afii57794', 'afii57795', 'afii57798', + 'afii57797', 'afii57806', '.notdef', 'afii57796', + 'afii57807', 'afii57839', 'afii57645', 'afii57841', + 'afii57842', 'afii57804', 'afii57803', 'afii57658', + 'afii57716', 'afii57717', 'afii57718', 'gereshhebrew', + 'gershayimhebrew','.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'afii57664', 'afii57665', 'afii57666', 'afii57667', + 'afii57668', 'afii57669', 'afii57670', 'afii57671', + 'afii57672', 'afii57673', 'afii57674', 'afii57675', + 'afii57676', 'afii57677', 'afii57678', 'afii57679', + 'afii57680', 'afii57681', 'afii57682', 'afii57683', + 'afii57684', 'afii57685', 'afii57686', 'afii57687', + 'afii57688', 'afii57689', 'afii57690', '.notdef', + '.notdef', 'afii299', 'afii300', '.notdef' + ], +# Baltic + 'cp1257' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', '.notdef', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + '.notdef', 'perthousand', '.notdef', 'guilsinglleft', + '.notdef', 'dieresis', 'caron', 'cedilla', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', 'trademark', '.notdef', 'guilsinglright', + '.notdef', 'macron', 'ogonek', '.notdef', + 'space', '.notdef', 'cent', 'sterling', + 'currency', '.notdef', 'brokenbar', 'section', + 'Oslash', 'copyright', 'Rcommaaccent', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'AE', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'oslash', 'onesuperior', 'rcommaaccent', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'ae', + 'Aogonek', 'Iogonek', 'Amacron', 'Cacute', + 'Adieresis', 'Aring', 'Eogonek', 'Emacron', + 'Ccaron', 'Eacute', 'Zacute', 'Edotaccent', + 'Gcommaaccent', 'Kcommaaccent', 'Imacron', 'Lcommaaccent', + 'Scaron', 'Nacute', 'Ncommaaccent', 'Oacute', + 'Omacron', 'Otilde', 'Odieresis', 'multiply', + 'Uogonek', 'Lslash', 'Sacute', 'Umacron', + 'Udieresis', 'Zdotaccent', 'Zcaron', 'germandbls', + 'aogonek', 'iogonek', 'amacron', 'cacute', + 'adieresis', 'aring', 'eogonek', 'emacron', + 'ccaron', 'eacute', 'zacute', 'edotaccent', + 'gcommaaccent', 'kcommaaccent', 'imacron', 'lcommaaccent', + 'scaron', 'nacute', 'ncommaaccent', 'oacute', + 'omacron', 'otilde', 'odieresis', 'divide', + 'uogonek', 'lslash', 'sacute', 'umacron', + 'udieresis', 'zdotaccent', 'zcaron', 'dotaccent' + ], +# Vietnamese + 'cp1258' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'circumflex', 'perthousand', '.notdef', 'guilsinglleft', + 'OE', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + 'tilde', 'trademark', '.notdef', 'guilsinglright', + 'oe', '.notdef', '.notdef', 'Ydieresis', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Abreve', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'gravecomb', 'Iacute', 'Icircumflex', 'Idieresis', + 'Dcroat', 'Ntilde', 'hookabovecomb', 'Oacute', + 'Ocircumflex', 'Ohorn', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Uhorn', 'tildecomb', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'abreve', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'acutecomb', 'iacute', 'icircumflex', 'idieresis', + 'dcroat', 'ntilde', 'dotbelowcomb', 'oacute', + 'ocircumflex', 'ohorn', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'uhorn', 'dong', 'ydieresis' + ], +# Thai + 'cp874' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', '.notdef', '.notdef', + '.notdef', 'ellipsis', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'kokaithai', 'khokhaithai', 'khokhuatthai', + 'khokhwaithai', 'khokhonthai', 'khorakhangthai', 'ngonguthai', + 'chochanthai', 'chochingthai', 'chochangthai', 'sosothai', + 'chochoethai', 'yoyingthai', 'dochadathai', 'topatakthai', + 'thothanthai', 'thonangmonthothai', 'thophuthaothai', 'nonenthai', + 'dodekthai', 'totaothai', 'thothungthai', 'thothahanthai', + 'thothongthai', 'nonuthai', 'bobaimaithai', 'poplathai', + 'phophungthai', 'fofathai', 'phophanthai', 'fofanthai', + 'phosamphaothai', 'momathai', 'yoyakthai', 'roruathai', + 'ruthai', 'lolingthai', 'luthai', 'wowaenthai', + 'sosalathai', 'sorusithai', 'sosuathai', 'hohipthai', + 'lochulathai', 'oangthai', 'honokhukthai', 'paiyannoithai', + 'saraathai', 'maihanakatthai', 'saraaathai', 'saraamthai', + 'saraithai', 'saraiithai', 'sarauethai', 'saraueethai', + 'sarauthai', 'sarauuthai', 'phinthuthai', '.notdef', + '.notdef', '.notdef', '.notdef', 'bahtthai', + 'saraethai', 'saraaethai', 'saraothai', 'saraaimaimuanthai', + 'saraaimaimalaithai', 'lakkhangyaothai', 'maiyamokthai', 'maitaikhuthai', + 'maiekthai', 'maithothai', 'maitrithai', 'maichattawathai', + 'thanthakhatthai', 'nikhahitthai', 'yamakkanthai', 'fongmanthai', + 'zerothai', 'onethai', 'twothai', 'threethai', + 'fourthai', 'fivethai', 'sixthai', 'seventhai', + 'eightthai', 'ninethai', 'angkhankhuthai', 'khomutthai', + '.notdef', '.notdef', '.notdef', '.notdef' + ], +# Western Europe + 'ISO-8859-1' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Eth', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Yacute', 'Thorn', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'eth', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'yacute', 'thorn', 'ydieresis' + ], +# Central Europe + 'ISO-8859-2' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'Aogonek', 'breve', 'Lslash', + 'currency', 'Lcaron', 'Sacute', 'section', + 'dieresis', 'Scaron', 'Scedilla', 'Tcaron', + 'Zacute', 'hyphen', 'Zcaron', 'Zdotaccent', + 'degree', 'aogonek', 'ogonek', 'lslash', + 'acute', 'lcaron', 'sacute', 'caron', + 'cedilla', 'scaron', 'scedilla', 'tcaron', + 'zacute', 'hungarumlaut', 'zcaron', 'zdotaccent', + 'Racute', 'Aacute', 'Acircumflex', 'Abreve', + 'Adieresis', 'Lacute', 'Cacute', 'Ccedilla', + 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', + 'Ecaron', 'Iacute', 'Icircumflex', 'Dcaron', + 'Dcroat', 'Nacute', 'Ncaron', 'Oacute', + 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'multiply', + 'Rcaron', 'Uring', 'Uacute', 'Uhungarumlaut', + 'Udieresis', 'Yacute', 'Tcommaaccent', 'germandbls', + 'racute', 'aacute', 'acircumflex', 'abreve', + 'adieresis', 'lacute', 'cacute', 'ccedilla', + 'ccaron', 'eacute', 'eogonek', 'edieresis', + 'ecaron', 'iacute', 'icircumflex', 'dcaron', + 'dcroat', 'nacute', 'ncaron', 'oacute', + 'ocircumflex', 'ohungarumlaut', 'odieresis', 'divide', + 'rcaron', 'uring', 'uacute', 'uhungarumlaut', + 'udieresis', 'yacute', 'tcommaaccent', 'dotaccent' + ], +# Baltic + 'ISO-8859-4' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'Aogonek', 'kgreenlandic', 'Rcommaaccent', + 'currency', 'Itilde', 'Lcommaaccent', 'section', + 'dieresis', 'Scaron', 'Emacron', 'Gcommaaccent', + 'Tbar', 'hyphen', 'Zcaron', 'macron', + 'degree', 'aogonek', 'ogonek', 'rcommaaccent', + 'acute', 'itilde', 'lcommaaccent', 'caron', + 'cedilla', 'scaron', 'emacron', 'gcommaaccent', + 'tbar', 'Eng', 'zcaron', 'eng', + 'Amacron', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Iogonek', + 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', + 'Edotaccent', 'Iacute', 'Icircumflex', 'Imacron', + 'Dcroat', 'Ncommaaccent', 'Omacron', 'Kcommaaccent', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Uogonek', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Utilde', 'Umacron', 'germandbls', + 'amacron', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'iogonek', + 'ccaron', 'eacute', 'eogonek', 'edieresis', + 'edotaccent', 'iacute', 'icircumflex', 'imacron', + 'dcroat', 'ncommaaccent', 'omacron', 'kcommaaccent', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'uogonek', 'uacute', 'ucircumflex', + 'udieresis', 'utilde', 'umacron', 'dotaccent' + ], +# Cyrillic + 'ISO-8859-5' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'afii10023', 'afii10051', 'afii10052', + 'afii10053', 'afii10054', 'afii10055', 'afii10056', + 'afii10057', 'afii10058', 'afii10059', 'afii10060', + 'afii10061', 'hyphen', 'afii10062', 'afii10145', + 'afii10017', 'afii10018', 'afii10019', 'afii10020', + 'afii10021', 'afii10022', 'afii10024', 'afii10025', + 'afii10026', 'afii10027', 'afii10028', 'afii10029', + 'afii10030', 'afii10031', 'afii10032', 'afii10033', + 'afii10034', 'afii10035', 'afii10036', 'afii10037', + 'afii10038', 'afii10039', 'afii10040', 'afii10041', + 'afii10042', 'afii10043', 'afii10044', 'afii10045', + 'afii10046', 'afii10047', 'afii10048', 'afii10049', + 'afii10065', 'afii10066', 'afii10067', 'afii10068', + 'afii10069', 'afii10070', 'afii10072', 'afii10073', + 'afii10074', 'afii10075', 'afii10076', 'afii10077', + 'afii10078', 'afii10079', 'afii10080', 'afii10081', + 'afii10082', 'afii10083', 'afii10084', 'afii10085', + 'afii10086', 'afii10087', 'afii10088', 'afii10089', + 'afii10090', 'afii10091', 'afii10092', 'afii10093', + 'afii10094', 'afii10095', 'afii10096', 'afii10097', + 'afii61352', 'afii10071', 'afii10099', 'afii10100', + 'afii10101', 'afii10102', 'afii10103', 'afii10104', + 'afii10105', 'afii10106', 'afii10107', 'afii10108', + 'afii10109', 'section', 'afii10110', 'afii10193' + ], +# Greek + 'ISO-8859-7' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'quoteleft', 'quoteright', 'sterling', + '.notdef', '.notdef', 'brokenbar', 'section', + 'dieresis', 'copyright', '.notdef', 'guillemotleft', + 'logicalnot', 'hyphen', '.notdef', 'afii00208', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'tonos', 'dieresistonos', 'Alphatonos', 'periodcentered', + 'Epsilontonos', 'Etatonos', 'Iotatonos', 'guillemotright', + 'Omicrontonos', 'onehalf', 'Upsilontonos', 'Omegatonos', + 'iotadieresistonos','Alpha', 'Beta', 'Gamma', + 'Delta', 'Epsilon', 'Zeta', 'Eta', + 'Theta', 'Iota', 'Kappa', 'Lambda', + 'Mu', 'Nu', 'Xi', 'Omicron', + 'Pi', 'Rho', '.notdef', 'Sigma', + 'Tau', 'Upsilon', 'Phi', 'Chi', + 'Psi', 'Omega', 'Iotadieresis', 'Upsilondieresis', + 'alphatonos', 'epsilontonos', 'etatonos', 'iotatonos', + 'upsilondieresistonos','alpha', 'beta', 'gamma', + 'delta', 'epsilon', 'zeta', 'eta', + 'theta', 'iota', 'kappa', 'lambda', + 'mu', 'nu', 'xi', 'omicron', + 'pi', 'rho', 'sigma1', 'sigma', + 'tau', 'upsilon', 'phi', 'chi', + 'psi', 'omega', 'iotadieresis', 'upsilondieresis', + 'omicrontonos', 'upsilontonos', 'omegatonos', '.notdef' + ], +# Turkish + 'ISO-8859-9' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Gbreve', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Idotaccent', 'Scedilla', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'gbreve', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'dotlessi', 'scedilla', 'ydieresis' + ], +# Thai + 'ISO-8859-11' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'kokaithai', 'khokhaithai', 'khokhuatthai', + 'khokhwaithai', 'khokhonthai', 'khorakhangthai', 'ngonguthai', + 'chochanthai', 'chochingthai', 'chochangthai', 'sosothai', + 'chochoethai', 'yoyingthai', 'dochadathai', 'topatakthai', + 'thothanthai', 'thonangmonthothai','thophuthaothai', 'nonenthai', + 'dodekthai', 'totaothai', 'thothungthai', 'thothahanthai', + 'thothongthai', 'nonuthai', 'bobaimaithai', 'poplathai', + 'phophungthai', 'fofathai', 'phophanthai', 'fofanthai', + 'phosamphaothai', 'momathai', 'yoyakthai', 'roruathai', + 'ruthai', 'lolingthai', 'luthai', 'wowaenthai', + 'sosalathai', 'sorusithai', 'sosuathai', 'hohipthai', + 'lochulathai', 'oangthai', 'honokhukthai', 'paiyannoithai', + 'saraathai', 'maihanakatthai', 'saraaathai', 'saraamthai', + 'saraithai', 'saraiithai', 'sarauethai', 'saraueethai', + 'sarauthai', 'sarauuthai', 'phinthuthai', '.notdef', + '.notdef', '.notdef', '.notdef', 'bahtthai', + 'saraethai', 'saraaethai', 'saraothai', 'saraaimaimuanthai', + 'saraaimaimalaithai','lakkhangyaothai','maiyamokthai', 'maitaikhuthai', + 'maiekthai', 'maithothai', 'maitrithai', 'maichattawathai', + 'thanthakhatthai','nikhahitthai', 'yamakkanthai', 'fongmanthai', + 'zerothai', 'onethai', 'twothai', 'threethai', + 'fourthai', 'fivethai', 'sixthai', 'seventhai', + 'eightthai', 'ninethai', 'angkhankhuthai', 'khomutthai', + '.notdef', '.notdef', '.notdef', '.notdef' + ], +# Western Europe + 'ISO-8859-15' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclamdown', 'cent', 'sterling', + 'Euro', 'yen', 'Scaron', 'section', + 'scaron', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'Zcaron', 'mu', 'paragraph', 'periodcentered', + 'zcaron', 'onesuperior', 'ordmasculine', 'guillemotright', + 'OE', 'oe', 'Ydieresis', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Eth', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Yacute', 'Thorn', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'eth', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'yacute', 'thorn', 'ydieresis' + ], +# Central Europe + 'ISO-8859-16' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'Aogonek', 'aogonek', 'Lslash', + 'Euro', 'quotedblbase', 'Scaron', 'section', + 'scaron', 'copyright', 'Scommaaccent', 'guillemotleft', + 'Zacute', 'hyphen', 'zacute', 'Zdotaccent', + 'degree', 'plusminus', 'Ccaron', 'lslash', + 'Zcaron', 'quotedblright', 'paragraph', 'periodcentered', + 'zcaron', 'ccaron', 'scommaaccent', 'guillemotright', + 'OE', 'oe', 'Ydieresis', 'zdotaccent', + 'Agrave', 'Aacute', 'Acircumflex', 'Abreve', + 'Adieresis', 'Cacute', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Dcroat', 'Nacute', 'Ograve', 'Oacute', + 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'Sacute', + 'Uhungarumlaut', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Eogonek', 'Tcommaaccent', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'abreve', + 'adieresis', 'cacute', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'dcroat', 'nacute', 'ograve', 'oacute', + 'ocircumflex', 'ohungarumlaut', 'odieresis', 'sacute', + 'uhungarumlaut', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'eogonek', 'tcommaaccent', 'ydieresis' + ], +# Russian + 'KOI8-R' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'SF100000', 'SF110000', 'SF010000', 'SF030000', + 'SF020000', 'SF040000', 'SF080000', 'SF090000', + 'SF060000', 'SF070000', 'SF050000', 'upblock', + 'dnblock', 'block', 'lfblock', 'rtblock', + 'ltshade', 'shade', 'dkshade', 'integraltp', + 'filledbox', 'periodcentered', 'radical', 'approxequal', + 'lessequal', 'greaterequal', 'space', 'integralbt', + 'degree', 'twosuperior', 'periodcentered', 'divide', + 'SF430000', 'SF240000', 'SF510000', 'afii10071', + 'SF520000', 'SF390000', 'SF220000', 'SF210000', + 'SF250000', 'SF500000', 'SF490000', 'SF380000', + 'SF280000', 'SF270000', 'SF260000', 'SF360000', + 'SF370000', 'SF420000', 'SF190000', 'afii10023', + 'SF200000', 'SF230000', 'SF470000', 'SF480000', + 'SF410000', 'SF450000', 'SF460000', 'SF400000', + 'SF540000', 'SF530000', 'SF440000', 'copyright', + 'afii10096', 'afii10065', 'afii10066', 'afii10088', + 'afii10069', 'afii10070', 'afii10086', 'afii10068', + 'afii10087', 'afii10074', 'afii10075', 'afii10076', + 'afii10077', 'afii10078', 'afii10079', 'afii10080', + 'afii10081', 'afii10097', 'afii10082', 'afii10083', + 'afii10084', 'afii10085', 'afii10072', 'afii10067', + 'afii10094', 'afii10093', 'afii10073', 'afii10090', + 'afii10095', 'afii10091', 'afii10089', 'afii10092', + 'afii10048', 'afii10017', 'afii10018', 'afii10040', + 'afii10021', 'afii10022', 'afii10038', 'afii10020', + 'afii10039', 'afii10026', 'afii10027', 'afii10028', + 'afii10029', 'afii10030', 'afii10031', 'afii10032', + 'afii10033', 'afii10049', 'afii10034', 'afii10035', + 'afii10036', 'afii10037', 'afii10024', 'afii10019', + 'afii10046', 'afii10045', 'afii10025', 'afii10042', + 'afii10047', 'afii10043', 'afii10041', 'afii10044' + ], +# Ukrainian + 'KOI8-U' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'SF100000', 'SF110000', 'SF010000', 'SF030000', + 'SF020000', 'SF040000', 'SF080000', 'SF090000', + 'SF060000', 'SF070000', 'SF050000', 'upblock', + 'dnblock', 'block', 'lfblock', 'rtblock', + 'ltshade', 'shade', 'dkshade', 'integraltp', + 'filledbox', 'bullet', 'radical', 'approxequal', + 'lessequal', 'greaterequal', 'space', 'integralbt', + 'degree', 'twosuperior', 'periodcentered', 'divide', + 'SF430000', 'SF240000', 'SF510000', 'afii10071', + 'afii10101', 'SF390000', 'afii10103', 'afii10104', + 'SF250000', 'SF500000', 'SF490000', 'SF380000', + 'SF280000', 'afii10098', 'SF260000', 'SF360000', + 'SF370000', 'SF420000', 'SF190000', 'afii10023', + 'afii10053', 'SF230000', 'afii10055', 'afii10056', + 'SF410000', 'SF450000', 'SF460000', 'SF400000', + 'SF540000', 'afii10050', 'SF440000', 'copyright', + 'afii10096', 'afii10065', 'afii10066', 'afii10088', + 'afii10069', 'afii10070', 'afii10086', 'afii10068', + 'afii10087', 'afii10074', 'afii10075', 'afii10076', + 'afii10077', 'afii10078', 'afii10079', 'afii10080', + 'afii10081', 'afii10097', 'afii10082', 'afii10083', + 'afii10084', 'afii10085', 'afii10072', 'afii10067', + 'afii10094', 'afii10093', 'afii10073', 'afii10090', + 'afii10095', 'afii10091', 'afii10089', 'afii10092', + 'afii10048', 'afii10017', 'afii10018', 'afii10040', + 'afii10021', 'afii10022', 'afii10038', 'afii10020', + 'afii10039', 'afii10026', 'afii10027', 'afii10028', + 'afii10029', 'afii10030', 'afii10031', 'afii10032', + 'afii10033', 'afii10049', 'afii10034', 'afii10035', + 'afii10036', 'afii10037', 'afii10024', 'afii10019', + 'afii10046', 'afii10045', 'afii10025', 'afii10042', + 'afii10047', 'afii10043', 'afii10041', 'afii10044' + ] +} + +def ReadAFM(file, map) + + # Read a font metric file + a = IO.readlines(file) + + raise "File no found: #{file}" if a.size == 0 + + widths = {} + fm = {} + fix = { 'Edot' => 'Edotaccent', 'edot' => 'edotaccent', + 'Idot' => 'Idotaccent', + 'Zdot' => 'Zdotaccent', 'zdot' => 'zdotaccent', + 'Odblacute' => 'Ohungarumlaut', 'odblacute' => 'ohungarumlaut', + 'Udblacute' => 'Uhungarumlaut', 'udblacute' => 'uhungarumlaut', + 'Gcedilla' => 'Gcommaaccent', 'gcedilla' => 'gcommaaccent', + 'Kcedilla' => 'Kcommaaccent', 'kcedilla' => 'kcommaaccent', + 'Lcedilla' => 'Lcommaaccent', 'lcedilla' => 'lcommaaccent', + 'Ncedilla' => 'Ncommaaccent', 'ncedilla' => 'ncommaaccent', + 'Rcedilla' => 'Rcommaaccent', 'rcedilla' => 'rcommaaccent', + 'Scedilla' => 'Scommaaccent',' scedilla' => 'scommaaccent', + 'Tcedilla' => 'Tcommaaccent',' tcedilla' => 'tcommaaccent', + 'Dslash' => 'Dcroat', 'dslash' => 'dcroat', + 'Dmacron' => 'Dcroat', 'dmacron' => 'dcroat', + 'combininggraveaccent' => 'gravecomb', + 'combininghookabove' => 'hookabovecomb', + 'combiningtildeaccent' => 'tildecomb', + 'combiningacuteaccent' => 'acutecomb', + 'combiningdotbelow' => 'dotbelowcomb', + 'dongsign' => 'dong' + } + + a.each do |line| + + e = line.rstrip.split(' ') + next if e.size < 2 + + code = e[0] + param = e[1] + + if code == 'C' then + + # Character metrics + cc = e[1].to_i + w = e[4] + gn = e[7] + + gn = 'Euro' if gn[-4, 4] == '20AC' + + if fix[gn] then + + # Fix incorrect glyph name + 0.upto(map.size - 1) do |i| + if map[i] == fix[gn] then + map[i] = gn + end + end + end + + if map.size == 0 then + # Symbolic font: use built-in encoding + widths[cc] = w + else + widths[gn] = w + fm['CapXHeight'] = e[13].to_i if gn == 'X' + end + + fm['MissingWidth'] = w if gn == '.notdef' + + elsif code == 'FontName' then + fm['FontName'] = param + elsif code == 'Weight' then + fm['Weight'] = param + elsif code == 'ItalicAngle' then + fm['ItalicAngle'] = param.to_f + elsif code == 'Ascender' then + fm['Ascender'] = param.to_i + elsif code == 'Descender' then + fm['Descender'] = param.to_i + elsif code == 'UnderlineThickness' then + fm['UnderlineThickness'] = param.to_i + elsif code == 'UnderlinePosition' then + fm['UnderlinePosition'] = param.to_i + elsif code == 'IsFixedPitch' then + fm['IsFixedPitch'] = (param == 'true') + elsif code == 'FontBBox' then + fm['FontBBox'] = "[#{e[1]},#{e[2]},#{e[3]},#{e[4]}]" + elsif code == 'CapHeight' then + fm['CapHeight'] = param.to_i + elsif code == 'StdVW' then + fm['StdVW'] = param.to_i + end + end + + raise 'FontName not found' unless fm['FontName'] + + if map.size > 0 then + widths['.notdef'] = 600 unless widths['.notdef'] + + if (widths['Delta'] == nil) && widths['increment'] then + widths['Delta'] = widths['increment'] + end + + # Order widths according to map + 0.upto(255) do |i| + if widths[map[i]] == nil + puts "Warning: character #{map[i]} is missing" + widths[i] = widths['.notdef'] + else + widths[i] = widths[map[i]] + end + end + end + + fm['Widths'] = widths + + return fm +end + +def MakeFontDescriptor(fm, symbolic) + + # Ascent + asc = fm['Ascender'] ? fm['Ascender'] : 1000 + fd = "{\n 'Ascent' => '#{asc}'" + + # Descent + desc = fm['Descender'] ? fm['Descender'] : -200 + fd += ", 'Descent' => '#{desc}'" + + # CapHeight + if fm['CapHeight'] then + ch = fm['CapHeight'] + elsif fm['CapXHeight'] + ch = fm['CapXHeight'] + else + ch = asc + end + fd += ", 'CapHeight' => '#{ch}'" + + # Flags + flags = 0 + + if fm['IsFixedPitch'] then + flags += 1 << 0 + end + + if symbolic then + flags += 1 << 2 + else + flags += 1 << 5 + end + + if fm['ItalicAngle'] && (fm['ItalicAngle'] != 0) then + flags += 1 << 6 + end + + fd += ",\n 'Flags' => '#{flags}'" + + # FontBBox + if fm['FontBBox'] then + fbb = fm['FontBBox'].gsub(/,/, ' ') + else + fbb = "[0 #{desc - 100} 1000 #{asc + 100}]" + end + + fd += ", 'FontBBox' => '#{fbb}'" + + # ItalicAngle + ia = fm['ItalicAngle'] ? fm['ItalicAngle'] : 0 + fd += ",\n 'ItalicAngle' => '#{ia}'" + + # StemV + if fm['StdVW'] then + stemv = fm['StdVW'] + elsif fm['Weight'] && (/bold|black/i =~ fm['Weight']) + stemv = 120 + else + stemv = 70 + end + + fd += ", 'StemV' => '#{stemv}'" + + # MissingWidth + if fm['MissingWidth'] then + fd += ", 'MissingWidth' => '#{fm['MissingWidth']}'" + end + + fd += "\n }" + return fd +end + +def MakeWidthArray(fm) + + # Make character width array + s = " [\n " + + cw = fm['Widths'] + + 0.upto(255) do |i| + s += "%5d" % cw[i] + s += "," if i != 255 + s += "\n " if (i % 8) == 7 + end + + s += ']' + + return s +end + +def MakeFontEncoding(map) + + # Build differences from reference encoding + ref = Charencodings['cp1252'] + s = '' + last = 0 + 32.upto(255) do |i| + if map[i] != ref[i] then + if i != last + 1 then + s += i.to_s + ' ' + end + last = i + s += '/' + map[i] + ' ' + end + end + return s.rstrip +end + +def ReadShort(f) + a = f.read(2).unpack('n') + return a[0] +end + +def ReadLong(f) + a = f.read(4).unpack('N') + return a[0] +end + +def CheckTTF(file) + + rl = false + pp = false + e = false + + # Check if font license allows embedding + File.open(file, 'rb') do |f| + + # Extract number of tables + f.seek(4, IO::SEEK_CUR) + nb = ReadShort(f) + f.seek(6, IO::SEEK_CUR) + + # Seek OS/2 table + found = false + 0.upto(nb - 1) do |i| + if f.read(4) == 'OS/2' then + found = true + break + end + + f.seek(12, IO::SEEK_CUR) + end + + if ! found then + return + end + + f.seek(4, IO::SEEK_CUR) + offset = ReadLong(f) + f.seek(offset, IO::SEEK_SET) + + # Extract fsType flags + f.seek(8, IO::SEEK_CUR) + fsType = ReadShort(f) + + rl = (fsType & 0x02) != 0 + pp = (fsType & 0x04) != 0 + e = (fsType & 0x08) != 0 + end + + if rl && ( ! pp) && ( ! e) then + puts 'Warning: font license does not allow embedding' + end +end + +# +# fontfile: path to TTF file (or empty string if not to be embedded) +# afmfile: path to AFM file +# enc: font encoding (or empty string for symbolic fonts) +# patch: optional patch for encoding +# type : font type if $fontfile is empty +# +def MakeFont(fontfile, afmfile, enc = 'cp1252', patch = {}, type = 'TrueType') + # Generate a font definition file + if (enc != nil) && (enc != '') then + map = Charencodings[enc] + patch.each { |cc, gn| map[cc] = gn } + else + map = [] + end + + raise "Error: AFM file not found: #{afmfile}" unless File.exists?(afmfile) + + fm = ReadAFM(afmfile, map) + + if (enc != nil) && (enc != '') then + diff = MakeFontEncoding(map) + else + diff = '' + end + + fd = MakeFontDescriptor(fm, (map.size == 0)) + + # Find font type + if fontfile then + ext = File.extname(fontfile).downcase.sub(/^\./, '') + + if ext == 'ttf' then + type = 'TrueType' + elsif ext == 'pfb' + type = 'Type1' + else + raise "Error: unrecognized font file extension: #{ext}" + end + else + raise "Error: incorrect font type: #{type}" if (type != 'TrueType') && (type != 'Type1') + end + printf "type = #{type}\n" + # Start generation + s = "# #{fm['FontName']} font definition\n\n" + s += "module FontDef\n" + s += " def FontDef.type\n '#{type}'\n end\n" + s += " def FontDef.name\n '#{fm['FontName']}'\n end\n" + s += " def FontDef.desc\n #{fd}\n end\n" + + if fm['UnderlinePosition'] == nil then + fm['UnderlinePosition'] = -100 + end + + if fm['UnderlineThickness'] == nil then + fm['UnderlineThickness'] = 50 + end + + s += " def FontDef.up\n #{fm['UnderlinePosition']}\n end\n" + s += " def FontDef.ut\n #{fm['UnderlineThickness']}\n end\n" + + w = MakeWidthArray(fm) + s += " def FontDef.cw\n#{w}\n end\n" + + s += " def FontDef.enc\n '#{enc}'\n end\n" + s += " def FontDef.diff\n #{(diff == nil) || (diff == '') ? 'nil' : '\'' + diff '\''}\n end\n" + + basename = File.basename(afmfile, '.*') + + if fontfile then + # Embedded font + if ! File.exist?(fontfile) then + raise "Error: font file not found: #{fontfile}" + end + + if type == 'TrueType' then + CheckTTF(fontfile) + end + + file = '' + File.open(fontfile, 'rb') do |f| + file = f.read() + end + + if type == 'Type1' then + # Find first two sections and discard third one + header = file[0] == 128 + file = file[6, file.length - 6] if header + + pos = file.index('eexec') + raise 'Error: font file does not seem to be valid Type1' if pos == nil + + size1 = pos + 6 + + file = file[0, size1] + file[size1 + 6, file.length - (size1 + 6)] if header && file[size1] == 128 + + pos = file.index('00000000') + raise 'Error: font file does not seem to be valid Type1' if pos == nil + + size2 = pos - size1 + file = file[0, size1 + size2] + end + + if require 'zlib' then + File.open(basename + '.z', 'wb') { |f| f.write(Zlib::Deflate.deflate(file)) } + s += " def FontDef.file\n '#{basename}.z'\n end\n" + puts "Font file compressed ('#{basename}.z')" + else + s += " def FontDef.file\n '#{File.basename(fontfile)}'\n end\n" + puts 'Notice: font file could not be compressed (zlib not available)' + end + + if type == 'Type1' then + s += " def FontDef.size1\n '#{size1}'\n end\n" + s += " def FontDef.size2\n '#{size2}'\n end\n" + else + s += " def FontDef.originalsize\n '#{File.size(fontfile)}'\n end\n" + end + + else + # Not embedded font + s += " def FontDef.file\n ''\n end\n" + end + + s += "end\n" + File.open(basename + '.rb', 'w') { |file| file.write(s)} + puts "Font definition file generated (#{basename}.rb)" +end + + +if $0 == __FILE__ then + if ARGV.length >= 3 then + enc = ARGV[2] + else + enc = 'cp1252' + end + + if ARGV.length >= 4 then + patch = ARGV[3] + else + patch = {} + end + + if ARGV.length >= 5 then + type = ARGV[4] + else + type = 'TrueType' + end + + MakeFont(ARGV[0], ARGV[1], enc, patch, type) +end diff --git a/vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb b/vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb new file mode 100644 index 000000000..5ad882903 --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb @@ -0,0 +1,346 @@ +module RFPDF + COLOR_PALETTE = { + :black => [0x00, 0x00, 0x00], + :white => [0xff, 0xff, 0xff], + }.freeze + + # Draw a line from (x1, y1) to (x2, y2). + # + # Options are: + # * :line_color - Default value is COLOR_PALETTE[:black]. + # * :line_width - Default value is 0.5. + # + # Example: + # + # draw_line(x1, y1, x1, y1+h, :line_color => ReportHelper::COLOR_PALETTE[:dark_blue], :line_width => 1) + # + def draw_line(x1, y1, x2, y2, options = {}) + options[:line_color] ||= COLOR_PALETTE[:black] + options[:line_width] ||= 0.5 + set_draw_color(options[:line_color]) + SetLineWidth(options[:line_width]) + Line(x1, y1, x2, y2) + end + + # Draw a string of text at (x, y). + # + # Options are: + # * :font_color - Default value is COLOR_PALETTE[:black]. + # * :font_size - Default value is 10. + # * :font_style - Default value is nothing or ''. + # + # Example: + # + # draw_text(x, y, header_left, :font_size => 10) + # + def draw_text(x, y, text, options = {}) + options[:font_color] ||= COLOR_PALETTE[:black] + options[:font_size] ||= 10 + options[:font_style] ||= '' + set_text_color(options[:font_color]) + SetFont('Arial', options[:font_style], options[:font_size]) + SetXY(x, y) + Write(options[:font_size] + 4, text) + end + + # Draw a block of text at (x, y) bounded by left_margin and right_margin. Both + # margins are measured from their corresponding edge. + # + # Options are: + # * :font_color - Default value is COLOR_PALETTE[:black]. + # * :font_size - Default value is 10. + # * :font_style - Default value is nothing or ''. + # + # Example: + # + # draw_text_block(left_margin, 85, "question", left_margin, 280, + # :font_color => ReportHelper::COLOR_PALETTE[:dark_blue], + # :font_size => 12, + # :font_style => 'I') + # + def draw_text_block(x, y, text, left_margin, right_margin, options = {}) + options[:font_color] ||= COLOR_PALETTE[:black] + options[:font_size] ||= 10 + options[:font_style] ||= '' + set_text_color(options[:font_color]) + SetFont('Arial', options[:font_style], options[:font_size]) + SetXY(x, y) + SetLeftMargin(left_margin) + SetRightMargin(right_margin) + Write(options[:font_size] + 4, text) + SetMargins(0,0,0) + end + + # Draw a box at (x, y), w wide and h high. + # + # Options are: + # * :border - Draw a border, 0 = no, 1 = yes? Default value is 1. + # * :border_color - Default value is COLOR_PALETTE[:black]. + # * :border_width - Default value is 0.5. + # * :fill - Fill the box, 0 = no, 1 = yes? Default value is 1. + # * :fill_color - Default value is nothing or COLOR_PALETTE[:white]. + # + # Example: + # + # draw_box(x, y - 1, 38, 22) + # + def draw_box(x, y, w, h, options = {}) + options[:border] ||= 1 + options[:border_color] ||= COLOR_PALETTE[:black] + options[:border_width] ||= 0.5 + options[:fill] ||= 1 + options[:fill_color] ||= COLOR_PALETTE[:white] + SetLineWidth(options[:border_width]) + set_draw_color(options[:border_color]) + set_fill_color(options[:fill_color]) + fd = "" + fd = "D" if options[:border] == 1 + fd += "F" if options[:fill] == 1 + Rect(x, y, w, h, fd) + end + + # Draw a string of text at (x, y) in a box w wide and h high. + # + # Options are: + # * :align - Vertical alignment 'C' = center, 'L' = left, 'R' = right. Default value is 'C'. + # * :border - Draw a border, 0 = no, 1 = yes? Default value is 0. + # * :border_color - Default value is COLOR_PALETTE[:black]. + # * :border_width - Default value is 0.5. + # * :fill - Fill the box, 0 = no, 1 = yes? Default value is 1. + # * :fill_color - Default value is nothing or COLOR_PALETTE[:white]. + # * :font_color - Default value is COLOR_PALETTE[:black]. + # * :font_size - Default value is nothing or 8. + # * :font_style - 'B' = bold, 'I' = italic, 'U' = underline. Default value is nothing ''. + # * :padding - Default value is nothing or 2. + # * :valign - 'M' = middle, 'T' = top, 'B' = bottom. Default value is nothing or 'M'. + # + # Example: + # + # draw_text_box(x, y - 1, 38, 22, + # "your_score_title", + # :fill => 0, + # :font_color => ReportHelper::COLOR_PALETTE[:blue], + # :font_line_spacing => 0, + # :font_style => "B", + # :valign => "M") + # + def draw_text_box(x, y, w, h, text, options = {}) + options[:align] ||= 'C' + options[:border] ||= 0 + options[:border_color] ||= COLOR_PALETTE[:black] + options[:border_width] ||= 0.5 + options[:fill] ||= 1 + options[:fill_color] ||= COLOR_PALETTE[:white] + options[:font_color] ||= COLOR_PALETTE[:black] + options[:font_size] ||= 8 + options[:font_line_spacing] ||= options[:font_size] * 0.3 + options[:font_style] ||= '' + options[:padding] ||= 2 + options[:valign] ||= "M" + if options[:fill] == 1 or options[:border] == 1 + draw_box(x, y, w, h, options) + end + SetMargins(0,0,0) + set_text_color(options[:font_color]) + font_size = options[:font_size] + SetFont('Arial', options[:font_style], font_size) + font_size += options[:font_line_spacing] + case options[:valign] + when "B" + y -= options[:padding] + text = "\n" + text if text["\n"].nil? + when "T" + y += options[:padding] + end + SetXY(x, y) + if GetStringWidth(text) > w or not text["\n"].nil? or options[:valign] == "T" + font_size += options[:font_size] * 0.1 + #TODO 2006-07-21 Level=1 - this is assuming a 2 line text + SetXY(x, y + ((h - (font_size * 2)) / 2)) if options[:valign] == "M" + MultiCell(w, font_size, text, 0, options[:align]) + else + Cell(w, h, text, 0, 0, options[:align]) + end + end + + # Draw a string of text at (x, y) as a title. + # + # Options are: + # * :font_color - Default value is COLOR_PALETTE[:black]. + # * :font_size - Default value is 18. + # * :font_style - Default value is nothing or ''. + # + # Example: + # + # draw_title(left_margin, 60, + # "title:", + # :font_color => ReportHelper::COLOR_PALETTE[:dark_blue]) + # + def draw_title(x, y, title, options = {}) + options[:font_color] ||= COLOR_PALETTE[:black] + options[:font_size] ||= 18 + options[:font_style] ||= '' + set_text_color(options[:font_color]) + SetFont('Arial', options[:font_style], options[:font_size]) + SetXY(x, y) + Write(options[:font_size] + 2, title) + end + + # Set the draw color. Default value is COLOR_PALETTE[:black]. + # + # Example: + # + # set_draw_color(ReportHelper::COLOR_PALETTE[:dark_blue]) + # + def set_draw_color(color = COLOR_PALETTE[:black]) + SetDrawColor(color[0], color[1], color[2]) + end + + # Set the fill color. Default value is COLOR_PALETTE[:white]. + # + # Example: + # + # set_fill_color(ReportHelper::COLOR_PALETTE[:dark_blue]) + # + def set_fill_color(color = COLOR_PALETTE[:white]) + SetFillColor(color[0], color[1], color[2]) + end + + # Set the text color. Default value is COLOR_PALETTE[:white]. + # + # Example: + # + # set_text_color(ReportHelper::COLOR_PALETTE[:dark_blue]) + # + def set_text_color(color = COLOR_PALETTE[:black]) + SetTextColor(color[0], color[1], color[2]) + end + + # Write a string containing html characters. Default value is COLOR_PALETTE[:white]. + # + # Options are: + # * :height - Line height. Default value is 20. + # + # Example: + # + # write_html(html, :height => 12) + # + def write_html(html, options = {}) + options[:height] ||= 20 + #HTML parser + @href = nil + @style = {} + html.gsub!("\n",' ') + re = %r{ ( | + < (?: + [^<>"] + + | + " (?: \\. | [^\\"]+ ) * " + ) * + > + ) }xm + + html.split(re).each do |value| + if "<" == value[0,1] + #Tag + if (value[1, 1] == '/') + close_tag(value[2..-2], options) + else + tag = value[1..-2] + open_tag(tag, options) + end + else + #Text + if @href + put_link(@href,value) + else + Write(options[:height], value) + end + end + end + end + + def open_tag(tag, options = {}) #:nodoc: + #Opening tag + tag = tag.to_s.upcase + set_style(tag, true) if tag == 'B' or tag == 'I' or tag == 'U' + @href = options['HREF'] if tag == 'A' + Ln(options[:height]) if tag == 'BR' + end + + def close_tag(tag, options = {}) #:nodoc: + #Closing tag + tag = tag.to_s.upcase + set_style(tag, false) if tag == 'B' or tag == 'I' or tag == 'U' + @href = '' if $tag == 'A' + end + + def set_style(tag, enable = true) #:nodoc: + #Modify style and select corresponding font + style = "" + @style[tag] = enable + ['B','I','U'].each do |s| + style += s if not @style[s].nil? and @style[s] + end + SetFont('', style) + end + + def put_link(url, txt) #:nodoc: + #Put a hyperlink + SetTextColor(0,0,255) + set_style('U',true) + Write(5, txt, url) + set_style('U',false) + SetTextColor(0) + end +end + +# class FPDF +# alias_method :set_margins , :SetMargins +# alias_method :set_left_margin , :SetLeftMargin +# alias_method :set_top_margin , :SetTopMargin +# alias_method :set_right_margin , :SetRightMargin +# alias_method :set_auto_pagebreak , :SetAutoPageBreak +# alias_method :set_display_mode , :SetDisplayMode +# alias_method :set_compression , :SetCompression +# alias_method :set_title , :SetTitle +# alias_method :set_subject , :SetSubject +# alias_method :set_author , :SetAuthor +# alias_method :set_keywords , :SetKeywords +# alias_method :set_creator , :SetCreator +# alias_method :set_draw_color , :SetDrawColor +# alias_method :set_fill_color , :SetFillColor +# alias_method :set_text_color , :SetTextColor +# alias_method :set_line_width , :SetLineWidth +# alias_method :set_font , :SetFont +# alias_method :set_font_size , :SetFontSize +# alias_method :set_link , :SetLink +# alias_method :set_y , :SetY +# alias_method :set_xy , :SetXY +# alias_method :get_string_width , :GetStringWidth +# alias_method :get_x , :GetX +# alias_method :set_x , :SetX +# alias_method :get_y , :GetY +# alias_method :accept_pagev_break , :AcceptPageBreak +# alias_method :add_font , :AddFont +# alias_method :add_link , :AddLink +# alias_method :add_page , :AddPage +# alias_method :alias_nb_pages , :AliasNbPages +# alias_method :cell , :Cell +# alias_method :close , :Close +# alias_method :error , :Error +# alias_method :footer , :Footer +# alias_method :header , :Header +# alias_method :image , :Image +# alias_method :line , :Line +# alias_method :link , :Link +# alias_method :ln , :Ln +# alias_method :multi_cell , :MultiCell +# alias_method :open , :Open +# alias_method :Open , :open +# alias_method :output , :Output +# alias_method :page_no , :PageNo +# alias_method :rect , :Rect +# alias_method :text , :Text +# alias_method :write , :Write +# end diff --git a/vendor/plugins/rfpdf/lib/rfpdf/view.rb b/vendor/plugins/rfpdf/lib/rfpdf/view.rb new file mode 100644 index 000000000..185811202 --- /dev/null +++ b/vendor/plugins/rfpdf/lib/rfpdf/view.rb @@ -0,0 +1,75 @@ +# Copyright (c) 2006 4ssoM LLC +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# Thanks go out to Bruce Williams of codefluency who created RTex. This +# template handler is modification of his work. +# +# Example Registration +# +# ActionView::Base::register_template_handler 'rfpdf', RFpdfView + +module RFPDF + + class View + + def initialize(action_view) + @action_view = action_view + # Override with @options_for_rfpdf Hash in your controller + @options = { + # Run through latex first? (for table of contents, etc) + :pre_process => false, + # Debugging mode; raises exception + :debug => false, + # Filename of pdf to generate + :file_name => "#{@action_view.controller.action_name}.pdf", + # Temporary Directory + :temp_dir => "#{File.expand_path(RAILS_ROOT)}/tmp" + }.merge(@action_view.controller.instance_eval{ @options_for_rfpdf } || {}).with_indifferent_access + end + + def render(template, local_assigns = {}) + @pdf_name = "Default.pdf" if @pdf_name.nil? + unless @action_view.controller.headers["Content-Type"] == 'application/pdf' + @generate = true + @action_view.controller.headers["Content-Type"] = 'application/pdf' + @action_view.controller.headers["Content-disposition:"] = "inline; filename=\"#{@options[:file_name]}\"" + end + assigns = @action_view.assigns.dup + + if content_for_layout = @action_view.instance_variable_get("@content_for_layout") + assigns['content_for_layout'] = content_for_layout + end + + result = @action_view.instance_eval do + assigns.each do |key,val| + instance_variable_set "@#{key}", val + end + local_assigns.each do |key,val| + class << self; self; end.send(:define_method,key){ val } + end + ERB.new(template).result(binding) + end + end + + end + +end \ No newline at end of file diff --git a/vendor/plugins/rfpdf/test/test_helper.rb b/vendor/plugins/rfpdf/test/test_helper.rb new file mode 100644 index 000000000..2e2ea3bc5 --- /dev/null +++ b/vendor/plugins/rfpdf/test/test_helper.rb @@ -0,0 +1 @@ +#!/usr/bin/env ruby \ No newline at end of file -- cgit v1.2.3