From f561c54356aba86a538aa5494b68dcb1eef440d1 Mon Sep 17 00:00:00 2001 From: Dominique Feyer Date: Sun, 12 Feb 2012 23:08:37 +0100 Subject: [PATCH 01/54] Fixes activity list column alignment --- public/stylesheets/application.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 920c951b..7c35b9c9 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -351,7 +351,7 @@ div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; } div#issue-changesets p { margin-top: 0; margin-bottom: 1em;} div#activity dl, #search-results { margin-left: 2em; } -div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; } +div#activity dd, #search-results dd { margin-bottom: 1em; font-size: 0.9em; overflow: hidden; } div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; } div#activity dt.me .time { border-bottom: 1px solid #999; } div#activity dt .time { color: #777; font-size: 80%; } From cbcce704006c6827b4a3134a2dda9de7c47f18ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Rigart?= Date: Fri, 24 Feb 2012 10:18:06 +0100 Subject: [PATCH 02/54] Fix requiring SCM classes in dev mode #828 Change require to require_dependency so SCM classes get loaded on each request in dev mode --- app/models/repository/bazaar.rb | 2 +- app/models/repository/cvs.rb | 2 +- app/models/repository/darcs.rb | 2 +- app/models/repository/filesystem.rb | 2 +- app/models/repository/git.rb | 2 +- app/models/repository/mercurial.rb | 2 +- app/models/repository/subversion.rb | 2 +- lib/redmine/scm/adapters/bazaar_adapter.rb | 2 +- lib/redmine/scm/adapters/cvs_adapter.rb | 2 +- lib/redmine/scm/adapters/darcs_adapter.rb | 2 +- lib/redmine/scm/adapters/filesystem_adapter.rb | 2 +- lib/redmine/scm/adapters/git_adapter.rb | 2 +- lib/redmine/scm/adapters/mercurial_adapter.rb | 2 +- lib/redmine/scm/adapters/subversion_adapter.rb | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/models/repository/bazaar.rb b/app/models/repository/bazaar.rb index 7fa3cb1e..8178e6db 100644 --- a/app/models/repository/bazaar.rb +++ b/app/models/repository/bazaar.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/bazaar_adapter' +require_dependency 'redmine/scm/adapters/bazaar_adapter' class Repository::Bazaar < Repository attr_protected :root_url diff --git a/app/models/repository/cvs.rb b/app/models/repository/cvs.rb index 99b8ccfa..fa37a17e 100644 --- a/app/models/repository/cvs.rb +++ b/app/models/repository/cvs.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/cvs_adapter' +require_dependency 'redmine/scm/adapters/cvs_adapter' require 'digest/sha1' class Repository::Cvs < Repository diff --git a/app/models/repository/darcs.rb b/app/models/repository/darcs.rb index 1f5bf69a..96924de2 100644 --- a/app/models/repository/darcs.rb +++ b/app/models/repository/darcs.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/darcs_adapter' +require_dependency 'redmine/scm/adapters/darcs_adapter' class Repository::Darcs < Repository validates_presence_of :url, :log_encoding diff --git a/app/models/repository/filesystem.rb b/app/models/repository/filesystem.rb index 722e5316..7d6ffbeb 100644 --- a/app/models/repository/filesystem.rb +++ b/app/models/repository/filesystem.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/filesystem_adapter' +require_dependency 'redmine/scm/adapters/filesystem_adapter' class Repository::Filesystem < Repository attr_protected :root_url diff --git a/app/models/repository/git.rb b/app/models/repository/git.rb index 7817aff4..9bacac68 100644 --- a/app/models/repository/git.rb +++ b/app/models/repository/git.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/git_adapter' +require_dependency 'redmine/scm/adapters/git_adapter' class Repository::Git < Repository attr_protected :root_url diff --git a/app/models/repository/mercurial.rb b/app/models/repository/mercurial.rb index 24c9d7a7..a67826a1 100644 --- a/app/models/repository/mercurial.rb +++ b/app/models/repository/mercurial.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/mercurial_adapter' +require_dependency 'redmine/scm/adapters/mercurial_adapter' class Repository::Mercurial < Repository # sort changesets by revision number diff --git a/app/models/repository/subversion.rb b/app/models/repository/subversion.rb index 0515460d..19f8e26b 100644 --- a/app/models/repository/subversion.rb +++ b/app/models/repository/subversion.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/subversion_adapter' +require_dependency 'redmine/scm/adapters/subversion_adapter' class Repository::Subversion < Repository attr_protected :root_url diff --git a/lib/redmine/scm/adapters/bazaar_adapter.rb b/lib/redmine/scm/adapters/bazaar_adapter.rb index bbc44b4d..58b6e0b4 100644 --- a/lib/redmine/scm/adapters/bazaar_adapter.rb +++ b/lib/redmine/scm/adapters/bazaar_adapter.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/abstract_adapter' +require_dependency 'redmine/scm/adapters/abstract_adapter' module Redmine module Scm diff --git a/lib/redmine/scm/adapters/cvs_adapter.rb b/lib/redmine/scm/adapters/cvs_adapter.rb index 4a74df6a..cee5b701 100644 --- a/lib/redmine/scm/adapters/cvs_adapter.rb +++ b/lib/redmine/scm/adapters/cvs_adapter.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/abstract_adapter' +require_dependency 'redmine/scm/adapters/abstract_adapter' module Redmine module Scm diff --git a/lib/redmine/scm/adapters/darcs_adapter.rb b/lib/redmine/scm/adapters/darcs_adapter.rb index a31ee593..796efdb1 100644 --- a/lib/redmine/scm/adapters/darcs_adapter.rb +++ b/lib/redmine/scm/adapters/darcs_adapter.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/abstract_adapter' +require_dependency 'redmine/scm/adapters/abstract_adapter' require 'rexml/document' module Redmine diff --git a/lib/redmine/scm/adapters/filesystem_adapter.rb b/lib/redmine/scm/adapters/filesystem_adapter.rb index 9051093b..687e9534 100644 --- a/lib/redmine/scm/adapters/filesystem_adapter.rb +++ b/lib/redmine/scm/adapters/filesystem_adapter.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/abstract_adapter' +require_dependency 'redmine/scm/adapters/abstract_adapter' require 'find' module Redmine diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb index 0674c22d..8f3008df 100644 --- a/lib/redmine/scm/adapters/git_adapter.rb +++ b/lib/redmine/scm/adapters/git_adapter.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/abstract_adapter' +require_dependency 'redmine/scm/adapters/abstract_adapter' module Redmine module Scm diff --git a/lib/redmine/scm/adapters/mercurial_adapter.rb b/lib/redmine/scm/adapters/mercurial_adapter.rb index 06d80c1f..c119e086 100644 --- a/lib/redmine/scm/adapters/mercurial_adapter.rb +++ b/lib/redmine/scm/adapters/mercurial_adapter.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/abstract_adapter' +require_dependency 'redmine/scm/adapters/abstract_adapter' require 'cgi' module Redmine diff --git a/lib/redmine/scm/adapters/subversion_adapter.rb b/lib/redmine/scm/adapters/subversion_adapter.rb index 1171a1ec..ab8b5d15 100644 --- a/lib/redmine/scm/adapters/subversion_adapter.rb +++ b/lib/redmine/scm/adapters/subversion_adapter.rb @@ -12,7 +12,7 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -require 'redmine/scm/adapters/abstract_adapter' +require_dependency 'redmine/scm/adapters/abstract_adapter' require 'uri' module Redmine From e678612d75203cabf6d620cd5f05f086e12e1c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Rigart?= Date: Fri, 24 Feb 2012 09:48:45 +0100 Subject: [PATCH 03/54] gitignore intellij project files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index bafc8e6c..2b276861 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,5 @@ doc/app /Gemfile.lock /Gemfile.local /.rvmrc* +/*.iml +/.idea From f327298f8867463ae9c0f404233629619b11da0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Scha=CC=88fer?= Date: Fri, 24 Feb 2012 15:55:21 +0100 Subject: [PATCH 04/54] Fix missing submenu hint on issue context menu #882 Contributed by Andrew Smith --- public/stylesheets/context_menu.css | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/public/stylesheets/context_menu.css b/public/stylesheets/context_menu.css index 4580042a..d820815b 100644 --- a/public/stylesheets/context_menu.css +++ b/public/stylesheets/context_menu.css @@ -39,7 +39,6 @@ } #context-menu li>a { width:auto; } /* others */ #context-menu a.disabled, #context-menu a.disabled:hover {color: #ccc;} -#context-menu li a.submenu { background:url("../images/bullet_arrow_right.png") right no-repeat; } #context-menu li:hover { border:1px solid gray; background-color:#eee; } #context-menu a:hover {color:#2A5685;} #context-menu li.folder:hover { z-index:40; } @@ -49,3 +48,15 @@ /* selected element */ .context-menu-selection { background-color:#507AAA !important; color:#000 !important; } .context-menu-selection:hover { background-color:#507AAA !important; color:#000 !important; } + +#context-menu .submenu { + border: transparent solid 5px; + border-left-color: #6A0406; + position: absolute; + top: 5px; + right: 3px; +} + +#context-menu .folder:hover .submenu { + border-left-color: #2A5685; +} From fbc71a80f8d154165d4996c48eb908fd277d9a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Fri, 24 Feb 2012 16:36:04 +0100 Subject: [PATCH 05/54] Fix issue option list orientation #869 Contributed by Alf Gaida. --- public/stylesheets/application.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 7c35b9c9..8fccc2dd 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -1703,6 +1703,7 @@ form#issue-list { .title-bar .title-bar-actions .contextual a.icon { color:#000000; margin-right: 0px; + float: none; } .title-bar .update { right:0; From b9b2c8c0d7c3aa69e50b13504db564ec2daee530 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Feb 2012 10:16:04 -0800 Subject: [PATCH 06/54] [#559] Group menus and add some dynamic menus --- config/locales/en.yml | 3 + lib/redmine.rb | 185 +++++++++++++++++++++++++++++++--- test/unit/lib/redmine_test.rb | 4 +- 3 files changed, 174 insertions(+), 18 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index adec4598..a879da48 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -309,6 +309,9 @@ en: field_visible: Visible field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" field_custom_filter: Custom LDAP filter + field_issue_summary: Issue summary + field_new_saved_query: New saved query + field_issue_view_all_open: View all open issues setting_app_title: Application title setting_app_subtitle: Application subtitle diff --git a/lib/redmine.rb b/lib/redmine.rb index 832dd56f..70d39b3b 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -212,25 +212,178 @@ Redmine::MenuManager.map :admin_menu do |menu| end Redmine::MenuManager.map :project_menu do |menu| - menu.push :overview, { :controller => 'projects', :action => 'show' } - menu.push :activity, { :controller => 'activities', :action => 'index' } - menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id, - :if => Proc.new { |p| p.shared_versions.any? } - menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural - menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new, + include ProjectsHelper + + # TODO: refactor to a helper that is available before app/helpers along with the other procs. + issue_query_proc = Proc.new { |p| + ##### Taken from IssuesHelper + # User can see public queries and his own queries + visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)]) + # Project specific queries and global queries + visible << (p.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", p.id]) + sidebar_queries = Query.find(:all, + :select => 'id, name', + :order => "name ASC", + :conditions => visible.conditions) + + sidebar_queries.collect do |query| + Redmine::MenuManager::MenuItem.new("query-#{query.id}".to_sym, { :controller => 'issues', :action => 'index', :project_id => p, :query_id => query }, { + :caption => query.name, + :param => :project_id, + :parent => :issues + }) + end + } + + menu.push(:overview, { :controller => 'projects', :action => 'show' }) + menu.push(:activity, { :controller => 'activities', :action => 'index' }) + menu.push(:roadmap, { :controller => 'versions', :action => 'index' }, { + :param => :project_id, + :if => Proc.new { |p| p.shared_versions.any? }, + :children => Proc.new { |p| + versions = p.shared_versions.sort + versions.reject! {|version| version.closed? || version.completed? } + + versions.collect do |version| + Redmine::MenuManager::MenuItem.new("version-#{version.id}".to_sym, + { :controller => 'versions', :action => 'show', :id => version }, + { + :caption => version.name, + :parent => :roadmap + }) + end + } + }) + menu.push(:issues, { :controller => 'issues', :action => 'index' }, { + :param => :project_id, + :caption => :label_issue_plural, + :children => issue_query_proc + }) + menu.push(:new_issue, { :controller => 'issues', :action => 'new' }, { + :param => :project_id, + :caption => :label_issue_new, + :parent => :issues, :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } - menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt - menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar - menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural - menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural - menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id, + }) + menu.push(:all_open_issues, { :controller => 'issues', :action => 'index', :set_filter => 1 }, { + :param => :project_id, + :caption => :field_issue_view_all_open, + :parent => :issues + }) + menu.push(:new_query, { :controller => 'queries', :action => 'new'}, { + :param => :project_id, + :caption => :field_new_saved_query, + :parent => :issues + }) + menu.push(:issue_summary, { :controller => 'reports', :action => 'issue_report' }, { + :caption => :field_issue_summary, + :parent => :issues + }) + menu.push(:time_entries, { :controller => 'timelog', :action => 'index' }, { + :param => :project_id, + :if => Proc.new {|p| User.current.allowed_to?(:view_time_entries, p) } + }); + menu.push(:new_time_entry, { :controller => 'timelog', :action => 'new' }, { + :param => :project_id, + :if => Proc.new {|p| User.current.allowed_to?(:log_time, p) }, + :parent => :time_entries + }) + menu.push(:time_entry_report, { :controller => 'time_entry_reports', :action => 'report' }, { + :param => :project_id, + :if => Proc.new {|p| User.current.allowed_to?(:view_time_entries, p) }, + :parent => :time_entries + }) + menu.push(:gantt, { :controller => 'gantts', :action => 'show' }, { + :param => :project_id, + :caption => :label_gantt + }) + menu.push(:calendar, { :controller => 'calendars', :action => 'show' }, { + :param => :project_id, + :caption => :label_calendar + }) + menu.push(:news, { :controller => 'news', :action => 'index' }, { + :param => :project_id, + :caption => :label_news_plural + }) + menu.push(:new_news, {:controller => 'news', :action => 'new' }, { + :param => :project_id, + :caption => :label_news_new, + :parent => :news, + :if => Proc.new {|p| User.current.allowed_to?(:manage_news, p) } + }) + menu.push(:documents, { :controller => 'documents', :action => 'index' }, { + :param => :project_id, + :caption => :label_document_plural + }) + menu.push(:new_document, { :controller => 'documents', :action => 'new' }, { + :param => :project_id, + :caption => :label_document_new, + :parent => :documents, + :if => Proc.new {|p| User.current.allowed_to?(:manage_documents, p) } + }) + menu.push(:wiki, { :controller => 'wiki', :action => 'show', :id => nil }, { + :param => :project_id, :if => Proc.new { |p| p.wiki && !p.wiki.new_record? } - menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, - :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural - menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id - menu.push :repository, { :controller => 'repositories', :action => 'show' }, + }) + menu.push(:wiki_by_title, { :controller => 'wiki', :action => 'index' }, { + :caption => :label_index_by_title, + :parent => :wiki, + :param => :project_id, + :if => Proc.new { |p| p.wiki && !p.wiki.new_record? } + }) + menu.push(:wiki_by_date, { :controller => 'wiki', :action => 'date_index'}, { + :caption => :label_index_by_date, + :parent => :wiki, + :param => :project_id, + :if => Proc.new { |p| p.wiki && !p.wiki.new_record? } + }) + menu.push(:boards, { :controller => 'boards', :action => 'index', :id => nil }, { + :param => :project_id, + :caption => :label_board_plural, + :if => Proc.new { |p| p.boards.any? }, + :children => Proc.new {|project| + project.boards.collect do |board| + Redmine::MenuManager::MenuItem.new( + "board-#{board.id}".to_sym, + { :controller => 'boards', :action => 'show', :id => board }, + { + :caption => board.name # is h() in menu_helper.rb + }) + end + } + }) + menu.push(:new_board, { :controller => 'boards', :action => 'new' }, { + :caption => :label_board_new, + :param => :project_id, + :parent => :boards, + :if => Proc.new {|p| User.current.allowed_to?(:manage_boards, p) } + }) + menu.push(:files, { :controller => 'files', :action => 'index' }, { + :caption => :label_file_plural, + :param => :project_id + }) + menu.push(:new_file, { :controller => 'files', :action => 'new' }, { + :caption => :label_attachment_new, + :param => :project_id, + :parent => :files, + :if => Proc.new {|p| User.current.allowed_to?(:manage_files, p) } + }) + menu.push(:repository, { :controller => 'repositories', :action => 'show' }, { :if => Proc.new { |p| p.repository && !p.repository.new_record? } - menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true + }) + menu.push(:settings, { :controller => 'projects', :action => 'settings' }, { + :last => true, + :children => Proc.new { |p| + @project = p # @project used in the helper + project_settings_tabs.collect do |tab| + Redmine::MenuManager::MenuItem.new("settings-#{tab[:name]}".to_sym, + { :controller => 'projects', :action => 'settings', :id => p, :tab => tab[:name] }, + { + :caption => tab[:label] + }) + end + } + }) end Redmine::Activity.map do |activity| diff --git a/test/unit/lib/redmine_test.rb b/test/unit/lib/redmine_test.rb index 599a04d1..94d60a74 100644 --- a/test/unit/lib/redmine_test.rb +++ b/test/unit/lib/redmine_test.rb @@ -73,8 +73,8 @@ class RedmineTest < ActiveSupport::TestCase assert_menu_contains_item_named :project_menu, :settings end - def test_new_issue_should_have_root_as_a_parent + def test_new_issue_should_have_issues_as_a_parent new_issue = get_menu_item(:project_menu, :new_issue) - assert_equal :root, new_issue.parent.name + assert_equal :issues, new_issue.parent.name end end From 4a3f10317fe7ddfed1d83db229bf600837b8407d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Wed, 29 Feb 2012 22:26:13 +0100 Subject: [PATCH 07/54] Correct (wrongly) assumed ordering in test #892 Contributed by Luke Carrier. --- test/functional/trackers_controller_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/trackers_controller_test.rb b/test/functional/trackers_controller_test.rb index 0dfb3dd7..a03a02cf 100644 --- a/test/functional/trackers_controller_test.rb +++ b/test/functional/trackers_controller_test.rb @@ -45,7 +45,7 @@ class TrackersControllerTest < ActionController::TestCase assert_redirected_to :action => 'index' tracker = Tracker.find_by_name('New tracker') assert_equal [1], tracker.project_ids.sort - assert_equal [1, 6], tracker.custom_field_ids + assert_equal [1, 6], tracker.custom_field_ids.sort assert_equal 0, tracker.workflows.count end From 4b5271f48750ad73d5b7395b09b049ab50c090a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Thu, 1 Mar 2012 00:40:23 +0100 Subject: [PATCH 08/54] Correct quotation #891 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Windows shell doesn't seem to support single quotes… Contributed by Dies Koper, Luke Carrier --- lib/chili_project/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/chili_project/version.rb b/lib/chili_project/version.rb index 80654518..894e8074 100644 --- a/lib/chili_project/version.rb +++ b/lib/chili_project/version.rb @@ -43,7 +43,7 @@ module ChiliProject git_dir = Rails.root.join('.git') if File.directory? git_dir - git.send(:shellout, "#{git.sq_bin} --git-dir='#{git_dir}' rev-parse --short=9 HEAD") { |io| io.read }.to_s.chomp + git.send(:shellout, "#{git.sq_bin} --git-dir=\"#{git_dir}\" rev-parse --short=9 HEAD") { |io| io.read }.to_s.chomp end end end From 900eda7a23dd3a6983f16d97283cfb9d2888f408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Thu, 1 Mar 2012 12:56:31 +0100 Subject: [PATCH 09/54] Don't require a specific pg gem version #915 pg was locked to ~> 0.9.0 as it was the last version to support ruby 1.8.6, we don't support it officially anymore, thus we can remove the version requirement. Contributed by Dies Koper. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 6ec56e28..0ef4d190 100644 --- a/Gemfile +++ b/Gemfile @@ -57,7 +57,7 @@ platforms :mri, :mingw do end group :postgres do - gem "pg", "~> 0.9.0" + gem "pg" # gem "postgres-pr" end end From 724bd484945f6cb8b8ccff4dc26983a48277f75a Mon Sep 17 00:00:00 2001 From: Holger Just Date: Mon, 5 Mar 2012 12:50:44 +0100 Subject: [PATCH 10/54] Remove unused code Since Rails 2.3.11, protect_from_forgery exclusively calls handle_unverified_request which defaults to resetting the session. The old code to handle an invalid CSRF token is not used anymore and is thus removed to un-confuse people. --- app/controllers/application_controller.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c5200d58..de47f042 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -64,7 +64,6 @@ class ApplicationController < ActionController::Base before_filter :user_setup, :check_if_login_required, :set_localization filter_parameter_logging :password - rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token # FIXME: This doesn't work with Rails >= 3.0 anymore # Possible workaround: https://github.com/rails/rails/issues/671#issuecomment-1780159 rescue_from ActionController::RoutingError, :with => proc{render_404} @@ -336,13 +335,6 @@ class ApplicationController < ActionController::Base request.xhr? ? false : 'base' end - def invalid_authenticity_token - if api_request? - logger.error "Form authenticity token is missing or is invalid. API calls must include a proper Content-type header (text/xml or text/json)." - end - render_error "Invalid form authenticity token." - end - def render_feed(items, options={}) @items = items || [] @items.sort! {|x,y| y.event_datetime <=> x.event_datetime } From 2c76240544629c750131cbb40d47100135f8ab33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Scha=CC=88fer?= Date: Fri, 2 Mar 2012 01:38:03 +0100 Subject: [PATCH 11/54] Fix edit issue notes permission #888 --- app/models/issue.rb | 9 +++++++++ app/models/journal.rb | 2 +- .../lib/redmine/acts/journalized/permissions.rb | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index 2f0d350e..a57e3199 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -707,6 +707,15 @@ class Issue < ActiveRecord::Base projects end + # Overrides Redmine::Acts::Journalized::Permissions + # + # The default assumption is that journals have the same permissions + # as the journaled object, issue notes have separate permissions though + def journal_editable_by?(journal, user) + return true if journal.author == user && user.allowed_to?(:edit_own_issue_notes, project) + user.allowed_to? :edit_issue_notes, project + end + private def update_nested_set_attributes diff --git a/app/models/journal.rb b/app/models/journal.rb index a0ec3000..45bfc4e0 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -76,7 +76,7 @@ class Journal < ActiveRecord::Base end def editable_by?(user) - journaled.journal_editable_by?(user) + journaled.journal_editable_by?(self, user) end def details diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb index 59bcc2e4..ab0dc038 100644 --- a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb @@ -22,7 +22,7 @@ module Redmine::Acts::Journalized module Permissions # Default implementation of journal editing permission # Is overridden if defined in the journalized model directly - def journal_editable_by?(user) + def journal_editable_by?(journal, user) return true if user.admin? if respond_to? :editable_by? editable_by? user From ef5dddf4dbea81908fc7849a66f56063c49138e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Mon, 5 Mar 2012 18:21:28 +0100 Subject: [PATCH 12/54] Switch to GitAdapter for quoting #891 Fixes problems with paths containing quotes (sic) --- lib/chili_project/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/chili_project/version.rb b/lib/chili_project/version.rb index 894e8074..2afb5a4f 100644 --- a/lib/chili_project/version.rb +++ b/lib/chili_project/version.rb @@ -43,7 +43,7 @@ module ChiliProject git_dir = Rails.root.join('.git') if File.directory? git_dir - git.send(:shellout, "#{git.sq_bin} --git-dir=\"#{git_dir}\" rev-parse --short=9 HEAD") { |io| io.read }.to_s.chomp + git.send(:shellout, "#{git.sq_bin} --git-dir=#{git.shell_quote git_dir.to_s} rev-parse --short=9 HEAD") { |io| io.read }.to_s.chomp end end end From 23864d99b57fab8c49eb50568a3ae21feebf7c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Rigart?= Date: Sat, 25 Feb 2012 19:15:06 +0100 Subject: [PATCH 13/54] Fix progress bar css #868 --- public/stylesheets/application.css | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 8fccc2dd..03e1557f 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -624,7 +624,7 @@ color:#505050; } /***** Progress bar *****/ -table.progress { +#content table.progress { border: 1px solid #D7D7D7; border-collapse: collapse; border-spacing: 0pt; @@ -634,12 +634,12 @@ table.progress { margin: 1px 6px 1px 0px; } -table.progress td { height: 0.9em; } -table.progress td.closed { background: #BAE0BA none repeat scroll 0%; } -table.progress td.done { background: #DEF0DE none repeat scroll 0%; } -table.progress td.open { background: #FFF none repeat scroll 0%; } -p.pourcent {font-size: 80%;} -p.progress-info {clear: left; font-style: italic; font-size: 80%;} +#content table.progress td { height: 0.9em; } +#content table.progress td.closed { background: #BAE0BA none repeat scroll 0%; } +#content table.progress td.done { background: #DEF0DE none repeat scroll 0%; } +#content table.progress td.open { background: #FFF none repeat scroll 0%; } +#content p.pourcent {font-size: 80%;} +#content p.progress-info {clear: left; font-style: italic; font-size: 80%;} /***** Tabs *****/ #content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;} From 1bc182405eb9200fc977d953303d893c630a466c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Fri, 9 Mar 2012 15:46:54 +0100 Subject: [PATCH 14/54] Correct truncated styles on journal entries #914 --- .../lib/journal_formatter.rb | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/vendor/plugins/acts_as_journalized/lib/journal_formatter.rb b/vendor/plugins/acts_as_journalized/lib/journal_formatter.rb index 9fd7d644..4faff9f4 100644 --- a/vendor/plugins/acts_as_journalized/lib/journal_formatter.rb +++ b/vendor/plugins/acts_as_journalized/lib/journal_formatter.rb @@ -114,23 +114,27 @@ module JournalFormatter end end - def format_html_detail(label, old_value, value) + def format_html_detail(label, key, old_value, value, options = {}) label = content_tag('strong', label) - old_value = content_tag("i", h(old_value)) if old_value && !old_value.blank? - old_value = content_tag("strike", old_value) if old_value and value.blank? - value = content_tag("i", h(value)) if value.present? - value ||= "" - [label, old_value, value] - end - # Formats a detail to be used with a Journal diff - # - # Truncates the content. Adds a link to view a diff. - def format_html_diff_detail(key, label, old_value, value) - link = link_to(l(:label_more), {:controller => 'journals', :action => 'diff', :id => id, :field => key.to_s}, :class => 'lightbox-ajax') - old_value = truncate(old_value, :length => 80) - value = truncate(value, :length => 80) + " " + link - [old_value, value] + # Sanitize values + old_value, value = h(old_value), h(value) + + # Truncate as needed + old_value, value = truncate(old_value, :length => 80), truncate(value, :length => 80) if options[:truncate].present? + + # Style + old_value = content_tag("i", old_value) if old_value.present? + old_value = content_tag("strike", old_value) if old_value.present? and value.blank? + value = content_tag("i", value) if value.present? + value ||= "" + + # More link + if options[:more_link].present? + value += " " + link_to(l(:label_more), {:controller => 'journals', :action => 'diff', :id => id, :field => key.to_s}, :class => 'lightbox-ajax') + end + + [label, old_value, value] end def property(detail) @@ -195,11 +199,10 @@ module JournalFormatter label, old_value, value = [label, old_value, value].collect(&:to_s) unless no_html - label, old_value, value = *format_html_detail(label, old_value, value) + options = {} + options = options.merge({:truncate => true, :more_link => true}) if property(detail) == :attribute && key == "description" + label, old_value, value = *format_html_detail(label, key, old_value, value, options) value = format_html_attachment_detail(key.sub("attachments", ""), value) if attachment_detail - if property(detail) == :attribute && key == "description" - old_value, value = *format_html_diff_detail(key, label, old_value, value) - end end unless value.blank? From 26c847a4ca3894728382b4b808aaeacbc1e0b7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Fri, 16 Mar 2012 00:30:20 +0100 Subject: [PATCH 15/54] More specific CSS #911 --- public/stylesheets/application.css | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 03e1557f..c5b1d35c 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -121,16 +121,16 @@ tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; tr.issue td.subject { text-align: left; } tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} -tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} -tr.issue.idnt-1 td.subject {padding-left: 0.5em;} -tr.issue.idnt-2 td.subject {padding-left: 2em;} -tr.issue.idnt-3 td.subject {padding-left: 3.5em;} -tr.issue.idnt-4 td.subject {padding-left: 5em;} -tr.issue.idnt-5 td.subject {padding-left: 6.5em;} -tr.issue.idnt-6 td.subject {padding-left: 8em;} -tr.issue.idnt-7 td.subject {padding-left: 9.5em;} -tr.issue.idnt-8 td.subject {padding-left: 11em;} -tr.issue.idnt-9 td.subject {padding-left: 12.5em;} +#content tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +#content tr.issue.idnt-1 td.subject {padding-left: 0.5em;} +#content tr.issue.idnt-2 td.subject {padding-left: 2em;} +#content tr.issue.idnt-3 td.subject {padding-left: 3.5em;} +#content tr.issue.idnt-4 td.subject {padding-left: 5em;} +#content tr.issue.idnt-5 td.subject {padding-left: 6.5em;} +#content tr.issue.idnt-6 td.subject {padding-left: 8em;} +#content tr.issue.idnt-7 td.subject {padding-left: 9.5em;} +#content tr.issue.idnt-8 td.subject {padding-left: 11em;} +#content tr.issue.idnt-9 td.subject {padding-left: 12.5em;} tr.entry { border: 1px solid #f8f8f8; } tr.entry td { white-space: nowrap; } From 20eed684216f48a7fe0d583e72c3143bd1a33521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Wed, 30 Nov 2011 08:51:38 +0100 Subject: [PATCH 16/54] [#739] Convert relative links to full links in textile Textile doesn't "understand" :only_path => false and thus doesn't convert links of the form
"foo":/bar
to full URLs, this is done in a subsequent method akin to the wiki_lins and so on --- app/helpers/application_helper.rb | 37 +++++++++++++++++++- test/unit/helpers/application_helper_test.rb | 32 +++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7503437c..394e05ae 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -502,7 +502,7 @@ module ApplicationHelper @parsed_headings = [] text = parse_non_pre_blocks(text) do |text| - [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name| + [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings, :parse_relative_urls].each do |method_name| send method_name, text, project, obj, attr, only_path, options end end @@ -543,6 +543,41 @@ module ApplicationHelper parsed end + RELATIVE_LINK_RE = %r{ + ]+?)')| + (?:"(\/[^>]+?)") + ) + )| + [^>] + )* + > + [^<]*?<\/a> # content and closing link tag. + }x unless const_defined?(:RELATIVE_LINK_RE) + + def parse_relative_urls(text, project, obj, attr, only_path, options) + return if only_path + text.gsub!(RELATIVE_LINK_RE) do |m| + href, relative_url = $1, $2 || $3 + next m unless href.present? + if defined?(request) && request.present? + # we have a request! + protocol, host_with_port = request.protocol, request.host_with_port + elsif @controller + # use the same methods as url_for in the Mailer + url_opts = @controller.class.default_url_options + next m unless url_opts && url_opts[:protocol] && url_opts[:host] + protocol, host_with_port = "#{url_opts[:protocol]}://", url_opts[:host] + else + next m + end + m.sub href, " href=\"#{protocol}#{host_with_port}#{relative_url}\"" + end + end + def parse_inline_attachments(text, project, obj, attr, only_path, options) # when using an image link, try to use an attachment, if possible if options[:attachments] || (obj && obj.respond_to?(:attachments)) diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb index 48c99c05..8c9af006 100644 --- a/test/unit/helpers/application_helper_test.rb +++ b/test/unit/helpers/application_helper_test.rb @@ -27,6 +27,10 @@ class ApplicationHelperTest < ActionView::TestCase super end + def request + @request ||= ActionController::TestRequest.new + end + context "#link_to_if_authorized" do context "authorized user" do should "be tested" @@ -144,6 +148,34 @@ RAW to_test.each { |text, result| assert_equal "

