Actualiza a Redmine 3.4.13

This commit is contained in:
Manuel Cillero 2020-07-03 21:39:03 +02:00
parent 807ff3308d
commit ecddcaf1d3
224 changed files with 2222 additions and 1000 deletions

20
Gemfile
View file

@ -1,10 +1,8 @@
source 'https://rubygems.org'
if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('1.5.0')
abort "Redmine requires Bundler 1.5.0 or higher (you're using #{Bundler::VERSION}).\nPlease update with 'gem update bundler'."
end
gem "bundler", ">= 1.5.0", "< 2.0.0"
gem "rails", "4.2.8"
gem "rails", "4.2.11.1"
gem "addressable", "2.4.0" if RUBY_VERSION < "2.0"
if RUBY_VERSION < "2.1"
gem "public_suffix", (RUBY_VERSION < "2.0" ? "~> 1.4" : "~> 2.0.5")
@ -23,13 +21,17 @@ gem "mail", "~> 2.6.4"
gem "nokogiri", (RUBY_VERSION >= "2.1" ? "~> 1.8.1" : "~> 1.6.8")
gem "i18n", "~> 0.7.0"
gem "ffi", "1.9.14", :platforms => :mingw if RUBY_VERSION < "2.0"
gem "xpath", "< 3.2.0" if RUBY_VERSION < "2.3"
# Request at least rails-html-sanitizer 1.0.3 because of security advisories
gem "rails-html-sanitizer", ">= 1.0.3"
# TODO: Remove the following line when #32223 is fixed
gem "sprockets", "~> 3.7.2"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin]
gem "rbpdf", "~> 1.19.3"
gem "rbpdf", "~> 1.19.6"
# Optional gem for LDAP authentication
group :ldap do
@ -38,14 +40,14 @@ end
# Optional gem for OpenID authentication
group :openid do
gem "ruby-openid", "~> 2.3.0", :require => "openid"
gem "ruby-openid", "~> 2.9.2", :require => "openid"
gem "rack-openid"
end
platforms :mri, :mingw, :x64_mingw do
# Optional gem for exporting the gantt to a PNG file, not supported with jruby
group :rmagick do
gem "rmagick", ">= 2.14.0"
gem "rmagick", "~> 2.16.0"
end
# Optional Markdown support, not for JRuby
@ -94,12 +96,12 @@ end
group :test do
gem "minitest"
gem "rails-dom-testing"
gem "mocha"
gem 'mocha', '>= 1.4.0'
gem "simplecov", "~> 0.9.1", :require => false
# TODO: remove this after upgrading to Rails 5
gem "test_after_commit", "~> 0.4.2"
# For running UI tests
gem "capybara"
gem "capybara", '~> 2.13'
gem "selenium-webdriver", "~> 2.53.4"
end

View file

@ -87,7 +87,7 @@ class AccountController < ApplicationController
@user.must_change_passwd = false
if @user.save
@token.destroy
Mailer.password_updated(@user)
Mailer.password_updated(@user, { remote_ip: request.remote_ip })
flash[:notice] = l(:notice_account_password_updated)
redirect_to signin_path
return

View file

@ -60,7 +60,7 @@ class AttachmentsController < ApplicationController
@attachment.increment_download
end
if stale?(:etag => @attachment.digest)
if stale?(:etag => @attachment.digest, :template => false)
# images are sent inline
send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),
:type => detect_content_type(@attachment),
@ -70,7 +70,7 @@ class AttachmentsController < ApplicationController
def thumbnail
if @attachment.thumbnailable? && tbnail = @attachment.thumbnail(:size => params[:size])
if stale?(:etag => tbnail)
if stale?(:etag => tbnail, :template => false)
send_file tbnail,
:filename => filename_for_content_disposition(@attachment.filename),
:type => detect_content_type(@attachment),

View file

@ -19,7 +19,7 @@ class AutoCompletesController < ApplicationController
before_action :find_project
def issues
@issues = []
issues = []
q = (params[:q] || params[:term]).to_s.strip
status = params[:status].to_s
issue_id = params[:issue_id].to_s
@ -32,13 +32,14 @@ class AutoCompletesController < ApplicationController
scope = scope.where.not(:id => issue_id.to_i)
end
if q.match(/\A#?(\d+)\z/)
@issues << scope.find_by_id($1.to_i)
issues << scope.find_by_id($1.to_i)
end
@issues += scope.like(q).order(:id => :desc).limit(10).to_a
@issues.compact!
issues += scope.like(q).order(:id => :desc).limit(10).to_a
issues.compact!
end
render :layout => false
render :json => format_issues_json(issues)
end
private
@ -50,4 +51,13 @@ class AutoCompletesController < ApplicationController
rescue ActiveRecord::RecordNotFound
render_404
end
def format_issues_json(issues)
issues.map {|issue| {
'id' => issue.id,
'label' => "#{issue.tracker} ##{issue.id}: #{issue.subject.to_s.truncate(60)}",
'value' => issue.id
}
}
end
end

View file

@ -91,8 +91,10 @@ class EnumerationsController < ApplicationController
def build_new_enumeration
class_name = params[:enumeration] && params[:enumeration][:type] || params[:type]
@enumeration = Enumeration.new_subclass_instance(class_name, enumeration_params)
if @enumeration.nil?
@enumeration = Enumeration.new_subclass_instance(class_name)
if @enumeration
@enumeration.attributes = enumeration_params || {}
else
render_404
end
end
@ -105,6 +107,7 @@ class EnumerationsController < ApplicationController
def enumeration_params
# can't require enumeration on #new action
params.permit(:enumeration => [:name, :active, :is_default, :position])[:enumeration]
cf_ids = @enumeration.available_custom_fields.map{|c| c.id.to_s}
params.permit(:enumeration => [:name, :active, :is_default, :position, :custom_field_values => cf_ids])[:enumeration]
end
end

View file

@ -40,7 +40,8 @@ class IssuesController < ApplicationController
helper :timelog
def index
retrieve_query
use_session = !request.format.csv?
retrieve_query(IssueQuery, use_session)
if @query.valid?
respond_to do |format|
@ -367,7 +368,12 @@ class IssuesController < ApplicationController
when 'destroy'
# nothing to do
when 'nullify'
if Setting.timelog_required_fields.include?('issue_id')
flash.now[:error] = l(:field_issue) + " " + ::I18n.t('activerecord.errors.messages.blank')
return
else
time_entries.update_all(:issue_id => nil)
end
when 'reassign'
reassign_to = @project && @project.issues.find_by_id(params[:reassign_to_id])
if reassign_to.nil?

View file

@ -37,7 +37,7 @@ class SearchController < ApplicationController
end
# quick jump to an issue
if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i))
if !api_request? && (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i))
redirect_to issue_path(issue)
return
end
@ -49,7 +49,7 @@ class SearchController < ApplicationController
when 'my_projects'
User.current.projects
when 'subprojects'
@project ? (@project.self_and_descendants.active.to_a) : nil
@project ? (@project.self_and_descendants.to_a) : nil
else
@project
end

View file

@ -114,6 +114,7 @@ class TimelogController < ApplicationController
:time_entry => {
:project_id => params[:time_entry][:project_id],
:issue_id => @time_entry.issue_id,
:spent_on => @time_entry.spent_on,
:activity_id => @time_entry.activity_id
},
:back_url => params[:back_url]

View file

@ -106,6 +106,6 @@ class TrackersController < ApplicationController
return
end
@trackers = Tracker.sorted.to_a
@custom_fields = IssueCustomField.all.sort
@custom_fields = IssueCustomField.sorted
end
end

View file

@ -32,7 +32,7 @@
class WikiController < ApplicationController
default_search_scope :wiki_pages
before_action :find_wiki, :authorize
before_action :find_existing_or_new_page, :only => [:show, :edit, :update]
before_action :find_existing_or_new_page, :only => [:show, :edit]
before_action :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version]
before_action :find_attachments, :only => [:preview]
accept_api_auth :index, :show, :update, :destroy
@ -42,8 +42,6 @@ class WikiController < ApplicationController
helper :watchers
include Redmine::Export::PDF
include ActionView::Helpers::SanitizeHelper
# List of pages, sorted alphabetically and by parent (hierarchy)
def index
load_pages_for_index
@ -109,7 +107,7 @@ class WikiController < ApplicationController
send_data(export, :type => 'text/html', :filename => filename_for_content_disposition("#{@page.title}.html"))
return
elsif params[:format] == 'txt'
send_data(strip_tags(@content.text), :type => 'text/plain', :filename => filename_for_content_disposition("#{@page.title}.txt"))
send_data(@content.text, :type => 'text/plain', :filename => filename_for_content_disposition("#{@page.title}.txt"))
return
end
end
@ -152,6 +150,8 @@ class WikiController < ApplicationController
# Creates a new page or updates an existing one
def update
@page = @wiki.find_or_new_page(params[:id])
return render_403 unless editable?
was_new_page = @page.new_record?
@page.safe_attributes = params[:wiki_page]

View file

@ -1272,7 +1272,7 @@ module ApplicationHelper
link_to_function '',
"toggleCheckboxesBySelector('#{selector}')",
:title => "#{l(:button_check_all)} / #{l(:button_uncheck_all)}",
:class => 'toggle-checkboxes'
:class => 'icon icon-checked'
end
def progress_bar(pcts, options={})
@ -1423,10 +1423,13 @@ module ApplicationHelper
end
if email.present?
gravatar(email.to_s.downcase, options) rescue nil
else
elsif user.is_a?(AnonymousUser)
options[:size] &&= options[:size].to_s
image_tag 'anonymous.png',
GravatarHelper::DEFAULT_OPTIONS
.except(:default, :rating, :ssl).merge(options)
else
nil
end
else
''

View file

@ -127,8 +127,8 @@ module IssuesHelper
content_tag('td', check_box_tag("ids[]", other_issue.id, false, :id => nil), :class => 'checkbox') +
content_tag('td', relation.to_s(@issue) {|other| link_to_issue(other, :project => Setting.cross_project_issue_relations?)}.html_safe, :class => 'subject', :style => 'width: 50%') +
content_tag('td', other_issue.status, :class => 'status') +
content_tag('td', other_issue.start_date, :class => 'start_date') +
content_tag('td', other_issue.due_date, :class => 'due_date') +
content_tag('td', format_date(other_issue.start_date), :class => 'start_date') +
content_tag('td', format_date(other_issue.due_date), :class => 'due_date') +
content_tag('td', other_issue.disabled_core_fields.include?('done_ratio') ? '' : progress_bar(other_issue.done_ratio), :class=> 'done_ratio') +
content_tag('td', link, :class => 'buttons'),
:id => "relation-#{relation.id}",
@ -246,8 +246,12 @@ module IssuesHelper
issue_fields_rows do |rows|
values.each_with_index do |value, i|
css = "cf_#{value.custom_field.id}"
attr_value = show_value(value)
if value.custom_field.text_formatting == 'full'
attr_value = content_tag('div', attr_value, class: 'wiki')
end
m = (i < half ? :left : :right)
rows.send m, custom_field_name_tag(value.custom_field), show_value(value), :class => css
rows.send m, custom_field_name_tag(value.custom_field), attr_value, :class => css
end
end
end
@ -310,7 +314,7 @@ module IssuesHelper
# Returns an array of users that are proposed as watchers
# on the new issue form
def users_for_new_issue_watchers(issue)
users = issue.watcher_users
users = issue.watcher_users.select{|u| u.status == User::STATUS_ACTIVE}
if issue.project.users.count <= 20
users = (users + issue.project.users.sort).uniq
end

View file

@ -18,14 +18,11 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module SearchHelper
include ActionView::Helpers::SanitizeHelper
def highlight_tokens(text, tokens)
return text unless text && tokens && !tokens.empty?
re_tokens = tokens.collect {|t| Regexp.escape(t)}
regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE
result = ''
text = strip_tags(text)
text.split(regexp).each_with_index do |words, i|
if result.length > 1200
# maximum length of the preview reached

View file

@ -156,7 +156,7 @@ class Attachment < ActiveRecord::Base
end
def title
title = filename.to_s
title = filename.dup
if description.present?
title << " (#{description})"
end

View file

