Compare commits

...
52 Commits
Author SHA1 Message Date
Jean-Philippe Lang 689d533049 tagged version 2.2.3
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/tags/2.2.3@11368 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 19:52:36 +00:00
Jean-Philippe Lang d094dea0ec Merged r11366 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11367 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 18:08:38 +00:00
Jean-Philippe Lang 3a98a14250 Merged r11350 from trunk (#13126).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11365 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 18:04:49 +00:00
Jean-Philippe Lang ecef96a6b9 Merged r11332 from trunk (#13097).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11364 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 18:03:16 +00:00
Jean-Philippe Lang 0951522247 Merged r11331 and r11333 from trunk (#13075).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11363 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 18:01:15 +00:00
Jean-Philippe Lang 42cc2d322a Merged r11281 from trunk (#12979).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11362 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 17:57:46 +00:00
Jean-Philippe Lang 0367c323de Merged r11258 from trunk (#12930).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11361 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 17:56:39 +00:00
Toshi MARUYAMA 80be82ae50 Merged r11353 from trunk to 2.2-stable
upgrade Rails to 3.2.12.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11358 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 06:28:11 +00:00
Toshi MARUYAMA ebed927de5 2.2-stable: svn propset svn:eol-style native SVG source files (#12971)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11357 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 03:52:41 +00:00
Toshi MARUYAMA cbd069118a 2.2-stable: backout r11355 (back to Rails 3.2.11)
jruby-1.6.7 tests fail on CI server.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11356 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 02:49:25 +00:00
Toshi MARUYAMA a211d1be7d Merged r11353 from trunk to 2.2-stable
upgrade Rails to 3.2.12.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11355 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 01:46:21 +00:00
Toshi MARUYAMA 0a8e0a3bed Merged r11306 from trunk to 2.2-stable (#11987)
pdf: fix broken new line in table.

Contributed by Jun NAITOH.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11308 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-03 06:53:18 +00:00
Toshi MARUYAMA 58cf34dea5 Merged r11263 from trunk to 2.2-stable (#12987)
Russian translation for 2.2-stable updated.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11266 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-26 00:40:21 +00:00
Toshi MARUYAMA 594a7bde95 Merged r11246 from trunk to 2.2-stable (#12926, #12928)
Bulgarian translation for 2.2-stable updated by Ivan Cenov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11251 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-21 13:54:49 +00:00
Toshi MARUYAMA c5e257d82b Merged r11243 from trunk to 2.2-stable (#12922)
Spanish translation for 2.2-stable updated by Jorge López.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11245 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-21 11:50:27 +00:00
Jean-Philippe Lang 56b12b289f Merged r11239 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11240 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 18:24:43 +00:00
Jean-Philippe Lang c99eef1aff Merged r11228 from trunk (#12851).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11236 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 17:09:36 +00:00
Jean-Philippe Lang ed891e2733 Merged r11227 from trunk (#9842).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11235 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 17:06:46 +00:00
Jean-Philippe Lang 4620b8b8db Backported r11233 from trunk (#12833).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11234 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 17:03:40 +00:00
Jean-Philippe Lang 98eb2edd25 Merged r11225 from trunk (#12838).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11232 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 17:01:03 +00:00
Jean-Philippe Lang ed7318fb8d Backported r11157 and r11158 from trunk (#12801).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11231 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 16:59:42 +00:00
Jean-Philippe Lang 5a1a2f5855 Merged r11159 from trunk (#12799).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11230 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 16:56:50 +00:00
Jean-Philippe Lang f1314278d5 Backported r11196 from trunk (#7510).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11229 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 16:55:37 +00:00
Toshi MARUYAMA 3a8b872a09 Merged r11170 from trunk to 2.2-stable (#12818)
Swedish translation updated by Nicklas Holm.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11172 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-12 12:43:51 +00:00
Toshi MARUYAMA 56290979fc Merged r11163 from trunk to 2.2-stable (#12809)
Swedish translation updated by Nicklas Holm.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11165 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-11 13:19:18 +00:00
Toshi MARUYAMA 6e0fb415a7 Merged r11160 from trunk to 2.2-stable (#12800)
Serbian translation updated by Miodrag Milic.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11162 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-11 08:31:14 +00:00
Jean-Philippe Lang f26654b29f Merged r11146 from trunk: Changes for 2.2.1 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11147 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-09 13:33:24 +00:00
Jean-Philippe Lang 5c62c1cf95 Merged r11126 from trunk (#12744).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11145 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-09 13:31:05 +00:00
Jean-Philippe Lang 2d6adbd7ff Merged r11088 from trunk (#12691).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11144 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-09 13:29:59 +00:00
Jean-Philippe Lang b0ccaffe1b Merged r11064 from trunk (#12652).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11143 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-09 13:29:08 +00:00
Toshi MARUYAMA 2c37617973 Merged r11140 from trunk to 2.2-stable.
Upgrade to Rails 3.2.11.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11142 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-08 23:57:13 +00:00
Toshi MARUYAMA 567eb70fdb Merged r11128 from trunk to 2.2-stable.
Test fails when run at the beginning of the day.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11141 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-08 23:14:03 +00:00
Toshi MARUYAMA de63102925 Merged r11109 from trunk to 2.2-stable
Upgrade to Rails 3.2.10.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11111 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-04 02:05:44 +00:00
Toshi MARUYAMA a8fcf9389e Merged r11091 from trunk (#12711, #11290)
fix incorrect min_x_value of lib/SVG/Graph/TimeSeries.rb by r10439.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11093 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-03 00:15:32 +00:00
Toshi MARUYAMA 3e4b36de83 Merged r11051 from trunk to 2.2-stable (#12630)
Russian "x_hours" translation updated by Mikhail Velkin.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11054 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-19 00:00:04 +00:00
Jean-Philippe Lang edd584d59e Merged r11041 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11042 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-18 12:24:17 +00:00
Toshi MARUYAMA e2b27ab696 Merged r11036 from trunk to 2.2-stable (#12615, #12619)
Russian translation changed by Kirill Bezrukov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11040 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-18 00:04:49 +00:00
Toshi MARUYAMA 1968d039ee Merged r11035 from trunk to 2.2-stable (#12615)
Russian translation updated by Kirill Bezrukov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11037 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-17 23:24:31 +00:00
Toshi MARUYAMA fddc33cd45 Merged r11022 from trunk to 2.2-stable (#12614)
Dutch translation updated.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11023 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-17 12:43:15 +00:00
Toshi MARUYAMA 29518ba0cf Merged r11015 from trunk to 2.2-stable (#12605, #12608)
Norwegian translation changed by Ketil Mehl.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11018 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-16 07:34:34 +00:00
Toshi MARUYAMA acd27b9eb1 Merged r11014 from trunk to 2.2-stable (#12605)
Norwegian translation for 1.4-stable updated by Ketil Mehl.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11017 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-16 07:34:09 +00:00
Toshi MARUYAMA 6445b5997c Merged r11012 from trunk to 2.2-stable (#12607)
Japanese translation for 2.2-stable updated.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11016 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-16 07:33:39 +00:00
Jean-Philippe Lang 416d33973f Merged r10991 from trunk (#12568).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11009 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 07:55:50 +00:00
Jean-Philippe Lang 82c7dc11d2 Merged r10992 from trunk (#12400).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11006 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 07:52:39 +00:00
Jean-Philippe Lang d22f782d3f Merged r10956 from trunk (#12513).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11004 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 07:51:12 +00:00
Jean-Philippe Lang 3717fdfa79 Merged r10975 from trunk (#12566).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11002 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 07:49:31 +00:00
Toshi MARUYAMA 9d3d932703 Merged r10999 from trunk (#12602)
Korean translation updated by Jongwook Choi.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11000 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 01:32:43 +00:00
Jean-Philippe Lang 3a379ce4b9 Merged r10948 into 2.2-stable (#3447).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10952 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-08 08:41:59 +00:00
Toshi MARUYAMA daa77f0109 Merged r10946 from trunk to 2.2-stable (#12514)
Lithuanian translation updated by Egidijus Zideckas.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10947 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-06 06:30:05 +00:00
Toshi MARUYAMA c0d66d626b Merged r10940 from trunk to 2.2-stable (#12494)
Bulgarian "button_submit" translation changed by Ivan Cenov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10942 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-04 05:43:41 +00:00
Jean-Philippe Lang bf02b76ca3 Sets stable branch.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10908 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-02 18:01:48 +00:00
Jean-Philippe Lang 75e02ca486 branch 2.2-stable added
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10907 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-02 17:58:22 +00:00
59 changed files with 3345 additions and 3004 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
source 'http://rubygems.org' source 'http://rubygems.org'
gem 'rails', '3.2.9' gem 'rails', '3.2.12'
gem "jquery-rails", "~> 2.0.2" gem "jquery-rails", "~> 2.0.2"
gem "i18n", "~> 0.6.0" gem "i18n", "~> 0.6.0"
gem "coderay", "~> 1.0.6" gem "coderay", "~> 1.0.6"
+10 -9
View File
@@ -147,15 +147,16 @@ class MyController < ApplicationController
# params[:block] : id of the block to add # params[:block] : id of the block to add
def add_block def add_block
block = params[:block].to_s.underscore block = params[:block].to_s.underscore
(render :nothing => true; return) unless block && (BLOCKS.keys.include? block) if block.present? && BLOCKS.key?(block)
@user = User.current @user = User.current
layout = @user.pref[:my_page_layout] || {} layout = @user.pref[:my_page_layout] || {}
# remove if already present in a group # remove if already present in a group
%w(top left right).each {|f| (layout[f] ||= []).delete block } %w(top left right).each {|f| (layout[f] ||= []).delete block }
# add it on top # add it on top
layout['top'].unshift block layout['top'].unshift block
@user.pref[:my_page_layout] = layout @user.pref[:my_page_layout] = layout
@user.pref.save @user.pref.save
end
redirect_to :action => 'page_layout' redirect_to :action => 'page_layout'
end end
+2 -1
View File
@@ -26,7 +26,8 @@ class PreviewsController < ApplicationController
if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n") if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n")
@description = nil @description = nil
end end
@notes = (params[:issue] ? params[:issue][:notes] : nil) # params[:notes] is useful for preview of notes in issue history
@notes = params[:notes] || (params[:issue] ? params[:issue][:notes] : nil)
else else
@description = (params[:issue] ? params[:issue][:description] : nil) @description = (params[:issue] ? params[:issue][:description] : nil)
end end
+8 -6
View File
@@ -597,8 +597,9 @@ module ApplicationHelper
def parse_inline_attachments(text, project, obj, attr, only_path, options) def parse_inline_attachments(text, project, obj, attr, only_path, options)
# when using an image link, try to use an attachment, if possible # when using an image link, try to use an attachment, if possible
if options[:attachments] || (obj && obj.respond_to?(:attachments)) attachments = options[:attachments] || []
attachments = options[:attachments] || obj.attachments attachments += obj.attachments if obj.respond_to?(:attachments)
if attachments.present?
text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
filename, ext, alt, alttext = $1.downcase, $2, $3, $4 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
# search for the picture in attachments # search for the picture in attachments
@@ -703,10 +704,11 @@ module ApplicationHelper
# identifier:document:"Some document" # identifier:document:"Some document"
# identifier:version:1.0.0 # identifier:version:1.0.0
# identifier:source:some/file # identifier:source:some/file
def parse_redmine_links(text, project, obj, attr, only_path, options) def parse_redmine_links(text, default_project, obj, attr, only_path, options)
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m| text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m|
leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17 leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17
link = nil link = nil
project = default_project
if project_identifier if project_identifier
project = Project.visible.find_by_identifier(project_identifier) project = Project.visible.find_by_identifier(project_identifier)
end end
@@ -792,7 +794,7 @@ module ApplicationHelper
when 'commit', 'source', 'export' when 'commit', 'source', 'export'
if project if project
repository = nil repository = nil
if name =~ %r{^(([a-z0-9\-]+)\|)(.+)$} if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$}
repo_prefix, repo_identifier, name = $1, $2, $3 repo_prefix, repo_identifier, name = $1, $2, $3
repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
else else
@@ -819,7 +821,7 @@ module ApplicationHelper
end end
when 'attachment' when 'attachment'
attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
if attachments && attachment = attachments.detect {|a| a.filename == name } if attachments && attachment = Attachment.latest_attach(attachments, name)
link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment}, link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
:class => 'attachment' :class => 'attachment'
end end
+8 -5
View File
@@ -371,12 +371,16 @@ module IssuesHelper
def issues_to_csv(issues, project, query, options={}) def issues_to_csv(issues, project, query, options={})
decimal_separator = l(:general_csv_decimal_separator) decimal_separator = l(:general_csv_decimal_separator)
encoding = l(:general_csv_encoding) encoding = l(:general_csv_encoding)
columns = (options[:columns] == 'all' ? query.available_columns : query.columns) columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
if options[:description]
if description = query.available_columns.detect {|q| q.name == :description}
columns << description
end
end
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
# csv header fields # csv header fields
csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } + csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
(options[:description] ? [Redmine::CodesetUtil.from_utf8(l(:field_description), encoding)] : [])
# csv lines # csv lines
issues.each do |issue| issues.each do |issue|
@@ -398,8 +402,7 @@ module IssuesHelper
end end
s.to_s s.to_s
end end
csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) } + csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) }
(options[:description] ? [Redmine::CodesetUtil.from_utf8(issue.description, encoding)] : [])
end end
end end
export export
+14 -4
View File
@@ -50,6 +50,14 @@ module QueriesHelper
end end
end end
def available_block_columns_tags(query)
tags = ''.html_safe
query.available_block_columns.each do |column|
tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column)) + " #{column.caption}", :class => 'inline')
end
tags
end
def column_header(column) def column_header(column)
column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
:default_order => column.default_order) : :default_order => column.default_order) :
@@ -70,6 +78,8 @@ module QueriesHelper
when 'String' when 'String'
if column.name == :subject if column.name == :subject
link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) link_to(h(value), :controller => 'issues', :action => 'show', :id => issue)
elsif column.name == :description
issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
else else
h(value) h(value)
end end
@@ -77,14 +87,14 @@ module QueriesHelper
format_time(value) format_time(value)
when 'Date' when 'Date'
format_date(value) format_date(value)
when 'Fixnum', 'Float' when 'Fixnum'
if column.name == :done_ratio if column.name == :done_ratio
progress_bar(value, :width => '80px') progress_bar(value, :width => '80px')
elsif column.name == :spent_hours
sprintf "%.2f", value
else else
h(value.to_s) value.to_s
end end
when 'Float'
sprintf "%.2f", value
when 'User' when 'User'
link_to_user value link_to_user value
when 'Project' when 'Project'
+7 -1
View File
@@ -158,7 +158,13 @@ class CustomField < ActiveRecord::Base
possible_values_options = possible_values_options(customized) possible_values_options = possible_values_options(customized)
if possible_values_options.present? if possible_values_options.present?
keyword = keyword.to_s.downcase keyword = keyword.to_s.downcase
possible_values_options.detect {|text, id| text.downcase == keyword}.try(:last) if v = possible_values_options.detect {|text, id| text.downcase == keyword}
if v.is_a?(Array)
v.last
else
v
end
end
else else
keyword keyword
end end
+1 -1
View File
@@ -418,7 +418,7 @@ class Issue < ActiveRecord::Base
if attrs['parent_issue_id'].present? if attrs['parent_issue_id'].present?
s = attrs['parent_issue_id'].to_s s = attrs['parent_issue_id'].to_s
unless (m = s.match(%r{\A#?(\d+)\z})) && Issue.visible(user).exists?(m[1]) unless (m = s.match(%r{\A#?(\d+)\z})) && (m[1] == parent_id.to_s || Issue.visible(user).exists?(m[1]))
@invalid_parent_issue_id = attrs.delete('parent_issue_id') @invalid_parent_issue_id = attrs.delete('parent_issue_id')
end end
end end
+3 -1
View File
@@ -731,7 +731,7 @@ class Project < ActiveRecord::Base
def copy_wiki(project) def copy_wiki(project)
# Check that the source project has a wiki first # Check that the source project has a wiki first
unless project.wiki.nil? unless project.wiki.nil?
self.wiki ||= Wiki.new wiki = self.wiki || Wiki.new
wiki.attributes = project.wiki.attributes.dup.except("id", "project_id") wiki.attributes = project.wiki.attributes.dup.except("id", "project_id")
wiki_pages_map = {} wiki_pages_map = {}
project.wiki.pages.each do |page| project.wiki.pages.each do |page|
@@ -743,6 +743,8 @@ class Project < ActiveRecord::Base
wiki.pages << new_wiki_page wiki.pages << new_wiki_page
wiki_pages_map[page.id] = new_wiki_page wiki_pages_map[page.id] = new_wiki_page
end end
self.wiki = wiki
wiki.save wiki.save
# Reproduce page hierarchy # Reproduce page hierarchy
project.wiki.pages.each do |page| project.wiki.pages.each do |page|
+24 -1
View File
@@ -27,6 +27,7 @@ class QueryColumn
self.groupable = name.to_s self.groupable = name.to_s
end end
self.default_order = options[:default_order] self.default_order = options[:default_order]
@inline = options.key?(:inline) ? options[:inline] : true
@caption_key = options[:caption] || "field_#{name}" @caption_key = options[:caption] || "field_#{name}"
end end
@@ -43,6 +44,10 @@ class QueryColumn
@sortable.is_a?(Proc) ? @sortable.call : @sortable @sortable.is_a?(Proc) ? @sortable.call : @sortable
end end
def inline?
@inline
end
def value(issue) def value(issue)
issue.send name issue.send name
end end
@@ -58,6 +63,7 @@ class QueryCustomFieldColumn < QueryColumn
self.name = "cf_#{custom_field.id}".to_sym self.name = "cf_#{custom_field.id}".to_sym
self.sortable = custom_field.order_statement || false self.sortable = custom_field.order_statement || false
self.groupable = custom_field.group_statement || false self.groupable = custom_field.group_statement || false
@inline = true
@cf = custom_field @cf = custom_field
end end
@@ -153,7 +159,8 @@ class Query < ActiveRecord::Base
QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"), QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"),
QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true), QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true),
QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'), QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
QueryColumn.new(:relations, :caption => :label_related_issues) QueryColumn.new(:relations, :caption => :label_related_issues),
QueryColumn.new(:description, :inline => false)
] ]
cattr_reader :available_columns cattr_reader :available_columns
@@ -511,6 +518,22 @@ class Query < ActiveRecord::Base
end.compact end.compact
end end
def inline_columns
columns.select(&:inline?)
end
def block_columns
columns.reject(&:inline?)
end
def available_inline_columns
available_columns.select(&:inline?)
end
def available_block_columns
available_columns.reject(&:inline?)
end
def default_columns_names def default_columns_names
@default_columns_names ||= begin @default_columns_names ||= begin
default_columns = Setting.issue_list_default_columns.map(&:to_sym) default_columns = Setting.issue_list_default_columns.map(&:to_sym)
+1 -1
View File
@@ -111,7 +111,7 @@
<li><%= bulk_update_custom_field_context_menu_link(field, text, value || text) %></li> <li><%= bulk_update_custom_field_context_menu_link(field, text, value || text) %></li>
<% end %> <% end %>
<% unless field.is_required? %> <% unless field.is_required? %>
<li><%= bulk_update_custom_field_context_menu_link(field, l(:label_none), '') %></li> <li><%= bulk_update_custom_field_context_menu_link(field, l(:label_none), '__none__') %></li>
<% end %> <% end %>
</ul> </ul>
</li> </li>
+1 -1
View File
@@ -18,7 +18,7 @@
<% end %> <% end %>
<% if @issue.safe_attribute? 'subject' %> <% if @issue.safe_attribute? 'subject' %>
<p><%= f.text_field :subject, :size => 80, :required => true %></p> <p><%= f.text_field :subject, :size => 80, :maxlength => 255, :required => true %></p>
<% end %> <% end %>
<% if @issue.safe_attribute? 'description' %> <% if @issue.safe_attribute? 'description' %>
+10 -3
View File
@@ -10,7 +10,7 @@
:title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
</th> </th>
<%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %> <%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %>
<% query.columns.each do |column| %> <% query.inline_columns.each do |column| %>
<%= column_header(column) %> <%= column_header(column) %>
<% end %> <% end %>
</tr> </tr>
@@ -21,7 +21,7 @@
<% if @query.grouped? && (group = @query.group_by_column.value(issue)) != previous_group %> <% if @query.grouped? && (group = @query.group_by_column.value(issue)) != previous_group %>
<% reset_cycle %> <% reset_cycle %>
<tr class="group open"> <tr class="group open">
<td colspan="<%= query.columns.size + 2 %>"> <td colspan="<%= query.inline_columns.size + 2 %>">
<span class="expander" onclick="toggleRowGroup(this);">&nbsp;</span> <span class="expander" onclick="toggleRowGroup(this);">&nbsp;</span>
<%= group.blank? ? l(:label_none) : column_content(@query.group_by_column, issue) %> <span class="count"><%= @issue_count_by_group[group] %></span> <%= group.blank? ? l(:label_none) : column_content(@query.group_by_column, issue) %> <span class="count"><%= @issue_count_by_group[group] %></span>
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", <%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}",
@@ -33,8 +33,15 @@
<tr id="issue-<%= issue.id %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> <tr id="issue-<%= issue.id %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>">
<td class="checkbox hide-when-print"><%= check_box_tag("ids[]", issue.id, false, :id => nil) %></td> <td class="checkbox hide-when-print"><%= check_box_tag("ids[]", issue.id, false, :id => nil) %></td>
<td class="id"><%= link_to issue.id, issue_path(issue) %></td> <td class="id"><%= link_to issue.id, issue_path(issue) %></td>
<%= raw query.columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, issue)}</td>"}.join %> <%= raw query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, issue)}</td>"}.join %>
</tr> </tr>
<% @query.block_columns.each do |column|
if (text = column_content(column, issue)) && text.present? -%>
<tr class="<%= current_cycle %>">
<td colspan="<%= @query.inline_columns.size + 2 %>" class="<%= column.css_classes %>"><%= text %></td>
</tr>
<% end -%>
<% end -%>
<% end -%> <% end -%>
</tbody> </tbody>
</table> </table>
+5 -1
View File
@@ -34,6 +34,10 @@
@query.group_by) @query.group_by)
) %></td> ) %></td>
</tr> </tr>
<tr>
<td><%= l(:button_show) %></td>
<td><%= available_block_columns_tags(@query) %></td>
</tr>
</table> </table>
</div> </div>
</fieldset> </fieldset>
@@ -73,7 +77,7 @@
<label><%= radio_button_tag 'columns', 'all' %> <%= l(:description_all_columns) %></label> <label><%= radio_button_tag 'columns', 'all' %> <%= l(:description_all_columns) %></label>
</p> </p>
<p> <p>
<label><%= check_box_tag 'description', '1' %> <%= l(:field_description) %></label> <label><%= check_box_tag 'description', '1', @query.has_column?(:description) %> <%= l(:field_description) %></label>
</p> </p>
<p class="buttons"> <p class="buttons">
<%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %> <%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %>
+7 -1
View File
@@ -1,2 +1,8 @@
$("#journal-<%= @journal.id %>-notes").hide(); $("#journal-<%= @journal.id %>-notes").hide();
$("#journal-<%= @journal.id %>-notes").after('<%= escape_javascript(render :partial => 'notes_form') %>');
if ($("form#journal-<%= @journal.id %>-form").length > 0) {
// journal edit form already loaded
$("#journal-<%= @journal.id %>-form").show();
} else {
$("#journal-<%= @journal.id %>-notes").after('<%= escape_javascript(render :partial => 'notes_form') %>');
}
+2 -2
View File
@@ -4,7 +4,7 @@
<%= label_tag "available_columns", l(:description_available_columns) %> <%= label_tag "available_columns", l(:description_available_columns) %>
<br /> <br />
<%= select_tag 'available_columns', <%= select_tag 'available_columns',
options_for_select((query.available_columns - query.columns).collect {|column| [column.caption, column.name]}), options_for_select((query.available_inline_columns - query.columns).collect {|column| [column.caption, column.name]}),
:multiple => true, :size => 10, :style => "width:150px", :multiple => true, :size => 10, :style => "width:150px",
:ondblclick => "moveOptions(this.form.available_columns, this.form.selected_columns);" %> :ondblclick => "moveOptions(this.form.available_columns, this.form.selected_columns);" %>
</td> </td>
@@ -18,7 +18,7 @@
<%= label_tag "selected_columns", l(:description_selected_columns) %> <%= label_tag "selected_columns", l(:description_selected_columns) %>
<br /> <br />
<%= select_tag((defined?(tag_name) ? tag_name : 'c[]'), <%= select_tag((defined?(tag_name) ? tag_name : 'c[]'),
options_for_select(query.columns.collect {|column| [column.caption, column.name]}), options_for_select(query.inline_columns.collect {|column| [column.caption, column.name]}),
:id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px", :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px",
:ondblclick => "moveOptions(this.form.selected_columns, this.form.available_columns);") %> :ondblclick => "moveOptions(this.form.selected_columns, this.form.available_columns);") %>
</td> </td>
+3
View File
@@ -21,6 +21,9 @@
<p><label for="query_group_by"><%= l(:field_group_by) %></label> <p><label for="query_group_by"><%= l(:field_group_by) %></label>
<%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %></p> <%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %></p>
<p><label><%= l(:button_show) %></label>
<%= available_block_columns_tags(@query) %></p>
</div> </div>
<fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend> <fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend>
+1 -1
View File
@@ -12,7 +12,7 @@
<p><%= f.text_field :issue_id, :size => 6 %> <em><%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %></em></p> <p><%= f.text_field :issue_id, :size => 6 %> <em><%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %></em></p>
<p><%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p> <p><%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p>
<p><%= f.text_field :hours, :size => 6, :required => true %></p> <p><%= f.text_field :hours, :size => 6, :required => true %></p>
<p><%= f.text_field :comments, :size => 100 %></p> <p><%= f.text_field :comments, :size => 100, :maxlength => 255 %></p>
<p><%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %></p> <p><%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %></p>
<% @time_entry.custom_field_values.each do |value| %> <% @time_entry.custom_field_values.each do |value| %>
<p><%= custom_field_tag_with_label :time_entry, value %></p> <p><%= custom_field_tag_with_label :time_entry, value %></p>
+2 -2
View File
@@ -833,7 +833,7 @@ bg:
label_generate_key: Генериране на ключ label_generate_key: Генериране на ключ
label_issue_watchers: Наблюдатели label_issue_watchers: Наблюдатели
label_example: Пример label_example: Пример
label_display: Display label_display: Показване
label_sort: Сортиране label_sort: Сортиране
label_ascending: Нарастващ label_ascending: Нарастващ
label_descending: Намаляващ label_descending: Намаляващ
@@ -892,7 +892,7 @@ bg:
label_cross_project_system: С всички проекти label_cross_project_system: С всички проекти
button_login: Вход button_login: Вход
button_submit: Прикачване button_submit: Изпращане
button_save: Запис button_save: Запис
button_check_all: Избор на всички button_check_all: Избор на всички
button_uncheck_all: Изчистване на всички button_uncheck_all: Изчистване на всички
+66 -66
View File
@@ -1037,84 +1037,84 @@ es:
description_selected_columns: Columnas seleccionadas description_selected_columns: Columnas seleccionadas
label_parent_revision: Padre label_parent_revision: Padre
label_child_revision: Hijo label_child_revision: Hijo
setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues setting_default_issue_start_date_to_creation_date: Utilizar la fecha actual como fecha de inicio para nuevas peticiones
button_edit_section: Edit this section button_edit_section: Editar esta sección
setting_repositories_encodings: Attachments and repositories encodings setting_repositories_encodings: Codificación de adjuntos y repositorios
description_all_columns: Todas las columnas description_all_columns: Todas las columnas
button_export: Exportar button_export: Exportar
label_export_options: "%{export_format} opciones de exportación" label_export_options: "%{export_format} opciones de exportación"
error_attachment_too_big: Este fichero no se puede adjuntar porque excede el tamaño máximo de fichero (%{max_size}) error_attachment_too_big: Este fichero no se puede adjuntar porque excede el tamaño máximo de fichero (%{max_size})
notice_failed_to_save_time_entries: "Error al guarda %{count} entradas de tiempo de las %{total} seleccionadas: %{ids}." notice_failed_to_save_time_entries: "Error al guardar %{count} entradas de tiempo de las %{total} seleccionadas: %{ids}."
label_x_issues: label_x_issues:
zero: 0 petición zero: 0 petición
one: 1 petición one: 1 petición
other: "%{count} peticiones" other: "%{count} peticiones"
label_repository_new: New repository label_repository_new: Nuevo repositorio
field_repository_is_default: Main repository field_repository_is_default: Repositorio principal
label_copy_attachments: Copy attachments label_copy_attachments: Copiar adjuntos
label_item_position: "%{position}/%{count}" label_item_position: "%{position}/%{count}"
label_completed_versions: Completed versions label_completed_versions: Versiones completadas
text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed. text_project_identifier_info: Solo se permiten letras en minúscula (a-z), números, guiones y barras bajas.<br />Una vez guardado, el identificador no se puede cambiar.
field_multiple: Multiple values field_multiple: Valores múltiples
setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed setting_commit_cross_project_ref: Permitir referenciar y resolver peticiones de todos los demás proyectos
text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes text_issue_conflict_resolution_add_notes: Añadir mis notas y descartar mis otros cambios
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) text_issue_conflict_resolution_overwrite: Aplicar mis campos de todas formas (las notas anteriores se mantendrán pero algunos cambios podrían ser sobreescritos)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. notice_issue_update_conflict: La petición ha sido actualizada por otro usuario mientras la editaba.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} text_issue_conflict_resolution_cancel: Descartar todos mis cambios y mostrar de nuevo %{link}
permission_manage_related_issues: Manage related issues permission_manage_related_issues: Gestionar peticiones relacionadas
field_auth_source_ldap_filter: LDAP filter field_auth_source_ldap_filter: Filtro LDAP
label_search_for_watchers: Search for watchers to add label_search_for_watchers: Buscar seguidores para añadirlos
notice_account_deleted: Your account has been permanently deleted. notice_account_deleted: Su cuenta ha sido eliminada
setting_unsubscribe: Allow users to delete their own account setting_unsubscribe: Permitir a los usuarios borrar sus propias cuentas
button_delete_my_account: Delete my account button_delete_my_account: Borrar mi cuenta
text_account_destroy_confirmation: |- text_account_destroy_confirmation: |-
Are you sure you want to proceed? ¿Está seguro de querer proceder?
Your account will be permanently deleted, with no way to reactivate it. Su cuenta quedará borrada permanentemente, sin la posibilidad de reactivarla.
error_session_expired: Your session has expired. Please login again. error_session_expired: Su sesn ha expirado. Por favor, vuelva a identificarse.
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." text_session_expiration_settings: "Advertencia: el cambio de estas opciones podría hacer expirar las sesiones activas, incluyendo la suya."
setting_session_lifetime: Session maximum lifetime setting_session_lifetime: Tiempo de vida máximo de las sesiones
setting_session_timeout: Session inactivity timeout setting_session_timeout: Tiempo máximo de inactividad de las sesiones
label_session_expiration: Session expiration label_session_expiration: Expiración de sesiones
permission_close_project: Close / reopen the project permission_close_project: Cerrar / reabrir el proyecto
label_show_closed_projects: View closed projects label_show_closed_projects: Ver proyectos cerrados
button_close: Close button_close: Cerrar
button_reopen: Reopen button_reopen: Reabrir
project_status_active: active project_status_active: activo
project_status_closed: closed project_status_closed: cerrado
project_status_archived: archived project_status_archived: archivado
text_project_closed: This project is closed and read-only. text_project_closed: Este proyecto está cerrado y es de sólo lectura
notice_user_successful_create: User %{id} created. notice_user_successful_create: Usuario %{id} creado.
field_core_fields: Standard fields field_core_fields: Campos básicos
field_timeout: Timeout (in seconds) field_timeout: Tiempo de inactividad (en segundos)
setting_thumbnails_enabled: Display attachment thumbnails setting_thumbnails_enabled: Mostrar miniaturas de los adjuntos
setting_thumbnails_size: Thumbnails size (in pixels) setting_thumbnails_size: Tamaño de las miniaturas (en píxeles)
label_status_transitions: Status transitions label_status_transitions: Transiciones de estado
label_fields_permissions: Fields permissions label_fields_permissions: Permisos sobre los campos
label_readonly: Read-only label_readonly: Sólo lectura
label_required: Required label_required: Requerido
text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed. text_repository_identifier_info: Solo se permiten letras en minúscula (a-z), números, guiones y barras bajas.<br />Una vez guardado, el identificador no se puede cambiar.
field_board_parent: Parent forum field_board_parent: Foro padre
label_attribute_of_project: Project's %{name} label_attribute_of_project: "%{name} del proyecto"
label_attribute_of_author: Author's %{name} label_attribute_of_author: "%{name} del autor"
label_attribute_of_assigned_to: Assignee's %{name} label_attribute_of_assigned_to: "%{name} de la persona asignada"
label_attribute_of_fixed_version: Target version's %{name} label_attribute_of_fixed_version: "%{name} de la versión indicada"
label_copy_subtasks: Copy subtasks label_copy_subtasks: Copiar subtareas
label_copied_to: copied to label_copied_to: copiada a
label_copied_from: copied from label_copied_from: copiada desde
label_any_issues_in_project: any issues in project label_any_issues_in_project: cualquier petición del proyecto
label_any_issues_not_in_project: any issues not in project label_any_issues_not_in_project: cualquier petición que no sea del proyecto
field_private_notes: Private notes field_private_notes: Notas privadas
permission_view_private_notes: View private notes permission_view_private_notes: Ver notas privadas
permission_set_notes_private: Set notes as private permission_set_notes_private: Poner notas como privadas
label_no_issues_in_project: no issues in project label_no_issues_in_project: no hay peticiones en el proyecto
label_any: todos label_any: todos
label_last_n_weeks: last %{count} weeks label_last_n_weeks: en las últimas %{count} semanas
setting_cross_project_subtasks: Allow cross-project subtasks setting_cross_project_subtasks: Permitir subtareas cruzadas entre proyectos
label_cross_project_descendants: Con proyectos hijo label_cross_project_descendants: Con proyectos hijo
label_cross_project_tree: Con el árbol del proyecto label_cross_project_tree: Con el árbol del proyecto
label_cross_project_hierarchy: Con la jerarquía del proyecto label_cross_project_hierarchy: Con la jerarquía del proyecto
label_cross_project_system: Con todos los proyectos label_cross_project_system: Con todos los proyectos
button_hide: Hide button_hide: Ocultar
setting_non_working_week_days: Non-working days setting_non_working_week_days: Días no laborables
label_in_the_next_days: in the next label_in_the_next_days: en los próximos
label_in_the_past_days: in the past label_in_the_past_days: en los anteriores
+1 -1
View File
@@ -1099,7 +1099,7 @@ ja:
field_private_notes: プライベート注記 field_private_notes: プライベート注記
permission_view_private_notes: プライベート注記の閲覧 permission_view_private_notes: プライベート注記の閲覧
permission_set_notes_private: 注記をプライベートに設定 permission_set_notes_private: 注記をプライベートに設定
label_no_issues_in_project: no issues in project label_no_issues_in_project: 次のプロジェクト内のチケットを除く
label_any: すべて label_any: すべて
label_last_n_weeks: 直近%{count}週間 label_last_n_weeks: 直近%{count}週間
setting_cross_project_subtasks: 異なるプロジェクトのチケット間の親子関係を許可 setting_cross_project_subtasks: 異なるプロジェクトのチケット間の親子関係を許可
+58 -58
View File
@@ -326,7 +326,7 @@ ko:
field_comments_sorting: 댓글 정렬 field_comments_sorting: 댓글 정렬
field_parent_title: 상위 제목 field_parent_title: 상위 제목
field_editable: 편집가능 field_editable: 편집가능
field_watcher: 일감관계자 field_watcher: 일감지킴이
field_identity_url: OpenID URL field_identity_url: OpenID URL
field_content: 내용 field_content: 내용
field_group_by: 결과를 묶어 보여줄 기준 field_group_by: 결과를 묶어 보여줄 기준
@@ -347,7 +347,7 @@ ko:
setting_wiki_compression: 위키 이력 압축 setting_wiki_compression: 위키 이력 압축
setting_feeds_limit: 피드에 포함할 항목의 수 setting_feeds_limit: 피드에 포함할 항목의 수
setting_default_projects_public: 새 프로젝트를 공개로 설정 setting_default_projects_public: 새 프로젝트를 공개로 설정
setting_autofetch_changesets: 제출(commit)된 변경묶음을 자동으로 가져오기 setting_autofetch_changesets: 커밋(commit)된 변경묶음을 자동으로 가져오기
setting_sys_api_enabled: 저장소 관리에 WS를 사용 setting_sys_api_enabled: 저장소 관리에 WS를 사용
setting_commit_ref_keywords: 일감 참조에 사용할 키워드들 setting_commit_ref_keywords: 일감 참조에 사용할 키워드들
setting_commit_fix_keywords: 일감 해결에 사용할 키워드들 setting_commit_fix_keywords: 일감 해결에 사용할 키워드들
@@ -392,8 +392,8 @@ ko:
permission_save_queries: 검색양식 저장 permission_save_queries: 검색양식 저장
permission_view_gantt: Gantt차트 보기 permission_view_gantt: Gantt차트 보기
permission_view_calendar: 달력 보기 permission_view_calendar: 달력 보기
permission_view_issue_watchers: 일감관계자 보기 permission_view_issue_watchers: 일감지킴이 보기
permission_add_issue_watchers: 일감관계자 추가 permission_add_issue_watchers: 일감지킴이 추가
permission_log_time: 작업시간 기록 permission_log_time: 작업시간 기록
permission_view_time_entries: 시간입력 보기 permission_view_time_entries: 시간입력 보기
permission_edit_time_entries: 시간입력 편집 permission_edit_time_entries: 시간입력 편집
@@ -664,8 +664,8 @@ ko:
label_time_tracking: 시간추적 label_time_tracking: 시간추적
label_change_plural: 변경사항들 label_change_plural: 변경사항들
label_statistics: 통계 label_statistics: 통계
label_commits_per_month: 월별 제출 내역 label_commits_per_month: 월별 커밋 내역
label_commits_per_author: 저자별 제출 내역 label_commits_per_author: 저자별 커밋 내역
label_view_diff: 차이점 보기 label_view_diff: 차이점 보기
label_diff_inline: 한줄로 label_diff_inline: 한줄로
label_diff_side_by_side: 두줄로 label_diff_side_by_side: 두줄로
@@ -679,8 +679,8 @@ ko:
label_relation_new: 새 관계 label_relation_new: 새 관계
label_relation_delete: 관계 지우기 label_relation_delete: 관계 지우기
label_relates_to: "다음 일감과 관련됨:" label_relates_to: "다음 일감과 관련됨:"
label_duplicates: "다음 일감과 겹침:" label_duplicates: "다음 일감에 중복됨:"
label_duplicated_by: "다음 일감과 겹침:" label_duplicated_by: "중복된 일감:"
label_blocks: "다음 일감의 해결을 막고 있음:" label_blocks: "다음 일감의 해결을 막고 있음:"
label_blocked_by: "다음 일감에게 막혀 있음:" label_blocked_by: "다음 일감에게 막혀 있음:"
label_precedes: "다음에 진행할 일감:" label_precedes: "다음에 진행할 일감:"
@@ -748,7 +748,7 @@ ko:
label_planning: 프로젝트계획 label_planning: 프로젝트계획
label_incoming_emails: 수신 메일 label_incoming_emails: 수신 메일
label_generate_key: 키 생성 label_generate_key: 키 생성
label_issue_watchers: 일감관계자 label_issue_watchers: 일감지킴이
label_example: label_example:
label_display: 표시방식 label_display: 표시방식
label_sort: 정렬 label_sort: 정렬
@@ -807,7 +807,7 @@ ko:
text_min_max_length_info: 0 는 제한이 없음을 의미함 text_min_max_length_info: 0 는 제한이 없음을 의미함
text_project_destroy_confirmation: 이 프로젝트를 삭제하고 모든 데이터를 지우시겠습니까? text_project_destroy_confirmation: 이 프로젝트를 삭제하고 모든 데이터를 지우시겠습니까?
text_subprojects_destroy_warning: "하위 프로젝트(%{value})이(가) 자동으로 지워질 것입니다." text_subprojects_destroy_warning: "하위 프로젝트(%{value})이(가) 자동으로 지워질 것입니다."
text_workflow_edit: 업무흐름 수정하려면 역할과 일감 유형을 선택하세요. text_workflow_edit: 업무흐름 수정하려면 역할과 일감 유형을 선택하세요.
text_are_you_sure: 계속 진행 하시겠습니까? text_are_you_sure: 계속 진행 하시겠습니까?
text_tip_issue_begin_day: 오늘 시작하는 업무(task) text_tip_issue_begin_day: 오늘 시작하는 업무(task)
text_tip_issue_end_day: 오늘 종료하는 업무(task) text_tip_issue_end_day: 오늘 종료하는 업무(task)
@@ -818,7 +818,7 @@ ko:
text_tracker_no_workflow: 이 일감 유형에는 업무흐름이 정의되지 않았습니다. text_tracker_no_workflow: 이 일감 유형에는 업무흐름이 정의되지 않았습니다.
text_unallowed_characters: 허용되지 않는 문자열 text_unallowed_characters: 허용되지 않는 문자열
text_comma_separated: "구분자','를 이용해서 여러 개의 값을 입력할 수 있습니다." text_comma_separated: "구분자','를 이용해서 여러 개의 값을 입력할 수 있습니다."
text_issues_ref_in_commit_messages: 제출 메시지에서 일감을 참조하거나 해결하기 text_issues_ref_in_commit_messages: 커밋 메시지에서 일감을 참조하거나 해결하기
text_issue_added: "%{author}이(가) 일감 %{id}을(를) 보고하였습니다." text_issue_added: "%{author}이(가) 일감 %{id}을(를) 보고하였습니다."
text_issue_updated: "%{author}이(가) 일감 %{id}을(를) 수정하였습니다." text_issue_updated: "%{author}이(가) 일감 %{id}을(를) 수정하였습니다."
text_wiki_destroy_confirmation: 이 위키와 모든 내용을 지우시겠습니까? text_wiki_destroy_confirmation: 이 위키와 모든 내용을 지우시겠습니까?
@@ -879,8 +879,8 @@ ko:
field_issue_to: 관련 일감 field_issue_to: 관련 일감
label_view_all_revisions: 모든 개정판 표시 label_view_all_revisions: 모든 개정판 표시
label_tag: 표지(票識)저장소 label_tag: 태그(Tag)
label_branch: 분기(分岐)저장소 label_branch: 브랜치(Branch)
error_no_tracker_in_project: 사용할 수 있도록 설정된 일감 유형이 없습니다. 프로젝트 설정을 확인하십시오. error_no_tracker_in_project: 사용할 수 있도록 설정된 일감 유형이 없습니다. 프로젝트 설정을 확인하십시오.
error_no_default_issue_status: '기본 상태가 정해져 있지 않습니다. 설정을 확인하십시오. (주 메뉴의 "관리" -> "일감 상태")' error_no_default_issue_status: '기본 상태가 정해져 있지 않습니다. 설정을 확인하십시오. (주 메뉴의 "관리" -> "일감 상태")'
text_journal_changed: "%{label}을(를) %{old}에서 %{new}(으)로 변경되었습니다." text_journal_changed: "%{label}을(를) %{old}에서 %{new}(으)로 변경되었습니다."
@@ -893,7 +893,7 @@ ko:
text_journal_added: "%{label}에 %{value}이(가) 추가되었습니다." text_journal_added: "%{label}에 %{value}이(가) 추가되었습니다."
field_active: 사용중 field_active: 사용중
enumeration_system_activity: 시스템 작업 enumeration_system_activity: 시스템 작업
permission_delete_issue_watchers: 일감관계자 지우기 permission_delete_issue_watchers: 일감지킴이 지우기
version_status_closed: 닫힘 version_status_closed: 닫힘
version_status_locked: 잠김 version_status_locked: 잠김
version_status_open: 진행 version_status_open: 진행
@@ -1011,7 +1011,7 @@ ko:
permission_set_issues_private: "일감을 공개나 비공개로 설정" permission_set_issues_private: "일감을 공개나 비공개로 설정"
label_issues_visibility_public: "모든 비공개 일감" label_issues_visibility_public: "모든 비공개 일감"
text_issues_destroy_descendants_confirmation: "%{count} 개의 하위 일감을 삭제할 것입니다." text_issues_destroy_descendants_confirmation: "%{count} 개의 하위 일감을 삭제할 것입니다."
field_commit_logs_encoding: "제출(commit) 기록 인코딩" field_commit_logs_encoding: "커밋(commit) 기록 인코딩"
field_scm_path_encoding: "경로 인코딩" field_scm_path_encoding: "경로 인코딩"
text_scm_path_encoding_note: "기본: UTF-8" text_scm_path_encoding_note: "기본: UTF-8"
field_path_to_repository: "저장소 경로" field_path_to_repository: "저장소 경로"
@@ -1021,14 +1021,14 @@ ko:
text_mercurial_repository_note: "로컬 저장소 (예: /hgrepo, c:\\hgrepo)" text_mercurial_repository_note: "로컬 저장소 (예: /hgrepo, c:\\hgrepo)"
text_scm_command: "명령" text_scm_command: "명령"
text_scm_command_version: "버전" text_scm_command_version: "버전"
label_git_report_last_commit: "파일이나 폴더의 마지막 제출(commit)을 보고" label_git_report_last_commit: "파일이나 폴더의 마지막 커밋(commit)을 보고"
text_scm_config: "SCM 명령을 config/configuration.yml에서 수정할 수 있습니다. 수정후에는 재시작하십시오." text_scm_config: "SCM 명령을 config/configuration.yml에서 수정할 수 있습니다. 수정후에는 재시작하십시오."
text_scm_command_not_available: "SCM 명령을 사용할 수 없습니다. 관리 페이지의 설정을 검사하십시오." text_scm_command_not_available: "SCM 명령을 사용할 수 없습니다. 관리 페이지의 설정을 검사하십시오."
notice_issue_successful_create: "%{id} 일감이 생성되었습니다." notice_issue_successful_create: "%{id} 일감이 생성되었습니다."
label_between: "사이" label_between: "사이"
setting_issue_group_assignment: "그룹에 일감 할당 허용" setting_issue_group_assignment: "그룹에 일감 할당 허용"
label_diff: "비교(diff)" label_diff: "비교(diff)"
text_git_repository_note: "저장소는 노출된 로컬입니다. (예: /gitrepo, c:\\gitrepo)" text_git_repository_note: "로컬의 bare 저장소 (예: /gitrepo, c:\\gitrepo)"
description_query_sort_criteria_direction: "정렬 방향" description_query_sort_criteria_direction: "정렬 방향"
description_project_scope: "검색 범위" description_project_scope: "검색 범위"
description_filter: "검색 조건" description_filter: "검색 조건"
@@ -1057,7 +1057,7 @@ ko:
label_export_options: "내보내기 옵션: %{export_format}" label_export_options: "내보내기 옵션: %{export_format}"
error_attachment_too_big: "이 파일은 제한된 크기(%{max_size})를 초과하였기 때문에 업로드 할 수 없습니다." error_attachment_too_big: "이 파일은 제한된 크기(%{max_size})를 초과하였기 때문에 업로드 할 수 없습니다."
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." notice_failed_to_save_time_entries: "%{total} 개의 시간입력중 다음 %{count} 개의 저장에 실패했습니다:: %{ids}."
label_x_issues: label_x_issues:
zero: 0 일감 zero: 0 일감
one: 1 일감 one: 1 일감
@@ -1074,12 +1074,12 @@ ko:
text_issue_conflict_resolution_overwrite: 변경내용 강제적용 (이전 덧글을 제외하고 덮어 씁니다) text_issue_conflict_resolution_overwrite: 변경내용 강제적용 (이전 덧글을 제외하고 덮어 씁니다)
notice_issue_update_conflict: 일감이 수정되는 동안 다른 사용자에 의해서 변경되었습니다. notice_issue_update_conflict: 일감이 수정되는 동안 다른 사용자에 의해서 변경되었습니다.
text_issue_conflict_resolution_cancel: "변경내용을 되돌리고 다시 표시 %{link}" text_issue_conflict_resolution_cancel: "변경내용을 되돌리고 다시 표시 %{link}"
permission_manage_related_issues: 된 일감 관리 permission_manage_related_issues: 된 일감 관리
field_auth_source_ldap_filter: LDAP filter field_auth_source_ldap_filter: LDAP 필터
label_search_for_watchers: 추가할 일감관계자 검색 label_search_for_watchers: 추가할 일감지킴이 검색
notice_account_deleted: 당신의 계정이 완전히 삭제되었습니다. notice_account_deleted: 당신의 계정이 완전히 삭제되었습니다.
setting_unsubscribe: 사용자들이 자신의 계정을 삭제토록 허용 setting_unsubscribe: 사용자들이 자신의 계정을 삭제토록 허용
button_delete_my_account: 나의계정삭제 button_delete_my_account: 나의 계정 삭제
text_account_destroy_confirmation: |- text_account_destroy_confirmation: |-
계속하시겠습니까? 계속하시겠습니까?
계정이 삭제되면 복구할 수 없습니다. 계정이 삭제되면 복구할 수 없습니다.
@@ -1088,46 +1088,46 @@ ko:
setting_session_lifetime: 세션 최대 시간 setting_session_lifetime: 세션 최대 시간
setting_session_timeout: 세션 비활성화 타임아웃 setting_session_timeout: 세션 비활성화 타임아웃
label_session_expiration: 세션 만료 label_session_expiration: 세션 만료
permission_close_project: Close / reopen the project permission_close_project: 프로젝트를 닫거나 다시 열기
label_show_closed_projects: View closed projects label_show_closed_projects: 닫힌 프로젝트 보기
button_close: Close button_close: 닫기
button_reopen: Reopen button_reopen: 다시 열기
project_status_active: active project_status_active: 사용중
project_status_closed: closed project_status_closed: 닫힘
project_status_archived: archived project_status_archived: 잠금보관
text_project_closed: This project is closed and read-only. text_project_closed: 이 프로젝트는 닫혀 있으며 읽기 전용입니다.
notice_user_successful_create: User %{id} created. notice_user_successful_create: 사용자 %{id} 이(가) 생성되었습니다.
field_core_fields: Standard fields field_core_fields: 표준 항목들
field_timeout: Timeout (in seconds) field_timeout: 타임아웃 (초)
setting_thumbnails_enabled: Display attachment thumbnails setting_thumbnails_enabled: 첨부파일의 썸네일을 보여줌
setting_thumbnails_size: Thumbnails size (in pixels) setting_thumbnails_size: 썸네일 크기 (픽셀)
label_status_transitions: Status transitions label_status_transitions: 일감 상태 변경
label_fields_permissions: Fields permissions label_fields_permissions: 항목 편집 권한
label_readonly: Read-only label_readonly: 읽기 전용
label_required: Required label_required: 필수
text_repository_identifier_info: "소문자(a-z),숫자,대쉬(-)와 밑줄(_)만 가능합니다.<br />식별자는 저장후에는 수정할 수 없습니다." text_repository_identifier_info: "소문자(a-z),숫자,대쉬(-)와 밑줄(_)만 가능합니다.<br />식별자는 저장후에는 수정할 수 없습니다."
field_board_parent: Parent forum field_board_parent: Parent forum
label_attribute_of_project: Project's %{name} label_attribute_of_project: "프로젝트의 %{name}"
label_attribute_of_author: Author's %{name} label_attribute_of_author: "저자의 %{name}"
label_attribute_of_assigned_to: Assignee's %{name} label_attribute_of_assigned_to: "담당자의 %{name}"
label_attribute_of_fixed_version: Target version's %{name} label_attribute_of_fixed_version: "목표버전의 %{name}"
label_copy_subtasks: Copy subtasks label_copy_subtasks: 하위 일감들을 복사
label_copied_to: copied to label_copied_to: "다음 일감으로 복사됨:"
label_copied_from: copied from label_copied_from: "다음 일감으로부터 복사됨:"
label_any_issues_in_project: any issues in project label_any_issues_in_project: 다음 프로젝트에 속한 아무 일감
label_any_issues_not_in_project: any issues not in project label_any_issues_not_in_project: 다음 프로젝트에 속하지 않은 아무 일감
field_private_notes: Private notes field_private_notes: 비공개 덧글
permission_view_private_notes: View private notes permission_view_private_notes: 비공개 덧글 보기
permission_set_notes_private: Set notes as private permission_set_notes_private: 덧글을 비공개로 설정
label_no_issues_in_project: no issues in project label_no_issues_in_project: 다음 프로젝트 내에서 해당 일감 없음
label_any: 모두 label_any: 모두
label_last_n_weeks: last %{count} weeks label_last_n_weeks: 최근 %{count}
setting_cross_project_subtasks: Allow cross-project subtasks setting_cross_project_subtasks: 다른 프로젝트의 일감을 상위 일감으로 지정하는 것을 허용
label_cross_project_descendants: 하위 프로젝트 label_cross_project_descendants: 하위 프로젝트
label_cross_project_tree: 최상위 및 모든 하위 프로젝트 label_cross_project_tree: 최상위 및 모든 하위 프로젝트
label_cross_project_hierarchy: 상위 및 하위 프로젝트 label_cross_project_hierarchy: 상위 및 하위 프로젝트
label_cross_project_system: 모든 프로젝트 label_cross_project_system: 모든 프로젝트
button_hide: Hide button_hide: 숨기기
setting_non_working_week_days: Non-working days setting_non_working_week_days: 비근무일 (non-working days)
label_in_the_next_days: in the next label_in_the_next_days: 다음
label_in_the_past_days: in the past label_in_the_past_days: 지난
+73 -73
View File
@@ -682,12 +682,12 @@ lt:
label_filter_plural: Filtrai label_filter_plural: Filtrai
label_equals: yra label_equals: yra
label_not_equals: nėra label_not_equals: nėra
label_in_less_than: mažiau negu label_in_less_than: anksčiau nei po
label_in_more_than: daugiau negu label_in_more_than: vėliau nei po
label_greater_or_equal: '>=' label_greater_or_equal: '>='
label_less_or_equal: '<=' label_less_or_equal: '<='
label_between: tarp label_between: tarp
label_in: po label_in: per
label_today: šiandien label_today: šiandien
label_all_time: visas laikas label_all_time: visas laikas
label_yesterday: vakar label_yesterday: vakar
@@ -698,11 +698,11 @@ lt:
label_last_month: praeitas mėnuo label_last_month: praeitas mėnuo
label_this_year: šiemet label_this_year: šiemet
label_date_range: Dienų diapazonas label_date_range: Dienų diapazonas
label_less_than_ago: prieš mažiau negu dienas label_less_than_ago: vėliau nei prieš
label_more_than_ago: prieš daugiau negu dienas label_more_than_ago: anksčiau nei prieš
label_ago: dienomis prieš label_ago: prieš
label_contains: turi savyje label_contains: turi
label_not_contains: neturi savyje label_not_contains: neturi
label_day_plural: dienų(os) label_day_plural: dienų(os)
label_repository: Saugykla label_repository: Saugykla
label_repository_plural: Saugyklos label_repository_plural: Saugyklos
@@ -1064,79 +1064,79 @@ lt:
description_date_from: Įvesti pradžios datą description_date_from: Įvesti pradžios datą
description_date_to: Įvesti pabaigos datą description_date_to: Įvesti pabaigos datą
label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee label_additional_workflow_transitions_for_assignee: Papildomi darbų eigos variantai kai darbas paskirtas vartotojui
label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author label_additional_workflow_transitions_for_author: Papildomi darbų eigos variantai kai vartotojas yra darbo autorius
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." notice_failed_to_save_time_entries: "Nepavyko išsaugoti %{count} laiko žurnalo įrašų iš %{total} parinktų: %{ids}."
label_x_issues: label_x_issues:
zero: 0 darbas zero: 0 darbas
one: 1 darbas one: 1 darbas
other: "%{count} darbai" other: "%{count} darbai(ų)"
label_repository_new: New repository label_repository_new: Nauja saugykla
field_repository_is_default: Main repository field_repository_is_default: Pagrindinė saugykla
label_copy_attachments: Copy attachments label_copy_attachments: Kopijuoti priedus
label_item_position: "%{position}/%{count}" label_item_position: "%{position}/%{count}"
label_completed_versions: Completed versions label_completed_versions: Užbaigtos versijos
text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed. text_project_identifier_info: Leidžiamos tik mažosios raidės (a-z), skaitmenys, brūkšneliai ir pabraukimo simboliai.<br />Kartą išsaugojus pakeitimai negalimi
field_multiple: Multiple values field_multiple: Keletas reikšmių
setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed
text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes text_issue_conflict_resolution_add_notes: Išsaugoti mano žinutę ir atmesti likusius mano pataisymus
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) text_issue_conflict_resolution_overwrite: Išsaugoti mano pakeitimus (ankstesnių pakeitimų žinutės bus išsaugotos, tačiau kai kurie pakeitimai bus perrašyti)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. notice_issue_update_conflict: Darbas buvo pakoreguotas kito vartotojo kol jūs atlikote pakeitimus.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} text_issue_conflict_resolution_cancel: Atmesti visus mano pakeitimus ir iš naujo rodyti %{link}
permission_manage_related_issues: Manage related issues permission_manage_related_issues: Tvarkyti susietus darbus
field_auth_source_ldap_filter: LDAP filter field_auth_source_ldap_filter: LDAP filtras
label_search_for_watchers: Search for watchers to add label_search_for_watchers: Ieškoti vartotojų kuriuos įtraukti kaip stebėtojus
notice_account_deleted: Your account has been permanently deleted. notice_account_deleted: Jūsų paskyra panaikinta.
setting_unsubscribe: Allow users to delete their own account setting_unsubscribe: Leisti vartotojams panaikinti savo paskyrą
button_delete_my_account: Delete my account button_delete_my_account: Panaikinti savo paskyrą
text_account_destroy_confirmation: |- text_account_destroy_confirmation: |-
Are you sure you want to proceed? Ar tikrai norite tęsti?
Your account will be permanently deleted, with no way to reactivate it. Jūsų paskyra bus panaikinta ir nebus galimybės jos atkurti.
error_session_expired: Your session has expired. Please login again. error_session_expired: Jūsų sesija pasibaigė. Prašome prisijunti iš naujo.
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." text_session_expiration_settings: "Įspėjimas: atlikus šiuos pakeitimus visos aktyvios sesijos gali nustoti galiojusios (įskaitant jūsų sesiją)."
setting_session_lifetime: Session maximum lifetime setting_session_lifetime: Sesijos maksimalus galiojimas
setting_session_timeout: Session inactivity timeout setting_session_timeout: Sesijos neveiklumo laiko tarpas
label_session_expiration: Session expiration label_session_expiration: Baigėsi sujungimo sesija
permission_close_project: Close / reopen the project permission_close_project: Uždaryti / atnaujinti projektą
label_show_closed_projects: View closed projects label_show_closed_projects: Matyti uždarytus projektus
button_close: Close button_close: Uždaryti
button_reopen: Reopen button_reopen: Atnaujinti
project_status_active: active project_status_active: aktyvus
project_status_closed: closed project_status_closed: uždarytas
project_status_archived: archived project_status_archived: archyvuotas
text_project_closed: This project is closed and read-only. text_project_closed: Šis projektas yra uždarytas, prieinamas tik peržiūrai.
notice_user_successful_create: User %{id} created. notice_user_successful_create: Vartotojas %{id} sukurtas.
field_core_fields: Standard fields field_core_fields: Standartiniai laukai
field_timeout: Timeout (in seconds) field_timeout: Timeout (po sek.)
setting_thumbnails_enabled: Display attachment thumbnails setting_thumbnails_enabled: Rodyti sumažintus priedų atvaizdus
setting_thumbnails_size: Thumbnails size (in pixels) setting_thumbnails_size: Sumažinto atvaizdo dydis (taškeliais)
label_status_transitions: Status transitions label_status_transitions: Darbų eiga
label_fields_permissions: Fields permissions label_fields_permissions: Leidimai
label_readonly: Read-only label_readonly: Tik peržiūra
label_required: Required label_required: Privaloma(s)
text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed. text_repository_identifier_info: Leidžiamos tik mažosios raidės (a-z), skaitmenys, brūkšneliai ir pabraukimo simboliai.<br />Kartą išsaugojus pakeitimai negalimi
field_board_parent: Parent forum field_board_parent: Pagrindinis forumas
label_attribute_of_project: Project's %{name} label_attribute_of_project: Projekto pavadinimas %{name}
label_attribute_of_author: Author's %{name} label_attribute_of_author: Autorius %{name}
label_attribute_of_assigned_to: Assignee's %{name} label_attribute_of_assigned_to: Paskirtas %{name}
label_attribute_of_fixed_version: Target version's %{name} label_attribute_of_fixed_version: Versijos %{name}
label_copy_subtasks: Copy subtasks label_copy_subtasks: Kopijuoti darbo dalis
label_copied_to: copied to label_copied_to: kopijuota į
label_copied_from: copied from label_copied_from: kopijuota iš
label_any_issues_in_project: any issues in project label_any_issues_in_project: bet kurie projekto darbai
label_any_issues_not_in_project: any issues not in project label_any_issues_not_in_project: bet kurie ne šio projekto darbai
field_private_notes: Private notes field_private_notes: Privačios žinutės
permission_view_private_notes: View private notes permission_view_private_notes: Matyti privačias žinutes
permission_set_notes_private: Set notes as private permission_set_notes_private: Pakeisti žinutę privačia
label_no_issues_in_project: no issues in project label_no_issues_in_project: projekte nėra darbų
label_any: visi label_any: visi
label_last_n_weeks: last %{count} weeks label_last_n_weeks: prieš %{count} sav.
setting_cross_project_subtasks: Allow cross-project subtasks setting_cross_project_subtasks: Leisti susieti skirtingų projektų užduočių dalis
label_cross_project_descendants: Su subprojektais label_cross_project_descendants: Su subprojektais
label_cross_project_tree: Su projekto medžiu label_cross_project_tree: Su projekto medžiu
label_cross_project_hierarchy: Su projekto hierarchija label_cross_project_hierarchy: Su projekto hierarchija
label_cross_project_system: Su visais projektais label_cross_project_system: Su visais projektais
button_hide: Hide button_hide: Slėpti
setting_non_working_week_days: Non-working days setting_non_working_week_days: Nedarbo dienos
label_in_the_next_days: in the next label_in_the_next_days: per ateinančias
label_in_the_past_days: in the past label_in_the_past_days: per paskutines
+50 -50
View File
@@ -49,7 +49,7 @@ nl:
one: "ongeveer 1 uur" one: "ongeveer 1 uur"
other: "ongeveer %{count} uren" other: "ongeveer %{count} uren"
x_hours: x_hours:
one: "1 hour" one: "1 uur"
other: "%{count} hours" other: "%{count} hours"
x_days: x_days:
one: "1 dag" one: "1 dag"
@@ -989,61 +989,61 @@ nl:
description_all_columns: Alle kolommen description_all_columns: Alle kolommen
button_export: Exporteren button_export: Exporteren
label_export_options: "%{export_format} export opties" label_export_options: "%{export_format} export opties"
error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) error_attachment_too_big: Dit bestand kan niet worden geupload omdat het de maximaal toegestane grootte overschrijd (%{max_size})
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." notice_failed_to_save_time_entries: "Opslaan gefaald voor %{count} tijdsnotatie(s) van %{total} geselecteerde: %{ids}."
label_x_issues: label_x_issues:
zero: 0 issue zero: 0 incidenten
one: 1 issue one: 1 incidenten
other: "%{count} issues" other: "%{count} incidenten"
label_repository_new: New repository label_repository_new: Nieuw repository
field_repository_is_default: Main repository field_repository_is_default: Hoofd repository
label_copy_attachments: Copy attachments label_copy_attachments: Copieer bijlage(n)
label_item_position: "%{position}/%{count}" label_item_position: "%{position}/%{count}"
label_completed_versions: Completed versions label_completed_versions: Versies compleet
field_multiple: Multiple values field_multiple: Meerdere waardes
setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed setting_commit_cross_project_ref: Sta toe om incidenten van alle projecten te refereren en oplossen
text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes text_issue_conflict_resolution_add_notes: Voeg mijn notities toe en annuleer andere wijzigingen
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) text_issue_conflict_resolution_overwrite: Voeg mijn wijzigingen alsnog toe (voorgaande notities worden bewaard, maar sommige kunnen overschreden worden)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. notice_issue_update_conflict: Dit incident is reeds geupdate door een andere gebruiker terwijl jij bezig was
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} text_issue_conflict_resolution_cancel: Annuleer mijn wijzigingen en geef pagina opnieuw weer %{link}
permission_manage_related_issues: Manage related issues permission_manage_related_issues: Beheer gerelateerde incidenten
field_auth_source_ldap_filter: LDAP filter field_auth_source_ldap_filter: LDAP filter
label_search_for_watchers: Search for watchers to add label_search_for_watchers: Zoek om monitoorders toe te voegen
notice_account_deleted: Your account has been permanently deleted. notice_account_deleted: Uw account is permanent verwijderd
setting_unsubscribe: Allow users to delete their own account setting_unsubscribe: Sta gebruikers toe hun eigen account te verwijderen
button_delete_my_account: Delete my account button_delete_my_account: Verwijder mijn account
text_account_destroy_confirmation: |- text_account_destroy_confirmation: |-
Are you sure you want to proceed? Weet u zeker dat u door wilt gaan?
Your account will be permanently deleted, with no way to reactivate it. Uw account wordt permanent verwijderd zonder mogelijkheid deze te heractiveren.
error_session_expired: Your session has expired. Please login again. error_session_expired: Uw sessie is verlopen. U dient opnieuw in te loggen.
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." text_session_expiration_settings: "Waarschuwing: door deze instelling te wijzigen kan sessies laten verlopen inclusief de uwe"
setting_session_lifetime: Session maximum lifetime setting_session_lifetime: Maximale sessieduur
setting_session_timeout: Session inactivity timeout setting_session_timeout: Sessie inactiviteit timeout
label_session_expiration: Session expiration label_session_expiration: Sessie verlopen
permission_close_project: Close / reopen the project permission_close_project: Sluit / heropen project
label_show_closed_projects: View closed projects label_show_closed_projects: Gesloten projecten weergeven
button_close: Close button_close: Sluiten
button_reopen: Reopen button_reopen: Heropen
project_status_active: active project_status_active: actief
project_status_closed: closed project_status_closed: gesloten
project_status_archived: archived project_status_archived: gearchiveerd
text_project_closed: This project is closed and read-only. text_project_closed: Dit project is gesloten en op alleen-lezen
notice_user_successful_create: User %{id} created. notice_user_successful_create: Gebruiker %{id} aangemaakt.
field_core_fields: Standard fields field_core_fields: Standaard verleden
field_timeout: Timeout (in seconds) field_timeout: Timeout (in seconds)
setting_thumbnails_enabled: Display attachment thumbnails setting_thumbnails_enabled: Geef bijlage miniaturen weer
setting_thumbnails_size: Thumbnails size (in pixels) setting_thumbnails_size: Grootte miniaturen (in pixels)
label_status_transitions: Status transitions label_status_transitions: Status transitie
label_fields_permissions: Fields permissions label_fields_permissions: Permissie velden
label_readonly: Read-only label_readonly: Alleen-lezen
label_required: Required label_required: Verplicht
text_repository_identifier_info: 'Alleen kleine letter (a-z), cijfers, streepjes en liggende streepjes zijn toegestaan.<br />Eenmaal opgeslagen kan de identifier niet worden gewijzigd.' text_repository_identifier_info: 'Alleen kleine letter (a-z), cijfers, streepjes en liggende streepjes zijn toegestaan.<br />Eenmaal opgeslagen kan de identifier niet worden gewijzigd.'
field_board_parent: Parent forum field_board_parent: Hoofd forum
label_attribute_of_project: Project's %{name} label_attribute_of_project: Project %{name}
label_attribute_of_author: Author's %{name} label_attribute_of_author: Auteur(s) %{name}
label_attribute_of_assigned_to: Assignee's %{name} label_attribute_of_assigned_to: Toegewezen %{name}
label_attribute_of_fixed_version: Target version's %{name} label_attribute_of_fixed_version: Target versions %{name}
label_copy_subtasks: Copy subtasks label_copy_subtasks: Kopieer subtaken
label_copied_to: copied to label_copied_to: copied to
label_copied_from: copied from label_copied_from: copied from
label_any_issues_in_project: any issues in project label_any_issues_in_project: any issues in project
+38 -38
View File
@@ -926,13 +926,13 @@
notice_gantt_chart_truncated: Diagrammet ble avkortet fordi det overstiger det maksimale antall elementer som kan vises (%{max}) notice_gantt_chart_truncated: Diagrammet ble avkortet fordi det overstiger det maksimale antall elementer som kan vises (%{max})
setting_gantt_items_limit: Maksimalt antall elementer vist på gantt-diagrammet setting_gantt_items_limit: Maksimalt antall elementer vist på gantt-diagrammet
field_warn_on_leaving_unsaved: Vis meg en advarsel når jeg forlater en side med ikke lagret tekst field_warn_on_leaving_unsaved: Vis meg en advarsel når jeg forlater en side med ikke lagret tekst
text_warn_on_leaving_unsaved: Den gjeldende siden inneholder tekst som ikke er lagret, som vil bli tapt hvis du forlater denne siden. text_warn_on_leaving_unsaved: Siden inneholder tekst som ikke er lagret og som vil bli tapt om du forlater denne siden.
label_my_queries: Mine egne spørringer label_my_queries: Mine egne spørringer
text_journal_changed_no_detail: "%{label} oppdatert" text_journal_changed_no_detail: "%{label} oppdatert"
label_news_comment_added: Kommentar lagt til en nyhet label_news_comment_added: Kommentar lagt til en nyhet
button_expand_all: Utvid alle button_expand_all: Utvid alle
button_collapse_all: Kollaps alle button_collapse_all: Kollaps alle
label_additional_workflow_transitions_for_assignee: Ytterligere overganger tillatt når brukeren er sakens tildelte label_additional_workflow_transitions_for_assignee: Ytterligere overganger tillatt når brukeren er den som er tildelt saken
label_additional_workflow_transitions_for_author: Ytterligere overganger tillatt når brukeren er den som har opprettet saken label_additional_workflow_transitions_for_author: Ytterligere overganger tillatt når brukeren er den som har opprettet saken
label_bulk_edit_selected_time_entries: Masserediger valgte timeliste-oppføringer label_bulk_edit_selected_time_entries: Masserediger valgte timeliste-oppføringer
text_time_entries_destroy_confirmation: Er du sikker på du vil slette de(n) valgte timeliste-oppføringen(e)? text_time_entries_destroy_confirmation: Er du sikker på du vil slette de(n) valgte timeliste-oppføringen(e)?
@@ -970,64 +970,64 @@
setting_issue_group_assignment: Tillat tildeling av saker til grupper setting_issue_group_assignment: Tillat tildeling av saker til grupper
label_diff: diff label_diff: diff
description_query_sort_criteria_direction: Sort direction description_query_sort_criteria_direction: Sorteringsretning
description_project_scope: Search scope description_project_scope: Search scope
description_filter: Filter description_filter: Filter
description_user_mail_notification: Mail notification settings description_user_mail_notification: Mail notification settings
description_date_from: Enter start date description_date_from: Oppgi startdato
description_message_content: Message content description_message_content: Meldingsinnhold
description_available_columns: Available Columns description_available_columns: Tilgjengelige kolonner
description_date_range_interval: Choose range by selecting start and end date description_date_range_interval: Velg datointervall ved å spesifisere start- og sluttdato
description_issue_category_reassign: Choose issue category description_issue_category_reassign: Choose issue category
description_search: Searchfield description_search: Søkefelt
description_notes: Notes description_notes: Notes
description_date_range_list: Choose range from list description_date_range_list: Choose range from list
description_choose_project: Projects description_choose_project: Prosjekter
description_date_to: Enter end date description_date_to: Oppgi sluttdato
description_query_sort_criteria_attribute: Sort attribute description_query_sort_criteria_attribute: Sort attribute
description_wiki_subpages_reassign: Choose new parent page description_wiki_subpages_reassign: Velg ny overordnet side
description_selected_columns: Selected Columns description_selected_columns: Valgte kolonner
label_parent_revision: Parent label_parent_revision: Overordnet
label_child_revision: Child label_child_revision: Underordnet
error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size.
setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues setting_default_issue_start_date_to_creation_date: Bruk dagens dato som startdato for nye saker
button_edit_section: Edit this section button_edit_section: Rediger denne seksjonen
setting_repositories_encodings: Attachments and repositories encodings setting_repositories_encodings: Attachments and repositories encodings
description_all_columns: All Columns description_all_columns: Alle kolonnene
button_export: Export button_export: Eksporter
label_export_options: "%{export_format} export options" label_export_options: "%{export_format} eksportvalg"
error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) error_attachment_too_big: Filen overstiger maksimum filstørrelse (%{max_size}) og kan derfor ikke lastes opp
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}."
label_x_issues: label_x_issues:
zero: 0 sak zero: 0 saker
one: 1 sak one: 1 sak
other: "%{count} saker" other: "%{count} saker"
label_repository_new: New repository label_repository_new: Nytt depot
field_repository_is_default: Main repository field_repository_is_default: Hoveddepot
label_copy_attachments: Copy attachments label_copy_attachments: Kopier vedlegg
label_item_position: "%{position}/%{count}" label_item_position: "%{position}/%{count}"
label_completed_versions: Completed versions label_completed_versions: Completed versions
text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed. text_project_identifier_info: Kun små bokstaver (a-z), tall, bindestrek (-) og "underscore" (_) er tillatt.<br />Etter lagring er det ikke mulig å gjøre endringer.
field_multiple: Multiple values field_multiple: Flere verdier
setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed
text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. notice_issue_update_conflict: Saken ble oppdatert av en annen bruker mens du redigerte den.
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} text_issue_conflict_resolution_cancel: Forkast alle endringen mine og vis %{link} på nytt
permission_manage_related_issues: Manage related issues permission_manage_related_issues: Manage related issues
field_auth_source_ldap_filter: LDAP filter field_auth_source_ldap_filter: LDAP filter
label_search_for_watchers: Search for watchers to add label_search_for_watchers: Search for watchers to add
notice_account_deleted: Your account has been permanently deleted. notice_account_deleted: Din konto er ugjenkallelig slettet.
setting_unsubscribe: Allow users to delete their own account setting_unsubscribe: Tillat brukere å slette sin egen konto
button_delete_my_account: Delete my account button_delete_my_account: Slett kontoen min
text_account_destroy_confirmation: |- text_account_destroy_confirmation: |-
Are you sure you want to proceed? Er du sikker på at du ønsker å fortsette?
Your account will be permanently deleted, with no way to reactivate it. Kontoen din vil bli ugjenkallelig slettet uten mulighet for å reaktiveres igjen.
error_session_expired: Your session has expired. Please login again. error_session_expired: Økten har gått ut på tid. Vennligst logg på igjen.
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." text_session_expiration_settings: "Advarsel: ved å endre disse innstillingene kan aktive økter gå ut på tid, inkludert din egen."
setting_session_lifetime: Session maximum lifetime setting_session_lifetime: Øktenes makslengde
setting_session_timeout: Session inactivity timeout setting_session_timeout: Økten er avsluttet på grunn av inaktivitet
label_session_expiration: Session expiration label_session_expiration: Økten er avsluttet
permission_close_project: Close / reopen the project permission_close_project: Close / reopen the project
label_show_closed_projects: View closed projects label_show_closed_projects: View closed projects
button_close: Close button_close: Close
+23 -23
View File
@@ -117,8 +117,8 @@ ru:
many: "около %{count} часов" many: "около %{count} часов"
other: "около %{count} часа" other: "около %{count} часа"
x_hours: x_hours:
one: "1 hour" one: "1 час"
other: "%{count} hours" other: "%{count} часов"
x_days: x_days:
one: "%{count} день" one: "%{count} день"
few: "%{count} дня" few: "%{count} дня"
@@ -502,7 +502,7 @@ ru:
label_enumeration_new: Новое значение label_enumeration_new: Новое значение
label_enumerations: Списки значений label_enumerations: Списки значений
label_environment: Окружение label_environment: Окружение
label_equals: является label_equals: соответствует
label_example: Пример label_example: Пример
label_export_to: Экспортировать в label_export_to: Экспортировать в
label_feed_plural: RSS label_feed_plural: RSS
@@ -603,7 +603,7 @@ ru:
label_no_data: Нет данных для отображения label_no_data: Нет данных для отображения
label_none: отсутствует label_none: отсутствует
label_not_contains: не содержит label_not_contains: не содержит
label_not_equals: не является label_not_equals: не соответствует
label_open_issues: открыто label_open_issues: открыто
label_open_issues_plural: открыто label_open_issues_plural: открыто
label_open_issues_plural2: открыто label_open_issues_plural2: открыто
@@ -1120,7 +1120,7 @@ ru:
button_export: Экспорт button_export: Экспорт
label_export_options: "%{export_format} параметры экспорта" label_export_options: "%{export_format} параметры экспорта"
error_attachment_too_big: Этот файл нельзя загрузить из-за превышения максимального размера файла (%{max_size}) error_attachment_too_big: Этот файл нельзя загрузить из-за превышения максимального размера файла (%{max_size})
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." notice_failed_to_save_time_entries: "Невозможно сохранить %{count} затраченное время для %{total} выбранных: %{ids}."
label_x_issues: label_x_issues:
zero: 0 Задач zero: 0 Задач
one: 1 Задача one: 1 Задача
@@ -1146,11 +1146,11 @@ ru:
setting_unsubscribe: "Разрешить пользователям удалять свои учетные записи" setting_unsubscribe: "Разрешить пользователям удалять свои учетные записи"
button_delete_my_account: "Удалить мою учетную запись" button_delete_my_account: "Удалить мою учетную запись"
text_account_destroy_confirmation: "Ваша учетная запись будет полностью удалена без возможности восстановления.\nВы уверены, что хотите продолжить?" text_account_destroy_confirmation: "Ваша учетная запись будет полностью удалена без возможности восстановления.\nВы уверены, что хотите продолжить?"
error_session_expired: Your session has expired. Please login again. error_session_expired: Срок вашей сессии истек. Пожалуйста войдите еще раз
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." text_session_expiration_settings: "Внимание! Изменение этих настроек может привести к завершению текущих сессий, включая вашу."
setting_session_lifetime: Session maximum lifetime setting_session_lifetime: Максимальная продолжительность сессии
setting_session_timeout: Session inactivity timeout setting_session_timeout: Таймут сессии
label_session_expiration: Session expiration label_session_expiration: Срок истечения сессии
permission_close_project: Закрывать / открывать проекты permission_close_project: Закрывать / открывать проекты
label_show_closed_projects: Просматривать закрытые проекты label_show_closed_projects: Просматривать закрытые проекты
button_close: Сделать закрытым button_close: Сделать закрытым
@@ -1161,19 +1161,19 @@ ru:
text_project_closed: Проект закрыт и находиться в режиме только для чтения. text_project_closed: Проект закрыт и находиться в режиме только для чтения.
notice_user_successful_create: Пользователь %{id} создан. notice_user_successful_create: Пользователь %{id} создан.
field_core_fields: Стандартные поля field_core_fields: Стандартные поля
field_timeout: Timeout (in seconds) field_timeout: Таймаут (в секундах)
setting_thumbnails_enabled: Display attachment thumbnails setting_thumbnails_enabled: Отображать превью для приложений
setting_thumbnails_size: Thumbnails size (in pixels) setting_thumbnails_size: Размер первью (в пикселях)
label_status_transitions: Статус-переходы label_status_transitions: Статус-переходы
label_fields_permissions: Права на изменения полей label_fields_permissions: Права на изменения полей
label_readonly: Не изменяется label_readonly: Не изменяется
label_required: Обязательное label_required: Обязательное
text_repository_identifier_info: Допускаются только строчные латинские буквы (a-z), цифры, тире и подчеркивания.<br />После сохранения идентификатор изменить нельзя. text_repository_identifier_info: Допускаются только строчные латинские буквы (a-z), цифры, тире и подчеркивания.<br />После сохранения идентификатор изменить нельзя.
field_board_parent: Родительский форум field_board_parent: Родительский форум
label_attribute_of_project: Project's %{name} label_attribute_of_project: Проект %{name}
label_attribute_of_author: Имя автора %{name} label_attribute_of_author: Имя автора %{name}
label_attribute_of_assigned_to: Assignee's %{name} label_attribute_of_assigned_to: Назначена %{name}
label_attribute_of_fixed_version: Target version's %{name} label_attribute_of_fixed_version: Версия %{name}
label_copy_subtasks: Копировать подзадачи label_copy_subtasks: Копировать подзадачи
label_copied_to: скопирована в label_copied_to: скопирована в
label_copied_from: скопирована с label_copied_from: скопирована с
@@ -1182,15 +1182,15 @@ ru:
field_private_notes: Приватный комментарий field_private_notes: Приватный комментарий
permission_view_private_notes: Просмотр приватных комментариев permission_view_private_notes: Просмотр приватных комментариев
permission_set_notes_private: Размещение приватных комментариев permission_set_notes_private: Размещение приватных комментариев
label_no_issues_in_project: no issues in project label_no_issues_in_project: нет задач в проекте
label_any: все label_any: все
label_last_n_weeks: last %{count} weeks label_last_n_weeks: последние %{count} недель
setting_cross_project_subtasks: Allow cross-project subtasks setting_cross_project_subtasks: Разрешить подзадачи в между проектами
label_cross_project_descendants: С подпроектами label_cross_project_descendants: С подпроектами
label_cross_project_tree: С деревом проектов label_cross_project_tree: С деревом проектов
label_cross_project_hierarchy: С иерархией проектов label_cross_project_hierarchy: С иерархией проектов
label_cross_project_system: Со всеми проектами label_cross_project_system: Со всеми проектами
button_hide: Hide button_hide: Скрыть
setting_non_working_week_days: Non-working days setting_non_working_week_days: Не рабочие дни
label_in_the_next_days: in the next label_in_the_next_days: в средующие дни
label_in_the_past_days: in the past label_in_the_past_days: в прошлые дни
+32 -32
View File
@@ -923,47 +923,47 @@ sr-YU:
project_module_calendar: Kalendar project_module_calendar: Kalendar
button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}"
field_text: Text field field_text: Text field
label_user_mail_option_only_owner: Only for things I am the owner of label_user_mail_option_only_owner: Samo za stvari koje posedujem
setting_default_notification_option: Default notification option setting_default_notification_option: Podrazumevana opcija za notifikaciju
label_user_mail_option_only_my_events: Only for things I watch or I'm involved in label_user_mail_option_only_my_events: Za dogadjaje koje pratim ili sam u njih uključen
label_user_mail_option_only_assigned: Only for things I am assigned to label_user_mail_option_only_assigned: Za dogadjaje koji su mi dodeljeni lično
label_user_mail_option_none: No events label_user_mail_option_none: Bez obaveštenja
field_member_of_group: Assignee's group field_member_of_group: Assignee's group
field_assigned_to_role: Assignee's role field_assigned_to_role: Assignee's role
notice_not_authorized_archived_project: The project you're trying to access has been archived. notice_not_authorized_archived_project: Projekat kome pokušavate da pristupite je arhiviran
label_principal_search: "Search for user or group:" label_principal_search: "Traži korisnike ili grupe:"
label_user_search: "Search for user:" label_user_search: "Traži korisnike:"
field_visible: Visible field_visible: Vidljivo
setting_emails_header: Emails header setting_emails_header: Email zaglavlje
setting_commit_logtime_activity_id: Activity for logged time setting_commit_logtime_activity_id: Activity for logged time
text_time_logged_by_changeset: Applied in changeset %{value}. text_time_logged_by_changeset: Applied in changeset %{value}.
setting_commit_logtime_enabled: Enable time logging setting_commit_logtime_enabled: Omogući praćenje vremena
notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})
setting_gantt_items_limit: Maximum number of items displayed on the gantt chart setting_gantt_items_limit: Maksimalan broj stavki na gant grafiku
field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text field_warn_on_leaving_unsaved: Upozori me ako napuštam stranu sa tekstom koji nije snimljen
text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. text_warn_on_leaving_unsaved: Strana sadrži tekst koji nije snimljen i biće izgubljen ako je napustite.
label_my_queries: My custom queries label_my_queries: My custom queries
text_journal_changed_no_detail: "%{label} updated" text_journal_changed_no_detail: "%{label} ažuriran"
label_news_comment_added: Comment added to a news label_news_comment_added: Komentar dodat u novosti
button_expand_all: Expand all button_expand_all: Proširi sve
button_collapse_all: Collapse all button_collapse_all: Zatvori sve
label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee
label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author
label_bulk_edit_selected_time_entries: Bulk edit selected time entries label_bulk_edit_selected_time_entries: Bulk edit selected time entries
text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? text_time_entries_destroy_confirmation: Da li ste sigurni da želite da obrišete selektovane stavke ?
label_role_anonymous: Anonymous label_role_anonymous: Anonimus
label_role_non_member: Non member label_role_non_member: Nije član
label_issue_note_added: Note added label_issue_note_added: Nota dodana
label_issue_status_updated: Status updated label_issue_status_updated: Status ažuriran
label_issue_priority_updated: Priority updated label_issue_priority_updated: Prioritet ažuriran
label_issues_visibility_own: Issues created by or assigned to the user label_issues_visibility_own: Problem kreiran od strane ili je dodeljen korisniku
field_issues_visibility: Issues visibility field_issues_visibility: Vidljivost problema
label_issues_visibility_all: All issues label_issues_visibility_all: Svi problemi
permission_set_own_issues_private: Set own issues public or private permission_set_own_issues_private: Podesi sopstveni problem kao privatan ili javan
field_is_private: Private field_is_private: Privatno
permission_set_issues_private: Set issues public or private permission_set_issues_private: Podesi problem kao privatan ili javan
label_issues_visibility_public: All non private issues label_issues_visibility_public: Svi javni problemi
text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). text_issues_destroy_descendants_confirmation: Ova operacija će takođe obrisati %{count} podzadataka.
field_commit_logs_encoding: Kodiranje izvršnih poruka field_commit_logs_encoding: Kodiranje izvršnih poruka
field_scm_path_encoding: Path encoding field_scm_path_encoding: Path encoding
text_scm_path_encoding_note: "Default: UTF-8" text_scm_path_encoding_note: "Default: UTF-8"
+45 -44
View File
@@ -79,8 +79,8 @@ sv:
one: "ungefär en timme" one: "ungefär en timme"
other: "ungefär %{count} timmar" other: "ungefär %{count} timmar"
x_hours: x_hours:
one: "1 hour" one: "1 timme"
other: "%{count} hours" other: "%{count} timmar"
x_days: x_days:
one: "en dag" one: "en dag"
other: "%{count} dagar" other: "%{count} dagar"
@@ -219,6 +219,7 @@ sv:
notice_issue_successful_create: Ärende %{id} skapades. notice_issue_successful_create: Ärende %{id} skapades.
notice_issue_update_conflict: Detta ärende har uppdaterats av en annan användare samtidigt som du redigerade det. notice_issue_update_conflict: Detta ärende har uppdaterats av en annan användare samtidigt som du redigerade det.
notice_account_deleted: Ditt konto har avslutats permanent. notice_account_deleted: Ditt konto har avslutats permanent.
notice_user_successful_create: "Användare %{id} skapad."
error_can_t_load_default_data: "Standardkonfiguration gick inte att läsa in: %{value}" error_can_t_load_default_data: "Standardkonfiguration gick inte att läsa in: %{value}"
error_scm_not_found: "Inlägg och/eller revision finns inte i detta versionsarkiv." error_scm_not_found: "Inlägg och/eller revision finns inte i detta versionsarkiv."
@@ -239,6 +240,7 @@ sv:
error_unable_delete_issue_status: 'Ärendestatus kunde inte tas bort' error_unable_delete_issue_status: 'Ärendestatus kunde inte tas bort'
error_unable_to_connect: "Kan inte ansluta (%{value})" error_unable_to_connect: "Kan inte ansluta (%{value})"
error_attachment_too_big: Denna fil kan inte laddas upp eftersom den överstiger maximalt tillåten filstorlek (%{max_size}) error_attachment_too_big: Denna fil kan inte laddas upp eftersom den överstiger maximalt tillåten filstorlek (%{max_size})
error_session_expired: "Din session har gått ut. Vänligen logga in på nytt."
warning_attachments_not_saved: "%{count} fil(er) kunde inte sparas." warning_attachments_not_saved: "%{count} fil(er) kunde inte sparas."
mail_subject_lost_password: "Ditt %{value} lösenord" mail_subject_lost_password: "Ditt %{value} lösenord"
@@ -368,6 +370,10 @@ sv:
field_repository_is_default: Huvudarkiv field_repository_is_default: Huvudarkiv
field_multiple: Flera värden field_multiple: Flera värden
field_auth_source_ldap_filter: LDAP-filter field_auth_source_ldap_filter: LDAP-filter
field_core_fields: Standardfält
field_timeout: "Timeout (i sekunder)"
field_board_parent: Förälderforum
field_private_notes: Privata anteckningar
setting_app_title: Applikationsrubrik setting_app_title: Applikationsrubrik
setting_app_subtitle: Applikationsunderrubrik setting_app_subtitle: Applikationsunderrubrik
@@ -392,6 +398,7 @@ sv:
setting_autologin: Automatisk inloggning setting_autologin: Automatisk inloggning
setting_date_format: Datumformat setting_date_format: Datumformat
setting_time_format: Tidsformat setting_time_format: Tidsformat
setting_cross_project_subtasks: Tillåt underaktiviteter mellan projekt
setting_cross_project_issue_relations: Tillåt ärenderelationer mellan projekt setting_cross_project_issue_relations: Tillåt ärenderelationer mellan projekt
setting_issue_list_default_columns: Standardkolumner i ärendelistan setting_issue_list_default_columns: Standardkolumner i ärendelistan
setting_repositories_encodings: Encoding för bilagor och versionsarkiv setting_repositories_encodings: Encoding för bilagor och versionsarkiv
@@ -430,10 +437,16 @@ sv:
setting_default_issue_start_date_to_creation_date: Använd dagens datum som startdatum för nya ärenden setting_default_issue_start_date_to_creation_date: Använd dagens datum som startdatum för nya ärenden
setting_commit_cross_project_ref: Tillåt ärende i alla de andra projekten att bli refererade och fixade setting_commit_cross_project_ref: Tillåt ärende i alla de andra projekten att bli refererade och fixade
setting_unsubscribe: Tillåt användare att avsluta prenumereration setting_unsubscribe: Tillåt användare att avsluta prenumereration
setting_session_lifetime: Maximal sessionslivslängd
setting_session_timeout: Tidsgräns för sessionsinaktivitet
setting_thumbnails_enabled: Visa miniatyrbilder av bilagor
setting_thumbnails_size: Storlek på miniatyrbilder (i pixlar)
setting_non_working_week_days: Lediga dagar
permission_add_project: Skapa projekt permission_add_project: Skapa projekt
permission_add_subprojects: Skapa underprojekt permission_add_subprojects: Skapa underprojekt
permission_edit_project: Ändra projekt permission_edit_project: Ändra projekt
permission_close_project: Stänga / återöppna projektet
permission_select_project_modules: Välja projektmoduler permission_select_project_modules: Välja projektmoduler
permission_manage_members: Hantera medlemmar permission_manage_members: Hantera medlemmar
permission_manage_project_activities: Hantera projektaktiviteter permission_manage_project_activities: Hantera projektaktiviteter
@@ -448,6 +461,8 @@ sv:
permission_add_issue_notes: Lägga till ärendenotering permission_add_issue_notes: Lägga till ärendenotering
permission_edit_issue_notes: Ändra ärendenoteringar permission_edit_issue_notes: Ändra ärendenoteringar
permission_edit_own_issue_notes: Ändra egna ärendenoteringar permission_edit_own_issue_notes: Ändra egna ärendenoteringar
permission_view_private_notes: Visa privata anteckningar
permission_set_notes_private: Ställa in anteckningar som privata
permission_move_issues: Flytta ärenden permission_move_issues: Flytta ärenden
permission_delete_issues: Ta bort ärenden permission_delete_issues: Ta bort ärenden
permission_manage_public_queries: Hantera publika frågor permission_manage_public_queries: Hantera publika frågor
@@ -682,6 +697,8 @@ sv:
label_not_equals: är inte label_not_equals: är inte
label_in_less_than: om mindre än label_in_less_than: om mindre än
label_in_more_than: om mer än label_in_more_than: om mer än
label_in_the_next_days: under kommande
label_in_the_past_days: under föregående
label_greater_or_equal: '>=' label_greater_or_equal: '>='
label_less_or_equal: '<=' label_less_or_equal: '<='
label_between: mellan label_between: mellan
@@ -691,6 +708,7 @@ sv:
label_yesterday: igår label_yesterday: igår
label_this_week: denna vecka label_this_week: denna vecka
label_last_week: senaste veckan label_last_week: senaste veckan
label_last_n_weeks: "senaste %{count} veckorna"
label_last_n_days: "senaste %{count} dagarna" label_last_n_days: "senaste %{count} dagarna"
label_this_month: denna månad label_this_month: denna månad
label_last_month: senaste månaden label_last_month: senaste månaden
@@ -701,6 +719,9 @@ sv:
label_ago: dagar sedan label_ago: dagar sedan
label_contains: innehåller label_contains: innehåller
label_not_contains: innehåller inte label_not_contains: innehåller inte
label_any_issues_in_project: några ärenden i projektet
label_any_issues_not_in_project: några ärenden utanför projektet
label_no_issues_in_project: inga ärenden i projektet
label_day_plural: dagar label_day_plural: dagar
label_repository: Versionsarkiv label_repository: Versionsarkiv
label_repository_new: Nytt versionsarkiv label_repository_new: Nytt versionsarkiv
@@ -776,6 +797,8 @@ sv:
label_blocked_by: blockerad av label_blocked_by: blockerad av
label_precedes: kommer före label_precedes: kommer före
label_follows: följer label_follows: följer
label_copied_to: Kopierad till
label_copied_from: Kopierad från
label_end_to_start: slut till start label_end_to_start: slut till start
label_end_to_end: slut till slut label_end_to_end: slut till slut
label_start_to_start: start till start label_start_to_start: start till start
@@ -889,9 +912,20 @@ sv:
label_child_revision: Barn label_child_revision: Barn
label_export_options: "%{export_format} exportalternativ" label_export_options: "%{export_format} exportalternativ"
label_copy_attachments: Kopiera bilagor label_copy_attachments: Kopiera bilagor
label_copy_subtasks: Kopiera underaktiviteter
label_item_position: "%{position}/%{count}" label_item_position: "%{position}/%{count}"
label_completed_versions: Klara versioner label_completed_versions: Klara versioner
label_search_for_watchers: Sök efter bevakare att lägga till label_search_for_watchers: Sök efter bevakare att lägga till
label_session_expiration: Sessionsutgång
label_show_closed_projects: Visa stängda projekt
label_status_transitions: Statusövergångar
label_fields_permissions: Fältbehörigheter
label_readonly: Skrivskyddad
label_required: Nödvändig
label_attribute_of_project: Projektets %{name}
label_attribute_of_author: Författarens %{name}
label_attribute_of_assigned_to: Tilldelads %{name}
label_attribute_of_fixed_version: Målversionens %{name}
button_login: Logga in button_login: Logga in
button_submit: Skicka button_submit: Skicka
@@ -939,14 +973,21 @@ sv:
button_quote: Citera button_quote: Citera
button_duplicate: Duplicera button_duplicate: Duplicera
button_show: Visa button_show: Visa
button_hide: Göm
button_edit_section: Redigera denna sektion button_edit_section: Redigera denna sektion
button_export: Exportera button_export: Exportera
button_delete_my_account: Ta bort mitt konto button_delete_my_account: Ta bort mitt konto
button_close: Stäng
button_reopen: Återöppna
status_active: aktiv status_active: aktiv
status_registered: registrerad status_registered: registrerad
status_locked: låst status_locked: låst
project_status_active: aktiv
project_status_closed: stängd
project_status_archived: arkiverad
version_status_open: öppen version_status_open: öppen
version_status_locked: låst version_status_locked: låst
version_status_closed: stängd version_status_closed: stängd
@@ -1026,6 +1067,8 @@ sv:
text_issue_conflict_resolution_add_notes: Lägg till mina anteckningar och kasta mina andra ändringar text_issue_conflict_resolution_add_notes: Lägg till mina anteckningar och kasta mina andra ändringar
text_issue_conflict_resolution_cancel: Kasta alla mina ändringar och visa igen %{link} text_issue_conflict_resolution_cancel: Kasta alla mina ändringar och visa igen %{link}
text_account_destroy_confirmation: "Är du säker på att du vill fortsätta?\nDitt konto kommer tas bort permanent, utan möjlighet att återaktivera det." text_account_destroy_confirmation: "Är du säker på att du vill fortsätta?\nDitt konto kommer tas bort permanent, utan möjlighet att återaktivera det."
text_session_expiration_settings: "Varning: ändring av dessa inställningar kan få alla nuvarande sessioner, inklusive din egen, att gå ut."
text_project_closed: Detta projekt är stängt och skrivskyddat.
default_role_manager: Projektledare default_role_manager: Projektledare
default_role_developer: Utvecklare default_role_developer: Utvecklare
@@ -1071,51 +1114,9 @@ sv:
description_date_range_interval: Ange intervall genom att välja start- och slutdatum description_date_range_interval: Ange intervall genom att välja start- och slutdatum
description_date_from: Ange startdatum description_date_from: Ange startdatum
description_date_to: Ange slutdatum description_date_to: Ange slutdatum
error_session_expired: Your session has expired. Please login again.
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours."
setting_session_lifetime: Session maximum lifetime
setting_session_timeout: Session inactivity timeout
label_session_expiration: Session expiration
permission_close_project: Close / reopen the project
label_show_closed_projects: View closed projects
button_close: Close
button_reopen: Reopen
project_status_active: active
project_status_closed: closed
project_status_archived: archived
text_project_closed: This project is closed and read-only.
notice_user_successful_create: User %{id} created.
field_core_fields: Standard fields
field_timeout: Timeout (in seconds)
setting_thumbnails_enabled: Display attachment thumbnails
setting_thumbnails_size: Thumbnails size (in pixels)
label_status_transitions: Status transitions
label_fields_permissions: Fields permissions
label_readonly: Read-only
label_required: Required
text_repository_identifier_info: Ändast gemener (a-z), siffror, streck och understreck är tillåtna.<br />När identifieraren sparats kan den inte ändras. text_repository_identifier_info: Ändast gemener (a-z), siffror, streck och understreck är tillåtna.<br />När identifieraren sparats kan den inte ändras.
field_board_parent: Parent forum
label_attribute_of_project: Project's %{name}
label_attribute_of_author: Author's %{name}
label_attribute_of_assigned_to: Assignee's %{name}
label_attribute_of_fixed_version: Target version's %{name}
label_copy_subtasks: Copy subtasks
label_copied_to: copied to
label_copied_from: copied from
label_any_issues_in_project: any issues in project
label_any_issues_not_in_project: any issues not in project
field_private_notes: Private notes
permission_view_private_notes: View private notes
permission_set_notes_private: Set notes as private
label_no_issues_in_project: no issues in project
label_any: alla label_any: alla
label_last_n_weeks: last %{count} weeks
setting_cross_project_subtasks: Allow cross-project subtasks
label_cross_project_descendants: Med underprojekt label_cross_project_descendants: Med underprojekt
label_cross_project_tree: Med projektträd label_cross_project_tree: Med projektträd
label_cross_project_hierarchy: Med projekthierarki label_cross_project_hierarchy: Med projekthierarki
label_cross_project_system: Med alla projekt label_cross_project_system: Med alla projekt
button_hide: Hide
setting_non_working_week_days: Non-working days
label_in_the_next_days: in the next
label_in_the_past_days: in the past
+107
View File
@@ -4,6 +4,113 @@ Redmine - project management software
Copyright (C) 2006-2012 Jean-Philippe Lang Copyright (C) 2006-2012 Jean-Philippe Lang
http://www.redmine.org/ http://www.redmine.org/
== 2013-02-12 v2.2.3
* Upgrade to Rails 3.2.12
* Defect #11987: pdf: Broken new line in table
* Defect #12930: 404 Error when referencing different project source files in the wiki syntax
* Defect #12979: Wiki link syntax commit:repo_a:abcd doesn't work
* Defect #13075: Can't clear custom field value through context menu in the issue list
* Defect #13097: Project copy fails when wiki module is disabled
* Defect #13126: Issue view: estimated time vs. spent time
* Patch #12922: Update Spanish translation
* Patch #12928: Bulgarian translation for 2.2-stable
* Patch #12987: Russian translation for 2.2-stable
== 2013-01-20 v2.2.2
* Defect #7510: Link to attachment should return latest attachment
* Defect #9842: {{toc}} is not replaced by table of content when exporting wiki page to pdf
* Defect #12749: Plugins cannot route wiki page sub-path
* Defect #12799: Cannot edit a wiki section which title starts with a tab
* Defect #12801: Viewing the history of a wiki page with attachments raises an error
* Defect #12833: Input fields restricted on length should have maxlength parameter set
* Defect #12838: Blank page when clicking Add with no block selected on my page layout
* Defect #12851: "Parent task is invalid" while editing child issues by Role with restricted Issues Visibility
* Patch #12800: Serbian Latin translation patch (sr-YU.yml)
* Patch #12809: Swedish Translation for r11162
* Patch #12818: Minor swedish translation fix
== 2013-01-09 v2.2.1
* Upgrade to Rails 3.2.11
* Defect #12652: "Copy ticket" selects "new ticket"
* Defect #12691: Textile Homepage Dead?
* Defect #12711: incorrect fix of lib/SVG/Graph/TimeSeries.rb
* Defect #12744: Unable to call a macro with a name that contains uppercase letters
* Defect #12776: Security vulnerability in Rails 3.2.10 (CVE-2013-0156)
* Patch #12630: Russian "x_hours" translation
== 2012-12-18 v2.2.0
* Defect #4787: Gannt to PNG - CJK (Chinese, Japanese and Korean) characters appear as ?
* Defect #8106: Issues by Category should show tasks without category
* Defect #8373: i18n string text_are_you_sure_with_children no longer used
* Defect #11426: Filtering with Due Date in less than N days should show overdue issues
* Defect #11834: Bazaar: "???" instead of non ASCII character in paths on non UTF-8 locale
* Defect #11868: Git and Mercurial diff displays deleted files as /dev/null
* Defect #11979: No validation errors when entering an invalid "Parent task"
* Defect #12012: Redmine::VERSION.revision method does not work on Subversion 1.7 working copy
* Defect #12018: Issue filter select box order changes randomly
* Defect #12090: email recipients not written to action_mailer log if BCC recipients setting is checked
* Defect #12092: Issue "start date" validation does not work correctly
* Defect #12285: Some unit and functional tests miss fixtures and break when run alone
* Defect #12286: Emails of private notes are sent to watcher users regardless of viewing permissions
* Defect #12310: Attachments may not be displayed in the order they were selected
* Defect #12356: Issue "Update" link broken focus
* Defect #12397: Error in Textile conversion of HTTP links, containing russian letters
* Defect #12434: Respond with 404 instead of 500 when requesting a wiki diff with invalid versions
* Feature #1554: Private comments in tickets
* Feature #2161: Time tracking code should respect weekends as "no work" days
* Feature #3239: Show related issues on the Issues Listing
* Feature #3265: Filter on issue relations
* Feature #3447: Option to display the issue descriptions on the issues list
* Feature #3511: Ability to sort issues by grouped column
* Feature #4590: Precede-Follow relation should move following issues when rescheduling issue earlier
* Feature #5487: Allow subtasks to cross projects
* Feature #6899: Add a relation between the original and copied issue
* Feature #7082: Rest API for wiki
* Feature #9835: REST API - List priorities
* Feature #10789: Macros {{child_pages}} with depth parameter
* Feature #10852: Ability to delete a version from a wiki page history
* Feature #10937: new user format #{lastname}
* Feature #11502: Expose roles details via REST API
* Feature #11755: Impersonate user through REST API auth
* Feature #12085: New user name format: firstname + first letter of lastname
* Feature #12125: Set filename used to store attachment updloaded via the REST API
* Feature #12167: Macro for inserting collapsible block of text
* Feature #12211: Wrap issue description and its contextual menu in a div
* Feature #12216: Textual CSS class for priorities
* Feature #12299: Redmine version requirement improvements (in plugins)
* Feature #12393: Upgrade to Rails 3.2.9
* Feature #12475: Lazy loading of translation files for faster startup
* Patch #11846: Fill username when authentification failed
* Patch #11862: Add "last 2 weeks" preset to time entries reporting
* Patch #11992: Japanese translation about issue relations improved
* Patch #12027: Incorrect Spanish "September" month name
* Patch #12061: Japanese translation improvement (permission names)
* Patch #12078: User#allowed_to? should return true or false
* Patch #12117: Change Japanese translation of "admin"
* Patch #12142: Updated translation in Lithuanian
* Patch #12232: German translation enhancements
* Patch #12316: Fix Lithuanian numeral translation
* Patch #12494: Bulgarian "button_submit" translation change
* Patch #12514: Updated translation in Lithuanian
* Patch #12602: Korean translation update for 2.2-stable
* Patch #12608: Norwegian translation changed
* Patch #12619: Russian translation change
== 2012-12-18 v2.1.5
* Defect #12400: Validation fails when receiving an email with list custom fields
* Defect #12451: Macros.rb extract_macro_options should use lazy search
* Defect #12513: Grouping of issues by custom fields not correct in PDF export
* Defect #12566: Issue history notes previews are broken
* Defect #12568: Clicking "edit" on a journal multiple times shows multiple forms
* Patch #12605: Norwegian translation for 1.4-stable update
* Patch #12614: Dutch translation
* Patch #12615: Russian translation
== 2012-11-24 v2.1.4 == 2012-11-24 v2.1.4
* Defect #12274: Wiki export from Index by title is truncated * Defect #12274: Wiki export from Index by title is truncated
+148 -148
View File
@@ -1,148 +1,148 @@
require 'rexml/document' require 'rexml/document'
require 'SVG/Graph/Graph' require 'SVG/Graph/Graph'
require 'SVG/Graph/BarBase' require 'SVG/Graph/BarBase'
module SVG module SVG
module Graph module Graph
# === Create presentation quality SVG bar graphs easily # === Create presentation quality SVG bar graphs easily
# #
# = Synopsis # = Synopsis
# #
# require 'SVG/Graph/Bar' # require 'SVG/Graph/Bar'
# #
# fields = %w(Jan Feb Mar); # fields = %w(Jan Feb Mar);
# data_sales_02 = [12, 45, 21] # data_sales_02 = [12, 45, 21]
# #
# graph = SVG::Graph::Bar.new( # graph = SVG::Graph::Bar.new(
# :height => 500, # :height => 500,
# :width => 300, # :width => 300,
# :fields => fields # :fields => fields
# ) # )
# #
# graph.add_data( # graph.add_data(
# :data => data_sales_02, # :data => data_sales_02,
# :title => 'Sales 2002' # :title => 'Sales 2002'
# ) # )
# #
# print "Content-type: image/svg+xml\r\n\r\n" # print "Content-type: image/svg+xml\r\n\r\n"
# print graph.burn # print graph.burn
# #
# = Description # = Description
# #
# This object aims to allow you to easily create high quality # This object aims to allow you to easily create high quality
# SVG[http://www.w3c.org/tr/svg bar graphs. You can either use the default # SVG[http://www.w3c.org/tr/svg bar graphs. You can either use the default
# style sheet or supply your own. Either way there are many options which # style sheet or supply your own. Either way there are many options which
# can be configured to give you control over how the graph is generated - # can be configured to give you control over how the graph is generated -
# with or without a key, data elements at each point, title, subtitle etc. # with or without a key, data elements at each point, title, subtitle etc.
# #
# = Notes # = Notes
# #
# The default stylesheet handles upto 12 data sets, if you # The default stylesheet handles upto 12 data sets, if you
# use more you must create your own stylesheet and add the # use more you must create your own stylesheet and add the
# additional settings for the extra data sets. You will know # additional settings for the extra data sets. You will know
# if you go over 12 data sets as they will have no style and # if you go over 12 data sets as they will have no style and
# be in black. # be in black.
# #
# = Examples # = Examples
# #
# * http://germane-software.com/repositories/public/SVG/test/test.rb # * http://germane-software.com/repositories/public/SVG/test/test.rb
# #
# = See also # = See also
# #
# * SVG::Graph::Graph # * SVG::Graph::Graph
# * SVG::Graph::BarHorizontal # * SVG::Graph::BarHorizontal
# * SVG::Graph::Line # * SVG::Graph::Line
# * SVG::Graph::Pie # * SVG::Graph::Pie
# * SVG::Graph::Plot # * SVG::Graph::Plot
# * SVG::Graph::TimeSeries # * SVG::Graph::TimeSeries
class Bar < BarBase class Bar < BarBase
include REXML include REXML
# See Graph::initialize and BarBase::set_defaults # See Graph::initialize and BarBase::set_defaults
def set_defaults def set_defaults
super super
self.top_align = self.top_font = 1 self.top_align = self.top_font = 1
end end
protected protected
def get_x_labels def get_x_labels
@config[:fields] @config[:fields]
end end
def get_y_labels def get_y_labels
maxvalue = max_value maxvalue = max_value
minvalue = min_value minvalue = min_value
range = maxvalue - minvalue range = maxvalue - minvalue
top_pad = range == 0 ? 10 : range / 20.0 top_pad = range == 0 ? 10 : range / 20.0
scale_range = (maxvalue + top_pad) - minvalue scale_range = (maxvalue + top_pad) - minvalue
scale_division = scale_divisions || (scale_range / 10.0) scale_division = scale_divisions || (scale_range / 10.0)
if scale_integers if scale_integers
scale_division = scale_division < 1 ? 1 : scale_division.round scale_division = scale_division < 1 ? 1 : scale_division.round
end end
rv = [] rv = []
maxvalue = maxvalue%scale_division == 0 ? maxvalue = maxvalue%scale_division == 0 ?
maxvalue : maxvalue + scale_division maxvalue : maxvalue + scale_division
minvalue.step( maxvalue, scale_division ) {|v| rv << v} minvalue.step( maxvalue, scale_division ) {|v| rv << v}
return rv return rv
end end
def x_label_offset( width ) def x_label_offset( width )
width / 2.0 width / 2.0
end end
def draw_data def draw_data
minvalue = min_value minvalue = min_value
fieldwidth = field_width fieldwidth = field_width
unit_size = (@graph_height.to_f - font_size*2*top_font) / unit_size = (@graph_height.to_f - font_size*2*top_font) /
(get_y_labels.max - get_y_labels.min) (get_y_labels.max - get_y_labels.min)
bargap = bar_gap ? (fieldwidth < 10 ? fieldwidth / 2 : 10) : 0 bargap = bar_gap ? (fieldwidth < 10 ? fieldwidth / 2 : 10) : 0
bar_width = fieldwidth - bargap bar_width = fieldwidth - bargap
bar_width /= @data.length if stack == :side bar_width /= @data.length if stack == :side
x_mod = (@graph_width-bargap)/2 - (stack==:side ? bar_width/2 : 0) x_mod = (@graph_width-bargap)/2 - (stack==:side ? bar_width/2 : 0)
bottom = @graph_height bottom = @graph_height
field_count = 0 field_count = 0
@config[:fields].each_index { |i| @config[:fields].each_index { |i|
dataset_count = 0 dataset_count = 0
for dataset in @data for dataset in @data
# cases (assume 0 = +ve): # cases (assume 0 = +ve):
# value min length # value min length
# +ve +ve value - min # +ve +ve value - min
# +ve -ve value - 0 # +ve -ve value - 0
# -ve -ve value.abs - 0 # -ve -ve value.abs - 0
value = dataset[:data][i] value = dataset[:data][i]
left = (fieldwidth * field_count) left = (fieldwidth * field_count)
length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size
# top is 0 if value is negative # top is 0 if value is negative
top = bottom - (((value < 0 ? 0 : value) - minvalue) * unit_size) top = bottom - (((value < 0 ? 0 : value) - minvalue) * unit_size)
left += bar_width * dataset_count if stack == :side left += bar_width * dataset_count if stack == :side
@graph.add_element( "rect", { @graph.add_element( "rect", {
"x" => left.to_s, "x" => left.to_s,
"y" => top.to_s, "y" => top.to_s,
"width" => bar_width.to_s, "width" => bar_width.to_s,
"height" => length.to_s, "height" => length.to_s,
"class" => "fill#{dataset_count+1}" "class" => "fill#{dataset_count+1}"
}) })
make_datapoint_text(left + bar_width/2.0, top - 6, value.to_s) make_datapoint_text(left + bar_width/2.0, top - 6, value.to_s)
dataset_count += 1 dataset_count += 1
end end
field_count += 1 field_count += 1
} }
end end
end end
end end
end end
+139 -139
View File
@@ -1,139 +1,139 @@
require 'rexml/document' require 'rexml/document'
require 'SVG/Graph/Graph' require 'SVG/Graph/Graph'
module SVG module SVG
module Graph module Graph
# = Synopsis # = Synopsis
# #
# A superclass for bar-style graphs. Do not attempt to instantiate # A superclass for bar-style graphs. Do not attempt to instantiate
# directly; use one of the subclasses instead. # directly; use one of the subclasses instead.
# #
# = Author # = Author
# #
# Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom> # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
# #
# Copyright 2004 Sean E. Russell # Copyright 2004 Sean E. Russell
# This software is available under the Ruby license[LICENSE.txt] # This software is available under the Ruby license[LICENSE.txt]
# #
class BarBase < SVG::Graph::Graph class BarBase < SVG::Graph::Graph
# Ensures that :fields are provided in the configuration. # Ensures that :fields are provided in the configuration.
def initialize config def initialize config
raise "fields was not supplied or is empty" unless config[:fields] && raise "fields was not supplied or is empty" unless config[:fields] &&
config[:fields].kind_of?(Array) && config[:fields].kind_of?(Array) &&
config[:fields].length > 0 config[:fields].length > 0
super super
end end
# In addition to the defaults set in Graph::initialize, sets # In addition to the defaults set in Graph::initialize, sets
# [bar_gap] true # [bar_gap] true
# [stack] :overlap # [stack] :overlap
def set_defaults def set_defaults
init_with( :bar_gap => true, :stack => :overlap ) init_with( :bar_gap => true, :stack => :overlap )
end end
# Whether to have a gap between the bars or not, default # Whether to have a gap between the bars or not, default
# is true, set to false if you don't want gaps. # is true, set to false if you don't want gaps.
attr_accessor :bar_gap attr_accessor :bar_gap
# How to stack data sets. :overlap overlaps bars with # How to stack data sets. :overlap overlaps bars with
# transparent colors, :top stacks bars on top of one another, # transparent colors, :top stacks bars on top of one another,
# :side stacks the bars side-by-side. Defaults to :overlap. # :side stacks the bars side-by-side. Defaults to :overlap.
attr_accessor :stack attr_accessor :stack
protected protected
def max_value def max_value
@data.collect{|x| x[:data].max}.max @data.collect{|x| x[:data].max}.max
end end
def min_value def min_value
min = 0 min = 0
if min_scale_value.nil? if min_scale_value.nil?
min = @data.collect{|x| x[:data].min}.min min = @data.collect{|x| x[:data].min}.min
min = min > 0 ? 0 : min min = min > 0 ? 0 : min
else else
min = min_scale_value min = min_scale_value
end end
return min return min
end end
def get_css def get_css
return <<EOL return <<EOL
/* default fill styles for multiple datasets (probably only use a single dataset on this graph though) */ /* default fill styles for multiple datasets (probably only use a single dataset on this graph though) */
.key1,.fill1{ .key1,.fill1{
fill: #ff0000; fill: #ff0000;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 0.5px; stroke-width: 0.5px;
} }
.key2,.fill2{ .key2,.fill2{
fill: #0000ff; fill: #0000ff;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key3,.fill3{ .key3,.fill3{
fill: #00ff00; fill: #00ff00;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key4,.fill4{ .key4,.fill4{
fill: #ffcc00; fill: #ffcc00;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key5,.fill5{ .key5,.fill5{
fill: #00ccff; fill: #00ccff;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key6,.fill6{ .key6,.fill6{
fill: #ff00ff; fill: #ff00ff;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key7,.fill7{ .key7,.fill7{
fill: #00ffff; fill: #00ffff;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key8,.fill8{ .key8,.fill8{
fill: #ffff00; fill: #ffff00;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key9,.fill9{ .key9,.fill9{
fill: #cc6666; fill: #cc6666;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key10,.fill10{ .key10,.fill10{
fill: #663399; fill: #663399;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key11,.fill11{ .key11,.fill11{
fill: #339900; fill: #339900;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key12,.fill12{ .key12,.fill12{
fill: #9966FF; fill: #9966FF;
fill-opacity: 0.5; fill-opacity: 0.5;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
EOL EOL
end end
end end
end end
end end
+149 -149
View File
@@ -1,149 +1,149 @@
require 'rexml/document' require 'rexml/document'
require 'SVG/Graph/BarBase' require 'SVG/Graph/BarBase'
module SVG module SVG
module Graph module Graph
# === Create presentation quality SVG horitonzal bar graphs easily # === Create presentation quality SVG horitonzal bar graphs easily
# #
# = Synopsis # = Synopsis
# #
# require 'SVG/Graph/BarHorizontal' # require 'SVG/Graph/BarHorizontal'
# #
# fields = %w(Jan Feb Mar) # fields = %w(Jan Feb Mar)
# data_sales_02 = [12, 45, 21] # data_sales_02 = [12, 45, 21]
# #
# graph = SVG::Graph::BarHorizontal.new({ # graph = SVG::Graph::BarHorizontal.new({
# :height => 500, # :height => 500,
# :width => 300, # :width => 300,
# :fields => fields, # :fields => fields,
# }) # })
# #
# graph.add_data({ # graph.add_data({
# :data => data_sales_02, # :data => data_sales_02,
# :title => 'Sales 2002', # :title => 'Sales 2002',
# }) # })
# #
# print "Content-type: image/svg+xml\r\n\r\n" # print "Content-type: image/svg+xml\r\n\r\n"
# print graph.burn # print graph.burn
# #
# = Description # = Description
# #
# This object aims to allow you to easily create high quality # This object aims to allow you to easily create high quality
# SVG horitonzal bar graphs. You can either use the default style sheet # SVG horitonzal bar graphs. You can either use the default style sheet
# or supply your own. Either way there are many options which can # or supply your own. Either way there are many options which can
# be configured to give you control over how the graph is # be configured to give you control over how the graph is
# generated - with or without a key, data elements at each point, # generated - with or without a key, data elements at each point,
# title, subtitle etc. # title, subtitle etc.
# #
# = Examples # = Examples
# #
# * http://germane-software.com/repositories/public/SVG/test/test.rb # * http://germane-software.com/repositories/public/SVG/test/test.rb
# #
# = See also # = See also
# #
# * SVG::Graph::Graph # * SVG::Graph::Graph
# * SVG::Graph::Bar # * SVG::Graph::Bar
# * SVG::Graph::Line # * SVG::Graph::Line
# * SVG::Graph::Pie # * SVG::Graph::Pie
# * SVG::Graph::Plot # * SVG::Graph::Plot
# * SVG::Graph::TimeSeries # * SVG::Graph::TimeSeries
# #
# == Author # == Author
# #
# Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom> # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
# #
# Copyright 2004 Sean E. Russell # Copyright 2004 Sean E. Russell
# This software is available under the Ruby license[LICENSE.txt] # This software is available under the Ruby license[LICENSE.txt]
# #
class BarHorizontal < BarBase class BarHorizontal < BarBase
# In addition to the defaults set in BarBase::set_defaults, sets # In addition to the defaults set in BarBase::set_defaults, sets
# [rotate_y_labels] true # [rotate_y_labels] true
# [show_x_guidelines] true # [show_x_guidelines] true
# [show_y_guidelines] false # [show_y_guidelines] false
def set_defaults def set_defaults
super super
init_with( init_with(
:rotate_y_labels => true, :rotate_y_labels => true,
:show_x_guidelines => true, :show_x_guidelines => true,
:show_y_guidelines => false :show_y_guidelines => false
) )
self.right_align = self.right_font = 1 self.right_align = self.right_font = 1
end end
protected protected
def get_x_labels def get_x_labels
maxvalue = max_value maxvalue = max_value
minvalue = min_value minvalue = min_value
range = maxvalue - minvalue range = maxvalue - minvalue
top_pad = range == 0 ? 10 : range / 20.0 top_pad = range == 0 ? 10 : range / 20.0
scale_range = (maxvalue + top_pad) - minvalue scale_range = (maxvalue + top_pad) - minvalue
scale_division = scale_divisions || (scale_range / 10.0) scale_division = scale_divisions || (scale_range / 10.0)
if scale_integers if scale_integers
scale_division = scale_division < 1 ? 1 : scale_division.round scale_division = scale_division < 1 ? 1 : scale_division.round
end end
rv = [] rv = []
maxvalue = maxvalue%scale_division == 0 ? maxvalue = maxvalue%scale_division == 0 ?
maxvalue : maxvalue + scale_division maxvalue : maxvalue + scale_division
minvalue.step( maxvalue, scale_division ) {|v| rv << v} minvalue.step( maxvalue, scale_division ) {|v| rv << v}
return rv return rv
end end
def get_y_labels def get_y_labels
@config[:fields] @config[:fields]
end end
def y_label_offset( height ) def y_label_offset( height )
height / -2.0 height / -2.0
end end
def draw_data def draw_data
minvalue = min_value minvalue = min_value
fieldheight = field_height fieldheight = field_height
unit_size = (@graph_width.to_f - font_size*2*right_font ) / unit_size = (@graph_width.to_f - font_size*2*right_font ) /
(get_x_labels.max - get_x_labels.min ) (get_x_labels.max - get_x_labels.min )
bargap = bar_gap ? (fieldheight < 10 ? fieldheight / 2 : 10) : 0 bargap = bar_gap ? (fieldheight < 10 ? fieldheight / 2 : 10) : 0
bar_height = fieldheight - bargap bar_height = fieldheight - bargap
bar_height /= @data.length if stack == :side bar_height /= @data.length if stack == :side
y_mod = (bar_height / 2) + (font_size / 2) y_mod = (bar_height / 2) + (font_size / 2)
field_count = 1 field_count = 1
@config[:fields].each_index { |i| @config[:fields].each_index { |i|
dataset_count = 0 dataset_count = 0
for dataset in @data for dataset in @data
value = dataset[:data][i] value = dataset[:data][i]
top = @graph_height - (fieldheight * field_count) top = @graph_height - (fieldheight * field_count)
top += (bar_height * dataset_count) if stack == :side top += (bar_height * dataset_count) if stack == :side
# cases (assume 0 = +ve): # cases (assume 0 = +ve):
# value min length left # value min length left
# +ve +ve value.abs - min minvalue.abs # +ve +ve value.abs - min minvalue.abs
# +ve -ve value.abs - 0 minvalue.abs # +ve -ve value.abs - 0 minvalue.abs
# -ve -ve value.abs - 0 minvalue.abs + value # -ve -ve value.abs - 0 minvalue.abs + value
length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size
left = (minvalue.abs + (value < 0 ? value : 0)) * unit_size left = (minvalue.abs + (value < 0 ? value : 0)) * unit_size
@graph.add_element( "rect", { @graph.add_element( "rect", {
"x" => left.to_s, "x" => left.to_s,
"y" => top.to_s, "y" => top.to_s,
"width" => length.to_s, "width" => length.to_s,
"height" => bar_height.to_s, "height" => bar_height.to_s,
"class" => "fill#{dataset_count+1}" "class" => "fill#{dataset_count+1}"
}) })
make_datapoint_text( make_datapoint_text(
left+length+5, top+y_mod, value, "text-anchor: start; " left+length+5, top+y_mod, value, "text-anchor: start; "
) )
dataset_count += 1 dataset_count += 1
end end
field_count += 1 field_count += 1
} }
end end
end end
end end
end end
+978 -978
View File
File diff suppressed because it is too large Load Diff
+395 -395
View File
@@ -1,395 +1,395 @@
require 'SVG/Graph/Graph' require 'SVG/Graph/Graph'
module SVG module SVG
module Graph module Graph
# === Create presentation quality SVG pie graphs easily # === Create presentation quality SVG pie graphs easily
# #
# == Synopsis # == Synopsis
# #
# require 'SVG/Graph/Pie' # require 'SVG/Graph/Pie'
# #
# fields = %w(Jan Feb Mar) # fields = %w(Jan Feb Mar)
# data_sales_02 = [12, 45, 21] # data_sales_02 = [12, 45, 21]
# #
# graph = SVG::Graph::Pie.new({ # graph = SVG::Graph::Pie.new({
# :height => 500, # :height => 500,
# :width => 300, # :width => 300,
# :fields => fields, # :fields => fields,
# }) # })
# #
# graph.add_data({ # graph.add_data({
# :data => data_sales_02, # :data => data_sales_02,
# :title => 'Sales 2002', # :title => 'Sales 2002',
# }) # })
# #
# print "Content-type: image/svg+xml\r\n\r\n" # print "Content-type: image/svg+xml\r\n\r\n"
# print graph.burn(); # print graph.burn();
# #
# == Description # == Description
# #
# This object aims to allow you to easily create high quality # This object aims to allow you to easily create high quality
# SVG pie graphs. You can either use the default style sheet # SVG pie graphs. You can either use the default style sheet
# or supply your own. Either way there are many options which can # or supply your own. Either way there are many options which can
# be configured to give you control over how the graph is # be configured to give you control over how the graph is
# generated - with or without a key, display percent on pie chart, # generated - with or without a key, display percent on pie chart,
# title, subtitle etc. # title, subtitle etc.
# #
# = Examples # = Examples
# #
# http://www.germane-software/repositories/public/SVG/test/single.rb # http://www.germane-software/repositories/public/SVG/test/single.rb
# #
# == See also # == See also
# #
# * SVG::Graph::Graph # * SVG::Graph::Graph
# * SVG::Graph::BarHorizontal # * SVG::Graph::BarHorizontal
# * SVG::Graph::Bar # * SVG::Graph::Bar
# * SVG::Graph::Line # * SVG::Graph::Line
# * SVG::Graph::Plot # * SVG::Graph::Plot
# * SVG::Graph::TimeSeries # * SVG::Graph::TimeSeries
# #
# == Author # == Author
# #
# Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom> # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
# #
# Copyright 2004 Sean E. Russell # Copyright 2004 Sean E. Russell
# This software is available under the Ruby license[LICENSE.txt] # This software is available under the Ruby license[LICENSE.txt]
# #
class Pie < Graph class Pie < Graph
# Defaults are those set by Graph::initialize, and # Defaults are those set by Graph::initialize, and
# [show_shadow] true # [show_shadow] true
# [shadow_offset] 10 # [shadow_offset] 10
# [show_data_labels] false # [show_data_labels] false
# [show_actual_values] false # [show_actual_values] false
# [show_percent] true # [show_percent] true
# [show_key_data_labels] true # [show_key_data_labels] true
# [show_key_actual_values] true # [show_key_actual_values] true
# [show_key_percent] false # [show_key_percent] false
# [expanded] false # [expanded] false
# [expand_greatest] false # [expand_greatest] false
# [expand_gap] 10 # [expand_gap] 10
# [show_x_labels] false # [show_x_labels] false
# [show_y_labels] false # [show_y_labels] false
# [datapoint_font_size] 12 # [datapoint_font_size] 12
def set_defaults def set_defaults
init_with( init_with(
:show_shadow => true, :show_shadow => true,
:shadow_offset => 10, :shadow_offset => 10,
:show_data_labels => false, :show_data_labels => false,
:show_actual_values => false, :show_actual_values => false,
:show_percent => true, :show_percent => true,
:show_key_data_labels => true, :show_key_data_labels => true,
:show_key_actual_values => true, :show_key_actual_values => true,
:show_key_percent => false, :show_key_percent => false,
:expanded => false, :expanded => false,
:expand_greatest => false, :expand_greatest => false,
:expand_gap => 10, :expand_gap => 10,
:show_x_labels => false, :show_x_labels => false,
:show_y_labels => false, :show_y_labels => false,
:datapoint_font_size => 12 :datapoint_font_size => 12
) )
@data = [] @data = []
end end
# Adds a data set to the graph. # Adds a data set to the graph.
# #
# graph.add_data( { :data => [1,2,3,4] } ) # graph.add_data( { :data => [1,2,3,4] } )
# #
# Note that the :title is not necessary. If multiple # Note that the :title is not necessary. If multiple
# data sets are added to the graph, the pie chart will # data sets are added to the graph, the pie chart will
# display the +sums+ of the data. EG: # display the +sums+ of the data. EG:
# #
# graph.add_data( { :data => [1,2,3,4] } ) # graph.add_data( { :data => [1,2,3,4] } )
# graph.add_data( { :data => [2,3,5,9] } ) # graph.add_data( { :data => [2,3,5,9] } )
# #
# is the same as: # is the same as:
# #
# graph.add_data( { :data => [3,5,8,13] } ) # graph.add_data( { :data => [3,5,8,13] } )
def add_data arg def add_data arg
arg[:data].each_index {|idx| arg[:data].each_index {|idx|
@data[idx] = 0 unless @data[idx] @data[idx] = 0 unless @data[idx]
@data[idx] += arg[:data][idx] @data[idx] += arg[:data][idx]
} }
end end
# If true, displays a drop shadow for the chart # If true, displays a drop shadow for the chart
attr_accessor :show_shadow attr_accessor :show_shadow
# Sets the offset of the shadow from the pie chart # Sets the offset of the shadow from the pie chart
attr_accessor :shadow_offset attr_accessor :shadow_offset
# If true, display the data labels on the chart # If true, display the data labels on the chart
attr_accessor :show_data_labels attr_accessor :show_data_labels
# If true, display the actual field values in the data labels # If true, display the actual field values in the data labels
attr_accessor :show_actual_values attr_accessor :show_actual_values
# If true, display the percentage value of each pie wedge in the data # If true, display the percentage value of each pie wedge in the data
# labels # labels
attr_accessor :show_percent attr_accessor :show_percent
# If true, display the labels in the key # If true, display the labels in the key
attr_accessor :show_key_data_labels attr_accessor :show_key_data_labels
# If true, display the actual value of the field in the key # If true, display the actual value of the field in the key
attr_accessor :show_key_actual_values attr_accessor :show_key_actual_values
# If true, display the percentage value of the wedges in the key # If true, display the percentage value of the wedges in the key
attr_accessor :show_key_percent attr_accessor :show_key_percent
# If true, "explode" the pie (put space between the wedges) # If true, "explode" the pie (put space between the wedges)
attr_accessor :expanded attr_accessor :expanded
# If true, expand the largest pie wedge # If true, expand the largest pie wedge
attr_accessor :expand_greatest attr_accessor :expand_greatest
# The amount of space between expanded wedges # The amount of space between expanded wedges
attr_accessor :expand_gap attr_accessor :expand_gap
# The font size of the data point labels # The font size of the data point labels
attr_accessor :datapoint_font_size attr_accessor :datapoint_font_size
protected protected
def add_defs defs def add_defs defs
gradient = defs.add_element( "filter", { gradient = defs.add_element( "filter", {
"id"=>"dropshadow", "id"=>"dropshadow",
"width" => "1.2", "width" => "1.2",
"height" => "1.2", "height" => "1.2",
} ) } )
gradient.add_element( "feGaussianBlur", { gradient.add_element( "feGaussianBlur", {
"stdDeviation" => "4", "stdDeviation" => "4",
"result" => "blur" "result" => "blur"
}) })
end end
# We don't need the graph # We don't need the graph
def draw_graph def draw_graph
end end
def get_y_labels def get_y_labels
[""] [""]
end end
def get_x_labels def get_x_labels
[""] [""]
end end
def keys def keys
total = 0 total = 0
max_value = 0 max_value = 0
@data.each {|x| total += x } @data.each {|x| total += x }
percent_scale = 100.0 / total percent_scale = 100.0 / total
count = -1 count = -1
a = @config[:fields].collect{ |x| a = @config[:fields].collect{ |x|
count += 1 count += 1
v = @data[count] v = @data[count]
perc = show_key_percent ? " "+(v * percent_scale).round.to_s+"%" : "" perc = show_key_percent ? " "+(v * percent_scale).round.to_s+"%" : ""
x + " [" + v.to_s + "]" + perc x + " [" + v.to_s + "]" + perc
} }
end end
RADIANS = Math::PI/180 RADIANS = Math::PI/180
def draw_data def draw_data
@graph = @root.add_element( "g" ) @graph = @root.add_element( "g" )
background = @graph.add_element("g") background = @graph.add_element("g")
midground = @graph.add_element("g") midground = @graph.add_element("g")
diameter = @graph_height > @graph_width ? @graph_width : @graph_height diameter = @graph_height > @graph_width ? @graph_width : @graph_height
diameter -= expand_gap if expanded or expand_greatest diameter -= expand_gap if expanded or expand_greatest
diameter -= datapoint_font_size if show_data_labels diameter -= datapoint_font_size if show_data_labels
diameter -= 10 if show_shadow diameter -= 10 if show_shadow
radius = diameter / 2.0 radius = diameter / 2.0
xoff = (width - diameter) / 2 xoff = (width - diameter) / 2
yoff = (height - @border_bottom - diameter) yoff = (height - @border_bottom - diameter)
yoff -= 10 if show_shadow yoff -= 10 if show_shadow
@graph.attributes['transform'] = "translate( #{xoff} #{yoff} )" @graph.attributes['transform'] = "translate( #{xoff} #{yoff} )"
wedge_text_pad = 5 wedge_text_pad = 5
wedge_text_pad = 20 if show_percent and show_data_labels wedge_text_pad = 20 if show_percent and show_data_labels
total = 0 total = 0
max_value = 0 max_value = 0
@data.each {|x| @data.each {|x|
max_value = max_value < x ? x : max_value max_value = max_value < x ? x : max_value
total += x total += x
} }
percent_scale = 100.0 / total percent_scale = 100.0 / total
prev_percent = 0 prev_percent = 0
rad_mult = 3.6 * RADIANS rad_mult = 3.6 * RADIANS
@config[:fields].each_index { |count| @config[:fields].each_index { |count|
value = @data[count] value = @data[count]
percent = percent_scale * value percent = percent_scale * value
radians = prev_percent * rad_mult radians = prev_percent * rad_mult
x_start = radius+(Math.sin(radians) * radius) x_start = radius+(Math.sin(radians) * radius)
y_start = radius-(Math.cos(radians) * radius) y_start = radius-(Math.cos(radians) * radius)
radians = (prev_percent+percent) * rad_mult radians = (prev_percent+percent) * rad_mult
x_end = radius+(Math.sin(radians) * radius) x_end = radius+(Math.sin(radians) * radius)
x_end -= 0.00001 if @data.length == 1 x_end -= 0.00001 if @data.length == 1
y_end = radius-(Math.cos(radians) * radius) y_end = radius-(Math.cos(radians) * radius)
path = "M#{radius},#{radius} L#{x_start},#{y_start} "+ path = "M#{radius},#{radius} L#{x_start},#{y_start} "+
"A#{radius},#{radius} "+ "A#{radius},#{radius} "+
"0, #{percent >= 50 ? '1' : '0'},1, "+ "0, #{percent >= 50 ? '1' : '0'},1, "+
"#{x_end} #{y_end} Z" "#{x_end} #{y_end} Z"
wedge = @foreground.add_element( "path", { wedge = @foreground.add_element( "path", {
"d" => path, "d" => path,
"class" => "fill#{count+1}" "class" => "fill#{count+1}"
}) })
translate = nil translate = nil
tx = 0 tx = 0
ty = 0 ty = 0
half_percent = prev_percent + percent / 2 half_percent = prev_percent + percent / 2
radians = half_percent * rad_mult radians = half_percent * rad_mult
if show_shadow if show_shadow
shadow = background.add_element( "path", { shadow = background.add_element( "path", {
"d" => path, "d" => path,
"filter" => "url(#dropshadow)", "filter" => "url(#dropshadow)",
"style" => "fill: #ccc; stroke: none;" "style" => "fill: #ccc; stroke: none;"
}) })
clear = midground.add_element( "path", { clear = midground.add_element( "path", {
"d" => path, "d" => path,
"style" => "fill: #fff; stroke: none;" "style" => "fill: #fff; stroke: none;"
}) })
end end
if expanded or (expand_greatest && value == max_value) if expanded or (expand_greatest && value == max_value)
tx = (Math.sin(radians) * expand_gap) tx = (Math.sin(radians) * expand_gap)
ty = -(Math.cos(radians) * expand_gap) ty = -(Math.cos(radians) * expand_gap)
translate = "translate( #{tx} #{ty} )" translate = "translate( #{tx} #{ty} )"
wedge.attributes["transform"] = translate wedge.attributes["transform"] = translate
clear.attributes["transform"] = translate if clear clear.attributes["transform"] = translate if clear
end end
if show_shadow if show_shadow
shadow.attributes["transform"] = shadow.attributes["transform"] =
"translate( #{tx+shadow_offset} #{ty+shadow_offset} )" "translate( #{tx+shadow_offset} #{ty+shadow_offset} )"
end end
if show_data_labels and value != 0 if show_data_labels and value != 0
label = "" label = ""
label += @config[:fields][count] if show_key_data_labels label += @config[:fields][count] if show_key_data_labels
label += " ["+value.to_s+"]" if show_actual_values label += " ["+value.to_s+"]" if show_actual_values
label += " "+percent.round.to_s+"%" if show_percent label += " "+percent.round.to_s+"%" if show_percent
msr = Math.sin(radians) msr = Math.sin(radians)
mcr = Math.cos(radians) mcr = Math.cos(radians)
tx = radius + (msr * radius) tx = radius + (msr * radius)
ty = radius -(mcr * radius) ty = radius -(mcr * radius)
if expanded or (expand_greatest && value == max_value) if expanded or (expand_greatest && value == max_value)
tx += (msr * expand_gap) tx += (msr * expand_gap)
ty -= (mcr * expand_gap) ty -= (mcr * expand_gap)
end end
@foreground.add_element( "text", { @foreground.add_element( "text", {
"x" => tx.to_s, "x" => tx.to_s,
"y" => ty.to_s, "y" => ty.to_s,
"class" => "dataPointLabel", "class" => "dataPointLabel",
"style" => "stroke: #fff; stroke-width: 2;" "style" => "stroke: #fff; stroke-width: 2;"
}).text = label.to_s }).text = label.to_s
@foreground.add_element( "text", { @foreground.add_element( "text", {
"x" => tx.to_s, "x" => tx.to_s,
"y" => ty.to_s, "y" => ty.to_s,
"class" => "dataPointLabel", "class" => "dataPointLabel",
}).text = label.to_s }).text = label.to_s
end end
prev_percent += percent prev_percent += percent
} }
end end
def round val, to def round val, to
up = 10**to.to_f up = 10**to.to_f
(val * up).to_i / up (val * up).to_i / up
end end
def get_css def get_css
return <<EOL return <<EOL
.dataPointLabel{ .dataPointLabel{
fill: #000000; fill: #000000;
text-anchor:middle; text-anchor:middle;
font-size: #{datapoint_font_size}px; font-size: #{datapoint_font_size}px;
font-family: "Arial", sans-serif; font-family: "Arial", sans-serif;
font-weight: normal; font-weight: normal;
} }
/* key - MUST match fill styles */ /* key - MUST match fill styles */
.key1,.fill1{ .key1,.fill1{
fill: #ff0000; fill: #ff0000;
fill-opacity: 0.7; fill-opacity: 0.7;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key2,.fill2{ .key2,.fill2{
fill: #0000ff; fill: #0000ff;
fill-opacity: 0.7; fill-opacity: 0.7;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key3,.fill3{ .key3,.fill3{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #00ff00; fill: #00ff00;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key4,.fill4{ .key4,.fill4{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #ffcc00; fill: #ffcc00;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key5,.fill5{ .key5,.fill5{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #00ccff; fill: #00ccff;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key6,.fill6{ .key6,.fill6{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #ff00ff; fill: #ff00ff;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key7,.fill7{ .key7,.fill7{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #00ff99; fill: #00ff99;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key8,.fill8{ .key8,.fill8{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #ffff00; fill: #ffff00;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key9,.fill9{ .key9,.fill9{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #cc6666; fill: #cc6666;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key10,.fill10{ .key10,.fill10{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #663399; fill: #663399;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key11,.fill11{ .key11,.fill11{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #339900; fill: #339900;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
.key12,.fill12{ .key12,.fill12{
fill-opacity: 0.7; fill-opacity: 0.7;
fill: #9966FF; fill: #9966FF;
stroke: none; stroke: none;
stroke-width: 1px; stroke-width: 1px;
} }
EOL EOL
end end
end end
end end
end end
+500 -500
View File
File diff suppressed because it is too large Load Diff
+238 -238
View File
@@ -1,238 +1,238 @@
require 'SVG/Graph/Plot' require 'SVG/Graph/Plot'
module SVG module SVG
module Graph module Graph
# === For creating SVG plots of scalar temporal data # === For creating SVG plots of scalar temporal data
# #
# = Synopsis # = Synopsis
# #
# require 'SVG/Graph/TimeSeriess' # require 'SVG/Graph/TimeSeriess'
# #
# # Data sets are x,y pairs # # Data sets are x,y pairs
# data1 = ["6/17/72", 11, "1/11/72", 7, "4/13/04 17:31", 11, # data1 = ["6/17/72", 11, "1/11/72", 7, "4/13/04 17:31", 11,
# "9/11/01", 9, "9/1/85", 2, "9/1/88", 1, "1/15/95", 13] # "9/11/01", 9, "9/1/85", 2, "9/1/88", 1, "1/15/95", 13]
# data2 = ["8/1/73", 18, "3/1/77", 15, "10/1/98", 4, # data2 = ["8/1/73", 18, "3/1/77", 15, "10/1/98", 4,
# "5/1/02", 14, "3/1/95", 6, "8/1/91", 12, "12/1/87", 6, # "5/1/02", 14, "3/1/95", 6, "8/1/91", 12, "12/1/87", 6,
# "5/1/84", 17, "10/1/80", 12] # "5/1/84", 17, "10/1/80", 12]
# #
# graph = SVG::Graph::TimeSeries.new( { # graph = SVG::Graph::TimeSeries.new( {
# :width => 640, # :width => 640,
# :height => 480, # :height => 480,
# :graph_title => title, # :graph_title => title,
# :show_graph_title => true, # :show_graph_title => true,
# :no_css => true, # :no_css => true,
# :key => true, # :key => true,
# :scale_x_integers => true, # :scale_x_integers => true,
# :scale_y_integers => true, # :scale_y_integers => true,
# :min_x_value => 0, # :min_x_value => 0,
# :min_y_value => 0, # :min_y_value => 0,
# :show_data_labels => true, # :show_data_labels => true,
# :show_x_guidelines => true, # :show_x_guidelines => true,
# :show_x_title => true, # :show_x_title => true,
# :x_title => "Time", # :x_title => "Time",
# :show_y_title => true, # :show_y_title => true,
# :y_title => "Ice Cream Cones", # :y_title => "Ice Cream Cones",
# :y_title_text_direction => :bt, # :y_title_text_direction => :bt,
# :stagger_x_labels => true, # :stagger_x_labels => true,
# :x_label_format => "%m/%d/%y", # :x_label_format => "%m/%d/%y",
# }) # })
# #
# graph.add_data({ # graph.add_data({
# :data => projection # :data => projection
# :title => 'Projected', # :title => 'Projected',
# }) # })
# #
# graph.add_data({ # graph.add_data({
# :data => actual, # :data => actual,
# :title => 'Actual', # :title => 'Actual',
# }) # })
# #
# print graph.burn() # print graph.burn()
# #
# = Description # = Description
# #
# Produces a graph of temporal scalar data. # Produces a graph of temporal scalar data.
# #
# = Examples # = Examples
# #
# http://www.germane-software/repositories/public/SVG/test/timeseries.rb # http://www.germane-software/repositories/public/SVG/test/timeseries.rb
# #
# = Notes # = Notes
# #
# The default stylesheet handles upto 10 data sets, if you # The default stylesheet handles upto 10 data sets, if you
# use more you must create your own stylesheet and add the # use more you must create your own stylesheet and add the
# additional settings for the extra data sets. You will know # additional settings for the extra data sets. You will know
# if you go over 10 data sets as they will have no style and # if you go over 10 data sets as they will have no style and
# be in black. # be in black.
# #
# Unlike the other types of charts, data sets must contain x,y pairs: # Unlike the other types of charts, data sets must contain x,y pairs:
# #
# [ "12:30", 2 ] # A data set with 1 point: ("12:30",2) # [ "12:30", 2 ] # A data set with 1 point: ("12:30",2)
# [ "01:00",2, "14:20",6] # A data set with 2 points: ("01:00",2) and # [ "01:00",2, "14:20",6] # A data set with 2 points: ("01:00",2) and
# # ("14:20",6) # # ("14:20",6)
# #
# Note that multiple data sets within the same chart can differ in length, # Note that multiple data sets within the same chart can differ in length,
# and that the data in the datasets needn't be in order; they will be ordered # and that the data in the datasets needn't be in order; they will be ordered
# by the plot along the X-axis. # by the plot along the X-axis.
# #
# The dates must be parseable by ParseDate, but otherwise can be # The dates must be parseable by ParseDate, but otherwise can be
# any order of magnitude (seconds within the hour, or years) # any order of magnitude (seconds within the hour, or years)
# #
# = See also # = See also
# #
# * SVG::Graph::Graph # * SVG::Graph::Graph
# * SVG::Graph::BarHorizontal # * SVG::Graph::BarHorizontal
# * SVG::Graph::Bar # * SVG::Graph::Bar
# * SVG::Graph::Line # * SVG::Graph::Line
# * SVG::Graph::Pie # * SVG::Graph::Pie
# * SVG::Graph::Plot # * SVG::Graph::Plot
# #
# == Author # == Author
# #
# Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom> # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
# #
# Copyright 2004 Sean E. Russell # Copyright 2004 Sean E. Russell
# This software is available under the Ruby license[LICENSE.txt] # This software is available under the Ruby license[LICENSE.txt]
# #
class TimeSeries < Plot class TimeSeries < Plot
# In addition to the defaults set by Graph::initialize and # In addition to the defaults set by Graph::initialize and
# Plot::set_defaults, sets: # Plot::set_defaults, sets:
# [x_label_format] '%Y-%m-%d %H:%M:%S' # [x_label_format] '%Y-%m-%d %H:%M:%S'
# [popup_format] '%Y-%m-%d %H:%M:%S' # [popup_format] '%Y-%m-%d %H:%M:%S'
def set_defaults def set_defaults
super super
init_with( init_with(
#:max_time_span => '', #:max_time_span => '',
:x_label_format => '%Y-%m-%d %H:%M:%S', :x_label_format => '%Y-%m-%d %H:%M:%S',
:popup_format => '%Y-%m-%d %H:%M:%S' :popup_format => '%Y-%m-%d %H:%M:%S'
) )
end end
# The format string use do format the X axis labels. # The format string use do format the X axis labels.
# See Time::strformat # See Time::strformat
attr_accessor :x_label_format attr_accessor :x_label_format
# Use this to set the spacing between dates on the axis. The value # Use this to set the spacing between dates on the axis. The value
# must be of the form # must be of the form
# "\d+ ?(days|weeks|months|years|hours|minutes|seconds)?" # "\d+ ?(days|weeks|months|years|hours|minutes|seconds)?"
# #
# EG: # EG:
# #
# graph.timescale_divisions = "2 weeks" # graph.timescale_divisions = "2 weeks"
# #
# will cause the chart to try to divide the X axis up into segments of # will cause the chart to try to divide the X axis up into segments of
# two week periods. # two week periods.
attr_accessor :timescale_divisions attr_accessor :timescale_divisions
# The formatting used for the popups. See x_label_format # The formatting used for the popups. See x_label_format
attr_accessor :popup_format attr_accessor :popup_format
# Add data to the plot. # Add data to the plot.
# #
# d1 = [ "12:30", 2 ] # A data set with 1 point: ("12:30",2) # d1 = [ "12:30", 2 ] # A data set with 1 point: ("12:30",2)
# d2 = [ "01:00",2, "14:20",6] # A data set with 2 points: ("01:00",2) and # d2 = [ "01:00",2, "14:20",6] # A data set with 2 points: ("01:00",2) and
# # ("14:20",6) # # ("14:20",6)
# graph.add_data( # graph.add_data(
# :data => d1, # :data => d1,
# :title => 'One' # :title => 'One'
# ) # )
# graph.add_data( # graph.add_data(
# :data => d2, # :data => d2,
# :title => 'Two' # :title => 'Two'
# ) # )
# #
# Note that the data must be in time,value pairs, and that the date format # Note that the data must be in time,value pairs, and that the date format
# may be any date that is parseable by ParseDate. # may be any date that is parseable by ParseDate.
def add_data data def add_data data
@data = [] unless @data @data = [] unless @data
raise "No data provided by #{@data.inspect}" unless data[:data] and raise "No data provided by #{@data.inspect}" unless data[:data] and
data[:data].kind_of? Array data[:data].kind_of? Array
raise "Data supplied must be x,y pairs! "+ raise "Data supplied must be x,y pairs! "+
"The data provided contained an odd set of "+ "The data provided contained an odd set of "+
"data points" unless data[:data].length % 2 == 0 "data points" unless data[:data].length % 2 == 0
return if data[:data].length == 0 return if data[:data].length == 0
x = [] x = []
y = [] y = []
data[:data].each_index {|i| data[:data].each_index {|i|
if i%2 == 0 if i%2 == 0
t = DateTime.parse( data[:data][i] ).to_time t = DateTime.parse( data[:data][i] ).to_time
x << t.to_i x << t.to_i
else else
y << data[:data][i] y << data[:data][i]
end end
} }
sort( x, y ) sort( x, y )
data[:data] = [x,y] data[:data] = [x,y]
@data << data @data << data
end end
protected protected
def min_x_value=(value) def min_x_value=(value)
@min_x_value = DateTime.parse( data[:data][i] ).to_time @min_x_value = DateTime.parse( value ).to_time
end end
def format x, y def format x, y
Time.at( x ).strftime( popup_format ) Time.at( x ).strftime( popup_format )
end end
def get_x_labels def get_x_labels
get_x_values.collect { |v| Time.at(v).strftime( x_label_format ) } get_x_values.collect { |v| Time.at(v).strftime( x_label_format ) }
end end
private private
def get_x_values def get_x_values
rv = [] rv = []
min, max, scale_division = x_range min, max, scale_division = x_range
if timescale_divisions if timescale_divisions
timescale_divisions =~ /(\d+) ?(day|week|month|year|hour|minute|second)?/ timescale_divisions =~ /(\d+) ?(day|week|month|year|hour|minute|second)?/
division_units = $2 ? $2 : "day" division_units = $2 ? $2 : "day"
amount = $1.to_i amount = $1.to_i
if amount if amount
step = nil step = nil
case division_units case division_units
when "month" when "month"
cur = min cur = min
while cur < max while cur < max
rv << cur rv << cur
arr = Time.at( cur ).to_a arr = Time.at( cur ).to_a
arr[4] += amount arr[4] += amount
if arr[4] > 12 if arr[4] > 12
arr[5] += (arr[4] / 12).to_i arr[5] += (arr[4] / 12).to_i
arr[4] = (arr[4] % 12) arr[4] = (arr[4] % 12)
end end
cur = Time.local(*arr).to_i cur = Time.local(*arr).to_i
end end
when "year" when "year"
cur = min cur = min
while cur < max while cur < max
rv << cur rv << cur
arr = Time.at( cur ).to_a arr = Time.at( cur ).to_a
arr[5] += amount arr[5] += amount
cur = Time.local(*arr).to_i cur = Time.local(*arr).to_i
end end
when "week" when "week"
step = 7 * 24 * 60 * 60 * amount step = 7 * 24 * 60 * 60 * amount
when "day" when "day"
step = 24 * 60 * 60 * amount step = 24 * 60 * 60 * amount
when "hour" when "hour"
step = 60 * 60 * amount step = 60 * 60 * amount
when "minute" when "minute"
step = 60 * amount step = 60 * amount
when "second" when "second"
step = amount step = amount
end end
min.step( max, step ) {|v| rv << v} if step min.step( max, step ) {|v| rv << v} if step
return rv return rv
end end
end end
min.step( max, scale_division ) {|v| rv << v} min.step( max, scale_division ) {|v| rv << v}
return rv return rv
end end
end end
end end
end end
+12 -1
View File
@@ -403,6 +403,9 @@ class TCPDF
Error("Incorrect orientation: #{orientation}") Error("Incorrect orientation: #{orientation}")
end end
@fw = @w_pt/@k
@fh = @h_pt/@k
@cur_orientation = @def_orientation @cur_orientation = @def_orientation
@w = @w_pt/@k @w = @w_pt/@k
@h = @h_pt/@k @h = @h_pt/@k
@@ -3615,9 +3618,9 @@ class TCPDF
restspace = GetPageHeight() - GetY() - GetBreakMargin(); restspace = GetPageHeight() - GetY() - GetBreakMargin();
writeHTML(html, true, fill); # write html text writeHTML(html, true, fill); # write html text
SetX(x)
currentY = GetY(); currentY = GetY();
@auto_page_break = false; @auto_page_break = false;
# check if a new page has been created # check if a new page has been created
if (@page > pagenum) if (@page > pagenum)
@@ -3625,11 +3628,13 @@ class TCPDF
currentpage = @page; currentpage = @page;
@page = pagenum; @page = pagenum;
SetY(GetPageHeight() - restspace - GetBreakMargin()); SetY(GetPageHeight() - restspace - GetBreakMargin());
SetX(x)
Cell(w, restspace - 1, "", b, 0, 'L', 0); Cell(w, restspace - 1, "", b, 0, 'L', 0);
b = b2; b = b2;
@page += 1; @page += 1;
while @page < currentpage while @page < currentpage
SetY(@t_margin); # put cursor at the beginning of text SetY(@t_margin); # put cursor at the beginning of text
SetX(x)
Cell(w, @page_break_trigger - @t_margin, "", b, 0, 'L', 0); Cell(w, @page_break_trigger - @t_margin, "", b, 0, 'L', 0);
@page += 1; @page += 1;
end end
@@ -3638,10 +3643,12 @@ class TCPDF
end end
# design a cell around the text on last page # design a cell around the text on last page
SetY(@t_margin); # put cursor at the beginning of text SetY(@t_margin); # put cursor at the beginning of text
SetX(x)
Cell(w, currentY - @t_margin, "", b, 0, 'L', 0); Cell(w, currentY - @t_margin, "", b, 0, 'L', 0);
else else
SetY(y); # put cursor at the beginning of text SetY(y); # put cursor at the beginning of text
# design a cell around the text # design a cell around the text
SetX(x)
Cell(w, [h, (currentY - y)].max, "", border, 0, 'L', 0); Cell(w, [h, (currentY - y)].max, "", border, 0, 'L', 0);
end end
@auto_page_break = true; @auto_page_break = true;
@@ -3995,6 +4002,10 @@ class TCPDF
@quote_page[@quote_count] = @page; @quote_page[@quote_count] = @page;
@quote_count += 1 @quote_count += 1
when 'br' when 'br'
if @tdbegin
@tdtext << "\n"
return
end
Ln(); Ln();
if (@li_spacer.length > 0) if (@li_spacer.length > 0)
+1 -1
View File
@@ -198,7 +198,7 @@ Redmine::MenuManager.map :project_menu do |menu|
menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id, menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id,
:if => Proc.new { |p| p.shared_versions.any? } :if => Proc.new { |p| p.shared_versions.any? }
menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural 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, menu.push :new_issue, { :controller => 'issues', :action => 'new', :copy_from => nil }, :param => :project_id, :caption => :label_issue_new,
:html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt 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 :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
+31 -12
View File
@@ -34,12 +34,12 @@ module Redmine
include Redmine::I18n include Redmine::I18n
attr_accessor :footer_date attr_accessor :footer_date
def initialize(lang) def initialize(lang, orientation='P')
@@k_path_cache = Rails.root.join('tmp', 'pdf') @@k_path_cache = Rails.root.join('tmp', 'pdf')
FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache) FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
set_language_if_valid lang set_language_if_valid lang
pdf_encoding = l(:general_pdf_encoding).upcase pdf_encoding = l(:general_pdf_encoding).upcase
super('P', 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding) super(orientation, 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding)
case current_language.to_s.downcase case current_language.to_s.downcase
when 'vi' when 'vi'
@font_for_content = 'DejaVuSans' @font_for_content = 'DejaVuSans'
@@ -109,6 +109,13 @@ module Redmine
RDMPdfEncoding::rdm_from_utf8(txt, l(:general_pdf_encoding)) RDMPdfEncoding::rdm_from_utf8(txt, l(:general_pdf_encoding))
end end
def formatted_text(text)
html = Redmine::WikiFormatting.to_html(Setting.text_formatting, text)
# Strip {{toc}} tags
html.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i, '')
html
end
def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='') def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link) Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link)
end end
@@ -120,8 +127,7 @@ module Redmine
def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0) def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
@attachments = attachments @attachments = attachments
writeHTMLCell(w, h, x, y, writeHTMLCell(w, h, x, y,
fix_text_encoding( fix_text_encoding(formatted_text(txt)),
Redmine::WikiFormatting.to_html(Setting.text_formatting, txt)),
border, ln, fill) border, ln, fill)
end end
@@ -236,7 +242,7 @@ module Redmine
# fetch row values # fetch row values
def fetch_row_values(issue, query, level) def fetch_row_values(issue, query, level)
query.columns.collect do |column| query.inline_columns.collect do |column|
s = if column.is_a?(QueryCustomFieldColumn) s = if column.is_a?(QueryCustomFieldColumn)
cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id} cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
show_value(cv) show_value(cv)
@@ -263,10 +269,10 @@ module Redmine
# by captions # by captions
pdf.SetFontStyle('B',8) pdf.SetFontStyle('B',8)
col_padding = pdf.GetStringWidth('OO') col_padding = pdf.GetStringWidth('OO')
col_width_min = query.columns.map {|v| pdf.GetStringWidth(v.caption) + col_padding} col_width_min = query.inline_columns.map {|v| pdf.GetStringWidth(v.caption) + col_padding}
col_width_max = Array.new(col_width_min) col_width_max = Array.new(col_width_min)
col_width_avg = Array.new(col_width_min) col_width_avg = Array.new(col_width_min)
word_width_max = query.columns.map {|c| word_width_max = query.inline_columns.map {|c|
n = 10 n = 10
c.caption.split.each {|w| c.caption.split.each {|w|
x = pdf.GetStringWidth(w) + col_padding x = pdf.GetStringWidth(w) + col_padding
@@ -370,13 +376,13 @@ module Redmine
# render it background to find the max height used # render it background to find the max height used
base_x = pdf.GetX base_x = pdf.GetX
base_y = pdf.GetY base_y = pdf.GetY
max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true) max_height = issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true)
pdf.Rect(base_x, base_y, table_width + col_id_width, max_height, 'FD'); pdf.Rect(base_x, base_y, table_width + col_id_width, max_height, 'FD');
pdf.SetXY(base_x, base_y); pdf.SetXY(base_x, base_y);
# write the cells on page # write the cells on page
pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1) pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true) issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true)
issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width) issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
pdf.SetY(base_y + max_height); pdf.SetY(base_y + max_height);
@@ -387,7 +393,7 @@ module Redmine
# Returns a PDF string of a list of issues # Returns a PDF string of a list of issues
def issues_to_pdf(issues, project, query) def issues_to_pdf(issues, project, query)
pdf = ITCPDF.new(current_language) pdf = ITCPDF.new(current_language, "L")
title = query.new_record? ? l(:label_issue_plural) : query.name title = query.new_record? ? l(:label_issue_plural) : query.name
title = "#{project} - #{title}" if project title = "#{project} - #{title}" if project
pdf.SetTitle(title) pdf.SetTitle(title)
@@ -407,11 +413,17 @@ module Redmine
# column widths # column widths
table_width = page_width - right_margin - 10 # fixed left margin table_width = page_width - right_margin - 10 # fixed left margin
col_width = [] col_width = []
unless query.columns.empty? unless query.inline_columns.empty?
col_width = calc_col_width(issues, query, table_width - col_id_width, pdf) col_width = calc_col_width(issues, query, table_width - col_id_width, pdf)
table_width = col_width.inject(0) {|s,v| s += v} table_width = col_width.inject(0) {|s,v| s += v}
end end
# use full width if the description is displayed
if table_width > 0 && query.has_column?(:description)
col_width = col_width.map {|w| w = w * (page_width - right_margin - 10 - col_id_width) / table_width}
table_width = col_width.inject(0) {|s,v| s += v}
end
# title # title
pdf.SetFontStyle('B',11) pdf.SetFontStyle('B',11)
pdf.RDMCell(190,10, title) pdf.RDMCell(190,10, title)
@@ -422,7 +434,7 @@ module Redmine
if query.grouped? && if query.grouped? &&
(group = query.group_by_column.value(issue)) != previous_group (group = query.group_by_column.value(issue)) != previous_group
pdf.SetFontStyle('B',10) pdf.SetFontStyle('B',10)
group_label = group.blank? ? 'None' : group.to_s group_label = group.blank? ? 'None' : group.to_s.dup
group_label << " (#{query.issue_count_by_group[group]})" group_label << " (#{query.issue_count_by_group[group]})"
pdf.Bookmark group_label, 0, -1 pdf.Bookmark group_label, 0, -1
pdf.RDMCell(table_width + col_id_width, row_height * 2, group_label, 1, 1, 'L') pdf.RDMCell(table_width + col_id_width, row_height * 2, group_label, 1, 1, 'L')
@@ -454,6 +466,13 @@ module Redmine
issues_to_pdf_write_cells(pdf, col_values, col_width, row_height) issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width) issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
pdf.SetY(base_y + max_height); pdf.SetY(base_y + max_height);
if query.has_column?(:description) && issue.description?
pdf.SetX(10)
pdf.SetAutoPageBreak(true, 20)
pdf.RDMwriteHTMLCell(0, 5, 10, 0, issue.description.to_s, issue.attachments, "LRBT")
pdf.SetAutoPageBreak(false)
end
end end
if issues.size == Setting.issues_export_limit.to_i if issues.size == Setting.issues_export_limit.to_i
+2 -2
View File
@@ -4,13 +4,13 @@ module Redmine
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 2 MAJOR = 2
MINOR = 2 MINOR = 2
TINY = 0 TINY = 3
# Branch values: # Branch values:
# * official release: nil # * official release: nil
# * stable branch: stable # * stable branch: stable
# * trunk: devel # * trunk: devel
BRANCH = 'devel' BRANCH = 'stable'
# Retrieves the revision from the working copy # Retrieves the revision from the working copy
def self.revision def self.revision
+2 -2
View File
@@ -147,10 +147,10 @@ module Redmine
unless block_given? unless block_given?
raise "Can not create a macro without a block!" raise "Can not create a macro without a block!"
end end
name = name.to_sym if name.is_a?(String) name = name.to_s.downcase.to_sym
available_macros[name] = {:desc => @@desc || ''}.merge(options) available_macros[name] = {:desc => @@desc || ''}.merge(options)
@@desc = nil @@desc = nil
Definitions.send :define_method, "macro_#{name}".downcase, &block Definitions.send :define_method, "macro_#{name}", &block
end end
# Sets description for the next macro to be defined # Sets description for the next macro to be defined
@@ -69,7 +69,7 @@ module Redmine
l = 1 l = 1
started = false started = false
ended = false ended = false
text.scan(/(((?:.*?)(\A|\r?\n\s*\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))? (.*?)$)|.*)/m).each do |all, content, lf, heading, level| text.scan(/(((?:.*?)(\A|\r?\n\s*\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))?[ \t](.*?)$)|.*)/m).each do |all, content, lf, heading, level|
if heading.nil? if heading.nil?
if ended if ended
after << all after << all
+1 -1
View File
@@ -169,7 +169,7 @@ http://www.redmine.org, someone@foo.bar
<h2><a name="5" class="wiki-page"></a>Text formatting</h2> <h2><a name="5" class="wiki-page"></a>Text formatting</h2>
<p>For things such as headlines, bold, tables, lists, Redmine supports Textile syntax. See <a class="external" href="http://www.textism.com/tools/textile/">http://www.textism.com/tools/textile/</a> for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.</p> <p>For things such as headlines, bold, tables, lists, Redmine supports Textile syntax. See <a class="external" href="http://en.wikipedia.org/wiki/Textile_%28markup_language%29">http://en.wikipedia.org/wiki/Textile_(markup_language)</a> for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.</p>
<h3><a name="6" class="wiki-page"></a>Font style</h3> <h3><a name="6" class="wiki-page"></a>Font style</h3>
+2
View File
@@ -149,6 +149,8 @@ tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, t
tr.issue td.subject, tr.issue td.relations { text-align: left; } tr.issue td.subject, tr.issue td.relations { text-align: left; }
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
tr.issue td.relations span {white-space: nowrap;} tr.issue td.relations span {white-space: nowrap;}
table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
table.issues td.description pre {white-space:normal;}
tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} 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-1 td.subject {padding-left: 0.5em;}
@@ -39,3 +39,4 @@ pulvinar dui, a gravida orci mi eget odio. Nunc a lacus.
category: Stock management category: Stock management
searchable field: Value for a custom field searchable field: Value for a custom field
Database: postgresql
+14
View File
@@ -99,4 +99,18 @@ wiki_content_versions_006:
version: 3 version: 3
author_id: 1 author_id: 1
comments: comments:
wiki_content_versions_007:
data: |-
h1. Page with an inline image
This is an inline image:
!logo.gif!
updated_on: 2007-03-08 00:18:07 +01:00
page_id: 4
wiki_content_id: 4
id: 7
version: 1
author_id: 1
comments:
@@ -37,7 +37,7 @@ class ActivitiesControllerTest < ActionController::TestCase
end end
def test_previous_project_index def test_previous_project_index
get :index, :id => 1, :from => 3.days.ago.to_date get :index, :id => 1, :from => 2.days.ago.to_date
assert_response :success assert_response :success
assert_template 'index' assert_template 'index'
assert_not_nil assigns(:events_by_day) assert_not_nil assigns(:events_by_day)
@@ -132,7 +132,7 @@ class ContextMenusControllerTest < ActionController::TestCase
:attributes => {:href => "/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bcustom_field_values%5D%5B#{field.id}%5D=Foo"} :attributes => {:href => "/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bcustom_field_values%5D%5B#{field.id}%5D=Foo"}
assert_tag 'a', assert_tag 'a',
:content => 'none', :content => 'none',
:attributes => {:href => "/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bcustom_field_values%5D%5B#{field.id}%5D="} :attributes => {:href => "/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bcustom_field_values%5D%5B#{field.id}%5D=__none__"}
end end
def test_context_menu_should_not_include_null_value_for_required_custom_fields def test_context_menu_should_not_include_null_value_for_required_custom_fields
+29 -1
View File
@@ -422,7 +422,7 @@ class IssuesControllerTest < ActionController::TestCase
assert_equal 'text/csv; header=present', @response.content_type assert_equal 'text/csv; header=present', @response.content_type
assert @response.body.starts_with?("#,") assert @response.body.starts_with?("#,")
lines = @response.body.chomp.split("\n") lines = @response.body.chomp.split("\n")
assert_equal assigns(:query).available_columns.size + 1, lines[0].split(',').size assert_equal assigns(:query).available_inline_columns.size + 1, lines[0].split(',').size
end end
def test_index_csv_with_multi_column_field def test_index_csv_with_multi_column_field
@@ -829,6 +829,17 @@ class IssuesControllerTest < ActionController::TestCase
assert_equal 'application/pdf', response.content_type assert_equal 'application/pdf', response.content_type
end end
def test_index_with_description_column
get :index, :set_filter => 1, :c => %w(subject description)
assert_select 'table.issues thead th', 3 # columns: chekbox + id + subject
assert_select 'td.description[colspan=3]', :text => 'Unable to print recipes'
get :index, :set_filter => 1, :c => %w(subject description), :format => 'pdf'
assert_response :success
assert_equal 'application/pdf', response.content_type
end
def test_index_send_html_if_query_is_invalid def test_index_send_html_if_query_is_invalid
get :index, :f => ['start_date'], :op => {:start_date => '='} get :index, :f => ['start_date'], :op => {:start_date => '='}
assert_equal 'text/html', @response.content_type assert_equal 'text/html', @response.content_type
@@ -2345,6 +2356,9 @@ class IssuesControllerTest < ActionController::TestCase
assert_tag 'select', :attributes => {:name => 'issue[project_id]'}, assert_tag 'select', :attributes => {:name => 'issue[project_id]'},
:child => {:tag => 'option', :attributes => {:value => '2', :selected => nil}, :content => 'OnlineStore'} :child => {:tag => 'option', :attributes => {:value => '2', :selected => nil}, :content => 'OnlineStore'}
assert_tag 'input', :attributes => {:name => 'copy_from', :value => '1'} assert_tag 'input', :attributes => {:name => 'copy_from', :value => '1'}
# "New issue" menu item should not link to copy
assert_select '#main-menu a.new-issue[href=/projects/ecookbook/issues/new]'
end end
def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
@@ -2900,6 +2914,20 @@ class IssuesControllerTest < ActionController::TestCase
assert_equal spent_hours_before + 2.5, issue.spent_hours assert_equal spent_hours_before + 2.5, issue.spent_hours
end end
def test_put_update_should_preserve_parent_issue_even_if_not_visible
parent = Issue.generate!(:project_id => 1, :is_private => true)
issue = Issue.generate!(:parent_issue_id => parent.id)
assert !parent.visible?(User.find(3))
@request.session[:user_id] = 3
get :edit, :id => issue.id
assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', parent.id.to_s
put :update, :id => issue.id, :issue => {:subject => 'New subject', :parent_issue_id => parent.id.to_s}
assert_response 302
assert_equal parent, issue.parent
end
def test_put_update_with_attachment_only def test_put_update_with_attachment_only
set_tmp_attachments_directory set_tmp_attachments_directory
+5
View File
@@ -187,6 +187,11 @@ class MyControllerTest < ActionController::TestCase
assert User.find(2).pref[:my_page_layout]['top'].include?('issuesreportedbyme') assert User.find(2).pref[:my_page_layout]['top'].include?('issuesreportedbyme')
end end
def test_add_invalid_block_should_redirect
post :add_block, :block => 'invalid'
assert_redirected_to '/my/page_layout'
end
def test_remove_block def test_remove_block
post :remove_block, :block => 'issuesassignedtome' post :remove_block, :block => 'issuesassignedtome'
assert_redirected_to '/my/page_layout' assert_redirected_to '/my/page_layout'
+1 -1
View File
@@ -48,7 +48,7 @@ class PreviewsControllerTest < ActionController::TestCase
def test_preview_journal_notes_for_update def test_preview_journal_notes_for_update
@request.session[:user_id] = 2 @request.session[:user_id] = 2
post :issue, :project_id => '1', :id => 1, :issue => {:notes => 'Foo'} post :issue, :project_id => '1', :id => 1, :notes => 'Foo'
assert_response :success assert_response :success
assert_template 'preview' assert_template 'preview'
assert_not_nil assigns(:notes) assert_not_nil assigns(:notes)
+13
View File
@@ -75,6 +75,19 @@ class WikiControllerTest < ActionController::TestCase
assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/ assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
end end
def test_show_old_version_with_attachments
page = WikiPage.find(4)
assert page.attachments.any?
content = page.content
content.text = "update"
content.save!
get :show, :project_id => 'ecookbook', :id => page.title, :version => '1'
assert_kind_of WikiContent::Version, assigns(:content)
assert_response :success
assert_template 'show'
end
def test_show_old_version_without_permission_should_be_denied def test_show_old_version_without_permission_should_be_denied
Role.anonymous.remove_permission! :view_wiki_edits Role.anonymous.remove_permission! :view_wiki_edits
+12
View File
@@ -118,4 +118,16 @@ module ObjectHelpers
board.save! board.save!
board board
end end
def Attachment.generate!(attributes={})
@generated_filename ||= 'testfile0'
@generated_filename.succ!
attributes = attributes.dup
attachment = Attachment.new(attributes)
attachment.container ||= Issue.find(1)
attachment.author ||= User.find(2)
attachment.filename = @generated_filename if attachment.filename.blank?
attachment.save!
attachment
end
end end
+5
View File
@@ -218,4 +218,9 @@ class CustomFieldTest < ActiveSupport::TestCase
assert_nil CustomField.new(:field_format => 'text').value_class assert_nil CustomField.new(:field_format => 'text').value_class
assert_nil CustomField.new.value_class assert_nil CustomField.new.value_class
end end
def test_value_from_keyword_for_list_custom_field
field = CustomField.find(1)
assert_equal 'PostgreSQL', field.value_from_keyword('postgresql', Issue.find(1))
end
end end
+21 -3
View File
@@ -347,6 +347,15 @@ RAW
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" } to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
end end
def test_redmine_links_with_a_different_project_before_current_project
vp1 = Version.generate!(:project_id => 1, :name => '1.4.4')
vp3 = Version.generate!(:project_id => 3, :name => '1.4.4')
@project = Project.find(3)
assert_equal %(<p><a href="/versions/#{vp1.id}" class="version">1.4.4</a> <a href="/versions/#{vp3.id}" class="version">1.4.4</a></p>),
textilizable("ecookbook:version:1.4.4 version:1.4.4")
end
def test_escaped_redmine_links_should_not_be_parsed def test_escaped_redmine_links_should_not_be_parsed
to_test = [ to_test = [
'#3.', '#3.',
@@ -394,14 +403,14 @@ RAW
end end
def test_multiple_repositories_redmine_links def test_multiple_repositories_redmine_links
svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///foo/hg') svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn_repo-1', :url => 'file:///foo/hg')
Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123') Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg') hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd') Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
changeset_link = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2}, changeset_link = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
:class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3') :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
svn_changeset_link = link_to('svn1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn1', :rev => 123}, svn_changeset_link = link_to('svn_repo-1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn_repo-1', :rev => 123},
:class => 'changeset', :title => '') :class => 'changeset', :title => '')
hg_changeset_link = link_to('hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'}, hg_changeset_link = link_to('hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
:class => 'changeset', :title => '') :class => 'changeset', :title => '')
@@ -411,7 +420,7 @@ RAW
to_test = { to_test = {
'r2' => changeset_link, 'r2' => changeset_link,
'svn1|r123' => svn_changeset_link, 'svn_repo-1|r123' => svn_changeset_link,
'invalid|r123' => 'invalid|r123', 'invalid|r123' => 'invalid|r123',
'commit:hg1|abcd' => hg_changeset_link, 'commit:hg1|abcd' => hg_changeset_link,
'commit:invalid|abcd' => 'commit:invalid|abcd', 'commit:invalid|abcd' => 'commit:invalid|abcd',
@@ -551,6 +560,15 @@ RAW
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => Issue.find(3).attachments), "#{text} failed" } to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => Issue.find(3).attachments), "#{text} failed" }
end end
def test_attachment_link_should_link_to_latest_attachment
set_tmp_attachments_directory
a1 = Attachment.generate!(:filename => "test.txt", :created_on => 1.hour.ago)
a2 = Attachment.generate!(:filename => "test.txt")
assert_equal %(<p><a href="/attachments/download/#{a2.id}" class="attachment">test.txt</a></p>),
textilizable('attachment:test.txt', :attachments => [a1, a2])
end
def test_wiki_links def test_wiki_links
to_test = { to_test = {
'[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>', '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
@@ -78,6 +78,12 @@ class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase
assert_equal "<p>Baz: (arg1,arg2) (String) (line1\nline2)</p>", textilizable("{{baz(arg1, arg2)\nline1\nline2\n}}") assert_equal "<p>Baz: (arg1,arg2) (String) (line1\nline2)</p>", textilizable("{{baz(arg1, arg2)\nline1\nline2\n}}")
end end
def test_macro_name_with_upper_case
Redmine::WikiFormatting::Macros.macro(:UpperCase) {|obj, args| "Upper"}
assert_equal "<p>Upper</p>", textilizable("{{UpperCase}}")
end
def test_multiple_macros_on_the_same_line def test_multiple_macros_on_the_same_line
Redmine::WikiFormatting::Macros.macro :foo do |obj, args| Redmine::WikiFormatting::Macros.macro :foo do |obj, args|
args.any? ? "args: #{args.join(',')}" : "no args" args.any? ? "args: #{args.join(',')}" : "no args"
@@ -419,6 +419,20 @@ STR
end end
end end
def test_get_section_should_support_headings_starting_with_a_tab
text = <<-STR
h1.\tHeading 1
Content 1
h1. Heading 2
Content 2
STR
assert_match /\Ah1.\tHeading 1\s+Content 1\z/, @formatter.new(text).get_section(1).first
end
private private
def assert_html_output(to_test, expect_paragraph = true) def assert_html_output(to_test, expect_paragraph = true)
+2 -2
View File
@@ -177,8 +177,8 @@ class MailHandlerTest < ActiveSupport::TestCase
assert !issue.new_record? assert !issue.new_record?
issue.reload issue.reload
assert_equal 'New ticket with custom field values', issue.subject assert_equal 'New ticket with custom field values', issue.subject
assert_equal 'Value for a custom field', assert_equal 'PostgreSQL', issue.custom_field_value(1)
issue.custom_value_for(CustomField.find_by_name('Searchable field')).value assert_equal 'Value for a custom field', issue.custom_field_value(2)
assert !issue.description.match(/^searchable field:/i) assert !issue.description.match(/^searchable field:/i)
end end
+18 -1
View File
@@ -737,7 +737,9 @@ class QueryTest < ActiveSupport::TestCase
def test_default_columns def test_default_columns
q = Query.new q = Query.new
assert !q.columns.empty? assert q.columns.any?
assert q.inline_columns.any?
assert q.block_columns.empty?
end end
def test_set_column_names def test_set_column_names
@@ -748,6 +750,21 @@ class QueryTest < ActiveSupport::TestCase
assert q.has_column?(c) assert q.has_column?(c)
end end
def test_inline_and_block_columns
q = Query.new
q.column_names = ['subject', 'description', 'tracker']
assert_equal [:subject, :tracker], q.inline_columns.map(&:name)
assert_equal [:description], q.block_columns.map(&:name)
end
def test_custom_field_columns_should_be_inline
q = Query.new
columns = q.available_columns.select {|column| column.is_a? QueryCustomFieldColumn}
assert columns.any?
assert_nil columns.detect {|column| !column.inline?}
end
def test_query_should_preload_spent_hours def test_query_should_preload_spent_hours
q = Query.new(:name => '_', :column_names => [:subject, :spent_hours]) q = Query.new(:name => '_', :column_names => [:subject, :spent_hours])
assert q.has_column?(:spent_hours) assert q.has_column?(:spent_hours)