#{result}

", textilizable(text) } end + def test_textile_relative_to_full_links_in_a_controller + # we have a request here + { + # shouldn't change non-relative links + 'This is a "link":http://foo.bar' => 'This is a
link', + 'This is an intern "link":/foo/bar' => 'This is an intern link', + 'This is an intern "link":/foo/bar and an extern "link":http://foo.bar' => 'This is an intern link and an extern link', + }.each { |text, result| assert_equal "

#{result}

", textilizable(text, :only_path => false) } + end + + def test_textile_relative_to_full_links_in_the_mailer + # we don't a request here + undef request + # mimic the mailer default_url_options + @controller.class.class_eval { + def self.default_url_options + ::Mailer.default_url_options + end + } + + { + # shouldn't change non-relative links + 'This is a "link":http://foo.bar' => 'This is a link', + 'This is an intern "link":/foo/bar' => 'This is an intern link', + 'This is an intern "link":/foo/bar and an extern "link":http://foo.bar' => 'This is an intern link and an extern link', + }.each { |text, result| assert_equal "

#{result}

", textilizable(text, :only_path => false) } + end + def test_redmine_links issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3}, :class => 'issue status-1 priority-1 overdue', :title => 'Error 281 when updating a recipe (New)') From df66e9b915ff53cef1b1d51d26e48eb215f8c28f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Sat, 17 Mar 2012 13:53:29 +0100 Subject: [PATCH 17/54] aaj: default to don't force notes as event descriptions #933 --- vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb index 7646d49c..670f6f33 100644 --- a/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb +++ b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb @@ -181,7 +181,7 @@ module Redmine end options[:type] ||= self.name.underscore.dasherize # Make sure the name of the journalized model and not the name of the journal is used for events options[:author] ||= :user - { :description => :notes }.reverse_merge options + options.reverse_merge({:description => :notes}) end end From f01194856f205d43e22026af5a6e186d98df74fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Sat, 17 Mar 2012 13:55:36 +0100 Subject: [PATCH 18/54] Use the news description as event description #933 --- app/models/news.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/news.rb b/app/models/news.rb index 1230bc87..3bf555e6 100644 --- a/app/models/news.rb +++ b/app/models/news.rb @@ -21,7 +21,8 @@ class News < ActiveRecord::Base validates_length_of :title, :maximum => 60 validates_length_of :summary, :maximum => 255 - acts_as_journalized :event_url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.journaled_id} } + acts_as_journalized :event_url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.journaled_id} }, + :event_description => :description acts_as_searchable :columns => ["#{table_name}.title", "#{table_name}.summary", "#{table_name}.description"], :include => :project acts_as_watchable From efac256a6bdbe19b29e620a0d986ae594628e49b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Sat, 17 Mar 2012 15:31:26 +0100 Subject: [PATCH 19/54] Design fix The lower would only show if you have the permission to see/add related issues --- app/views/issues/show.rhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index 9642c289..8c4ad67b 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -91,9 +91,9 @@
<%= render :partial => 'relations' %>
-
<% end %> +
<% if @changesets.present? %> From 68efc3de32252a2b8aabd6db0aa63d1838add674 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Sun, 18 Mar 2012 18:15:08 +0100 Subject: [PATCH 20/54] [#903] Require updated tzinfo with fix for Ruby 1.9.3 --- Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile b/Gemfile index 0ef4d190..03820dea 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem "liquid", "~> 2.3.0" gem "acts-as-taggable-on", "= 2.1.0" # Needed only on RUBY_VERSION = 1.8, ruby 1.9+ compatible interpreters should bring their csv gem "fastercsv", "~> 1.5.0", :platforms => [:ruby_18, :jruby, :mingw_18] +gem "tzinfo", "~> 0.3.31" # Fixes #903. Not required for Rails >= 3.2 group :test do gem 'shoulda', '~> 2.10.3' From 565aeabc79ccc5d13c66c30a504d5f5f4277e8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Sat, 17 Mar 2012 15:23:14 +0100 Subject: [PATCH 21/54] Issue hierarchy on issue show view #906 --- app/helpers/issues_helper.rb | 16 ++++++++++++++++ app/views/issues/_tree_simple.html.erb | 11 +++++++++++ app/views/issues/show.rhtml | 12 +----------- config/locales/de.yml | 2 ++ config/locales/en.yml | 2 ++ public/stylesheets/application.css | 2 ++ 6 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 app/views/issues/_tree_simple.html.erb diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index d8d6cd00..a26cb615 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -79,6 +79,22 @@ module IssuesHelper s end + def render_parents_and_subtree(issue) + return if issue.leaf? && !issue.parent + s = '
' + issue_list(issue.self_and_ancestors.sort_by(&:lft) + issue.descendants.sort_by(&:lft)) do |el, level| + s << content_tag('tr', + content_tag('td', check_box_tag("ids[]", el.id, false, :id => nil), :class => 'checkbox') + + content_tag('td', link_to_issue(el, :truncate => 60), :class => 'subject') + + content_tag('td', h(el.status)) + + content_tag('td', link_to_user(el.assigned_to)) + + content_tag('td', progress_bar(el.done_ratio, :width => '80px')), + :class => "issue issue-#{el.id} #{"self" if el == issue} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}") + end + s << '
' + s + end + def render_custom_fields_rows(issue) return if issue.custom_field_values.empty? ordered_values = [] diff --git a/app/views/issues/_tree_simple.html.erb b/app/views/issues/_tree_simple.html.erb new file mode 100644 index 00000000..9ad973c7 --- /dev/null +++ b/app/views/issues/_tree_simple.html.erb @@ -0,0 +1,11 @@ +<% if !@issue.leaf? || @issue.parent || User.current.allowed_to?(:manage_subtasks, @project) %> +
+

+ <%= l(:label_issue_hierarchy) %> + <% if User.current.allowed_to?(:manage_subtasks, @project) %> + (<%= link_to(l(:label_subtask_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) %>) + <% end %> +

+<% end %> + +<%= render_parents_and_subtree @issue %> diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index 8c4ad67b..a358201f 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -74,17 +74,7 @@ <%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %> -<% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %> -
-
-

- <%=l(:label_subtask_plural)%> - (<%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>) -

- -<%= render_descendants_tree(@issue) unless @issue.leaf? %> -
-<% end %> +<%= render :partial => 'tree_simple' %> <% if authorize_for('issue_relations', 'new') || @issue.relations.present? %>
diff --git a/config/locales/de.yml b/config/locales/de.yml index 3654836a..0448b4fd 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -796,6 +796,8 @@ de: label_api_access_key_created_on: Der API-Zugriffsschlüssel wurde vor %{value} erstellt label_profile: Profil label_subtask_plural: Unteraufgaben + label_subtask_add: Unteraufgabe hinzufügen + label_issue_hierarchy: Tickethierarchie label_project_copy_notifications: Sende Mailbenachrichtigungen beim Kopieren des Projekts. label_principal_search: "Nach Benutzer oder Gruppe suchen:" label_user_search: "Nach Benutzer suchen:" diff --git a/config/locales/en.yml b/config/locales/en.yml index a879da48..fb48c1db 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -808,6 +808,8 @@ en: label_api_access_key_created_on: "API access key created %{value} ago" label_profile: Profile label_subtask_plural: Subtasks + label_subtask_add: Add a subtask + label_issue_hierarchy: Issue hierarchy label_project_copy_notifications: Send email notifications during the project copy label_principal_search: "Search for user or group:" label_user_search: "Search for user:" diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index c5b1d35c..2c1be07a 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -264,8 +264,10 @@ div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: div.issue div.subject>div>p { margin-top: 0.5em; } div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;} +#issue_tree {border: none;} #issue_tree table.issues { border: 0; } #issue_tree td.checkbox {display:none;} +#issue_tree tr.self a.issue {color: inherit;} #content fieldset#filters { padding-bottom:10px; From c9a403a4b55752c69530433fc61191a71507b69f Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Tue, 20 Mar 2012 22:19:52 +0100 Subject: [PATCH 22/54] [#939] Update documentation for GMail setup It now matches the current guide in ChiliProject Wiki at https://www.chiliproject.org/projects/chiliproject/wiki/Email_Delivery#SMTP-server-using-TLS-GMail --- config/configuration.yml.example | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/config/configuration.yml.example b/config/configuration.yml.example index b75a9243..73abee9d 100644 --- a/config/configuration.yml.example +++ b/config/configuration.yml.example @@ -53,17 +53,16 @@ # # ==== SMTP server at using TLS (GMail) # -# This requires some additional configuration. See the article at: -# http://redmineblog.com/articles/setup-redmine-to-send-email-using-gmail/ +# This might require some additional configuration. See the guides at: +# https://www.chiliproject.org/projects/chiliproject/wiki/Email_Delivery#SMTP-server-using-TLS-GMail # # production: # email_delivery: # delivery_method: :smtp # smtp_settings: -# tls: true +# enable_starttls_auto: true # address: "smtp.gmail.com" # port: 587 -# domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps # authentication: :plain # user_name: "your_email@gmail.com" # password: "your_password" From 27160b76f578315bdd9070f38637a69052049829 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Mon, 19 Mar 2012 00:38:02 +0000 Subject: [PATCH 23/54] The jQuery ajaxStart/Stop functions are being called at the wrong time. The ajaxStart/ajaxStop functions were being called before the document was ready and the 'ajax-indicator' element existed. This meant that they would never be called when an ajax event happened. --- public/javascripts/application.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/public/javascripts/application.js b/public/javascripts/application.js index b62e0f8e..b2c4b730 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -470,13 +470,12 @@ jQuery.ajaxSetup({ 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")} }) -// Show/hide the ajax indicators -jQuery("#ajax-indicator").ajaxStart(function(){ jQuery(this).show().css('z-index', '9999'); }); -jQuery("#ajax-indicator").ajaxStop(function(){ jQuery(this).hide(); }); - /* TODO: integrate with existing code and/or refactor */ jQuery(document).ready(function($) { + // Show/hide the ajax indicators + jQuery("#ajax-indicator").ajaxStart(function(){ jQuery(this).show().css('z-index', '9999'); }); + jQuery("#ajax-indicator").ajaxStop(function(){ jQuery(this).hide(); }); // file table thumbnails $("table a.has-thumb").hover(function() { From 1b7ddb3cd767bc1832b77c31bf6953163c01373b Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Fri, 17 Feb 2012 15:49:26 +1000 Subject: [PATCH 24/54] jQuery version of the issue context menu --- app/helpers/application_helper.rb | 4 +- app/views/issues/show.rhtml | 4 +- public/javascripts/context_menu.jquery.js | 211 ++++++++++++++++++++++ 3 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 public/javascripts/context_menu.jquery.js diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 394e05ae..af424852 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -885,7 +885,7 @@ module ApplicationHelper def context_menu(url) unless @context_menu_included content_for :header_tags do - javascript_include_tag('context_menu') + + javascript_include_tag('context_menu.jquery') + stylesheet_link_tag('context_menu') end if l(:direction) == 'rtl' @@ -895,7 +895,7 @@ module ApplicationHelper end @context_menu_included = true end - javascript_tag "new ContextMenu('#{ url_for(url) }')" + javascript_tag "jQuery(document).ContextMenu('#{ url_for(url) }')" end def context_menu_link(name, url, options={}) diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index a358201f..90014cff 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -138,9 +138,9 @@ <% content_for :header_tags do %> <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %> <%= stylesheet_link_tag 'scm' %> - <%= javascript_include_tag 'context_menu' %> + <%= javascript_include_tag 'context_menu.jquery' %> <%= stylesheet_link_tag 'context_menu' %> <%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %> <% end %> -<%= javascript_tag "new ContextMenu('#{issues_context_menu_path}')" %> +<%= javascript_tag "jQuery(document).ContextMenu('#{issues_context_menu_path}')" %> diff --git a/public/javascripts/context_menu.jquery.js b/public/javascripts/context_menu.jquery.js new file mode 100644 index 00000000..40c062c5 --- /dev/null +++ b/public/javascripts/context_menu.jquery.js @@ -0,0 +1,211 @@ +(function($) { + var observingContextMenuClick; + var url; + var lastSelected; + var menu; + var menuId = 'context-menu'; + var selectorName = 'hascontextmenu'; + var contextMenuSelectionClass = 'context-menu-selection'; + var reverseXClass = 'reverse-x'; + var reverseYClass = 'reverse-y'; + + var methods = { + createMenu: function() { + if(!menu) { + $('#wrapper').append(''); + menu = $('#' + menuId); + } + }, + click: function(e) { + var target = $(e.target); + + if(target.is('a')) { + return; + } + + switch(e.which) { + case 1: + if(e.type === 'click') { + methods.hideMenu(); + methods.leftClick(e); + break; + } + case 3: + if(e.type === 'contextmenu') { + methods.hideMenu(); + methods.rightClick(e); + break; + } + default: + return; + } + }, + leftClick: function(e) { + var target = $(e.target); + var tr = target.parents('tr'); + if((tr.size() > 0) && tr.hasClass(selectorName)) + { + // a row was clicked, check if the click was on checkbox + if(target.is('input')) + { + // a checkbox may be clicked + if (target.is(':checked')) { + tr.addClass(contextMenuSelectionClass); + } else { + tr.removeClass(contextMenuSelectionClass); + } + } + else + { + if (e.ctrlKey || e.metaKey) + { + methods.toggleSelection(tr); + } + else if (e.shiftKey) + { + if (lastSelected !== null) + { + var toggling = false; + var rows = $(selectorName); + for (i = 0; i < rows.length; i++) + { + if (toggling || rows[i] == tr) + { + methods.addSelection(rows[i]); + } + if (rows[i] == tr || rows[i] == lastSelected) + { + toggling = !toggling; + } + } + } else { + methods.addSelection(tr); + } + } else { + methods.unselectAll(); + methods.addSelection(tr); + } + lastSelected = tr; + } + } + else + { + // click is outside the rows + if (target.is('a') === false) { + this.unselectAll(); + } else { + if (target.hasClass('disabled') || target.hasClass('submenu')) { + e.preventDefault(); + } + } + } + }, + rightClick: function(e) { + var target = $(e.target); + var tr = target.parents('tr'); + + if((tr.size() === 0) || !(tr.hasClass(selectorName))) { + return; + } + e.preventDefault(); + + if(!methods.isSelected(tr)) { + methods.unselectAll(); + methods.addSelection(tr); + lastSelected = tr; + } + methods.showMenu(e); + }, + unselectAll: function() { + var rows = $('.' + contextMenuSelectionClass); + rows.each(function() { + methods.removeSelection($(this)); + }); + }, + hideMenu: function() { + menu.hide(); + }, + showMenu: function(e) { + var target = $(e.target); + var params = target.parents('form').serialize(); + + var mouseX = e.pageX; + var mouseY = e.pageY; + var renderX = mouseX; + var renderY = mouseY; + + $.ajax({ + url: url, + data: params, + success: function(response, success) { + menu.html(response); + + var maxWidth = mouseX + (2 * menu.width()); + var maxHeight = mouseY + menu.height(); + + if(maxWidth > $(window).width()) { + renderX -= menu.width(); + menu.addClass(reverseXClass); + } else { + menu.removeClass(reverseXClass); + } + + if(maxHeight > $(window).height()) { + renderY =+ menu.height(); + menu.addClass(reverseYClass); + } else { + menu.removeClass(reverseYClass); + } + + if(renderX <= 0) { + renderX = 1; + } + if(renderY <= 0) { + renderY = 1; + } + + menu.css('top', renderY).css('left', renderX); + menu.show(); + } + }); + }, + addSelection: function(element) { + element.addClass(contextMenuSelectionClass); + methods.checkSelectionBox(element, true); + }, + isSelected: function(element) { + return element.hasClass(contextMenuSelectionClass); + }, + toggleSelection: function(element) { + if(methods.isSelected(element)) { + methods.removeSelection(element); + } else { + methods.addSelection(element); + } + }, + removeSelection: function(element) { + element.removeClass(contextMenuSelectionClass); + methods.checkSelectionBox(element, false); + }, + checkSelectionBox: function(element, checked) { + var inputs = element.find('input'); + inputs.each(function() { + inputs.attr('checked', checked ? 'checked' : false); + }); + } + }; + + $.fn.ContextMenu = function(u) { + url = u; + methods.createMenu(); + + if(!observingContextMenuClick) { + $(document).bind('click.contextMenu', methods.click); + $(document).bind('contextmenu.contextMenu', methods.click); + observingContextMenuClick = true; + } + + methods.unselectAll(); + lastSelected = null; + }; +})(jQuery); From 2b640f76ec5f173d425c483c38d5da114278ef0f Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Fri, 24 Feb 2012 09:08:47 +1000 Subject: [PATCH 25/54] Simple wrapper for backwards compatibility --- public/javascripts/context_menu.jquery.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/public/javascripts/context_menu.jquery.js b/public/javascripts/context_menu.jquery.js index 40c062c5..782eabd0 100644 --- a/public/javascripts/context_menu.jquery.js +++ b/public/javascripts/context_menu.jquery.js @@ -209,3 +209,10 @@ lastSelected = null; }; })(jQuery); + +/** + * Wrapper function to support the old way of creating aa context menu. + */ +function ContextMenu() { + jQuery(document).ContextMenu(arguments); +} From a510f0a85f3f779b8136d40b62e5c942191c5fb5 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Fri, 24 Feb 2012 09:12:29 +1000 Subject: [PATCH 26/54] Updates the plugin so that it can support multiple instances. Multiple instances need to be applied to different elements in the DOM otherwise multiple menus will be called for each click/right click. e.g. jQuery(document).ContextMenu(url); would work for any form on a page. Using this would mean that multiple instances couldn't be used though jQuery('#content form').eq(0).ContextMenu(url); jQuery('#content form').eq(3).ContextMenu(url); Using the above 2 menus will be created for the first and 4th forms on the page. Any of forms won't response to menu clicks. jQuery(docuemnt).ContextMenu(url); jQuery('#content form').eq(0).ContextMenu(url); With the above any form on the page will respond to menu clicks but the first form will send 2 requests for the context menu. --- public/javascripts/context_menu.jquery.js | 375 +++++++++++----------- 1 file changed, 190 insertions(+), 185 deletions(-) diff --git a/public/javascripts/context_menu.jquery.js b/public/javascripts/context_menu.jquery.js index 782eabd0..b5148738 100644 --- a/public/javascripts/context_menu.jquery.js +++ b/public/javascripts/context_menu.jquery.js @@ -1,212 +1,217 @@ (function($) { - var observingContextMenuClick; - var url; - var lastSelected; - var menu; - var menuId = 'context-menu'; - var selectorName = 'hascontextmenu'; - var contextMenuSelectionClass = 'context-menu-selection'; - var reverseXClass = 'reverse-x'; - var reverseYClass = 'reverse-y'; + var ContextMenuClass = function(el, options) { + var element = el; + var opts = options; + var observingContextMenuClick; + var lastSelected = null; + var menu; + var menuId = 'context-menu'; + var selectorName = 'hascontextmenu'; + var contextMenuSelectionClass = 'context-menu-selection'; + var reverseXClass = 'reverse-x'; + var reverseYClass = 'reverse-y'; - var methods = { - createMenu: function() { - if(!menu) { - $('#wrapper').append(''); - menu = $('#' + menuId); - } - }, - click: function(e) { - var target = $(e.target); + var methods = { + createMenu: function() { + if(!menu) { + $('#wrapper').append(''); + menu = $('#' + menuId); + } + }, + click: function(e) { + var target = $(e.target); - if(target.is('a')) { - return; - } - - switch(e.which) { - case 1: - if(e.type === 'click') { - methods.hideMenu(); - methods.leftClick(e); - break; - } - case 3: - if(e.type === 'contextmenu') { - methods.hideMenu(); - methods.rightClick(e); - break; - } - default: + if(target.is('a')) { return; - } - }, - leftClick: function(e) { - var target = $(e.target); - var tr = target.parents('tr'); - if((tr.size() > 0) && tr.hasClass(selectorName)) - { - // a row was clicked, check if the click was on checkbox - if(target.is('input')) + } + + switch(e.which) { + case 1: + if(e.type === 'click') { + methods.hideMenu(); + methods.leftClick(e); + break; + } + case 3: + if(e.type === 'contextmenu') { + methods.hideMenu(); + methods.rightClick(e); + break; + } + default: + return; + } + }, + leftClick: function(e) { + var target = $(e.target); + var tr = target.parents('tr'); + if((tr.size() > 0) && tr.hasClass(selectorName)) { - // a checkbox may be clicked - if (target.is(':checked')) { - tr.addClass(contextMenuSelectionClass); - } else { - tr.removeClass(contextMenuSelectionClass); + // a row was clicked, check if the click was on checkbox + if(target.is('input')) + { + // a checkbox may be clicked + if (target.is(':checked')) { + tr.addClass(contextMenuSelectionClass); + } else { + tr.removeClass(contextMenuSelectionClass); + } + } + else + { + if (e.ctrlKey || e.metaKey) + { + methods.toggleSelection(tr); + } + else if (e.shiftKey) + { + if (lastSelected !== null) + { + var toggling = false; + var rows = $(selectorName); + for (i = 0; i < rows.length; i++) + { + if (toggling || rows[i] == tr) + { + methods.addSelection(rows[i]); + } + if (rows[i] == tr || rows[i] == lastSelected) + { + toggling = !toggling; + } + } + } else { + methods.addSelection(tr); + } + } else { + methods.unselectAll(); + methods.addSelection(tr); + } + lastSelected = tr; } } else { - if (e.ctrlKey || e.metaKey) - { - methods.toggleSelection(tr); - } - else if (e.shiftKey) - { - if (lastSelected !== null) - { - var toggling = false; - var rows = $(selectorName); - for (i = 0; i < rows.length; i++) - { - if (toggling || rows[i] == tr) - { - methods.addSelection(rows[i]); - } - if (rows[i] == tr || rows[i] == lastSelected) - { - toggling = !toggling; - } - } - } else { - methods.addSelection(tr); - } + // click is outside the rows + if (target.is('a') === false) { + this.unselectAll(); } else { - methods.unselectAll(); - methods.addSelection(tr); + if (target.hasClass('disabled') || target.hasClass('submenu')) { + e.preventDefault(); + } } + } + }, + rightClick: function(e) { + var target = $(e.target); + var tr = target.parents('tr'); + + if((tr.size() === 0) || !(tr.hasClass(selectorName))) { + return; + } + e.preventDefault(); + + if(!methods.isSelected(tr)) { + methods.unselectAll(); + methods.addSelection(tr); lastSelected = tr; } - } - else - { - // click is outside the rows - if (target.is('a') === false) { - this.unselectAll(); + methods.showMenu(e); + }, + unselectAll: function() { + var rows = $('.' + contextMenuSelectionClass); + rows.each(function() { + methods.removeSelection($(this)); + }); + }, + hideMenu: function() { + menu.hide(); + }, + showMenu: function(e) { + var target = $(e.target); + var params = target.parents('form').serialize(); + + var mouseX = e.pageX; + var mouseY = e.pageY; + var renderX = mouseX; + var renderY = mouseY; + + $.ajax({ + url: opts.url, + data: params, + success: function(response, success) { + menu.html(response); + + var maxWidth = mouseX + (2 * menu.width()); + var maxHeight = mouseY + menu.height(); + + if(maxWidth > $(window).width()) { + renderX -= menu.width(); + menu.addClass(reverseXClass); + } else { + menu.removeClass(reverseXClass); + } + + if(maxHeight > $(window).height()) { + renderY =+ menu.height(); + menu.addClass(reverseYClass); + } else { + menu.removeClass(reverseYClass); + } + + if(renderX <= 0) { + renderX = 1; + } + if(renderY <= 0) { + renderY = 1; + } + + menu.css('top', renderY).css('left', renderX); + menu.show(); + } + }); + }, + addSelection: function(element) { + element.addClass(contextMenuSelectionClass); + methods.checkSelectionBox(element, true); + }, + isSelected: function(element) { + return element.hasClass(contextMenuSelectionClass); + }, + toggleSelection: function(element) { + if(methods.isSelected(element)) { + methods.removeSelection(element); } else { - if (target.hasClass('disabled') || target.hasClass('submenu')) { - e.preventDefault(); - } + methods.addSelection(element); } + }, + removeSelection: function(element) { + element.removeClass(contextMenuSelectionClass); + methods.checkSelectionBox(element, false); + }, + checkSelectionBox: function(element, checked) { + var inputs = element.find('input'); + inputs.each(function() { + inputs.attr('checked', checked ? 'checked' : false); + }); } - }, - rightClick: function(e) { - var target = $(e.target); - var tr = target.parents('tr'); + }; - if((tr.size() === 0) || !(tr.hasClass(selectorName))) { - return; - } - e.preventDefault(); - - if(!methods.isSelected(tr)) { - methods.unselectAll(); - methods.addSelection(tr); - lastSelected = tr; - } - methods.showMenu(e); - }, - unselectAll: function() { - var rows = $('.' + contextMenuSelectionClass); - rows.each(function() { - methods.removeSelection($(this)); - }); - }, - hideMenu: function() { - menu.hide(); - }, - showMenu: function(e) { - var target = $(e.target); - var params = target.parents('form').serialize(); - - var mouseX = e.pageX; - var mouseY = e.pageY; - var renderX = mouseX; - var renderY = mouseY; - - $.ajax({ - url: url, - data: params, - success: function(response, success) { - menu.html(response); - - var maxWidth = mouseX + (2 * menu.width()); - var maxHeight = mouseY + menu.height(); - - if(maxWidth > $(window).width()) { - renderX -= menu.width(); - menu.addClass(reverseXClass); - } else { - menu.removeClass(reverseXClass); - } - - if(maxHeight > $(window).height()) { - renderY =+ menu.height(); - menu.addClass(reverseYClass); - } else { - menu.removeClass(reverseYClass); - } - - if(renderX <= 0) { - renderX = 1; - } - if(renderY <= 0) { - renderY = 1; - } - - menu.css('top', renderY).css('left', renderX); - menu.show(); - } - }); - }, - addSelection: function(element) { - element.addClass(contextMenuSelectionClass); - methods.checkSelectionBox(element, true); - }, - isSelected: function(element) { - return element.hasClass(contextMenuSelectionClass); - }, - toggleSelection: function(element) { - if(methods.isSelected(element)) { - methods.removeSelection(element); - } else { - methods.addSelection(element); - } - }, - removeSelection: function(element) { - element.removeClass(contextMenuSelectionClass); - methods.checkSelectionBox(element, false); - }, - checkSelectionBox: function(element, checked) { - var inputs = element.find('input'); - inputs.each(function() { - inputs.attr('checked', checked ? 'checked' : false); - }); - } - }; - - $.fn.ContextMenu = function(u) { - url = u; methods.createMenu(); if(!observingContextMenuClick) { - $(document).bind('click.contextMenu', methods.click); - $(document).bind('contextmenu.contextMenu', methods.click); + element.bind('click.contextMenu', methods.click); + element.bind('contextmenu.contextMenu', methods.click); observingContextMenuClick = true; } methods.unselectAll(); - lastSelected = null; + }; + + $.fn.ContextMenu = function(u) { + return this.each(function() { + new ContextMenuClass($(this), {url: u}); + }); }; })(jQuery); From 23a857bf7545cf712c04e57d7a26010a865b7049 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Mon, 19 Mar 2012 00:57:54 +0000 Subject: [PATCH 27/54] Remove hard-coded div on issue page --- app/views/issues/show.rhtml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index 90014cff..8600fbb9 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -142,5 +142,4 @@ <%= stylesheet_link_tag 'context_menu' %> <%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %> <% end %> - <%= javascript_tag "jQuery(document).ContextMenu('#{issues_context_menu_path}')" %> From 2a70e2704f0ac498b88ed5a28e508b2b02ecced1 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Fri, 24 Feb 2012 13:07:01 +0000 Subject: [PATCH 28/54] HTML corrections --- app/views/account/_login.rhtml | 1 + app/views/layouts/base.rhtml | 2 -- app/views/queries/_columns.rhtml | 4 ++-- app/views/queries/_filters.rhtml | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/views/account/_login.rhtml b/app/views/account/_login.rhtml index bebade71..b27e979b 100644 --- a/app/views/account/_login.rhtml +++ b/app/views/account/_login.rhtml @@ -5,6 +5,7 @@ + <%= text_field_tag 'username', nil, :tabindex => '1', :id => 'username-pulldown' %> diff --git a/app/views/layouts/base.rhtml b/app/views/layouts/base.rhtml index 4d34d8d8..b490262e 100644 --- a/app/views/layouts/base.rhtml +++ b/app/views/layouts/base.rhtml @@ -74,7 +74,6 @@ <% end %> -
  • <%= render_menu_node(help_menu_item) %> <% unless User.current.logged? %> <% if Setting.self_registration? %> @@ -98,7 +97,6 @@
  • <% end %> - <% end %> diff --git a/app/views/queries/_columns.rhtml b/app/views/queries/_columns.rhtml index f5a0ca4c..f2bb5993 100644 --- a/app/views/queries/_columns.rhtml +++ b/app/views/queries/_columns.rhtml @@ -2,7 +2,7 @@ <%= label_tag "available_columns", l(:description_available_columns) %> -
    +
    <%= select_tag 'available_columns', options_for_select((query.available_columns - query.columns).collect {|column| [column.caption, column.name]}), :multiple => true, :size => 10, :style => "width:150px" %> @@ -15,7 +15,7 @@ <%= label_tag "selected_columns", l(:description_selected_columns) %> -
    +
    <%= select_tag 'c[]', options_for_select(query.columns.collect {|column| [column.caption, column.name]}), :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px" %> diff --git a/app/views/queries/_filters.rhtml b/app/views/queries/_filters.rhtml index 3c969807..3e30df72 100644 --- a/app/views/queries/_filters.rhtml +++ b/app/views/queries/_filters.rhtml @@ -113,7 +113,7 @@ Event.observe(document,"dom:loaded", apply_filters_observer); - <%= label_tag "op_#{field}", l(:description_filter), :class => "hidden-for-sighted" %> + <%= label_tag "operators_#{field}", l(:description_filter), :class => "hidden-for-sighted" %> <%= select_tag "op[#{field}]", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :id => "operators_#{field}", :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %> From b15e6d83053c4c2ea175a85b554cefa6b6c13b63 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Sun, 26 Feb 2012 11:42:25 +0000 Subject: [PATCH 29/54] Fix duplicated 'back_url' IDs Various hidden input fields are used to hold a URL to send the user back to the correct page after submitting a form, however, they all use the same ID which isn't allowed in HTML. Passing in 'id' as nil stops the 'hidden_field_tag' from adding an ID attribute to the tag. --- app/helpers/application_helper.rb | 2 +- app/views/account/_login.rhtml | 2 +- app/views/issues/_list.rhtml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index af424852..3528957c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -851,7 +851,7 @@ module ApplicationHelper def back_url_hidden_field_tag back_url = params[:back_url] || request.env['HTTP_REFERER'] back_url = CGI.unescape(back_url.to_s) - hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank? + hidden_field_tag('back_url', CGI.escape(back_url), :id => nil) unless back_url.blank? end def check_all_links(form_name) diff --git a/app/views/account/_login.rhtml b/app/views/account/_login.rhtml index b27e979b..44027a38 100644 --- a/app/views/account/_login.rhtml +++ b/app/views/account/_login.rhtml @@ -1,6 +1,6 @@