@ -217,6 +217,7 @@ class Import < ActiveRecord::Base
csv_options = {:headers => false}
csv_options[:encoding] = settings['encoding'].to_s.presence || 'UTF-8'
csv_options[:encoding] = 'bom|UTF-8' if csv_options[:encoding] == 'UTF-8'
separator = settings['separator'].to_s
csv_options[:col_sep] = separator if separator.size == 1
wrapper = settings['wrapper'].to_s

View file

@ -275,7 +275,8 @@ class Issue < ActiveRecord::Base
end
end
unless options[:watchers] == false
self.watcher_user_ids = issue.watcher_user_ids.dup
self.watcher_user_ids =
issue.watcher_users.select{|u| u.status == User::STATUS_ACTIVE}.map(&:id)
end
@copied_from = issue
@copy_options = options
@ -1086,7 +1087,7 @@ class Issue < ActiveRecord::Base
if leaf?
estimated_hours
else
@total_estimated_hours ||= self_and_descendants.sum(:estimated_hours)
@total_estimated_hours ||= self_and_descendants.visible.sum(:estimated_hours)
end
end
@ -1300,7 +1301,7 @@ class Issue < ActiveRecord::Base
# Reschedules the issue on the given date or the next working day and saves the record.
# If the issue is a parent task, this is done by rescheduling its subtasks.
def reschedule_on!(date)
def reschedule_on!(date, journal=nil)
return if date.nil?
if leaf? || !dates_derived?
if start_date.nil? || start_date != date
@ -1308,6 +1309,9 @@ class Issue < ActiveRecord::Base
# Issue can not be moved earlier than its soonest start date
date = [soonest_start(true), date].compact.max
end
if journal
init_journal(journal.user)
end
reschedule_on(date)
begin
save
@ -1631,6 +1635,8 @@ class Issue < ActiveRecord::Base
copy.author = author
copy.project = project
copy.parent_issue_id = copied_issue_ids[child.parent_id]
copy.fixed_version_id = nil unless child.fixed_version.present? && child.fixed_version.status == 'open'
copy.assigned_to = nil unless child.assigned_to_id.present? && child.assigned_to.status == User::STATUS_ACTIVE
unless copy.save
logger.error "Could not copy subtask ##{child.id} while copying ##{@copied_from.id} to ##{id} due to validation errors: #{copy.errors.full_messages.join(', ')}" if logger
next
@ -1789,7 +1795,7 @@ class Issue < ActiveRecord::Base
def reschedule_following_issues
if start_date_changed? || due_date_changed?
relations_from.each do |relation|
relation.set_issue_to_dates
relation.set_issue_to_dates(@current_journal)
end
end
end

View file

@ -122,7 +122,10 @@ class IssueImport < Import
end
end
if issue.project && version_name = row_value(row, 'fixed_version')
if version = issue.project.versions.named(version_name).first
version =
issue.project.versions.named(version_name).first ||
issue.project.shared_versions.named(version_name).first
if version
attributes['fixed_version_id'] = version.id
elsif create_versions?
version = issue.project.versions.build

View file

@ -37,8 +37,8 @@ class IssueQuery < Query
QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours", :totalable => true),
QueryColumn.new(:total_estimated_hours,
:sortable => "COALESCE((SELECT SUM(estimated_hours) FROM #{Issue.table_name} subtasks" +
" WHERE subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)",
:sortable => -> { "COALESCE((SELECT SUM(estimated_hours) FROM #{Issue.table_name} subtasks" +
" WHERE #{Issue.visible_condition(User.current).gsub(/\bissues\b/, 'subtasks')} AND subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)" },
:default_order => 'desc'),
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'),
@ -221,6 +221,7 @@ class IssueQuery < Query
end
disabled_fields = Tracker.disabled_core_fields(trackers).map {|field| field.sub(/_id$/, '')}
disabled_fields << "total_estimated_hours" if disabled_fields.include?("estimated_hours")
@available_columns.reject! {|column|
disabled_fields.include?(column.name.to_s)
}
@ -373,7 +374,7 @@ class IssueQuery < Query
neg = (operator == '!' ? 'NOT' : '')
subquery = "SELECT 1 FROM #{Journal.table_name} sj" +
" WHERE sj.journalized_type='Issue' AND sj.journalized_id=#{Issue.table_name}.id AND (#{sql_for_field field, '=', value, 'sj', 'user_id'})" +
" AND sj.id = (SELECT MAX(#{Journal.table_name}.id) FROM #{Journal.table_name}" +
" AND sj.id IN (SELECT MAX(#{Journal.table_name}.id) FROM #{Journal.table_name}" +
" WHERE #{Journal.table_name}.journalized_type='Issue' AND #{Journal.table_name}.journalized_id=#{Issue.table_name}.id" +
" AND (#{Journal.visible_notes_condition(User.current, :skip_pre_condition => true)}))"
@ -382,8 +383,26 @@ class IssueQuery < Query
def sql_for_watcher_id_field(field, operator, value)
db_table = Watcher.table_name
"#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " +
sql_for_field(field, '=', value, db_table, 'user_id') + ')'
me, others = value.partition { |id| ['0', User.current.id.to_s].include?(id) }
sql = if others.any?
"SELECT #{Issue.table_name}.id FROM #{Issue.table_name} " +
"INNER JOIN #{db_table} ON #{Issue.table_name}.id = #{db_table}.watchable_id AND #{db_table}.watchable_type = 'Issue' " +
"LEFT OUTER JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Issue.table_name}.project_id " +
"WHERE (" +
sql_for_field(field, '=', me, db_table, 'user_id') +
') OR (' +
Project.allowed_to_condition(User.current, :view_issue_watchers) +
' AND ' +
sql_for_field(field, '=', others, db_table, 'user_id') +
')'
else
"SELECT #{db_table}.watchable_id FROM #{db_table} " +
"WHERE #{db_table}.watchable_type='Issue' AND " +
sql_for_field(field, '=', me, db_table, 'user_id')
end
"#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (#{sql})"
end
def sql_for_member_of_group_field(field, operator, value)

View file

@ -176,10 +176,10 @@ class IssueRelation < ActiveRecord::Base
set_issue_to_dates
end
def set_issue_to_dates
def set_issue_to_dates(journal=nil)
soonest_start = self.successor_soonest_start
if soonest_start && issue_to
issue_to.reschedule_on!(soonest_start)
issue_to.reschedule_on!(soonest_start, journal)
end
end

View file

@ -54,7 +54,7 @@ class MailHandler < ActionMailer::Base
def self.safe_receive(*args)
receive(*args)
rescue Exception => e
logger.error "MailHandler: an unexpected error occurred when receiving email: #{e.message}" if logger
Rails.logger.error "MailHandler: an unexpected error occurred when receiving email: #{e.message}"
return false
end
@ -65,7 +65,7 @@ class MailHandler < ActionMailer::Base
%w(project status tracker category priority assigned_to fixed_version).each do |option|
options[:issue][option.to_sym] = env[option] if env[option]
end
%w(allow_override unknown_user no_permission_check no_account_notice default_group project_from_subaddress).each do |option|
%w(allow_override unknown_user no_permission_check no_account_notice no_notification default_group project_from_subaddress).each do |option|
options[option.to_sym] = env[option] if env[option]
end
if env['private']
@ -250,8 +250,8 @@ class MailHandler < ActionMailer::Base
# add To and Cc as watchers before saving so the watchers can reply to Redmine
add_watchers(issue)
add_attachments(issue)
issue.save!
add_attachments(issue)
if logger
logger.info "MailHandler: issue ##{issue.id} updated by #{user}"
end
@ -286,7 +286,7 @@ class MailHandler < ActionMailer::Base
reply
else
if logger
logger.info "MailHandler: ignoring reply from [#{sender_email}] to a locked topic"
logger.info "MailHandler: ignoring reply from [#{email.from.first}] to a locked topic"
end
end
end

View file

@ -311,7 +311,7 @@ class Mailer < ActionMailer::Base
end
# Notifies user that his password was updated
def self.password_updated(user)
def self.password_updated(user, options={})
# Don't send a notification to the dummy email address when changing the password
# of the default admin account which is required after the first login
# TODO: maybe not the best way to handle this
@ -320,6 +320,8 @@ class Mailer < ActionMailer::Base
security_notification(user,
message: :mail_body_password_updated,
title: :button_change_password,
remote_ip: options[:remote_ip],
originator: user,
url: {controller: 'my', action: 'password'}
).deliver
end
@ -333,7 +335,6 @@ class Mailer < ActionMailer::Base
end
def security_notification(recipients, options={})
redmine_headers 'Sender' => User.current.login
@user = Array(recipients).detect{|r| r.is_a? User }
set_language_if_valid(@user.try :language)
@message = l(options[:message],
@ -341,7 +342,11 @@ class Mailer < ActionMailer::Base
value: options[:value]
)
@title = options[:title] && l(options[:title])
@originator = options[:originator] || User.current
@remote_ip = options[:remote_ip] || @originator.remote_ip
@url = options[:url] && (options[:url].is_a?(Hash) ? url_for(options[:url]) : options[:url])
redmine_headers 'Sender' => @originator.login
redmine_headers 'Url' => @url
mail :to => recipients,
:subject => "[#{Setting.app_title}] #{l(:mail_subject_security_notification)}"
end

View file

@ -319,9 +319,10 @@ class Query < ActiveRecord::Base
" INNER JOIN #{table_name_prefix}queries_roles#{table_name_suffix} qr on qr.query_id = q.id" +
" INNER JOIN #{MemberRole.table_name} mr ON mr.role_id = qr.role_id" +
" INNER JOIN #{Member.table_name} m ON m.id = mr.member_id AND m.user_id = ?" +
" INNER JOIN #{Project.table_name} p ON p.id = m.project_id AND p.status <> ?" +
" WHERE q.project_id IS NULL OR q.project_id = m.project_id))" +
" OR #{table_name}.user_id = ?",
VISIBILITY_PUBLIC, VISIBILITY_ROLES, user.id, user.id)
VISIBILITY_PUBLIC, VISIBILITY_ROLES, user.id, Project::STATUS_ARCHIVED, user.id)
elsif user.logged?
scope.where("#{table_name}.visibility = ? OR #{table_name}.user_id = ?", VISIBILITY_PUBLIC, user.id)
else
@ -340,7 +341,7 @@ class Query < ActiveRecord::Base
if project
(user.roles_for_project(project) & roles).any?
else
Member.where(:user_id => user.id).joins(:roles).where(:member_roles => {:role_id => roles.map(&:id)}).any?
user.memberships.joins(:member_roles).where(:member_roles => {:role_id => roles.map(&:id)}).any?
end
else
user == self.user
@ -398,6 +399,8 @@ class Query < ActiveRecord::Base
params[:v][field] = options[:values]
end
params[:c] = column_names
params[:group_by] = group_by.to_s if group_by.present?
params[:t] = totalable_names.map(&:to_s) if totalable_names.any?
params[:sort] = sort_criteria.to_param
params[:set_filter] = 1
params

View file

@ -45,7 +45,7 @@ class Version < ActiveRecord::Base
scope :like, lambda {|arg|
if arg.present?
pattern = "%#{arg.to_s.strip}%"
where("LOWER(#{Version.table_name}.name) LIKE :p", :p => pattern)
where([Redmine::Database.like("#{Version.table_name}.name", '?'), pattern])
end
}
scope :open, lambda { where(:status => 'open') }
@ -268,7 +268,7 @@ class Version < ActiveRecord::Base
end
def deletable?
fixed_issues.empty? && !referenced_by_a_custom_field?
fixed_issues.empty? && !referenced_by_a_custom_field? && attachments.empty?
end
def default_project_version

View file

@ -1,7 +1,6 @@
<%= call_hook :view_account_login_top %>
<div id="login-form">
<h2><%= l(:label_login) %></h2>
<%= form_tag(signin_path, onsubmit: 'return keepAnchorOnSignIn(this);') do %>
<%= back_url_hidden_field_tag %>

View file

@ -11,7 +11,7 @@
<% end %>
</table>
<br />
<div class="box">
<div class="box autoscroll">
<pre><%= Redmine::Info.environment %></pre>
</div>

View file

@ -1,7 +1,8 @@
<%= title l(:label_plugins) %>
<% if @plugins.any? %>
<table class="list plugins">
<div class="autoscroll">
<table class="list plugins">
<% @plugins.each do |plugin| %>
<tr id="plugin-<%= plugin.id %>">
<td class="name"><span class="name"><%= plugin.name %></span>
@ -13,7 +14,8 @@
<td class="configure"><%= link_to(l(:button_configure), plugin_settings_path(plugin)) if plugin.configurable? %></td>
</tr>
<% end %>
</table>
</table>
</div>
<p><a href="#" id="check-for-updates"><%= l(:label_check_for_updates) %></a></p>
<% else %>
<p class="nodata"><%= l(:label_no_data) %></p>
@ -27,7 +29,7 @@ $(document).ready(function(){
dataType: "jsonp",
url: "https://www.redmine.org/plugins/check_updates",
data: <%= raw_json plugin_data_for_updates(@plugins) %>,
timeout: 3000,
timeout: 10000,
beforeSend: function(){
$('#ajax-indicator').show();
},

View file

@ -39,7 +39,7 @@
<ul>
<% @priorities.each do |p| -%>
<li><%= context_menu_link p.name, bulk_update_issues_path(:ids => @issue_ids, :issue => {'priority_id' => p}, :back_url => @back), :method => :post,
:selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit]) %></li>
:selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.any?(&:priority_derived?)) %></li>
<% end -%>
</ul>
</li>
@ -97,7 +97,7 @@
<ul>
<% (0..10).map{|x|x*10}.each do |p| -%>
<li><%= context_menu_link "#{p}%", bulk_update_issues_path(:ids => @issue_ids, :issue => {'done_ratio' => p}, :back_url => @back), :method => :post,
:selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
:selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.any?(&:done_ratio_derived?)) %></li>
<% end -%>
</ul>
</li>

View file

@ -6,7 +6,8 @@
<% delete_allowed = User.current.allowed_to?(:manage_files, @project) %>
<table class="list files">
<div class="autoscroll">
<table class="list files">
<thead><tr>
<%= sort_header_tag('filename', :caption => l(:field_filename)) %>
<%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
@ -16,7 +17,7 @@
<th></th>
</tr></thead>
<tbody>
<% @containers.each do |container| %>
<% @containers.each do |container| %>
<% next if container.attachments.empty? -%>
<% if container.is_a?(Version) -%>
<tr>
@ -39,8 +40,9 @@
</td>
</tr>
<% end %>
<% end %>
<% end %>
</tbody>
</table>
</table>
</div>
<% html_title(l(:label_attachment_plural)) -%>

View file

@ -2,6 +2,6 @@ $('#relations').html('<%= escape_javascript(render :partial => 'issues/relations
<% if @relation.errors.empty? %>
$('#relation_delay').val('');
$('#relation_issue_to_id').val('');
$('#relation_issue_to_id').focus();
<% end %>
$('#new-relation-form').show();
$('#relation_issue_to_id').focus();

View file

@ -13,6 +13,8 @@
<% end %>
<br />
<span class="author"><%= authoring(changeset.committed_on, changeset.author) %></span></p>
<div class="wiki changeset-comments"><%= format_changeset_comments changeset %></div>
<div class="wiki changeset-comments">
<%= format_changeset_comments changeset %>
</div>
</div>
<% end %>

View file

@ -6,7 +6,9 @@
<p><strong><%= l(:text_destroy_time_entries_question, :hours => number_with_precision(@hours, :precision => 2)) %></strong></p>
<p>
<label><%= radio_button_tag 'todo', 'destroy', true %> <%= l(:text_destroy_time_entries) %></label><br />
<% unless Setting.timelog_required_fields.include?('issue_id') %>
<label><%= radio_button_tag 'todo', 'nullify', false %> <%= l(:text_assign_time_entries_to_project) %></label><br />
<% end %>
<% if @project %>
<label><%= radio_button_tag 'todo', 'reassign', false, :onchange => 'if (this.checked) { $("#reassign_to_id").focus(); }' %> <%= l(:text_reassign_time_entries) %></label>
<%= text_field_tag 'reassign_to_id', params[:reassign_to_id], :size => 6, :onfocus => '$("#todo_reassign").attr("checked", true);' %>

View file

@ -2,31 +2,28 @@
<html lang="<%= current_language %>">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title><%= html_title %></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="description" content="<%= Redmine::Info.app_name %>" />
<meta name="keywords" content="issue,bug,tracker" />
<%= csrf_meta_tag %>
<%= favicon %>
<%= stylesheet_link_tag 'jquery/jquery-ui-1.11.0', 'cookieconsent.min', 'application', 'responsive', :media => 'all' %>
<%= stylesheet_link_tag 'jquery/jquery-ui-1.11.0', 'application', 'responsive', :media => 'all' %>
<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %>
<% is_welcome = !User.current.logged? && current_page?(:controller => 'welcome', :action => 'index') %>
<%= stylesheet_link_tag 'frontpage', :media => 'all' if is_welcome %>
<%= javascript_heads %>
<script src="/themes/circlepro/javascripts/cookieconsent.min.js"></script>
<%= heads_for_theme %>
<%= call_hook :view_layouts_base_html_head %>
<!-- page specific tags -->
<%= yield :header_tags -%>
</head>
<body class="<%= body_css_classes %><%= ' is-preload' if is_welcome %>">
<body class="<%= body_css_classes %>">
<%= call_hook :view_layouts_base_body_top %>
<div id="wrapper">
<div class="flyout-menu js-flyout-menu">
<% if User.current.logged? || !Setting.login_required? %>
<div class="flyout-menu__search">
<%= form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>
@ -64,58 +61,45 @@
<div id="wrapper2">
<div id="wrapper3">
<div id="top-menu">
<div id="wrapper-top-menu">
<ul class="social-menu">
<li class="social-link-blog"><a href="https://manuel.cillero.es" title="<%= l(:link_my_blog) %>" class="icon-blog"><span><%= l(:link_my_blog) %></span></a></li>
<li class="social-link-twitter"><a href="https://twitter.com/manuelcillero" title="Twitter" target="_blank" class="icon-twitter"><span>Twitter</span></a></li>
<li class="social-link-facebook"><a href="https://facebook.com/manuelcillero" title="Facebook" target="_blank" class="icon-facebook"><span>Facebook</span></a></li>
<li class="social-link-linkedin"><a href="https://es.linkedin.com/in/manuelcillero" title="Linkedin" target="_blank" class="icon-linkedin"><span>Linkedin</span></a></li>
<li class="social-link-gitlab"><a href="https://gitlab.com/manuelcillero" title="Gitlab" target="_blank" class="icon-gitlab"><span>Gitlab</span></a></li>
<li class="social-link-mail"><a href="https://manuel.cillero.es/contacto/#suitepro" title="Mail" class="icon-mail"><span>Mail</span></a></li>
</ul>
<div id="account">
<%= render_menu :account_menu -%>
</div>
<%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %>
<%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%>
</div>
</div>
<div id="header">
<a href="#" class="mobile-toggle-button js-flyout-menu-toggle-button"></a>
<div id="wrapper-header">
<% if User.current.logged? || !Setting.login_required? %>
<div id="quick-search" class="hide-when-print">
<div id="quick-search">
<%= form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>
<%= hidden_field_tag 'scope', default_search_project_scope, :id => nil %>
<%= hidden_field_tag(controller.default_search_scope, 1, :id => nil) if controller.default_search_scope %>
<label for='q'>
<%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project}, :accesskey => accesskey(:search) %>:
<%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project, :scope => default_search_project_scope}, :accesskey => accesskey(:search) %>:
</label>
<%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search) %>
<% end %>
<%= render_project_jump_box %>
</div>
<% end %>
<h1><%= page_header_title %></h1>
</div>
<% if display_main_menu?(@project) %>
<div id="main-menu" class="tabs">
<div id="wrapper-main-menu">
<%= render_main_menu(@project) %>
<div class="tabs-buttons" style="display:none;">
<button class="tab-left" onclick="moveTabLeft(this); return false;"></button>
<button class="tab-right" onclick="moveTabRight(this); return false;"></button>
</div>
</div>
</div>
<% end %>
</div>
<div id="main" class="<%= sidebar_content? ? '' : 'nosidebar' %>">
<div id="wrapper-main">
<div id="sidebar">
<%= yield :sidebar %>
<%= view_layouts_base_sidebar_hook_response %>
@ -127,51 +111,19 @@
<%= call_hook :view_layouts_base_content %>
<div style="clear:both;"></div>
</div>
</div>
</div>
</div>
<a href="#" id="scrollup" class="hide-when-print"><%=l(:label_sort_higher)%></a><%= javascript_tag "$('#scrollup').click(function(){$('html,body').animate({scrollTop:0},600);return false;});" %>
<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>
<div id="ajax-modal" style="display:none;"></div>
<div id="footer">
<div id="wrapper-footer">
<ul class="social-menu">
<li class="social-link-blog"><a href="https://manuel.cillero.es" title="<%= l(:link_my_blog) %>" class="icon-blog"><span><%= l(:link_my_blog) %></span></a></li>
<li class="social-link-twitter"><a href="https://twitter.com/manuelcillero" title="Twitter" target="_blank" class="icon-twitter"><span>Twitter</span></a></li>
<li class="social-link-facebook"><a href="https://facebook.com/manuelcillero" title="Facebook" target="_blank" class="icon-facebook"><span>Facebook</span></a></li>
<li class="social-link-linkedin"><a href="https://es.linkedin.com/in/manuelcillero" title="Linkedin" target="_blank" class="icon-linkedin"><span>Linkedin</span></a></li>
<li class="social-link-gitlab"><a href="https://gitlab.com/manuelcillero" title="Gitlab" target="_blank" class="icon-gitlab"><span>Gitlab</span></a></li>
<li class="social-link-mail"><a href="https://manuel.cillero.es/contacto/#suitepro" title="Mail" class="icon-mail"><span>Mail</span></a></li>
</ul>
<div class="bgl"><div class="bgr">
<div id="legal">
<span class="legal-legal"><a href="/projects/suitepro/wiki/Legal"><%= l(:label_legal) %></a></span>
<span class="legal-terms"> &nbsp;|&nbsp; <a href="/projects/suitepro/wiki/Condiciones_de_uso"><%= l(:label_legal_terms) %></a></span>
<span class="legal-privacy"> &nbsp;|&nbsp; <a href="/projects/suitepro/wiki/Política_de_privacidad"><%= l(:label_legal_privacy) %></a></span>
<span class="legal-cookies"> &nbsp;|&nbsp; <a href="/projects/suitepro/wiki/Política_de_cookies"><%= l(:label_legal_cookies) %></a></span>
</div>
<%= Time.current.year %> &copy; SuitePro (powered by <%= link_to Redmine::Info.app_name, Redmine::Info.url %>)
Powered by <%= link_to Redmine::Info.app_name, Redmine::Info.url %> &copy; 2006-2019 Jean-Philippe Lang
</div></div>
</div>
</div>
</div>
</div>
<%= call_hook :view_layouts_base_body_bottom %>
<script>
//<![CDATA[
window.addEventListener("load", function(){
window.cookieconsent.initialise({
"palette": { "popup": { "background": "rgba(20,20,20,0.8)" }, "button": { "background": "#fff" } },
"theme": "classic",
"position": "bottom-left",
"content": { "message": "<a href='https://suitepro.cillero.es'>SuitePro</a> requiere el uso de cookies para ofrecer la mejor experiencia de acceso a sus contenidos. Puedes aceptar su uso o abandonar la página si lo deseas.", "dismiss": "ACEPTO SU USO", "link": "Más información", "href": "/projects/suitepro/wiki/Pol%C3%ADtica_de_cookies", "target": "_self" }
})});
//]]>
</script>
</body>
</html>

View file

@ -7,7 +7,7 @@
<%= content_tag :h1, @title -%>
<% end %></p>
<p><%= l(:field_user) %>: <strong><%= User.current.login %></strong><br/>
<%= l(:field_remote_ip) %>: <strong><%= User.current.remote_ip %></strong><br/>
<p><%= l(:field_user) %>: <strong><%= @originator.login %></strong><br/>
<%= l(:field_remote_ip) %>: <strong><%= @remote_ip %></strong><br/>
<%= l(:label_date) %>: <strong><%= format_time Time.now, true, @user %></strong></p>

View file

@ -2,7 +2,7 @@
<%= @url || @title %>
<%= l(:field_user) %>: <%= User.current.login %>
<%= l(:field_remote_ip) %>: <%= User.current.remote_ip %>
<%= l(:field_user) %>: <%= @originator.login %>
<%= l(:field_remote_ip) %>: <%= @remote_ip %>
<%= l(:label_date) %>: <%= format_time Time.now, true, @user %>

View file

@ -7,7 +7,7 @@
</div>
</fieldset>
<fieldset class="box">
<legend><%= l(:label_role_plural) %> <%= toggle_checkboxes_link('.roles-selection input') %></legend>
<legend><%= toggle_checkboxes_link('.roles-selection input') %><%= l(:label_role_plural) %></legend>
<div class="roles-selection">
<% User.current.managed_roles(@project).each do |role| %>
<label><%= check_box_tag 'membership[role_ids][]', role.id, false, :id => nil %> <%= role %></label>

View file

@ -1,5 +1,5 @@
<fieldset class="box">
<legend><%= l(:label_project_plural) %> <%= toggle_checkboxes_link('.projects-selection input:enabled') %></legend>
<legend><%= toggle_checkboxes_link('.projects-selection input:enabled') %><%= l(:label_project_plural) %></legend>
<div class="objects-selection">
<div class="projects-selection">
<%= render_project_nested_lists(@projects) do |p| %>
@ -12,7 +12,7 @@
</fieldset>
<fieldset class="box">
<legend><%= l(:label_role_plural) %> <%= toggle_checkboxes_link('.roles-selection input') %></legend>
<legend><%= toggle_checkboxes_link('.roles-selection input') %><%= l(:label_role_plural) %></legend>
<div class="roles-selection">
<% @roles.each do |role| %>
<label>

View file

@ -3,7 +3,8 @@
<% end %>
<% if @project.repositories.any? %>
<table class="list">
<div class="autoscroll">
<table class="list">
<thead>
<tr>
<th><%= l(:field_identifier) %></th>
@ -35,7 +36,8 @@
</tr>
<% end %>
</tbody>
</table>
</table>
</div>
<% else %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% end %>

View file

@ -33,7 +33,9 @@
</div>
<div class="wiki changeset-comments"><%= format_changeset_comments @changeset %></div>
<div class="wiki changeset-comments">
<%= format_changeset_comments @changeset %>
</div>
<% if @changeset.issues.visible.any? || User.current.allowed_to?(:manage_related_issues, @repository.project) %>
<%= render :partial => 'related_issues' %>

View file

@ -21,10 +21,11 @@
</p>
<%= hidden_field_tag 'tracker[core_fields][]', '' %>
<% if IssueCustomField.all.any? %>
<% @issue_custom_fields = IssueCustomField.sorted %>
<% if @issue_custom_fields.present? %>
<p>
<label><%= l(:label_custom_field_plural) %></label>
<% IssueCustomField.all.each do |field| %>
<% @issue_custom_fields.each do |field| %>
<label class="block">
<%= check_box_tag 'tracker[custom_field_ids][]',field.id, @tracker.custom_fields.to_a.include?(field), :id => nil %>
<%= field.name %>

View file

@ -1,5 +1,3 @@
<% if User.current.logged? %>
<h2><%= l(:label_home) %></h2>
<div class="splitcontentleft">
@ -26,149 +24,3 @@
<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :key => User.current.rss_key, :format => 'atom'},
:title => "#{Setting.app_title}: #{l(:label_activity)}") %>
<% end %>
<% else %><!-- Frontpage -->
<div id="fp"><%= text_field_tag 'forcetop', nil, :style => 'display: none;' %>
<!-- Banner -->
<section id="fp-banner">
<div class="inner">
<h2>SuitePro</h2>
<p><%= l(:welcome_suitepro) %></p>
<ul class="actions special">
<li><a href="#fp-login" class="button primary scrolly"><%= l(:label_login) %></a></li>
</ul>
</div>
<a href="#one" class="more scrolly"><%= l(:welcome_discover) %></a>
</section>
<!-- One -->
<section id="one" class="frapper style1 special">
<div class="inner">
<header class="major">
<h2>A SIMPLE WAY TO GET WORK DONE&nbsp;&nbsp;;)</h2>
<p><%= raw l(:welcome_suitepro_is_redmine, :suitepro => '<strong>SuitePro</strong>', :redmine => '<a href="https://www.redmine.org"><strong>Redmine</strong></a>') %></p>
</header>
<ul class="icons major">
<li><span class="fp-icon fp-icon_1 major style1"><span class="label">Lorem</span></span></li>
<li><span class="fp-icon fp-icon_2 major style2"><span class="label">Ipsum</span></span></li>
<li><span class="fp-icon fp-icon_3 major style3"><span class="label">Dolor</span></span></li>
</ul>
</div>
</section>
<!-- Two -->
<section id="two" class="frapper alt style2">
<section class="spotlight">
<div class="image"><%= image_tag '/themes/circlepro/images/pic01.jpg' %></div><div class="content">
<h2><%= raw l(:welcome_spotlight_1_title) %></h2>
<p><%= l(:welcome_spotlight_1_text) %></p>
</div>
</section>
<section class="spotlight">
<div class="image"><%= image_tag '/themes/circlepro/images/pic02.jpg' %></div><div class="content">
<h2><%= raw l(:welcome_spotlight_2_title) %></h2>
<p><%= l(:welcome_spotlight_2_text) %></p>
</div>
</section>
<section class="spotlight">
<div class="image"><%= image_tag '/themes/circlepro/images/pic03.jpg' %></div><div class="content">
<h2><%= raw l(:welcome_spotlight_3_title) %></h2>
<p><%= l(:welcome_spotlight_3_text) %></p>
</div>
</section>
</section>
<!-- Three -->
<section id="three" class="frapper style3 special">
<div class="inner">
<header class="major">
<h2><%= l(:welcome_other_features) %></h2>
</header>
<ul class="features">
<li class="fp-icon fp-icon_4">
<h3><%= l(:welcome_feature_1_title) %></h3>
<p><%= l(:welcome_feature_1_text) %></p>
</li>
<li class="fp-icon fp-icon_5">
<h3><%= l(:welcome_feature_2_title) %></h3>
<p><%= l(:welcome_feature_2_text) %></p>
</li>
<li class="fp-icon fp-icon_6">
<h3><%= l(:welcome_feature_3_title) %></h3>
<p><%= l(:welcome_feature_3_text) %></p>
</li>
<li class="fp-icon fp-icon_7">
<h3><%= l(:welcome_feature_4_title) %></h3>
<p><%= l(:welcome_feature_4_text) %></p>
</li>
<li class="fp-icon fp-icon_8">
<h3><%= l(:welcome_feature_5_title) %></h3>
<p><%= l(:welcome_feature_5_text) %></p>
</li>
<li class="fp-icon fp-icon_9">
<h3><%= l(:welcome_feature_6_title) %></h3>
<p><%= l(:welcome_feature_6_text) %></p>
</li>
</ul>
</div>
</section>
<!-- Login -->
<section id="fp-login" class="frapper style4">
<div class="inner">
<%= call_hook :view_account_login_top %>
<div id="login-form">
<h2><%= l(:label_login) %></h2>
<%= form_tag(signin_path, onsubmit: 'return keepAnchorOnSignIn(this);') do %>
<%= back_url_hidden_field_tag %>
<label for="username"><%=l(:field_login)%></label>
<%= text_field_tag 'username', params[:username], :tabindex => '1' %>
<label for="password">
<%=l(:field_password)%>
<%= link_to l(:label_password_lost), lost_password_path, :class => "lost_password" if Setting.lost_password? %>
</label>
<%= password_field_tag 'password', nil, :tabindex => '2' %>
<% if Setting.openid? %>
<label for="openid_url"><%=l(:field_identity_url)%></label>
<%= text_field_tag "openid_url", nil, :tabindex => '3' %>
<% end %>
<% if Setting.autologin? %>
<label for="autologin"><%= check_box_tag 'autologin', 1, false, :tabindex => 4 %> <%= l(:label_stay_logged_in) %></label>
<% end %>
<input type="submit" name="login" value="<%=l(:button_login)%>" tabindex="5" id="login-submit" />
<% end %>
</div>
</div>
</section>
<!-- CTA -->
<section id="fp-cta" class="frapper style4">
<div class="inner">
<header>
<h2><%= l(:welcome_any_questions) %></h2>
<p><%= l(:welcome_please_contact) %></p>
</header>
<ul class="actions stacked">
<li><a href="https://manuel.cillero.es/contacto/#suitepro" class="button fit primary"><%= l(:welcome_contact) %></a></li>
<li><a href="https://manuel.cillero.es/sobre-mi" class="button fit"><%= l(:welcome_about_me) %></a></li>
</ul>
</div>
</section>
</div>
<script src="/themes/circlepro/javascripts/frontpage/jquery.scrolly.min.js"></script>
<script src="/themes/circlepro/javascripts/frontpage/browser.min.js"></script>
<script src="/themes/circlepro/javascripts/frontpage/breakpoints.min.js"></script>
<script src="/themes/circlepro/javascripts/frontpage/util.js"></script>
<script src="/themes/circlepro/javascripts/frontpage/main.js"></script>
<% end %>

View file

@ -46,8 +46,7 @@
<%= render(:partial => "wiki/content", :locals => {:content => @content}) %>
<% if @page.attachments.length > 0 || (@editable && authorize_for('wiki', 'add_attachment')) %>
<fieldset class="collapsible collapsed<% if @page.attachments.length == 0 %> hide-when-print<% end %>">
<fieldset class="collapsible collapsed hide-when-print">
<legend onclick="toggleFieldset(this);"><%= l(:label_attachment_plural) %> (<%= @page.attachments.length %>)</legend>
<div style="display: none;">
@ -67,7 +66,6 @@
<% end %>
</div>
</fieldset>
<% end %>
<% other_formats_links do |f| %>
<%= f.link_to 'PDF', :url => {:id => @page.title, :version => params[:version]} %>

View file

@ -1211,8 +1211,8 @@ de:
label_table_of_contents: Inhaltsverzeichnis
error_no_projects_with_tracker_allowed_for_new_issue: Es gibt keine Projekte mit Trackern, für welche sie Tickets erzeugen können
field_textarea_font: Schriftart für Textbereiche
label_font_default: Strandardschrift
label_font_monospace: Nichtproporzionale Schrift
label_font_default: Standardschrift
label_font_monospace: Nichtproportionale Schrift
label_font_proportional: Proportionale Schrift
setting_commit_logs_formatting: Textformatierung für Commit Nachrichten
setting_mail_handler_enable_regex_delimiters: Reguläre Ausdrücke erlauben

View file

@ -1209,40 +1209,3 @@ en:
description_issue_category_reassign: Choose issue category
description_wiki_subpages_reassign: Choose new parent page
text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.'
welcome_suitepro: Planning, knowledge sharing, clients support and personal productivity, with both powerful and simplicity in mind.
welcome_discover: Discover
welcome_suitepro_is_redmine: "%{suitepro} is powered by %{redmine}, the popular project management and issue tracking solution based on the Ruby on Rails framework. Redmine lets us have a powerful workflow for getting tasks done and keep information in one place."
welcome_spotlight_1_title: "The Basics: Projects,<br /> Tasks, Issue Tracking"
welcome_spotlight_1_text: Keep track of everything, with visual indicators to monitorize tasks and subtasks in order to stay up to date with milestones, track of time, workflows and all that requires attention.
welcome_spotlight_2_title: "Documents, Wikis,<br /> File Management"
welcome_spotlight_2_text: Keep documents and files availables wherever you are. Use the wiki project to save project requeriments, attached files, install and user guides, or meeting minutes at your fingertips.
welcome_spotlight_3_title: "Flexible control<br /> of user access"
welcome_spotlight_3_text: Using a role-based approach, roles are a collection of permissions outlining how users can operate with the projects. Each member of a project can have one or more roles assigned by administrators.
welcome_other_features: Other Features
welcome_feature_1_title: Gantt Chart And Calendar
welcome_feature_1_text: The gantt chart displays issues that have a start date and a due date. The calendar provides an overview of a project as a monthly view.
welcome_feature_2_title: News And Forums
welcome_feature_2_text: News to show information about the status of projects or any other subjects. The forums allow users from a project to communicate with each others.
welcome_feature_3_title: Email notifications And Feeds
welcome_feature_3_text: SuitePro can be configured to receive notifications via email. It also provides web feeds to use with external readers or aggregators.
welcome_feature_4_title: Code Repositories
welcome_feature_4_text: Version Control Systems like Git or Subversion can be used as code repositories and also keep track of changes made to the code.
welcome_feature_5_title: Responsive Design
welcome_feature_5_text: SuitePro is optimized to look great on mobile devices thanks to its responsive design. All pages adapt automatically to the screen size on a mobile phone, tablet or desktop computer.
welcome_feature_6_title: Is Open Source Software
welcome_feature_6_text: It means you are not locked into using a particular vendors system, and its continually evolving in real time as developers add to it and modify it.
welcome_any_questions: Any Questions?
welcome_please_contact: Please feel free to contact me if you need any further information.
welcome_contact: Contact
welcome_about_me: More About Me
link_my_blog: My Blog
label_legal: Legal notice
label_legal_terms: Terms of use
label_legal_privacy: Privacy policy
label_legal_cookies: Cookies policy

View file

@ -504,7 +504,7 @@ es:
label_loading: Cargando...
label_logged_as: Conectado como
label_login: Iniciar sesión
label_logout: Cerrar sesión
label_logout: Terminar sesión
label_max_size: Tamaño máximo
label_me: yo mismo
label_member: Miembro
@ -543,7 +543,7 @@ es:
label_optional_description: Descripción opcional
label_options: Opciones
label_overall_activity: Actividad global
label_overview: Resumen
label_overview: Vistazo
label_password_lost: ¿Olvidaste la contraseña?
label_permissions: Permisos
label_permissions_report: Informe de permisos
@ -1217,7 +1217,7 @@ es:
mail_body_security_notification_notify_disabled: Se han desactivado las notificaciones para el correo electrónico %{value}
mail_body_settings_updated: ! 'Las siguientes opciones han sido actualizadas:'
field_remote_ip: Dirección IP
label_wiki_page_new: Nueva página
label_wiki_page_new: Nueva pagina wiki
label_relations: Relaciones
button_filter: Filtro
mail_body_password_updated: Su contraseña se ha cambiado.
@ -1233,7 +1233,7 @@ es:
label_font_monospace: Fuente Monospaced
label_font_proportional: Fuente Proportional
setting_timespan_format: Time span format
label_table_of_contents: Tabla de contenidos
label_table_of_contents: Table of contents
setting_commit_logs_formatting: Apply text formatting to commit messages
setting_mail_handler_enable_regex_delimiters: Enable regular expressions
error_move_of_child_not_possible: 'Subtask %{child} could not be moved to the new
@ -1256,41 +1256,3 @@ es:
permission_view_news: View news
label_no_preview_alternative_html: No preview available. %{link} the file instead.
label_no_preview_download: Download
welcome_suitepro: Potencia y sencillez para planificar, compartir conocimiento, prestar soporte a clientes y acelerar la productividad.
welcome_discover: Descubre
welcome_suitepro_is_redmine: "%{suitepro} es %{redmine}, la conocida herramienta para la gestión de proyectos y el seguimiento de peticiones basada en Ruby on Rails. Redmine apremia la finalización de las tareas y mantiene la información en un único sitio."
welcome_spotlight_1_title: "Lo Básico: Proyectos,<br /> Tareas, Peticiones"
welcome_spotlight_1_text: Podrás hacer un seguimiento completo de todo, monitorizar tareas y subtareas para estar al día de los hitos de proyecto, controlar los tiempos, los flujos de trabajo o cualquier elemento que requiera atención.
welcome_spotlight_2_title: "Documentos, Wikis,<br /> Gestión de Archivos"
welcome_spotlight_2_text: Organizados para disponer de los documentos y los archivos allá donde se esté. Y el wiki de proyecto para estructurar los requerimientos, las guías de instalación y de usuario, o las actas de trabajo.
welcome_spotlight_3_title: "Control de accesos<br /> flexible"
welcome_spotlight_3_text: Usando permisos agrupados en roles para establecer cómo pueden operar los usuarios en los proyectos. Cada miembro de un proyecto podrá tener uno o más roles asignados por los administradores.
welcome_other_features: Otras Características
welcome_feature_1_title: Diagrama de Gantt y Calendario
welcome_feature_1_text: El diagrama de Gantt muestra las tareas que tienen fecha de inicio y vencimiento. Y el calendario da una visión general de los proyectos en una vista mensual.
welcome_feature_2_title: Noticias y Foros
welcome_feature_2_text: Las noticias muestran información sobre novedades en los proyectos u otros temas de interés. Y los foros permiten que los usuarios de un proyecto se comuniquen entre sí.
welcome_feature_3_title: Notificaciones y Sindicación
welcome_feature_3_text: SuitePro se puede configurar para recibir notificaciones por correo electrónico. Y también proporciona sindicaciones para utilizar con agregadores externos.
welcome_feature_4_title: Repositorios de Código
welcome_feature_4_text: Sistemas de Control de Versiones como Git o Subversion pueden usarse como repositorios de código y seguir desde SuitePro los cambios realizados en el código.
welcome_feature_5_title: Responsive Design
welcome_feature_5_text: SuitePro está optimizado para visualizarse en dispositivos móviles. Las páginas se adaptan automáticamente al tamaño de la pantalla, ya sea un teléfono móvil, una tableta o un ordenador.
welcome_feature_6_title: Es Software de Código Abierto
welcome_feature_6_text: Esto supone no estar limitado por ningún proveedor, y seguir en permanente evolución con desarrolladores que se involucran continuamente.
welcome_any_questions: ¿Alguna Pregunta?
welcome_please_contact: No dudar en contactar conmigo para obtener más información.
welcome_contact: Contactar
welcome_about_me: Más Sobre Mí
link_my_blog: Mi blog personal
label_legal: Aviso legal
label_legal_terms: Condiciones de uso
label_legal_privacy: Política de privacidad
label_legal_cookies: Uso de cookies

View file

@ -140,8 +140,8 @@ gl:
invalid: "non é válido"
confirmation: "non coincide coa confirmación"
accepted: "debe ser aceptado"
empty: "non pode estar valeiro"
blank: "non pode estar en blanco"
empty: "non pode estar baleiro"
blank: "non pode estar en branco"
too_long: "é demasiado longo (non máis de %{count} carácteres)"
too_short: "é demasiado curto (non menos de %{count} carácteres)"
wrong_length: "non ten a lonxitude correcta (debe ser de %{count} carácteres)"
@ -426,7 +426,7 @@ gl:
label_f_hour: "%{value} hora"
label_f_hour_plural: "%{value} horas"
label_feed_plural: Feeds
label_feeds_access_key_created_on: "Clave de acceso por Atom creada hai %{value}"
label_feeds_access_key_created_on: "Chave de acceso por Atom creada hai %{value}"
label_file_added: Ficheiro engadido
label_file_plural: Ficheiros
label_filter_add: Engadir o filtro
@ -435,7 +435,7 @@ gl:
label_follows: posterior a
label_gantt: Gantt
label_general: Xeral
label_generate_key: Xerar clave
label_generate_key: Xerar chave
label_help: Axuda
label_history: Histórico
label_home: Inicio
@ -648,7 +648,7 @@ gl:
notice_email_error: "Ocorreu un error enviando o correo (%{value})"
notice_email_sent: "Enviouse un correo a %{value}"
notice_failed_to_save_issues: "Imposible gravar %{count} petición(s) de %{total} seleccionada(s): %{ids}."
notice_feeds_access_key_reseted: A súa clave de acceso para Atom reiniciouse.
notice_feeds_access_key_reseted: A súa chave de acceso para Atom reiniciouse.
notice_file_not_found: A páxina á que tenta acceder non existe.
notice_locking_conflict: Os datos modificáronse por outro usuario.
notice_no_issue_selected: "Ningunha petición seleccionada. Por favor, comprobe a petición que quere modificar"
@ -720,8 +720,8 @@ gl:
setting_autofetch_changesets: Autorechear as remisións do repositorio
setting_autologin: "Identificarse automaticamente."
setting_bcc_recipients: Ocultar as copias de carbón (bcc)
setting_commit_fix_keywords: Palabras clave para a corrección
setting_commit_ref_keywords: Palabras clave para a referencia
setting_commit_fix_keywords: Palabras chave para a corrección
setting_commit_ref_keywords: Palabras chave para a referencia
setting_cross_project_issue_relations: Permitir relacionar peticións de distintos proxectos
setting_date_format: Formato da data
setting_default_language: Idioma predeterminado
@ -738,7 +738,7 @@ gl:
setting_login_required: Requírese identificación
setting_mail_from: Correo dende o que enviar mensaxes
setting_mail_handler_api_enabled: Activar o programa para mensaxes entrantes
setting_mail_handler_api_key: Clave da API
setting_mail_handler_api_key: Chave da API
setting_per_page_options: Obxectos por páxina
setting_plain_text_mail: só texto plano (non HTML)
setting_protocol: Protocolo
@ -1121,118 +1121,118 @@ gl:
setting_link_copied_issue: "Ligar aos tíckets ao copialos"
label_link_copied_issue: "Ligar ao tícket copiado"
label_ask: "Preguntar"
label_search_attachments_yes: Search attachment filenames and descriptions
label_search_attachments_no: Do not search attachments
label_search_attachments_only: Search attachments only
label_search_open_issues_only: Open issues only
label_search_attachments_yes: Buscar nomes e descricións dos ficheiros
label_search_attachments_no: Non buscar ficheiros
label_search_attachments_only: Buscar só ficheiros
label_search_open_issues_only: Só peticións abertas
field_address: Correo electrónico
setting_max_additional_emails: Maximum number of additional email addresses
label_email_address_plural: Emails
label_email_address_add: Add email address
label_enable_notifications: Enable notifications
label_disable_notifications: Disable notifications
setting_search_results_per_page: Search results per page
label_blank_value: blank
permission_copy_issues: Copy issues
error_password_expired: Your password has expired or the administrator requires you
to change it.
field_time_entries_visibility: Time logs visibility
setting_password_max_age: Require password change after
label_parent_task_attributes: Parent tasks attributes
label_parent_task_attributes_derived: Calculated from subtasks
label_parent_task_attributes_independent: Independent of subtasks
label_time_entries_visibility_all: All time entries
label_time_entries_visibility_own: Time entries created by the user
label_member_management: Member management
label_member_management_all_roles: All roles
label_member_management_selected_roles_only: Only these roles
label_password_required: Confirm your password to continue
setting_max_additional_emails: Máximo número de enderezos de correo adicionais
label_email_address_plural: Correos
label_email_address_add: Engadir enderezo de correo
label_enable_notifications: Activar notificacións
label_disable_notifications: Desactivar notificacións
setting_search_results_per_page: Resultados da busca por páxina
label_blank_value: En branco
permission_copy_issues: Copiar peticións
error_password_expired: A túa contrasinal caducou ou o administrador obrígate
a cambiala.
field_time_entries_visibility: Visibilidade das entradas de tempo
setting_password_max_age: Obrigar a cambiar a contrasinal despois de
label_parent_task_attributes: Atributos da tarefa pai
label_parent_task_attributes_derived: Calculada a partir das subtarefas
label_parent_task_attributes_independent: Independente das subtarefas
label_time_entries_visibility_all: Todas as entradas de tempo
label_time_entries_visibility_own: Horas creadas polo usuario
label_member_management: Xestión de membros
label_member_management_all_roles: Todos os roles
label_member_management_selected_roles_only: Só estes roles
label_password_required: Confirma a túa contrasinal para continuar
label_total_spent_time: "Tempo total empregado"
notice_import_finished: "%{count} items have been imported"
notice_import_finished_with_errors: "%{count} out of %{total} items could not be imported"
error_invalid_file_encoding: The file is not a valid %{encoding} encoded file
error_invalid_csv_file_or_settings: The file is not a CSV file or does not match the
settings below
error_can_not_read_import_file: An error occurred while reading the file to import
permission_import_issues: Import issues
label_import_issues: Import issues
label_select_file_to_import: Select the file to import
label_fields_separator: Field separator
label_fields_wrapper: Field wrapper
label_encoding: Encoding
label_comma_char: Comma
label_semi_colon_char: Semicolon
label_quote_char: Quote
label_double_quote_char: Double quote
label_fields_mapping: Fields mapping
label_file_content_preview: File content preview
label_create_missing_values: Create missing values
button_import: Import
field_total_estimated_hours: Total estimated time
notice_import_finished: "%{count} elementos foron importados"
notice_import_finished_with_errors: "%{count} dun total de %{total} elementos non puideron ser importados"
error_invalid_file_encoding: O ficheiro non é un ficheiro codificado %{encoding} válido
error_invalid_csv_file_or_settings: O ficheiro non é un arquivo CSV ou non coincide coas
opcións de abaixo
error_can_not_read_import_file: Aconteceu un erro lendo o ficheiro a importar
permission_import_issues: Importar peticións
label_import_issues: Importar peticións
label_select_file_to_import: Selecciona o ficheiro a importar
label_fields_separator: Separador dos campos
label_fields_wrapper: Envoltorio dos campos
label_encoding: Codificación
label_comma_char: Coma
label_semi_colon_char: Punto e coma
label_quote_char: Comilla simple
label_double_quote_char: Comilla dobre
label_fields_mapping: Mapeo de campos
label_file_content_preview: Vista previa do contido
label_create_missing_values: Crear valores non presentes
button_import: Importar
field_total_estimated_hours: Total de tempo estimado
label_api: API
label_total_plural: Totals
label_assigned_issues: Assigned issues
label_field_format_enumeration: Key/value list
label_total_plural: Totais
label_assigned_issues: Peticións asignadas
label_field_format_enumeration: Listaxe chave/valor
label_f_hour_short: '%{value} h'
field_default_version: Default version
error_attachment_extension_not_allowed: Attachment extension %{extension} is not allowed
setting_attachment_extensions_allowed: Allowed extensions
setting_attachment_extensions_denied: Disallowed extensions
label_any_open_issues: any open issues
label_no_open_issues: no open issues
label_default_values_for_new_users: Default values for new users
error_ldap_bind_credentials: Invalid LDAP Account/Password
setting_sys_api_key: Clave da API
setting_lost_password: "Esqueceu o contrasinal?"
mail_subject_security_notification: Security notification
mail_body_security_notification_change: ! '%{field} was changed.'
mail_body_security_notification_change_to: ! '%{field} was changed to %{value}.'
mail_body_security_notification_add: ! '%{field} %{value} was added.'
mail_body_security_notification_remove: ! '%{field} %{value} was removed.'
mail_body_security_notification_notify_enabled: Email address %{value} now receives
notifications.
mail_body_security_notification_notify_disabled: Email address %{value} no longer
receives notifications.
mail_body_settings_updated: ! 'The following settings were changed:'
field_remote_ip: IP address
label_wiki_page_new: New wiki page
label_relations: Relations
button_filter: Filter
mail_body_password_updated: Your password has been changed.
label_no_preview: No preview available
error_no_tracker_allowed_for_new_issue_in_project: The project doesn't have any trackers
for which you can create an issue
label_tracker_all: All trackers
label_new_project_issue_tab_enabled: Display the "New issue" tab
setting_new_item_menu_tab: Project menu tab for creating new objects
label_new_object_tab_enabled: Display the "+" drop-down
error_no_projects_with_tracker_allowed_for_new_issue: There are no projects with trackers
for which you can create an issue
field_textarea_font: Font used for text areas
label_font_default: Default font
label_font_monospace: Monospaced font
label_font_proportional: Proportional font
setting_timespan_format: Time span format
label_table_of_contents: Table of contents
setting_commit_logs_formatting: Apply text formatting to commit messages
setting_mail_handler_enable_regex_delimiters: Enable regular expressions
error_move_of_child_not_possible: 'Subtask %{child} could not be moved to the new
project: %{errors}'
error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Spent time cannot
be reassigned to an issue that is about to be deleted
setting_timelog_required_fields: Required fields for time logs
field_default_version: Versión predeterminada
error_attachment_extension_not_allowed: A extensión anexada %{extension} non é permitida
setting_attachment_extensions_allowed: Extensións permitidas
setting_attachment_extensions_denied: Extensións prohibidas
label_any_open_issues: Calquera petición aberta
label_no_open_issues: Peticións non abertas
label_default_values_for_new_users: Valor predeterminado para novos usuarios
error_ldap_bind_credentials: A conta/contrasinal do LDAP non é válida
setting_sys_api_key: Chave da API
setting_lost_password: Esqueceu a contrasinal?
mail_subject_security_notification: Notificación de seguridade
mail_body_security_notification_change: ! '%{field} modificado.'
mail_body_security_notification_change_to: ! '%{field} modificado por %{value}.'
mail_body_security_notification_add: ! '%{field} %{value} engadido.'
mail_body_security_notification_remove: ! '%{field} %{value} eliminado.'
mail_body_security_notification_notify_enabled: O correo electrónico %{value} agora recibirá
notificacións
mail_body_security_notification_notify_disabled: O correo electrónico %{value} deixará de recibir
notificacións
mail_body_settings_updated: ! 'As seguintes opcións foron actualizadas:'
field_remote_ip: Enderezo IP
label_wiki_page_new: Nova páxina wiki
label_relations: Relacións
button_filter: Filtro
mail_body_password_updated: A súa contrasinal foi cambiada.
label_no_preview: Non hai vista previa dispoñible
error_no_tracker_allowed_for_new_issue_in_project: O proxecto non ten ningún tipo
para que poida crear unha petición
label_tracker_all: Tódolos tipos
label_new_project_issue_tab_enabled: Amosar a lapela "Nova petición"
setting_new_item_menu_tab: Lapela no menú de cada proxecto para creación de novos obxectos
label_new_object_tab_enabled: Amosar a lista despregable "+"
error_no_projects_with_tracker_allowed_for_new_issue: Non hai proxectos con tipos
para as que poida crear unha petición
field_textarea_font: Fonte usada nas áreas de texto
label_font_default: Fonte por defecto
label_font_monospace: Fonte Monospaced
label_font_proportional: Fonte Proporcional
setting_timespan_format: Formato de período temporal
label_table_of_contents: Índice de contidos
setting_commit_logs_formatting: Aplicar formateo de texto para as mensaxes de commit
setting_mail_handler_enable_regex_delimiters: Activar expresións regulares
error_move_of_child_not_possible: 'A subtarefa %{child} non se pode mover ao novo
proxecto: %{errors}'
error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: O tempo empregado non pode
ser reasignado a unha petición que vai ser eliminada
setting_timelog_required_fields: Campos obrigatorios para as imputacións de tempo
label_attribute_of_object: '%{object_name}''s %{name}'
label_user_mail_option_only_assigned: Only for things I watch or I am assigned to
label_user_mail_option_only_owner: Only for things I watch or I am the owner of
warning_fields_cleared_on_bulk_edit: Changes will result in the automatic deletion
of values from one or more fields on the selected objects
field_updated_by: Updated by
field_last_updated_by: Last updated by
field_full_width_layout: Full width layout
label_last_notes: Last notes
field_digest: Checksum
field_default_assigned_to: Default assignee
setting_show_custom_fields_on_registration: Show custom fields on registration
permission_view_news: View news
label_no_preview_alternative_html: No preview available. %{link} the file instead.
label_no_preview_download: Download
label_user_mail_option_only_assigned: Só para as cousas que sigo ou que teño asignado
label_user_mail_option_only_owner: Só para as cousas que sigo ou son o propietario
warning_fields_cleared_on_bulk_edit: Os cambios provocarán o borrado automático
dos valores de un ou máis campos dos obxectos seleccionados
field_updated_by: Actualizado por
field_last_updated_by: Última actualización por
field_full_width_layout: Deseño para ancho completo
label_last_notes: Últimas notas
field_digest: Suma de verificación
field_default_assigned_to: Asignado por defecto
setting_show_custom_fields_on_registration: Amosar os campos personalizados no rexistro
permission_view_news: Ver noticias
label_no_preview_alternative_html: Non hai vista previa dispoñible. %{link} o ficheiro no seu lugar.
label_no_preview_download: Descargar

View file

@ -618,7 +618,7 @@ ja:
one: 1コメント
other: "%{count}コメント"
label_comment_add: コメント追加
label_comment_added: 追加されたコメント
label_comment_added: コメントが追加されました
label_comment_delete: コメント削除
label_query: カスタムクエリ
label_query_plural: カスタムクエリ

View file

@ -890,7 +890,7 @@ lt:
label_version_sharing_none: Nesidalinama
label_version_sharing_descendants: Su sub-projektais
label_version_sharing_hierarchy: Su projekto hierarchija
label_version_sharing_tree: WiSu projekto medžiu
label_version_sharing_tree: Su projekto medžiu
label_version_sharing_system: Su visais projektais
label_update_issue_done_ratios: Atnaujinti darbo atlikimo progresą
label_copy_source: Šaltinis

View file

@ -149,9 +149,9 @@ pt-BR:
not_same_project: "não pertence ao mesmo projeto"
circular_dependency: "Esta relação geraria uma dependência circular"
cant_link_an_issue_with_a_descendant: "Uma tarefa não pode ser relacionada a uma de suas subtarefas"
earlier_than_minimum_start_date: "cannot be earlier than %{date} because of preceding issues"
not_a_regexp: "is not a valid regular expression"
open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task"
earlier_than_minimum_start_date: "não pode ser anterior a %{date} por causa de tarefas anteriores"
not_a_regexp: "não é uma expressão regular válida"
open_issue_with_closed_parent: "Uma tarefa aberta não pode ser associada à uma tarefa pai fechada"
actionview_instancetag_blank_option: Selecione
@ -159,7 +159,7 @@ pt-BR:
general_text_Yes: 'Sim'
general_text_no: 'não'
general_text_yes: 'sim'
general_lang_name: 'Portuguese/Brasil (Português/Brasil)'
general_lang_name: 'Portuguese/Brazil (Português/Brasil)'
general_csv_separator: ';'
general_csv_decimal_separator: ','
general_csv_encoding: ISO-8859-1
@ -1125,7 +1125,7 @@ pt-BR:
label_group_non_member: Usuários não membros
label_add_projects: Adicionar projetos
field_default_status: Situação padrão
text_subversion_repository_note: 'Examplos: file:///, http://, https://, svn://, svn+[tunnelscheme]://'
text_subversion_repository_note: 'Exemplos: file:///, http://, https://, svn://, svn+[tunnelscheme]://'
field_users_visibility: Visibilidade do usuário
label_users_visibility_all: Todos usuários ativos
label_users_visibility_members_of_visible_projects: Membros de projetos visíveis

View file

@ -1166,7 +1166,7 @@ ru:
label_cross_project_system: Со всеми проектами
button_hide: Скрыть
setting_non_working_week_days: Нерабочие дни
label_in_the_next_days: в средующие дни
label_in_the_next_days: в следующие дни
label_in_the_past_days: в прошлые дни
label_attribute_of_user: Пользователь %{name}
text_turning_multiple_off: Если отключить множественные значения, лишние значения из списка будут удалены, чтобы осталось только по одному значению.

View file

@ -134,7 +134,7 @@ sv:
not_same_project: "tillhör inte samma projekt"
circular_dependency: "Denna relation skulle skapa ett cirkulärt beroende"
cant_link_an_issue_with_a_descendant: "Ett ärende kan inte länkas till ett av dess underärenden"
earlier_than_minimum_start_date: "kan inte vara tidigare än% {datum} på grund av föregående ärenden"
earlier_than_minimum_start_date: "kan inte vara tidigare än %{date} på grund av föregående ärenden"
not_a_regexp: "is not a valid regular expression"
open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task"

View file

@ -1215,12 +1215,12 @@ uk:
field_updated_by: Оновлено
field_last_updated_by: Востаннє оновлено
field_full_width_layout: Макет на повну ширину
label_user_mail_option_only_assigned: Only for things I watch or I am assigned to
label_user_mail_option_only_owner: Only for things I watch or I am the owner of
label_last_notes: Last notes
field_digest: Checksum
field_default_assigned_to: Default assignee
setting_show_custom_fields_on_registration: Show custom fields on registration
permission_view_news: View news
label_no_preview_alternative_html: No preview available. %{link} the file instead.
label_no_preview_download: Download
label_user_mail_option_only_assigned: Лише для об'єктів за якими я спостерігаю або до яких прикріплений
label_user_mail_option_only_owner: Лише для об'єктів за якими я спостерігаю або є власником
label_last_notes: Останні коментарі
field_digest: Контрольна сума
field_default_assigned_to: Призначити по замовчуванню
setting_show_custom_fields_on_registration: Показувати додаткові поля при реєстрації
permission_view_news: Переглядати новини
label_no_preview_alternative_html: Попередній перегляд недоступний. %{link} файл натомість.
label_no_preview_download: Завантажити

View file

@ -304,7 +304,7 @@ zh:
field_comments_sorting: 显示注释
field_parent_title: 上级页面
field_editable: 可编辑
field_watcher: 跟踪
field_watcher: 关注
field_identity_url: OpenID URL
field_content: 内容
field_group_by: 根据此条件分组
@ -393,9 +393,9 @@ zh:
permission_save_queries: 保存查询
permission_view_gantt: 查看甘特图
permission_view_calendar: 查看日历
permission_view_issue_watchers: 查看跟踪者列表
permission_add_issue_watchers: 添加跟踪
permission_delete_issue_watchers: 删除跟踪
permission_view_issue_watchers: 查看关注者列表
permission_add_issue_watchers: 添加关注
permission_delete_issue_watchers: 删除关注
permission_log_time: 登记工时
permission_view_time_entries: 查看耗时
permission_edit_time_entries: 编辑耗时
@ -675,7 +675,7 @@ zh:
label_options: 选项
label_copy_workflow_from: 从以下选项复制工作流程
label_permissions_report: 权限报表
label_watched_issues: 跟踪的问题
label_watched_issues: 关注的问题
label_related_issues: 相关的问题
label_applied_status: 应用后的状态
label_loading: 载入中...
@ -731,7 +731,7 @@ zh:
label_user_mail_option_all: "收取我的项目的所有通知"
label_user_mail_option_selected: "收取选中项目的所有通知..."
label_user_mail_option_none: "不收取任何通知"
label_user_mail_option_only_my_events: "只收取我跟踪或参与的项目的通知"
label_user_mail_option_only_my_events: "只收取我关注或参与的项目的通知"
label_user_mail_no_self_notified: "不要发送对我自己提交的修改的通知"
label_registration_activation_by_email: 通过邮件认证激活帐号
label_registration_manual_activation: 手动激活帐号
@ -751,7 +751,7 @@ zh:
label_reverse_chronological_order: 按时间顺序(倒序)
label_incoming_emails: 接收邮件
label_generate_key: 生成一个key
label_issue_watchers: 跟踪
label_issue_watchers: 关注
label_example: 示例
label_display: 显示
label_sort: 排序
@ -811,8 +811,8 @@ zh:
button_sort: 排序
button_log_time: 登记工时
button_rollback: 恢复到这个版本
button_watch: 跟踪
button_unwatch: 取消跟踪
button_watch: 关注
button_unwatch: 取消关注
button_reply: 回复
button_archive: 存档
button_unarchive: 取消存档
@ -866,7 +866,7 @@ zh:
text_issue_category_destroy_question: "有一些问题(%{count} 个)属于此类别。您想进行哪种操作?"
text_issue_category_destroy_assignments: 删除问题的所属类别(问题变为无类别)
text_issue_category_reassign_to: 为问题选择其它类别
text_user_mail_option: "对于没有选中的项目,您将只会收到您跟踪或参与的项目的通知(比如说,您是问题的报告者, 或被指派解决此问题)。"
text_user_mail_option: "对于没有选中的项目,您将只会收到您关注或参与的项目的通知(比如说,您是问题的报告者, 或被指派解决此问题)。"
text_no_configuration_data: "角色、跟踪标签、问题状态和工作流程还没有设置。\n强烈建议您先载入默认设置然后在此基础上进行修改。"
text_load_default_configuration: 载入默认设置
text_status_changed_by_changeset: "已应用到变更列表 %{value}."
@ -1008,7 +1008,7 @@ zh:
text_issue_conflict_resolution_cancel: 取消我所有的变更并重新刷新显示 %{link} 。
permission_manage_related_issues: 相关问题管理
field_auth_source_ldap_filter: LDAP 过滤器
label_search_for_watchers: 通过查找方式添加跟踪
label_search_for_watchers: 通过查找方式添加关注
notice_account_deleted: 您的账号已被永久删除(账号已无法恢复)。
setting_unsubscribe: 允许用户退订
button_delete_my_account: 删除我的账号

View file

@ -4,6 +4,340 @@ Redmine - project management software
Copyright (C) 2006-2017 Jean-Philippe Lang
http://www.redmine.org/
== 2019-12-20 v3.4.13
=== [Attachments]
* Defect #20277: "Couldn't find template for digesting" error in the log when sending a thumbnail or an attachment
=== [Gems support]
* Patch #32592: Require 'mocha/minitest' instead of deprecated 'mocha/setup'
=== [Text formatting]
* Patch #25742: Improper markup sanitization in user content for space separated attribute values and different quoting styles
== 2019-10-19 v3.4.12
=== [Code cleanup/refactoring]
* Defect #32022: IssueSubtaskingTest fails with high probability
=== [Documentation]
* Defect #32170: Text enclosed in pre tag in Wiki formatting reference is not displayed in monospaced font in Chrome
* Defect #32184: Incorrect headings example in Textile help
=== [Gems support]
* Defect #32300: Don't use sprockets 4.0.0 in order to avoid Sprockets::Railtie::ManifestNeededError
* Patch #32294: Update ruby-openid to 2.9.2
=== [Issues]
* Defect #31778: Total estimated time issue query column and issue field might leak information
=== [Issues list]
* Defect #31779: Total estimated time column shown even when estimated time field is deactivated
=== [Translations]
* Defect #32290: Typo in Russian translation for label_in_the_next_days
=== [UI]
* Defect #32012: Broken JavaScript icon in the repository view
* Defect #32024: Broken gzip icon in the repository view
== 2019-06-10 v3.4.11
=== [Administration]
* Defect #31125: Don't output ImageMagick version information to stdout
=== [Code cleanup/refactoring]
* Defect #30811: "rake db:fixtures:load" does not work
=== [Email receiving]
* Defect #30457: MailHandler.safe_receive does not output any error log
* Defect #31503: Undefined local variable sender_email in MailHandler#receive_message_reply
=== [Issues filter]
* Patch #31276: Serialize group_by and totalable_names in Query#as_params
=== [SCM]
* Defect #31120: Garbage lines in the output of 'git branch' break git adapter
=== [Security]
* Defect #31520: Persistent XSS in textile formatting
=== [Translations]
* Defect #31264: Conflicting translation between "track" and "watch" in Simplified Chinese
=== [UI - Responsive]
* Defect #31153: Display horizontal scroll bar of files table when overflow occurs on small screen
* Defect #31311: admin/info page: text cut off in pre tag on mobile
=== [Wiki]
* Patch #31334: Do not lose content when updating a wiki page that has been renamed in the meantime
== 2019-03-31 v3.4.10
=== [Administration]
* Defect #30939: Timeout for "Check for updates" on Plugins page is too short
=== [Files]
* Defect #31087: Deleting a version silently deletes its attachments
=== [Issues filter]
* Defect #30367: "Last updated by" filter causes an SQL error with MariaDB
=== [REST API]
* Defect #29055: Searching for issue number with REST API redirects to issue HTML page
=== [Rails support]
* Feature #31027: Upgrade to Rails 4.2.11.1
=== [Search engine]
* Defect #30923: Project search should select subprojects scope when the project has subprojects
=== [UI]
* Defect #30872: Copyright is outdated
== 2019-02-21 v3.4.9
=== [Gems support]
* Defect #30114: Installing xpath with Bundler fails in Ruby <=2.2
* Patch #30821: Stay in RMagick 2.16.0 and don't update to 3.0.0
=== [UI]
* Patch #30818: Issues autocomplete should respond with content type json
== 2019-01-20 v3.4.8
=== [Code cleanup/refactoring]
* Patch #30413: Add ".ruby-version" to svn:ignore, .git:ignore, and .hgignore
=== [Database]
* Defect #30171: Decrypting LDAP and SCM passwords fail if the plaintext password is longer than 31 bytes
=== [Gems support]
* Defect #30353: Installing rails with Bundler 2.0 fails in 3.x
=== [Importers]
* Patch #30412: Import UTF-8 issue CSV files with BOM and quoted strings
=== [Translations]
* Patch #30293: Ukrainian translation update for 3.4-stable
=== [UI]
* Defect #30426: Table rows are not highlighted on mouseover on some pages
* Patch #29951: Quick design fix/proposals for projects index page
== 2018-12-09 v3.4.7
=== [Custom fields]
* Defect #8317: Strip whitespace from integer custom field
* Defect #28925: Custom field values for enumerations not saved
* Patch #29674: Missing validation for custom field formats based on RecordList
=== [Email receiving]
* Defect #28576: Attachments are added even if validation fails when updating an issue via email
* Defect #29191: Cannot set no_notification option when receiving emails via IMAP or POP3
=== [Importers]
* Defect #30001: CSV importer ignores shared version names of other projects
=== [Issues]
* Defect #28946: If assignee is locked subtasks don't get copied
* Defect #30009: Empty sort criteria for issue query gives error
* Defect #30027: Some styles (for ex: borders for tables) in a custom field with text formatting enabled are not displayed
=== [Issues filter]
* Defect #26785: Wrong columns after CSV export
=== [PDF export]
* Defect #28125: PNG images on a wiki page don't appear in exported PDF
* Defect #28565: PDF export has too many whitespaces
=== [REST API]
* Defect #20788: REST API with JSON content missing attributes with false values
=== [Rails support]
* Feature #30043: Update Rails to 4.2.11
=== [SCM]
* Defect #29413: Mercurial 4.7 compatibility
=== [Search engine]
* Defect #28636: Cannot find an issue from a closed subproject when search scope is Project and its subprojects
=== [Text formatting]
* Defect #8395: Tags start with 'pre' are handled as 'pre' tag in Textile
* Defect #29038: Thumbnail macro causes attachment file not found and broken filename and link
* Defect #29247: Textile phrase modifiers break wiki macros
* Defect #29756: \f or \v character in Textile markup may cause RegexpError exception
=== [Time tracking]
* Patch #29308: Time entry creation: preserve 'spent on' value when using 'Create and Continue'
=== [Translations]
* Patch #29702: Brazilian wiki help translation update
* Patch #29703: Brazilian translation (jstoolbar-pt-br.js) update
* Patch #29718: Brazilian translation update for 3.4-stable
* Patch #29735: Galician translation fix for the words empty, blank, and key
* Patch #29736: Galician translation update for 3.4-stable
=== [UI]
* Defect #29918: Related issues section ignores the date format setting
* Defect #29950: Fix list rendering inside project description in projects#index
=== [UI - Responsive]
* Defect #24309: Setting page for repository does not scroll horizontally on small screens
=== [Wiki]
* Feature #29791: Hide "Files" section in wiki pages when printing
== 2018-06-10 v3.4.6
=== [Issues]
* Defect #27863: If version is closed or locked subtasks don't get copied
* Defect #28765: Copying an issue fails if the issue is watched by a locked user
* Patch #28649: Log automatic rescheduling of following issues to journal
=== [Permissions and roles]
* Defect #28693: Irrelevant permission is required to access some tabs in project settings page
=== [Project settings]
* Defect #27122: Filter for version name should be case-insensitive
=== [SCM]
* Defect #28725: Mercurial 4.6 compatibility
=== [Text formatting]
* Defect #28469: Syntax highlighter does not work if language name is single-quoted
=== [Translations]
* Patch #28881: Fix Japanese mistranslation for label_comment_added
=== [UI]
* Defect #22023: Issue id input should get focus after adding related issue
=== [UI - Responsive]
* Defect #28523: Display horizontal scroll bar of plugins table when overflow occurs on small screen
=== [Wiki]
* Patch #27090: Show the number of attachments on wiki pages
== 2018-04-07 v3.4.5
=== [Custom fields]
* Defect #28393: Sort issue custom fields by position in tracker UI
=== [Email notifications]
* Defect #28302: Security notification when changing password on password forgotten is empty
=== [Gantt]
* Defect #28204: Too large avatar breaks gantt when assignee is a group
=== [Issues]
* Defect #27862: Preformatted text overflows in preview
* Patch #28168: Allow context-menu edit of % done and priority of parent issues if the fields are not derived
=== [Issues filter]
* Defect #28180: Role-base cross-project issue query visibility calculated incorrectly
=== [Plugin API]
* Patch #27963: Remove 'unloadable' from bundled sample plugin
=== [Security]
* Defect #26857: Fix for CVE-2015-9251 in JQuery 1.11.1
=== [Text formatting]
* Defect #27884: RTL wiki class broken in Redmine 3.2.6
* Defect #28331: h4, h5 and h6 headings on wiki pages should have a paragraph mark
* Patch #28119: Enable lax_spacing for markdown formatting in order to allow markdown blocks not surrounded by empty lines
=== [Time tracking]
* Defect #28110: Don't allow reassigning reported hours to the project if issue is a required field for time logs
=== [Translations]
* Defect #28109: Incorrect interpolation in Swedish locale
* Defect #28113: Fix typo in German label_font_default
* Defect #28192: Fix typo in German label_font_monospace
* Patch #27994: Galician translation update (jstoolbar-gl.js)
* Patch #28102: Fix typo in Lithuanian label_version_sharing_tree
=== [UI]
* Defect #28079: The green tick is positioned after the label in the new member modals
* Defect #28208: Anonymous icon is wrongly displayed when assignee is a group
* Defect #28259: attachments_fields id to class change not properly reflected in all CSS
=== [Wiki]
* Defect #25299: Markdown pre-block could derive incorrect wiki sections
== 2018-01-08 v3.4.4
=== [Accounts / authentication]

View file

@ -1,7 +1,5 @@
# Sample plugin controller
class ExampleController < ApplicationController
unloadable
layout 'base'
before_action :find_project, :authorize
menu_item :sample_plugin

View file

@ -126,7 +126,7 @@ Redmine::AccessControl.map do |map|
map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
map.permission :manage_project_activities, {:projects => :settings, :project_enumerations => [:update, :destroy]}, :require => :member
end
map.project_module :news do |map|
@ -164,7 +164,7 @@ Redmine::AccessControl.map do |map|
map.permission :browse_repository, {:repositories => [:show, :browse, :entry, :raw, :annotate, :changes, :diff, :stats, :graph]}, :read => true
map.permission :commit_access, {}
map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]}
map.permission :manage_repository, {:repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
map.permission :manage_repository, {:projects => :settings, :repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
end
map.project_module :boards do |map|
@ -174,7 +174,7 @@ Redmine::AccessControl.map do |map|
map.permission :edit_own_messages, {:messages => :edit, :attachments => :upload}, :require => :loggedin
map.permission :delete_messages, {:messages => :destroy}, :require => :member
map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
map.permission :manage_boards, {:projects => :settings, :boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
end
map.project_module :calendar do |map|

View file

@ -33,7 +33,7 @@ module Redmine
c.iv = iv
e = c.update(text.to_s)
e << c.final
"aes-256-cbc:" + [e, iv].map {|v| Base64.encode64(v).strip}.join('--')
"aes-256-cbc:" + [e, iv].map {|v| Base64.strict_encode64(v)}.join('--')
end
end

View file

@ -486,7 +486,7 @@ module Redmine
def validate_single_value(custom_field, value, customized=nil)
errs = super
errs << ::I18n.t('activerecord.errors.messages.not_a_number') unless value.to_s =~ /^[+-]?\d+$/
errs << ::I18n.t('activerecord.errors.messages.not_a_number') unless value.to_s.strip =~ /^[+-]?\d+$/
errs
end
@ -736,6 +736,16 @@ module Redmine
options
end
def validate_custom_value(custom_value)
values = Array.wrap(custom_value.value).reject {|value| value.to_s == ''}
invalid_values = values - possible_custom_value_options(custom_value).map(&:last)
if invalid_values.any?
[::I18n.t('activerecord.errors.messages.inclusion')]
else
[]
end
end
def order_statement(custom_field)
if target_class.respond_to?(:fields_for_order_statement)
target_class.fields_for_order_statement(value_join_alias(custom_field))

View file

@ -81,7 +81,7 @@ module Redmine
# below : list unreadable files, but dont link them.
:path => utf_8_path,
:kind => (File.directory?(t1) ? 'dir' : 'file'),
:size => (File.directory?(t1) ? nil : [File.size(t1)].pack('l').unpack('L').first),
:size => (File.directory?(t1) ? nil : File.size(t1)),
:lastrev =>
Revision.new({:time => (File.mtime(t1)) })
})

View file

@ -83,6 +83,7 @@ module Redmine
io.each_line do |line|
branch_rev = line.match('\s*(\*?)\s*(.*?)\s*([0-9a-f]{40}).*$')
bran = GitBranch.new(branch_rev[2])
next unless branch_rev
bran.revision = branch_rev[3]
bran.scmid = branch_rev[3]
bran.is_default = ( branch_rev[1] == '*' )

View file

@ -46,14 +46,22 @@ Output example of rhmanifest::
</rhmanifest>
"""
import re, time, cgi, urllib
from mercurial import cmdutil, commands, node, error, hg
from mercurial import cmdutil, commands, node, error, hg, registrar
cmdtable = {}
command = cmdutil.command(cmdtable)
command = registrar.command(cmdtable) if hasattr(registrar, 'command') else cmdutil.command(cmdtable)
_x = cgi.escape
_u = lambda s: cgi.escape(urllib.quote(s))
def _changectx(repo, rev):
if isinstance(rev, str):
rev = repo.lookup(rev)
if hasattr(repo, 'changectx'):
return repo.changectx(rev)
else:
return repo[rev]
def _tip(ui, repo):
# see mercurial/commands.py:tip
def tiprev():
@ -61,7 +69,7 @@ def _tip(ui, repo):
return len(repo) - 1
except TypeError: # Mercurial < 1.1
return repo.changelog.count() - 1
tipctx = repo.changectx(tiprev())
tipctx = _changectx(repo, tiprev())
ui.write('<tip revision="%d" node="%s"/>\n'
% (tipctx.rev(), _x(node.hex(tipctx.node()))))
@ -94,13 +102,18 @@ def _branches(ui, repo):
return repo.branchheads(branch, closed=False)
except TypeError: # Mercurial < 1.2
return repo.branchheads(branch)
def lookup(rev, n):
try:
return repo.lookup(rev)
except RuntimeError:
return n
for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True):
if repo.lookup(r) in branchheads(t):
if lookup(r, n) in branchheads(t):
ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
% (r, _x(node.hex(n)), _x(t)))
def _manifest(ui, repo, path, rev):
ctx = repo.changectx(rev)
ctx = _changectx(repo, rev)
ui.write('<manifest revision="%d" path="%s">\n'
% (ctx.rev(), _u(path)))
@ -155,7 +168,7 @@ def rhdiff(ui, repo, *pats, **opts):
"""diff repository (or selected files)"""
change = opts.pop('change', None)
if change: # add -c option for Mercurial<1.1
base = repo.changectx(change).parents()[0].rev()
base = _changectx(repo, change).parents()[0].rev()
opts['rev'] = [str(base), change]
opts['nodates'] = True
return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)

View file

@ -87,6 +87,7 @@ module Redmine
private
def normalize!
self.reject! {|s| s.first.blank? }
self.collect! {|s| s = Array(s); [s.first, (s.last == false || s.last.to_s == 'desc') ? 'desc' : 'asc']}
self.slice!(3)
self

View file

@ -49,7 +49,12 @@ module Redmine
def self.convert_available?
return @convert_available if defined?(@convert_available)
@convert_available = system("#{shell_quote CONVERT_BIN} -version") rescue false
begin
`#{shell_quote CONVERT_BIN} -version`
@convert_available = $?.success?
rescue
@convert_available = false
end
logger.warn("Imagemagick's convert binary (#{CONVERT_BIN}) not available") unless @convert_available
@convert_available
end

View file

@ -4,7 +4,7 @@ module Redmine
module VERSION #:nodoc:
MAJOR = 3
MINOR = 4
TINY = 4
TINY = 13
# Branch values:
# * official release: nil

View file

@ -48,7 +48,7 @@ module Redmine
end
def method_missing(sym, *args, &block)
if args.any?
if args.count > 0
if args.first.is_a?(Hash)
if @struct.last.is_a?(Array)
@struct.last << args.first unless block

View file

@ -94,15 +94,13 @@ module Redmine
i = 0
l = 1
inside_pre = false
@text.split(/(^(?:.+\r?\n\r?(?:\=+|\-+)|#+.+|~~~.*)\s*$)/).each do |part|
@text.split(/(^(?:.+\r?\n\r?(?:\=+|\-+)|#+.+|(?:~~~|```).*)\s*$)/).each do |part|
level = nil
if part =~ /\A~{3,}(\S+)?\s*$/
if $1
if part =~ /\A(~{3,}|`{3,})(\S+)?\s*$/
if !inside_pre
inside_pre = true
end
else
inside_pre = !inside_pre
elsif !$2
inside_pre = false
end
elsif inside_pre
# nop
@ -142,7 +140,8 @@ module Redmine
:strikethrough => true,
:superscript => true,
:no_intra_emphasis => true,
:footnotes => true
:footnotes => true,
:lax_spacing => true
)
end
end

View file

@ -120,9 +120,10 @@ module Redmine
## replace <pre> content
text.gsub!(/<redpre#(\d+)>/) do
content = @pre_list[$1.to_i]
if content.match(/<code\s+class="(\w+)">\s?(.+)/m)
language = $1
text = $2
# This regex must match any data produced by RedCloth3#rip_offtags
if content.match(/<code\s+class=(?:"([^"]+)"|'([^']+)')>\s?(.*)/m)
language = $1 || $2
text = $3
if Redmine::SyntaxHighlighting.language_supported?(language)
content = "<code class=\"#{language} syntaxhl\">" +
Redmine::SyntaxHighlighting.highlight_by_language(text, language)

View file

@ -343,7 +343,7 @@ class RedCloth3 < String
A_VLGN = /[\-^~]/
C_CLAS = '(?:\([^")]+\))'
C_LNGE = '(?:\[[a-z\-_]+\])'
C_STYL = '(?:\{[^"}]+\})'
C_STYL = '(?:\{[^{][^"}]+\})'
S_CSPN = '(?:\\\\\d+)'
S_RSPN = '(?:/\d+)'
A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
@ -1034,7 +1034,7 @@ class RedCloth3 < String
def flush_left( text )
indt = 0
if text =~ /^ /
while text !~ /^ {#{indt}}\S/
while text !~ /^ {#{indt}}[^ ]/
indt += 1
end unless text.empty?
if indt.nonzero?
@ -1049,7 +1049,7 @@ class RedCloth3 < String
end
OFFTAGS = /(code|pre|kbd|notextile)/
OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }\W|\Z)/mi
OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }\b>)|(<#{ OFFTAGS }\b[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }\b\W|\Z)/mi
OFFTAG_OPEN = /<#{ OFFTAGS }/
OFFTAG_CLOSE = /<\/?#{ OFFTAGS }/
HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m
@ -1213,7 +1213,13 @@ class RedCloth3 < String
ALLOWED_TAGS = %w(redpre pre code kbd notextile)
def escape_html_tags(text)
text.gsub!(%r{<(\/?([!\w]+)[^<>\n]*)(>?)}) {|m| ALLOWED_TAGS.include?($2) ? "<#{$1}#{$3}" : "&lt;#{$1}#{'&gt;' unless $3.blank?}" }
text.gsub!(%r{<(\/?([!\w]+)[^<>\n]*)(>?)}) do |m|
if ALLOWED_TAGS.include?($2) && $3.present?
"<#{$1}#{$3}"
else
"&lt;#{$1}#{'&gt;' unless $3.blank?}"
end
end
end
end

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -209,7 +209,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Nadpis 1. úrovně
h2. Nadpis 2. úrovně
h3. Nadpis 3. úrovně
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Titre
h2. Sous-titre
h3. Sous-sous-titre
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

View file

@ -200,7 +200,9 @@ http://www.redmine.org, someone@foo.bar
<pre>
h1. Heading
h2. Subheading
h3. Subsubheading
</pre>

Some files were not shown because too many files have changed in this diff Show more